Kodları lütfen aşağıdaki butonları kullanarak renklendirin. Örnek: <php> echo "Selam Dünya"; </php>
Yardım
karakter kaldı

Php - MySql Kategori : (Nested Set Model)

Merhaba Arkadaşlar,
Php ile Hiyeraşik Kategorileme sistemi yapmak istiyorum ancak bir türlü beceremedim :(
Yardımcı olursanız çok sevinirim yabancı kaynaklarda vs cok aradım ama bir türlü olamdı... :(((

Tablo Yapım Şu Şekilde ;

kategori_id kategori_adi kategori_sol kategori_sag kategori_seviye
1 root 1 2 0

Yapmak istediğim şey tam olarak;
Yeni bir kategori eklendiğinde kategori_id ne göre kategori_seviye değeri otomatik olarak artacak böylece kategoriler arasında bir sıkısma olmamıs olacak.

Insert, Update, Delete işlemleri için sade ve temiz yazılmıs bir örnek varmı yardımlarınızı bekliyorum..

Teşekkürler

Şöyle bir Örnek Buldum Ama class yapılarına hakim olmadığım için hiç bişi anlamadım :(
Ancak aradığım aslında tam olarak bu şekilde (Ekleme, Silme, Güncelleme, Taşıma) işlemini yapmakta bunu normal bir şekilde yapma imkanımız varmı ???
Örnek;
index.php

<?php
/**
* $Id: dbtree_demo.php,v 2.0 2005/09/08 19:32:45 Kuzma Exp $
*
* Copyright (C) 2005 Kuzma Feskov <kuzma@russofile.ru>
*
* This file may be distributed and/or modified under the terms of the
* "GNU General Public License" version 2 as published by the Free
* Software Foundation and appearing in the file LICENSE included in
* the packaging of this file.
*
* This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING
* THE WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE.
*
* The "GNU General Public License" (GPL) is available at
* http:*www.gnu.org/copyleft/gpl.html.
*/

ob_start();
?>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<html>
<head>
<title>DB Tree - Demo sample</title>
<meta http-equiv="content-type" content="text/html; charset=UTF-8">
<meta name="author" content="Kuzma Feskov (kuzma@russofile.ru)">
</head>
<body>
<h2>TB Tree class demo by Kuzma Feskov</h2>
[<a href="dbtree_visual_demo.php?mode=map">Visual demo (Site map)</a>] [<a href="dbtree_visual_demo.php?mode=ajar">Visual demo (Ajar tree)</a>] [<a href="dbtree_visual_demo.php?mode=branch">Visual demo (Branch)</a>]
<?php

// DB CLASS: adodb or db_mysql
define('DB_CLASS', 'db_mysql');

/** DB Host */
define('DB_HOST', 'localhost');

/** DB user name */
$DB_USER = 'root';

/** DB user password */
$DB_PASSWORD = '';

/** DB name */
define('DB_BASE_NAME', 'sample_dump');

/** Global cache settings */
define('DB_CACHE', FALSE);

/* ------------------------ ADDOB SETTINGS ------------------------ */
if (DB_CLASS == 'adodb') {
    /** Path to ADODB */
    define('ADODB_DIR', '../adodb');

    /** ADODB driver */
    define('DB_DRIVER', 'mysql');

    require_once(ADODB_DIR . '/adodb.inc.php');
    $ADODB_FETCH_MODE = 2; // ASSOC
    $ADODB_CACHE_DIR = ADODB_DIR . '/ADOdbcache';
    $db = &ADONewConnection(DB_DRIVER);
    $db->Connect(DB_HOST, $DB_USER, $DB_PASSWORD, DB_BASE_NAME);
    //$db->debug = TRUE; // Debugg
    if ('mysql' == DB_DRIVER) {
        $sql = 'SET NAMES utf8';
        $res = $db->Execute($sql);
    }
}

/* ------------------------ DB_MYSQL SETTINGS ------------------------ */
if (DB_CLASS == 'db_mysql') {
    require_once('db_mysql/db_mysql.class.php');

    $db = new db(DB_HOST, $DB_USER, $DB_PASSWORD, DB_BASE_NAME);

    $sql = 'SET NAMES utf8';
    $db->Execute($sql);

}
unset($DB_PASSWORD, $DB_USER);


/* ------------------------ NEW OBJECT ------------------------ */

require_once('dbtree.class.php');

// Create new object
$dbtree = new dbtree('test_sections', 'section', $db);

/* ------------------------ MOVE ------------------------ */

/* ------------------------ MOVE 2 ------------------------ */

// Method 2: Assigns a node with all its children to another parent.
if (!empty($_GET['action']) && 'move_2' == $_GET['action']) {

    // Move node ($_GET['section_id']) and its children to new parent ($_POST['section2_id'])
    $dbtree->MoveAll((int)$_GET['section_id'], (int)$_POST['section2_id']);

    // Check errors
    if (!empty($dbtree->ERRORS_MES)) {
        echo 'DB Tree Error!';
        echo '<pre>';
        print_r($dbtree->ERRORS_MES);
        if (!empty($dbtree->ERRORS)) {
            print_r($dbtree->ERRORS);
        }
        echo '</pre>';
        exit;
    }

    header('Location:dbtree_demo.php');
    exit;
}

/* ------------------------ MOVE 1 ------------------------ */

// Method 1: Swapping nodes within the same level and limits of one parent with all its children.
if (!empty($_GET['action']) && 'move_1' == $_GET['action']) {

    // Change node ($_GET['section_id']) position and all its childrens to
    // before or after ($_POST['position']) node 2 ($_POST['section2_id'])
    $dbtree->ChangePositionAll((int)$_GET['section_id'], (int)$_POST['section2_id'], $_POST['position']);

    // Check class errors
    if (!empty($dbtree->ERRORS_MES)) {
        echo 'DB Tree Error!';
        echo '<pre>';
        print_r($dbtree->ERRORS_MES);
        if (!empty($dbtree->ERRORS)) {
            print_r($dbtree->ERRORS);
        }
        echo '</pre>';
        exit;
    }

    header('Location:dbtree_demo.php');
    exit;
}

/* ------------------------ MOVE FORM------------------------ */

// Move section form
if (!empty($_GET['action']) && 'move' == $_GET['action']) {

    // Prepare the restrictive data for the first method:
    // Swapping nodes within the same level and limits of one parent with all its children
    $current_section = $dbtree->GetNodeInfo((int)$_GET['section_id']);
    $dbtree->Parents((int)$_GET['section_id'], array('section_id'), array('and' => array('section_level = ' . ($current_section[2] - 1))));

    // Check class errors
    if (!empty($dbtree->ERRORS_MES)) {
        echo 'DB Tree Error!';
        echo '<pre>';
        print_r($dbtree->ERRORS_MES);
        if (!empty($dbtree->ERRORS)) {
            print_r($dbtree->ERRORS);
        }
        echo '</pre>';
        exit;
    }

    $item = $dbtree->NextRow();
    $dbtree->Branch($item['section_id'], array('section_id', 'section_name'), array('and' => array('section_level = ' . $current_section[2])));

    // Create form
    ?>
    <table border="1" cellpadding="5" align="center">
        <tr>
            <td>
                Move section
            </td>
        </tr>
        <tr>
            <td>
                <form action="dbtree_demo.php?action=move_1§ion_id=<?php echo $_GET['section_id']?>" method="POST">
                <strong>1) Swapping nodes within the same level and limits of one parent with all its children.</strong>
                Choose second section:
                <select name="section2_id">
    <?php

    while ($item = $dbtree->NextRow()) {

        ?>
                    <option value="<?php echo $item['section_id']?>"><?php echo $item['section_name']?> <?php echo $item['section_id'] == (int)$_GET['section_id'] ? '<<<' : ''?></option>
        <?php

    }

    ?>
                </select>
                Choose position:
                <select name="position">
                    <option value="after">After</option>
                    <option value="before">Before</option>
                </select>
                <center><input type="submit" value="Apply"></center>
                </form>
                <form action="dbtree_demo.php?action=move_2§ion_id=<?php echo $_GET['section_id']?>" method="POST">
                <strong>2) Assigns a node with all its children to another parent.</strong>
                Choose second section:
                <select name="section2_id">
    <?php

    // Prepare the data for the second method:
    // Assigns a node with all its children to another parent
    $dbtree->Full(array('section_id', 'section_level', 'section_name'), array('or' => array('section_left <= ' . $current_section[0], 'section_right >= ' . $current_section[1])));

    // Check class errors
    if (!empty($dbtree->ERRORS_MES)) {
        echo 'DB Tree Error!';
        echo '<pre>';
        print_r($dbtree->ERRORS_MES);
        if (!empty($dbtree->ERRORS)) {
            print_r($dbtree->ERRORS);
        }
        echo '</pre>';
        exit;
    }

    while ($item = $dbtree->NextRow()) {

        ?>
                    <option value="<?php echo $item['section_id']?>"><?php echo str_repeat(' ', 6 * $item['section_level'])?><?php echo $item['section_name']?> <?php echo $item['section_id'] == (int)$_GET['section_id'] ? '<<<' : ''?></option>
        <?php

    }

    ?>
                </select>
                <center><input type="submit" value="Apply"></center>
                </form>
            </td>
        </tr>
    </table>
    <?php

}

/* ------------------------ DELETE ------------------------ */

// Delete node ($_GET['section_id']) from the tree wihtout deleting it's children
// All children apps to one level
if (!empty($_GET['action']) && 'delete' == $_GET['action']) {
    $dbtree->Delete((int)$_GET['section_id']);

    // Check class errors
    if (!empty($dbtree->ERRORS_MES)) {
        echo 'DB Tree Error!';
        echo '<pre>';
        print_r($dbtree->ERRORS_MES);
        if (!empty($dbtree->ERRORS)) {
            print_r($dbtree->ERRORS);
        }
        echo '</pre>';
        exit;
    }

    header('Location:dbtree_demo.php');
    exit;
}

/* ------------------------ EDIT ------------------------ */

/* ------------------------ EDIT OK ------------------------ */

// Update node ($_GET['section_id']) info
if (!empty($_GET['action']) && 'edit_ok' == $_GET['action']) {
    $sql = 'SELECT * FROM test_sections WHERE section_id = ' . (int)$_GET['section_id'];
    $res = $db->Execute($sql);

    // Check adodb errors
    if (FALSE === $res) {
        echo 'internal_error';
        echo '<pre>';
        print_r(array(2, 'SQL query error.', __FILE__ . '::' . __CLASS__ . '::' . __FUNCTION__ . '::' . __LINE__, 'SQL QUERY: ' . $sql, 'SQL ERROR: ' . $db->ErrorMsg()));
        echo '</pre>';
        exit;
    }

    if (0 == $res->RecordCount()) {
        echo 'section_not_found';
        exit;
    }
    $sql = $db->GetUpdateSQL($res, $_POST['section']);
    if (!empty($sql)) {
        $res = $db->Execute($sql);

        // Check adodb errors
        if (FALSE === $res) {
            echo 'internal_error';
            echo '<pre>';
            print_r(array(2, 'SQL query error.', __FILE__ . '::' . __CLASS__ . '::' . __FUNCTION__ . '::' . __LINE__, 'SQL QUERY: ' . $sql, 'SQL ERROR: ' . $db->ErrorMsg()));
            echo '</pre>';
            exit;
        }

    }
    header('Location:dbtree_demo.php');
    exit;
}

/* ------------------------ EDIT FORM ------------------------ */

// Node edit form
if (!empty($_GET['action']) && 'edit' == $_GET['action']) {
    $sql = 'SELECT section_name FROM test_sections WHERE section_id = ' . (int)$_GET['section_id'];
    $res = $db->GetOne($sql);

    // Check adodb errors
    if (FALSE === $res) {
        echo 'internal_error';
        echo '<pre>';
        print_r(array(2, 'SQL query error.', __FILE__ . '::' . __CLASS__ . '::' . __FUNCTION__ . '::' . __LINE__, 'SQL QUERY: ' . $sql, 'SQL ERROR: ' . $db->ErrorMsg()));
        echo '</pre>';
        exit;
    }

    ?>
    <table border="1" cellpadding="5" align="center">
        <tr>
            <td>
                Edit section
            </td>
        </tr>
        <tr>
            <td align="center">
                <form action="dbtree_demo.php?action=edit_ok§ion_id=<?php echo $_GET['section_id']?>" method="POST">
                Section name:
                <input type="text" name="section[section_name]" value="<?php echo $res?>">
                <input type="submit" name="submit" value="Submit">
                </form>
            </td>
        </tr>
    </table>
    <?php
}

/* ------------------------ ADD ------------------------ */

/* ------------------------ ADD OK ------------------------ */

// Add new node as children to selected node ($_GET['section_id'])
if (!empty($_GET['action']) && 'add_ok' == $_GET['action']) {

echo 'Section :'.$_POST['section'];
echo 'Section ID :'.$_GET['section_id'];

	// Add new node
    $dbtree->Insert((int)$_GET['section_id'], '', $_POST['section']);

    // Check class errors
    if (!empty($dbtree->ERRORS_MES)) {
        echo 'DB Tree Error!';
        echo '<pre>';
        print_r($dbtree->ERRORS_MES);
        if (!empty($dbtree->ERRORS)) {
            print_r($dbtree->ERRORS);
        }
        echo '</pre>';
        exit;
    }

    header('Location:dbtree_demo.php');
    exit;
}

/* ------------------------ ADD FORM ------------------------ */

// Add new node form
if (!empty($_GET['action']) && 'add' == $_GET['action']) {

    ?>
    <table border="1" cellpadding="5" align="center">
        <tr>
            <td>
                New section
            </td>
        </tr>
        <tr>
            <td align="center">
                <form action="dbtree_demo.php?action=add_ok§ion_id=<?php echo $_GET['section_id']?>" method="POST">
                Section name:
                <input type="text" name="section[section_name]" value="">
                <input type="submit" name="submit" value="Submit">
                </form>
            </td>
        </tr>
    </table>
    <?php

}

/* ------------------------ LIST ------------------------ */

// Prepare data to view all tree
$dbtree->Full('');

// Check class errors
if (!empty($dbtree->ERRORS_MES)) {
    echo 'DB Tree Error!';
    echo '<pre>';
    print_r($dbtree->ERRORS_MES);
    if (!empty($dbtree->ERRORS)) {
        print_r($dbtree->ERRORS);
    }
    echo '</pre>';
    exit;
}

    ?>
    <h3>Manage tree:</h3>
    <table border="1" cellpadding="5" width="100%">
        <tr>
            <td width="100%">Section name</td>
            <td colspan="4">Actions</td>
        </tr>
    <?php

    $counter = 1;
    while ($item = $dbtree->NextRow()) {
        if ($counter % 2) {
            $bgcolor = 'lightgreen';
        } else {
            $bgcolor = 'yellow';
        }
        $counter++;

        ?>
        <tr>
            <td bgcolor="<?php echo $bgcolor?>">
                <?php echo str_repeat(' ', 6 * $item['section_level']) . '<strong>' . $item['section_name']?></strong> [<strong><?php echo $item['section_left']?></strong>, <strong><?php echo $item['section_right']?></strong>, <strong><?php echo $item['section_level']?></strong>]
            </td>
            <td bgcolor="<?php echo $bgcolor?>">
                <a href="dbtree_demo.php?action=add§ion_id=<?php echo $item['section_id']?>">Add</a>
            </td>
            <td bgcolor="<?php echo $bgcolor?>">
                <a href="dbtree_demo.php?action=edit§ion_id=<?php echo $item['section_id']?>">Edit</a>
            </td>
            <td bgcolor="<?php echo $bgcolor?>">
            
            <?php
            if (0 == $item['section_level']) {
                echo 'Delete';
            } else {

                ?>
                <a href="dbtree_demo.php?action=delete§ion_id=<?php echo $item['section_id']?>">Delete</a>
                <?php
            }
            ?>
            
            </td>
            <td bgcolor="<?php echo $bgcolor?>">
            
            <?php
            if (0 == $item['section_level']) {
                echo 'Move';
            } else {

                ?>
                <a href="dbtree_demo.php?action=move§ion_id=<?php echo $item['section_id']?>">Move</a>
                <?php
            }
            ?>

            </td>
        </tr>
        <?php
    }

    ?>
    </table>
</body>
</html>
<?php
ob_flush();
$db->Close();
?>


db_mysql.class.php

<?php
/**
* $Id: db_mysql.class.php,v 1.1 2005/09/23 19:32:45 Kuzma Exp $
*
* Copyright (C) 2005 Kuzma Feskov <kuzma@russofile.ru>
*
* KF_SITE_VERSION
*
* CLASS DESCRIPTION:
* DB_MYSQL   The class-example showing variant of creation of the own
*            engine for dialogue with a database, it's emulate
*            some ADODB functions (ATTENTION, class only shows variant
*            of a spelling of the driver, use it only as example)
*
* This source file is part of the KFSITE Open Source Content
* Management System.
*
* This file may be distributed and/or modified under the terms of the
* "GNU General Public License" version 2 as published by the Free
* Software Foundation and appearing in the file LICENSE included in
* the packaging of this file.
*
* This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING
* THE WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE.
*
* The "GNU General Public License" (GPL) is available at
* http:*www.gnu.org/copyleft/gpl.html.
* 
* CHANGELOG:
*
* v1.1
*
* [-] GetUpdateSql bug fixed (thx to Nico Tautenhahn)
*/

class db {
    /**
    * Database connection
    *
    * @var resource
    */
    var $conn;

    /**
    * Constructor
    *
    * @return db object
    */
    function db($host, $user, $password, $database) {
        $this->conn = mysql_connect($host, $user, $password);
        if (false === $this->conn) {
            return false;
        }
        if (false === mysql_select_db($database)) {
            return false;
        }
        return true;
    }

    /**
    * Generate unique insert ID
    *
    * @param string $seqname - Sequence table name
    * @param integer $start - Initial value
    */
    function GenID($seqname, $start) {
        $sql = 'update ' . addslashes($seqname) . ' set id=LAST_INSERT_ID(id+1)';
        $res = $this->Execute($sql);
        if (false === $res) {
            $sql = 'create table ' . addslashes(strtoupper($seqname)) . ' (id int not null)';
            $this->Execute($sql);
            $sql = 'insert into ' . addslashes(strtoupper($seqname)) . ' values (' . (int)$start-1 . ')';
            $this->Execute($sql);
        }
        return mysql_insert_id($this->conn);
    }

    /**
    * Execute SQL query
    *
    * @param string $sql - SQL query
    * @return object Recordset
    */
    function Execute($sql) {
        $res = mysql_query($sql, $this->conn);
        if (false === $res) {
            return false;
        }
        $recordset = new recordset($res, $sql);
        return $recordset;
    }

    /**
    * Cache SQL query (added for compatibility), not realized
    *
    * @param integer $cache
    * @param string $sql - SQL query
    */
    function CacheExecute($cache, $sql) {
        return $this->Execute($sql);
    }

    /**
    * Generate UPDATE SQL query
    *
    * @param object $recordset - SELECT query result
    * @param array $data - Contains parameters for additional fields of a tree (if is): array('filed name' => 'importance', etc)
    * @return string - Complete SQL query or empty string
    */
    function GetUpdateSQL($recordset, $data) {
        if (empty($data)) {
            return '';
        }
        preg_match_all("~FROM\s+([^\s]*)~", $recordset->sql, $maches, PREG_PATTERN_ORDER);
        if (!isset($maches[1][0])) {
            return '';
        } else {
            $table = $maches[1][0];
        }
        preg_match_all("~(WHERE\s+.*)~is", $recordset->sql, $maches, PREG_PATTERN_ORDER);
        if (!isset($maches[0][0])) {
            return '';
        } else {
            $where = $maches[0][0];
        }
        $fld_names = array_keys($data);
        $fld_values = array_values($data);
        $data = 'SET ';
        for ($max = count($fld_names), $i = 0;$i < $max;$i++) {
            $data .= $fld_names[$i] . ' = \'' . $fld_values[$i] . '\' ';
            if ($i < $max-1) $data .= ', ';
        }
        $sql = 'UPDATE ' . $table . ' ' . $data . ' ' . $where;
        return $sql;
    }

    /**
    * Generate SELECT SQL query
    *
    * @param object $recordset - SELECT query result
    * @param array $data - Contains parameters for additional fields of a tree (if is): array('filed name' => 'importance', etc)
    * @return string - Complete SQL query or empty string
    */
    function GetInsertSQL($recordset, $data) {
        if (empty($data)) {
            return '';
        }
        preg_match_all("~FROM\s+([^\s]*)~", $recordset->sql, $maches, PREG_PATTERN_ORDER);
        if (!isset($maches[1][0])) {
            return '';
        } else {
            $table = $maches[1][0];
        }
        if (!empty($data)) {
            $fld_names = implode(', ', array_keys($data));
            $fld_values = '\'' . implode('\', \'', array_values($data)) . '\'';
        }
        $sql = 'INSERT INTO ' . $table . ' (' . $fld_names . ') VALUES (' . $fld_values . ')';
        return $sql;
    }

    /**
    * Return on field result
    *
    * @param string $sql - SQL query
    * @return unknown
    */
    function GetOne($sql) {
        $res = $this->Execute($sql);
        if (false === $res) {
            return false;
        }
        return reset($res->FetchRow());
    }

    /**
    * Transactions mechanism (added for compatibility, not realised)
    *
    */
    function StartTrans() {
        return;
    }

    /**
    * Transactions mechanism (added for compatibility, not realised)
    *
    */
    function FailTrans() {
        return;
    }

    /**
    * Transactions mechanism (added for compatibility, not realised)
    *
    */
    function CompleteTrans() {

    }

    /**
    * Return database error message
    *
    * @return string
    */
    function ErrorMsg() {
        return mysql_error();
    }

    /**
    * Close database connection
    *
    */
    function Close() {
        mysql_close($this->conn);
    }
}

class recordset {
    /**
    * Recordset resource.
    *
    * @var resource
    */
    var $recordset;

    /**
    * SQL query
    *
    * @var string
    */
    var $sql;

    /**
    * Constructor.
    *
    * @param resource $recordset
    * @return recordset object
    */
    function recordset($recordset, $sql) {
        $this->recordset = $recordset;
        $this->sql = $sql;
    }

    /**
    * Returns amount of lines in result.
    * 
    * @return integer
    */
    function RecordCount() {
        return mysql_num_rows($this->recordset);
    }

    /**
    * Returns the current row
    * @return array
    */
    function FetchRow() {
        return mysql_fetch_array($this->recordset);
    }
}
?>
+0
-0
Cevaba KatılıyorumKatılmıyorum
Cevap Yaz Yorum Yaz Arşivime Ekle Takip Et

Cevaplar

  • Raks adlı üyenin fotoğrafı
    10 yıl önce yazılmış
    1 cevap - 11 soru
    dbtree.class.php

    <?php
    /**
    * $Id: dbtree.class.php,v 2.1 2005/09/21 19:32:45 Kuzma Exp $
    *
    * Copyright (C) 2005 Kuzma Feskov <kuzma@russofile.ru>
    *
    * KF_SITE_VERSION
    *
    * CLASS DESCRIPTION:
    * This class can be used to manipulate nested sets of database table
    * records that form an hierarchical tree.
    * 
    * It provides means to initialize the record tree, insert record nodes
    * in specific tree positions, retrieve node and parent records, change
    * position of nodes and delete record nodes.
    * 
    * It uses ANSI SQL statements and abstract DB libraryes, such as:
    * ADODB      Provides full functionality of the class: to make it
    *            work with many database types, support transactions,
    *            and caching of SQL queries to minimize database
    *            access overhead
    * DB_MYSQL   The class-example showing variant of creation of the own
    *            engine for dialogue with a database, it's emulate
    *            some ADODB functions (ATTENTION, class only shows variant
    *            of a spelling of the driver, use it only as example)
    * 
    * The library works with support multilanguage interface of
    * technology GetText (GetText autodetection).
    * 
    * This source file is part of the KFSITE Open Source Content
    * Management System.
    *
    * This file may be distributed and/or modified under the terms of the
    * "GNU General Public License" version 2 as published by the Free
    * Software Foundation and appearing in the file LICENSE included in
    * the packaging of this file.
    *
    * This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING
    * THE WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR
    * PURPOSE.
    *
    * The "GNU General Public License" (GPL) is available at
    * http://www.gnu.org/copyleft/gpl.html.
    * 
    * CHANGELOG:
    *
    * v2.0
    *
    * [+] GetText autodetect added
    * 
    * [+] DB libraries abstraction added
    */
    
    class dbtree {
        /**
        * Detailed errors of a class (for the programmer and log-files)
        * array('error type (1 - fatal (write log), 2 - fatal (write log, send email)',
        * 'error info string', 'function', 'info 1', 'info 2').
        * 
        * @var array
        */
        var $ERRORS = array();
    
        /**
        * The information on a error for the user
        * array('string (error information)').
        * 
        * @var array
        */
        var $ERRORS_MES = array();
    
        /**
        * Name of the table where tree is stored.
        * 
        * @var string
        */
        var $table;
    
        /**
        * Unique number of node.
        * 
        * @var bigint
        */
        var $table_id;
    
        /**
        * @var integer
        */
        var $table_left;
    
        /**
        * @var integer
        */
        var $table_right;
    
        /**
        * Level of nesting.
        * 
        * @var integer
        */
        var $table_level;
    
        /**
        * DB resource object.
        * 
        * @var object
        */
        var $res;
    
        /**
        * Databse layer object.
        * 
        * @var object
        */
        var $db;
    
        /**
        * The class constructor: initializes dbtree variables.
        * 
        * @param string $table Name of the table
        * @param string $prefix A prefix for fields of the table(the example, mytree_id. 'mytree' is prefix)
        * @param object $db
        * @return object
        */
        function dbtree($table, $prefix, &$db) {
            $this->db = &$db;
            $this->table = $table;
            $this->table_id = $prefix . '_id';
            $this->table_left = $prefix . '_left';
            $this->table_right = $prefix . '_right';
            $this->table_level = $prefix . '_level';
            unset($prefix, $table);
        }
    
        /**
        * Sets initial parameters of a tree and creates root of tree
        * ATTENTION, all previous values in table are destroyed.
        * 
        * @param array $data Contains parameters for additional fields of a tree (if is): 'filed name' => 'importance'
        * @return bool TRUE if successful, FALSE otherwise.
        */
        function Clear($data = array()) {
            $sql = 'TRUNCATE ' . $this->table;
            $res = $this->db->Execute($sql);
            if (FALSE === $res) {
                $this->ERRORS[] = array(2, 'SQL query error.', __FILE__ . '::' . __CLASS__ . '::' . __FUNCTION__ . '::' . __LINE__, 'SQL QUERY: ' . $sql, 'SQL ERROR: ' . $this->db->ErrorMsg());
                $this->ERRORS_MES[] = extension_loaded('gettext') ? _('internal_error') : 'internal_error';
                return FALSE;
            }
            $sql = 'DELETE FROM ' . $this->table;
            $res = $this->db->Execute($sql);
            if (FALSE === $res) {
                $this->ERRORS[] = array(2, 'SQL query error.', __FILE__ . '::' . __CLASS__ . '::' . __FUNCTION__ . '::' . __LINE__, 'SQL QUERY: ' . $sql, 'SQL ERROR: ' . $this->db->ErrorMsg());
                $this->ERRORS_MES[] = extension_loaded('gettext') ? _('internal_error') : 'internal_error';
                return FALSE;
            }
            if (!empty($data)) {
                $fld_names = implode(', ', array_keys($data)) . ', ';
                $fld_values = '\'' . implode('\', \'', array_values($data)) . '\', ';
            }
            $fld_names .= $this->table_left . ', ' . $this->table_right . ', ' . $this->table_level;
            $fld_values .= '1, 2, 0';
            $id = $this->db->GenID($this->table . '_seq', 1);
            $sql = 'INSERT INTO ' . $this->table . ' (' . $this->table_id . ', ' . $fld_names . ') VALUES (' . $id . ', ' . $fld_values . ')';
            $res = $this->db->Execute($sql);
            if (FALSE === $res) {
                $this->ERRORS[] = array(2, 'SQL query error.', __FILE__ . '::' . __CLASS__ . '::' . __FUNCTION__ . '::' . __LINE__, 'SQL QUERY: ' . $sql, 'SQL ERROR: ' . $this->db->ErrorMsg());
                $this->ERRORS_MES[] = extension_loaded('gettext') ? _('internal_error') : 'internal_error';
                return FALSE;
            }
            return TRUE;
        }
    
        /**
        * Receives left, right and level for unit with number id.
        *
        * @param integer $section_id Unique section id
        * @param integer $cache Recordset is cached for $cache microseconds
        * @return array - left, right, level
        */
        function GetNodeInfo($section_id, $cache = FALSE) {
            $sql = 'SELECT ' . $this->table_left . ', ' . $this->table_right . ', ' . $this->table_level . ' FROM ' . $this->table . ' WHERE ' . $this->table_id . ' = ' . (int)$section_id;
            if (FALSE === DB_CACHE || FALSE === $cache || 0 == (int)$cache) {
                $res = $this->db->Execute($sql);
            } else {
                $res = $this->db->CacheExecute((int)$cache, $sql);
            }
            if (FALSE === $res) {
                $this->ERRORS[] = array(2, 'SQL query error.', __FILE__ . '::' . __CLASS__ . '::' . __FUNCTION__ . '::' . __LINE__, 'SQL QUERY: ' . $sql, 'SQL ERROR: ' . $this->db->ErrorMsg());
                $this->ERRORS_MES[] = extension_loaded('gettext') ? _('internal_error') : 'internal_error';
                return FALSE;
            }
            if (0 == $res->RecordCount()) {
                $this->ERRORS_MES[] = extension_loaded('gettext') ? _('no_element_in_tree') : 'no_element_in_tree';
                return FALSE;
            }
            $data = $res->FetchRow();
            unset($res);
            return array($data[$this->table_left], $data[$this->table_right], $data[$this->table_level]);
        }
    
        /**
        * Receives parent left, right and level for unit with number $id.
        *
        * @param integer $section_id
        * @param integer $cache Recordset is cached for $cache microseconds
        * @param array $condition Array structure: array('and' => array('id = 0', 'id2 >= 3'), 'or' => array('sec = \'www\'', 'sec2 <> \'erere\'')), etc where array key - condition (AND, OR, etc), value - condition string
        * @return array - left, right, level
        */
        function GetParentInfo($section_id, $condition = '', $cache = FALSE) {
            $node_info = $this->GetNodeInfo($section_id);
            if (FALSE === $node_info) {
                return FALSE;
            }
            list($leftId, $rightId, $level) = $node_info;
            $level--;
            if (!empty($condition)) {
                $condition = $this->_PrepareCondition($condition);
            }
            $sql = 'SELECT * FROM ' . $this->table
            . ' WHERE ' . $this->table_left . ' < ' . $leftId
            . ' AND ' . $this->table_right . ' > ' . $rightId
            . ' AND ' . $this->table_level . ' = ' . $level
            . $condition
            . ' ORDER BY ' . $this->table_left;
            if (FALSE === DB_CACHE || FALSE === $cache || 0 == (int)$cache) {
                $res = $this->db->Execute($sql);
            } else {
                $res = $this->db->CacheExecute((int)$cache, $sql);
            }
            if (FALSE === $res) {
                $this->ERRORS[] = array(2, 'SQL query error.', __FILE__ . '::' . __CLASS__ . '::' . __FUNCTION__ . '::' . __LINE__, 'SQL QUERY: ' . $sql, 'SQL ERROR: ' . $this->db->ErrorMsg());
                $this->ERRORS_MES[] = extension_loaded('gettext') ? _('internal_error') : 'internal_error';
                return FALSE;
            }
            return $res->FetchRow();
        }
    
    
        /**
        * Add a new element in the tree to element with number $section_id.
        *
        * @param integer $section_id Number of a parental element
        * @param array $condition Array structure: array('and' => array('id = 0', 'id2 >= 3'), 'or' => array('sec = \'www\'', 'sec2 <> \'erere\'')), etc where array key - condition (AND, OR, etc), value - condition string
        * @param array $data Contains parameters for additional fields of a tree (if is): array('filed name' => 'importance', etc)
        * @return integer Inserted element id
        */
        function Insert($section_id, $condition = '', $data = array()) {
            $node_info = $this->GetNodeInfo($section_id);
            if (FALSE === $node_info) {
                return FALSE;
            }
            list($leftId, $rightId, $level) = $node_info;
            $data[$this->table_left] = $rightId;
            $data[$this->table_right] = ($rightId + 1);
            $data[$this->table_level] = ($level + 1);
            if (!empty($condition)) {
                $condition = $this->_PrepareCondition($condition);
            }
            $sql = 'UPDATE ' . $this->table . ' SET '
            . $this->table_left . '=CASE WHEN ' . $this->table_left . '>' . $rightId . ' THEN ' . $this->table_left . '+2 ELSE ' . $this->table_left . ' END, '
            . $this->table_right . '=CASE WHEN ' . $this->table_right . '>=' . $rightId . ' THEN ' . $this->table_right . '+2 ELSE ' . $this->table_right . ' END '
            . 'WHERE ' . $this->table_right . '>=' . $rightId;
            $sql .= $condition;
            $this->db->StartTrans();
            $res = $this->db->Execute($sql);
            if (FALSE === $res) {
                $this->ERRORS[] = array(2, 'SQL query error.', __FILE__ . '::' . __CLASS__ . '::' . __FUNCTION__ . '::' . __LINE__, 'SQL QUERY: ' . $sql, 'SQL ERROR: ' . $this->db->ErrorMsg());
                $this->ERRORS_MES[] = extension_loaded('gettext') ? _('internal_error') : 'internal_error';
                $this->db->FailTrans();
                return FALSE;
            }
            $sql = 'SELECT * FROM ' . $this->table . ' WHERE ' . $this->table_id . ' = -1';
            $res = $this->db->Execute($sql);
            if (FALSE === $res) {
                $this->ERRORS[] = array(2, 'SQL query error', __FILE__ . '::' . __CLASS__ . '::' . __FUNCTION__ . '::' . __LINE__, 'SQL QUERY: ' . $sql, 'SQL ERROR: ' . $this->db->ErrorMsg());
                $this->ERRORS_MES[] = extension_loaded('gettext') ? _('internal_error') : 'internal_error';
                $this->db->FailTrans();
                return FALSE;
            }
            $data[$this->table_id] = $this->db->GenID($this->table . '_seq', 2);
            $sql = $this->db->GetInsertSQL($res, $data);
            if (!empty($sql)) {
                $res = $this->db->Execute($sql);
                if (FALSE === $res) {
                    $this->ERRORS[] = array(2, 'SQL query error', __FILE__ . '::' . __CLASS__ . '::' . __FUNCTION__ . '::' . __LINE__, 'SQL QUERY: ' . $sql, 'SQL ERROR: ' . $this->db->ErrorMsg());
                    $this->ERRORS_MES[] = extension_loaded('gettext') ? _('internal_error') : 'internal_error';
                    $this->db->FailTrans();
                    return FALSE;
                }
            }
            $this->db->CompleteTrans();
            return $data[$this->table_id];
        }
    
        /**
        * Add a new element in the tree near element with number id.
        *
        * @param integer $ID Number of a parental element
        * @param array $condition Array structure: array('and' => array('id = 0', 'id2 >= 3'), 'or' => array('sec = \'www\'', 'sec2 <> \'erere\'')), etc where array key - condition (AND, OR, etc), value - condition string
        * @param array $data Contains parameters for additional fields of a tree (if is): array('filed name' => 'importance', etc)
        * @return integer Inserted element id
        */
        function InsertNear($ID, $condition = '', $data = array()) {
            $node_info = $this->GetNodeInfo($ID);
            if (FALSE === $node_info) {
                return FALSE;
            }
            list($leftId, $rightId, $level) = $node_info;
            $data[$this->table_left] = ($rightId + 1);
            $data[$this->table_right] = ($rightId + 2);
            $data[$this->table_level] = ($level);
            if (!empty($condition)) {
                $condition = $this->_PrepareCondition($condition);
            }
            $sql = 'UPDATE ' . $this->table . ' SET '
            . $this->table_left . ' = CASE WHEN ' . $this->table_left . ' > ' . $rightId . ' THEN ' . $this->table_left . ' + 2 ELSE ' . $this->table_left . ' END, '
            . $this->table_right . ' = CASE WHEN ' . $this->table_right . '> ' . $rightId . ' THEN ' . $this->table_right . ' + 2 ELSE ' . $this->table_right . ' END, '
            . 'WHERE ' . $this->table_right . ' > ' . $rightId;
            $sql .= $condition;
            $this->db->StartTrans();
            $res = $this->db->Execute($sql);
            if (FALSE === $res) {
                $this->ERRORS[] = array(2, 'SQL query error.', __FILE__ . '::' . __CLASS__ . '::' . __FUNCTION__ . '::' . __LINE__, 'SQL QUERY: ' . $sql, 'SQL ERROR: ' . $this->db->ErrorMsg());
                $this->ERRORS_MES[] = extension_loaded('gettext') ? _('internal_error') : 'internal_error';
                $this->db->FailTrans();
                return FALSE;
            }
            $sql = 'SELECT * FROM ' . $this->table . ' WHERE ' . $this->table_id . ' = -1';
            $res = $this->db->Execute($sql);
            if (FALSE === $res) {
                $this->ERRORS[] = array(2, 'SQL query error', __FILE__ . '::' . __CLASS__ . '::' . __FUNCTION__ . '::' . __LINE__, 'SQL QUERY: ' . $sql, 'SQL ERROR: ' . $this->db->ErrorMsg());
                $this->ERRORS_MES[] = extension_loaded('gettext') ? _('internal_error') : 'internal_error';
                $this->db->FailTrans();
                return FALSE;
            }
            $data[$this->table_id] = $this->db->GenID($this->table . '_seq', 2);
            $sql = $this->db->GetInsertSQL($res, $data);
            if (!empty($sql)) {
                $res = $this->db->Execute($sql);
                if (FALSE === $res) {
                    $this->ERRORS[] = array(2, 'SQL query error', __FILE__ . '::' . __CLASS__ . '::' . __FUNCTION__ . '::' . __LINE__, 'SQL QUERY: ' . $sql, 'SQL ERROR: ' . $this->db->ErrorMsg());
                    $this->ERRORS_MES[] = extension_loaded('gettext') ? _('internal_error') : 'internal_error';
                    $this->db->FailTrans();
                    return FALSE;
                }
            }
            $this->db->CompleteTrans();
            return $data[$this->table_id];
        }
    
        /**
        * Assigns a node with all its children to another parent.
        *
        * @param integer $ID node ID
        * @param integer $newParentId ID of new parent node
        * @param array $condition Array structure: array('and' => array('id = 0', 'id2 >= 3'), 'or' => array('sec = \'www\'', 'sec2 <> \'erere\'')), etc where array key - condition (AND, OR, etc), value - condition string
        * @return bool TRUE if successful, FALSE otherwise.
        */
        function MoveAll($ID, $newParentId, $condition = '') {
            $node_info = $this->GetNodeInfo($ID);
            if (FALSE === $node_info) {
                return FALSE;
            }
            list($leftId, $rightId, $level) = $node_info;
            $node_info = $this->GetNodeInfo($newParentId);
            if (FALSE === $node_info) {
                return FALSE;
            }
            list($leftIdP, $rightIdP, $levelP) = $node_info;
            if ($ID == $newParentId || $leftId == $leftIdP || ($leftIdP >= $leftId && $leftIdP <= $rightId) || ($level == $levelP+1 && $leftId > $leftIdP && $rightId < $rightIdP)) {
                $this->ERRORS_MES[] = extension_loaded('gettext') ? _('cant_move_tree') : 'cant_move_tree';
                return FALSE;
            }
            if (!empty($condition)) {
                $condition = $this->_PrepareCondition($condition);
            }
            if ($leftIdP < $leftId && $rightIdP > $rightId && $levelP < $level - 1) {
                $sql = 'UPDATE ' . $this->table . ' SET '
                . $this->table_level . ' = CASE WHEN ' . $this->table_left . ' BETWEEN ' . $leftId . ' AND ' . $rightId . ' THEN ' . $this->table_level.sprintf('%+d', -($level-1)+$levelP) . ' ELSE ' . $this->table_level . ' END, '
                . $this->table_right . ' = CASE WHEN ' . $this->table_right . ' BETWEEN ' . ($rightId+1) . ' AND ' . ($rightIdP-1) . ' THEN ' . $this->table_right . '-' . ($rightId-$leftId+1) . ' '
                . 'WHEN ' . $this->table_left . ' BETWEEN ' . $leftId . ' AND ' . $rightId . ' THEN ' . $this->table_right . '+' . ((($rightIdP-$rightId-$level+$levelP)/2)*2+$level-$levelP-1) . ' ELSE ' . $this->table_right . ' END, '
                . $this->table_left . ' = CASE WHEN ' . $this->table_left . ' BETWEEN ' . ($rightId+1) . ' AND ' . ($rightIdP-1) . ' THEN ' . $this->table_left . '-' . ($rightId-$leftId+1) . ' '
                . 'WHEN ' . $this->table_left . ' BETWEEN ' . $leftId . ' AND ' . $rightId . ' THEN ' . $this->table_left . '+' . ((($rightIdP-$rightId-$level+$levelP)/2)*2+$level-$levelP-1) . ' ELSE ' . $this->table_left . ' END '
                . 'WHERE ' . $this->table_left . ' BETWEEN ' . ($leftIdP+1) . ' AND ' . ($rightIdP-1);
            } elseif ($leftIdP < $leftId) {
                $sql = 'UPDATE ' . $this->table . ' SET '
                . $this->table_level . ' = CASE WHEN ' . $this->table_left . ' BETWEEN ' . $leftId . ' AND ' . $rightId . ' THEN ' . $this->table_level.sprintf('%+d', -($level-1)+$levelP) . ' ELSE ' . $this->table_level . ' END, '
                . $this->table_left . ' = CASE WHEN ' . $this->table_left . ' BETWEEN ' . $rightIdP . ' AND ' . ($leftId-1) . ' THEN ' . $this->table_left . '+' . ($rightId-$leftId+1) . ' '
                . 'WHEN ' . $this->table_left . ' BETWEEN ' . $leftId . ' AND ' . $rightId . ' THEN ' . $this->table_left . '-' . ($leftId-$rightIdP) . ' ELSE ' . $this->table_left . ' END, '
                . $this->table_right . ' = CASE WHEN ' . $this->table_right . ' BETWEEN ' . $rightIdP . ' AND ' . $leftId . ' THEN ' . $this->table_right . '+' . ($rightId-$leftId+1) . ' '
                . 'WHEN ' . $this->table_right . ' BETWEEN ' . $leftId . ' AND ' . $rightId . ' THEN ' . $this->table_right . '-' . ($leftId-$rightIdP) . ' ELSE ' . $this->table_right . ' END '
                . 'WHERE (' . $this->table_left . ' BETWEEN ' . $leftIdP . ' AND ' . $rightId. ' '
                . 'OR ' . $this->table_right . ' BETWEEN ' . $leftIdP . ' AND ' . $rightId . ')';
            } else {
                $sql = 'UPDATE ' . $this->table . ' SET '
                . $this->table_level . ' = CASE WHEN ' . $this->table_left . ' BETWEEN ' . $leftId . ' AND ' . $rightId . ' THEN ' . $this->table_level.sprintf('%+d', -($level-1)+$levelP) . ' ELSE ' . $this->table_level . ' END, '
                . $this->table_left . ' = CASE WHEN ' . $this->table_left . ' BETWEEN ' . $rightId . ' AND ' . $rightIdP . ' THEN ' . $this->table_left . '-' . ($rightId-$leftId+1) . ' '
                . 'WHEN ' . $this->table_left . ' BETWEEN ' . $leftId . ' AND ' . $rightId . ' THEN ' . $this->table_left . '+' . ($rightIdP-1-$rightId) . ' ELSE ' . $this->table_left . ' END, '
                . $this->table_right . ' = CASE WHEN ' . $this->table_right . ' BETWEEN ' . ($rightId+1) . ' AND ' . ($rightIdP-1) . ' THEN ' . $this->table_right . '-' . ($rightId-$leftId+1) . ' '
                . 'WHEN ' . $this->table_right . ' BETWEEN ' . $leftId . ' AND ' . $rightId . ' THEN ' . $this->table_right . '+' . ($rightIdP-1-$rightId) . ' ELSE ' . $this->table_right . ' END '
                . 'WHERE (' . $this->table_left . ' BETWEEN ' . $leftId . ' AND ' . $rightIdP . ' '
                . 'OR ' . $this->table_right . ' BETWEEN ' . $leftId . ' AND ' . $rightIdP . ')';
            }
            $sql .= $condition;
            $this->db->StartTrans();
            $res = $this->db->Execute($sql);
            if (FALSE === $res) {
                $this->ERRORS[] = array(2, 'SQL query error.', __FILE__ . '::' . __CLASS__ . '::' . __FUNCTION__ . '::' . __LINE__, 'SQL QUERY: ' . $sql, 'SQL ERROR: ' . $this->db->ErrorMsg());
                $this->ERRORS_MES[] = extension_loaded('gettext') ? _('internal_error') : 'internal_error';
                $this->db->FailTrans();
                return FALSE;
            }
            $this->db->CompleteTrans();
            return TRUE;
        }
    
        /**
        * Change items position.
        *
        * @param integer $id1 first item ID
        * @param integer $id2 second item ID
        * @return bool TRUE if successful, FALSE otherwise.
        */
        function ChangePosition($id1, $id2) {
            $node_info = $this->GetNodeInfo($id1);
            if (FALSE === $node_info) {
                return FALSE;
            }
            list($leftId1, $rightId1, $level1) = $node_info;
            $node_info = $this->GetNodeInfo($id2);
            if (FALSE === $node_info) {
                return FALSE;
            }
            list($leftId2, $rightId2, $level2) = $node_info;
            $sql = 'UPDATE ' . $this->table . ' SET '
            . $this->table_left . ' = ' . $leftId2 .', '
            . $this->table_right . ' = ' . $rightId2 .', '
            . $this->table_level . ' = ' . $level2 .' '
            . 'WHERE ' . $this->table_id . ' = ' . (int)$id1;
            $this->db->StartTrans();
            $res = $this->db->Execute($sql);
            if (FALSE === $res) {
                $this->ERRORS[] = array(2, 'SQL query error.', __FILE__ . '::' . __CLASS__ . '::' . __FUNCTION__ . '::' . __LINE__, 'SQL QUERY: ' . $sql, 'SQL ERROR: ' . $this->db->ErrorMsg());
                $this->ERRORS_MES[] = extension_loaded('gettext') ? _('internal_error') : 'internal_error';
                $this->db->FailTrans();
                return FALSE;
            }
            $sql = 'UPDATE ' . $this->table . ' SET '
            . $this->table_left . ' = ' . $leftId1 .', '
            . $this->table_right . ' = ' . $rightId1 .', '
            . $this->table_level . ' = ' . $level1 .' '
            . 'WHERE ' . $this->table_id . ' = ' . (int)$id2;
            $res = $this->db->Execute($sql);
            if (FALSE === $res) {
                $this->ERRORS[] = array(2, 'SQL query error.', __FILE__ . '::' . __CLASS__ . '::' . __FUNCTION__ . '::' . __LINE__, 'SQL QUERY: ' . $sql, 'SQL ERROR: ' . $this->db->ErrorMsg());
                $this->ERRORS_MES[] = extension_loaded('gettext') ? _('internal_error') : 'internal_error';
                $this->db->FailTrans();
                return FALSE;
            }
            $this->db->CompleteTrans();
            return TRUE;
        }
    
        /**
        * Swapping nodes within the same level and limits of one parent with all its children: $id1 placed before or after $id2.
        *
        * @param integer $id1 first item ID
        * @param integer $id2 second item ID
        * @param string $position 'before' or 'after' $id2
        * @param array $condition Array structure: array('and' => array('id = 0', 'id2 >= 3'), 'or' => array('sec = \'www\'', 'sec2 <> \'erere\'')), etc where array key - condition (AND, OR, etc), value - condition string
        * @return bool TRUE if successful, FALSE otherwise.
        */
        function ChangePositionAll($id1, $id2, $position = 'after', $condition = '') {
            $node_info = $this->GetNodeInfo($id1);
            if (FALSE === $node_info) {
                $this->ERRORS_MES[] = extension_loaded('gettext') ? _('cant_change_position') : 'cant_change_position';
                return FALSE;
            }
            list($leftId1, $rightId1, $level1) = $node_info;
            $node_info = $this->GetNodeInfo($id2);
            if (FALSE === $node_info) {
                $this->ERRORS_MES[] = extension_loaded('gettext') ? _('cant_change_position') : 'cant_change_position';
                return FALSE;
            }
            list($leftId2, $rightId2, $level2) = $node_info;
            if ($level1 <> $level2) {
                $this->ERRORS_MES[] = extension_loaded('gettext') ? _('cant_change_position') : 'cant_change_position';
                return FALSE;
            }
            if ('before' == $position) {
                if ($leftId1 > $leftId2) {
                    $sql = 'UPDATE ' . $this->table . ' SET '
                    . $this->table_right . ' = CASE WHEN ' . $this->table_left . ' BETWEEN ' . $leftId1 . ' AND ' . $rightId1 . ' THEN ' . $this->table_right . ' - ' . ($leftId1 - $leftId2) . ' '
                    . 'WHEN ' . $this->table_left . ' BETWEEN ' . $leftId2 . ' AND ' . ($leftId1 - 1) . ' THEN ' . $this->table_right . ' +  ' . ($rightId1 - $leftId1 + 1) . ' ELSE ' . $this->table_right . ' END, '
                    . $this->table_left . ' = CASE WHEN ' . $this->table_left . ' BETWEEN ' . $leftId1 . ' AND ' . $rightId1 . ' THEN ' . $this->table_left . ' - ' . ($leftId1 - $leftId2) . ' '
                    . 'WHEN ' . $this->table_left . ' BETWEEN ' . $leftId2 . ' AND ' . ($leftId1 - 1) . ' THEN ' . $this->table_left . ' + ' . ($rightId1 - $leftId1 + 1) . ' ELSE ' . $this->table_left . ' END '
                    . 'WHERE ' . $this->table_left . ' BETWEEN ' . $leftId2 . ' AND ' . $rightId1;
                } else {
                    $sql = 'UPDATE ' . $this->table . ' SET '
                    . $this->table_right . ' = CASE WHEN ' . $this->table_left . ' BETWEEN ' . $leftId1 . ' AND ' . $rightId1 . ' THEN ' . $this->table_right . ' + ' . (($leftId2 - $leftId1) - ($rightId1 - $leftId1 + 1)) . ' '
                    . 'WHEN ' . $this->table_left . ' BETWEEN ' . ($rightId1 + 1) . ' AND ' . ($leftId2 - 1) . ' THEN ' . $this->table_right . ' - ' . (($rightId1 - $leftId1 + 1)) . ' ELSE ' . $this->table_right . ' END, '
                    . $this->table_left . ' = CASE WHEN ' . $this->table_left . ' BETWEEN ' . $leftId1 . ' AND ' . $rightId1 . ' THEN ' . $this->table_left . ' + ' . (($leftId2 - $leftId1) - ($rightId1 - $leftId1 + 1)) . ' '
                    . 'WHEN ' . $this->table_left . ' BETWEEN ' . ($rightId1 + 1) . ' AND ' . ($leftId2 - 1) . ' THEN ' . $this->table_left . ' - ' . ($rightId1 - $leftId1 + 1) . ' ELSE ' . $this->table_left . ' END '
                    . 'WHERE ' . $this->table_left . ' BETWEEN ' . $leftId1 . ' AND ' . ($leftId2 - 1);
                }
            }
            if ('after' == $position) {
                if ($leftId1 > $leftId2) {
                    $sql = 'UPDATE ' . $this->table . ' SET '
                    . $this->table_right . ' = CASE WHEN ' . $this->table_left . ' BETWEEN ' . $leftId1 . ' AND ' . $rightId1 . ' THEN ' . $this->table_right . ' - ' . ($leftId1 - $leftId2 - ($rightId2 - $leftId2 + 1)) . ' '
                    . 'WHEN ' . $this->table_left . ' BETWEEN ' . ($rightId2 + 1) . ' AND ' . ($leftId1 - 1) . ' THEN ' . $this->table_right . ' +  ' . ($rightId1 - $leftId1 + 1) . ' ELSE ' . $this->table_right . ' END, '
                    . $this->table_left . ' = CASE WHEN ' . $this->table_left . ' BETWEEN ' . $leftId1 . ' AND ' . $rightId1 . ' THEN ' . $this->table_left . ' - ' . ($leftId1 - $leftId2 - ($rightId2 - $leftId2 + 1)) . ' '
                    . 'WHEN ' . $this->table_left . ' BETWEEN ' . ($rightId2 + 1) . ' AND ' . ($leftId1 - 1) . ' THEN ' . $this->table_left . ' + ' . ($rightId1 - $leftId1 + 1) . ' ELSE ' . $this->table_left . ' END '
                    . 'WHERE ' . $this->table_left . ' BETWEEN ' . ($rightId2 + 1) . ' AND ' . $rightId1;
                } else {
                    $sql = 'UPDATE ' . $this->table . ' SET '
                    . $this->table_right . ' = CASE WHEN ' . $this->table_left . ' BETWEEN ' . $leftId1 . ' AND ' . $rightId1 . ' THEN ' . $this->table_right . ' + ' . ($rightId2 - $rightId1) . ' '
                    . 'WHEN ' . $this->table_left . ' BETWEEN ' . ($rightId1 + 1) . ' AND ' . $rightId2 . ' THEN ' . $this->table_right . ' - ' . (($rightId1 - $leftId1 + 1)) . ' ELSE ' . $this->table_right . ' END, '
                    . $this->table_left . ' = CASE WHEN ' . $this->table_left . ' BETWEEN ' . $leftId1 . ' AND ' . $rightId1 . ' THEN ' . $this->table_left . ' + ' . ($rightId2 - $rightId1) . ' '
                    . 'WHEN ' . $this->table_left . ' BETWEEN ' . ($rightId1 + 1) . ' AND ' . $rightId2 . ' THEN ' . $this->table_left . ' - ' . ($rightId1 - $leftId1 + 1) . ' ELSE ' . $this->table_left . ' END '
                    . 'WHERE ' . $this->table_left . ' BETWEEN ' . $leftId1 . ' AND ' . $rightId2;
                }
            }
            if (!empty($condition)) {
                $condition = $this->_PrepareCondition($condition);
            }
            $sql .= $condition;
            $this->db->StartTrans();
            $res = $this->db->Execute($sql);
            if (FALSE === $res) {
                $this->ERRORS[] = array(2, 'SQL query error.', __FILE__ . '::' . __CLASS__ . '::' . __FUNCTION__ . '::' . __LINE__, 'SQL QUERY: ' . $sql, 'SQL ERROR: ' . $this->db->ErrorMsg());
                $this->ERRORS_MES[] = extension_loaded('gettext') ? _('internal_error') : 'internal_error';
                $this->db->FailTrans();
                return FALSE;
            }
            $this->db->CompleteTrans();
            return TRUE;
        }
    
        /**
        * Delete element with number $id from the tree wihtout deleting it's children.
        *
        * @param integer $ID Number of element
        * @param array $condition Array structure: array('and' => array('id = 0', 'id2 >= 3'), 'or' => array('sec = \'www\'', 'sec2 <> \'erere\'')), etc where array key - condition (AND, OR, etc), value - condition string
        * @return bool TRUE if successful, FALSE otherwise.
        */
        function Delete($ID, $condition = '') {
            $node_info = $this->GetNodeInfo($ID);
            if (FALSE === $node_info) {
                return FALSE;
            }
            list($leftId, $rightId) = $node_info;
            if (!empty($condition)) {
                $condition = $this->_PrepareCondition($condition);
            }
            $sql = 'DELETE FROM ' . $this->table . ' WHERE ' . $this->table_id . ' = ' . (int)$ID;
            $this->db->StartTrans();
            $res = $this->db->Execute($sql);
            if (FALSE === $res) {
                $this->ERRORS[] = array(2, 'SQL query error.', __FILE__ . '::' . __CLASS__ . '::' . __FUNCTION__ . '::' . __LINE__, 'SQL QUERY: ' . $sql, 'SQL ERROR: ' . $this->db->ErrorMsg());
                $this->ERRORS_MES[] = extension_loaded('gettext') ? _('internal_error') : 'internal_error';
                $this->db->FailTrans();
                return FALSE;
            }
            $sql = 'UPDATE ' . $this->table . ' SET '
            . $this->table_level . ' = CASE WHEN ' . $this->table_left . ' BETWEEN ' . $leftId . ' AND ' . $rightId . ' THEN ' . $this->table_level . ' - 1 ELSE ' . $this->table_level . ' END, '
            . $this->table_right . ' = CASE WHEN ' . $this->table_right . ' BETWEEN ' . $leftId . ' AND ' . $rightId . ' THEN ' . $this->table_right . ' - 1 '
            . 'WHEN ' . $this->table_right . ' > ' . $rightId . ' THEN ' . $this->table_right . ' - 2 ELSE ' . $this->table_right . ' END, '
            . $this->table_left . ' = CASE WHEN ' . $this->table_left . ' BETWEEN ' . $leftId . ' AND ' . $rightId . ' THEN ' . $this->table_left . ' - 1 '
            . 'WHEN ' . $this->table_left . ' > ' . $rightId . ' THEN ' . $this->table_left . ' - 2 ELSE ' . $this->table_left . ' END '
            . 'WHERE ' . $this->table_right . ' > ' . $leftId;
            $sql .= $condition;
            $res = $this->db->Execute($sql);
            if (FALSE === $res) {
                $this->ERRORS[] = array(2, 'SQL query error.', __FILE__ . '::' . __CLASS__ . '::' . __FUNCTION__ . '::' . __LINE__, 'SQL QUERY: ' . $sql, 'SQL ERROR: ' . $this->db->ErrorMsg());
                $this->ERRORS_MES[] = extension_loaded('gettext') ? _('internal_error') : 'internal_error';
                $this->db->FailTrans();
                return FALSE;
            }
            $this->db->CompleteTrans();
            return TRUE;
        }
    
        /**
        * Delete element with number $ID from the tree and all it childret.
        *
        * @param integer $ID Number of element
        * @param array $condition Array structure: array('and' => array('id = 0', 'id2 >= 3'), 'or' => array('sec = \'www\'', 'sec2 <> \'erere\'')), etc where array key - condition (AND, OR, etc), value - condition string
        * @return bool TRUE if successful, FALSE otherwise.
        */
        function DeleteAll($ID, $condition = '') {
            $node_info = $this->GetNodeInfo($ID);
            if (FALSE === $node_info) {
                return FALSE;
            }
            list($leftId, $rightId) = $node_info;
            if (!empty($condition)) {
                $condition = $this->_PrepareCondition($condition);
            }
            $sql = 'DELETE FROM ' . $this->table . ' WHERE ' . $this->table_left . ' BETWEEN ' . $leftId . ' AND ' . $rightId;
            $this->db->StartTrans();
            $res = $this->db->Execute($sql);
            if (FALSE === $res) {
                $this->ERRORS[] = array(2, 'SQL query error.', __FILE__ . '::' . __CLASS__ . '::' . __FUNCTION__ . '::' . __LINE__, 'SQL QUERY: ' . $sql, 'SQL ERROR: ' . $this->db->ErrorMsg());
                $this->ERRORS_MES[] = extension_loaded('gettext') ? _('internal_error') : 'internal_error';
                $this->db->FailTrans();
                return FALSE;
            }
            $deltaId = (($rightId - $leftId) + 1);
            $sql = 'UPDATE ' . $this->table . ' SET '
            . $this->table_left . ' = CASE WHEN ' . $this->table_left . ' > ' . $leftId.' THEN ' . $this->table_left . ' - ' . $deltaId . ' ELSE ' . $this->table_left . ' END, '
            . $this->table_right . ' = CASE WHEN ' . $this->table_right . ' > ' . $leftId . ' THEN ' . $this->table_right . ' - ' . $deltaId . ' ELSE ' . $this->table_right . ' END '
            . 'WHERE ' . $this->table_right . ' > ' . $rightId;
            $sql .= $condition;
            $res = $this->db->Execute($sql);
            if (FALSE === $res) {
                $this->ERRORS[] = array(2, 'SQL query error.', __FILE__ . '::' . __CLASS__ . '::' . __FUNCTION__ . '::' . __LINE__, 'SQL QUERY: ' . $sql, 'SQL ERROR: ' . $this->db->ErrorMsg());
                $this->ERRORS_MES[] = extension_loaded('gettext') ? _('internal_error') : 'internal_error';
                $this->db->FailTrans();
                return FALSE;
            }
            $this->db->CompleteTrans();
            return TRUE;
        }
    
        /**
        * Returns all elements of the tree sortet by left.
        *
        * @param array $condition Array structure: array('and' => array('id = 0', 'id2 >= 3'), 'or' => array('sec = \'www\'', 'sec2 <> \'erere\'')), etc where array key - condition (AND, OR, etc), value - condition string
        * @param array $fields needed fields (if is): array('filed1 name', 'filed2 name', etc)
        * @param integer $cache Recordset is cached for $cache microseconds
        * @return array needed fields
        */
        function Full($fields, $condition = '', $cache = FALSE) {
            if (!empty($condition)) {
                $condition = $this->_PrepareCondition($condition, TRUE);
            }
            if (is_array($fields)) {
                $fields = implode(', ', $fields);
            } else {
                $fields = '*';
            }
            $sql = 'SELECT ' . $fields . ' FROM ' . $this->table;
            $sql .= $condition;
            $sql .= ' ORDER BY ' . $this->table_left;
            if (FALSE === DB_CACHE || FALSE === $cache || 0 == (int)$cache) {
                $res = $this->db->Execute($sql);
            } else {
                $res = $this->db->CacheExecute((int)$cache, $sql);
            }
            if (FALSE === $res) {
                $this->ERRORS[] = array(2, 'SQL query error.', __FILE__ . '::' . __CLASS__ . '::' . __FUNCTION__ . '::' . __LINE__, 'SQL QUERY: ' . $sql, 'SQL ERROR: ' . $this->db->ErrorMsg());
                $this->ERRORS_MES[] = extension_loaded('gettext') ? _('internal_error') : 'internal_error';
                return FALSE;
            }
            $this->res = $res;
            return TRUE;
        }
    
        /**
        * Returns all elements of a branch starting from an element with number $ID.
        *
        * @param array $condition Array structure: array('and' => array('id = 0', 'id2 >= 3'), 'or' => array('sec = \'www\'', 'sec2 <> \'erere\'')), etc where array key - condition (AND, OR, etc), value - condition string
        * @param array $fields needed fields (if is): array('filed1 name', 'filed2 name', etc)
        * @param integer $cache Recordset is cached for $cache microseconds
        * @param integer $ID Node unique id
        * @return array - [0] => array(id, left, right, level, additional fields), [1] => array(...), etc.
        */
        function Branch($ID, $fields, $condition = '', $cache = FALSE) {
            if (is_array($fields)) {
                $fields = 'A.' . implode(', A.', $fields);
            } else {
                $fields = 'A.*';
            }
            if (!empty($condition)) {
                $condition = $this->_PrepareCondition($condition, FALSE, 'A.');
            }
            $sql = 'SELECT ' . $fields . ', CASE WHEN A.' . $this->table_left . ' + 1 < A.' . $this->table_right . ' THEN 1 ELSE 0 END AS nflag FROM ' . $this->table . ' A, ' . $this->table . ' B WHERE B.' . $this->table_id . ' = ' . (int)$ID . ' AND A.' . $this->table_left . ' >= B.' . $this->table_left . ' AND A.' . $this->table_right . ' <= B.' . $this->table_right;
            $sql .= $condition;
            $sql .= ' ORDER BY A.' . $this->table_left;
            if (FALSE === DB_CACHE || FALSE === $cache || 0 == (int)$cache) {
                $res = $this->db->Execute($sql);
            } else {
                $res = $this->db->CacheExecute((int)$cache, $sql);
            }
            if (FALSE === $res) {
                $this->ERRORS[] = array(2, 'SQL query error.', __FILE__ . '::' . __CLASS__ . '::' . __FUNCTION__ . '::' . __LINE__, 'SQL QUERY: ' . $sql, 'SQL ERROR: ' . $this->db->ErrorMsg());
                $this->ERRORS_MES[] = extension_loaded('gettext') ? _('internal_error') : 'internal_error';
                return FALSE;
            }
            $this->res = $res;
            return TRUE;
        }
    
        /**
        * Returns all parents of element with number $ID.
        *
        * @param array $condition Array structure: array('and' => array('id = 0', 'id2 >= 3'), 'or' => array('sec = \'www\'', 'sec2 <> \'erere\'')), etc where array key - condition (AND, OR, etc), value - condition string
        * @param array $fields needed fields (if is): array('filed1 name', 'filed2 name', etc)
        * @param integer $cache Recordset is cached for $cache microseconds
        * @param integer $ID Node unique id
        * @return array - [0] => array(id, left, right, level, additional fields), [1] => array(...), etc.
        */
        function Parents($ID, $fields, $condition = '', $cache = FALSE) {
            if (is_array($fields)) {
                $fields = 'A.' . implode(', A.', $fields);
            } else {
                $fields = 'A.*';
            }
            if (!empty($condition)) {
                $condition = $this->_PrepareCondition($condition, FALSE, 'A.');
            }
            $sql = 'SELECT ' . $fields . ', CASE WHEN A.' . $this->table_left . ' + 1 < A.' . $this->table_right . ' THEN 1 ELSE 0 END AS nflag FROM ' . $this->table . ' A, ' . $this->table . ' B WHERE B.' . $this->table_id . ' = ' . (int)$ID . ' AND B.' . $this->table_left . ' BETWEEN A.' . $this->table_left . ' AND A.' . $this->table_right;
            $sql .= $condition;
            $sql .= ' ORDER BY A.' . $this->table_left;
            if (FALSE === DB_CACHE || FALSE === $cache || 0 == (int)$cache) {
                $res = $this->db->Execute($sql);
            } else {
                $res = $this->db->CacheExecute((int)$cache, $sql);
            }
            if (FALSE === $res) {
                $this->ERRORS[] = array(2, 'SQL query error.', __FILE__ . '::' . __CLASS__ . '::' . __FUNCTION__ . '::' . __LINE__, 'SQL QUERY: ' . $sql, 'SQL ERROR: ' . $this->db->ErrorMsg());
                $this->ERRORS_MES[] = extension_loaded('gettext') ? _('internal_error') : 'internal_error';
                return FALSE;
            }
            $this->res = $res;
            return TRUE;
        }
    
        /**
        * Returns a slightly opened tree from an element with number $ID.
        *
        * @param array $condition Array structure: array('and' => array('id = 0', 'id2 >= 3'), 'or' => array('sec = \'www\'', 'sec2 <> \'erere\'')), etc where array key - condition (AND, OR, etc), value - condition string
        * @param array $fields needed fields (if is): array('filed1 name', 'filed2 name', etc)
        * @param integer $cache Recordset is cached for $cache microseconds
        * @param integer $ID Node unique id
        * @return array - [0] => array(id, left, right, level, additional fields), [1] => array(...), etc.
        */
        function Ajar($ID, $fields, $condition = '', $cache = FALSE) {
            if (is_array($fields)) {
                $fields = 'A.' . implode(', A.', $fields);
            } else {
                $fields = 'A.*';
            }
            $condition1 = '';
            if (!empty($condition)) {
                $condition1 = $this->_PrepareCondition($condition, FALSE, 'B.');
            }
            $sql = 'SELECT A.' . $this->table_left . ', A.' . $this->table_right . ', A.' . $this->table_level . ' FROM ' . $this->table . ' A, ' . $this->table . ' B '
            . 'WHERE B.' . $this->table_id . ' = ' . (int)$ID . ' AND B.' . $this->table_left . ' BETWEEN A.' . $this->table_left . ' AND A.' . $this->table_right;
            $sql .= $condition1;
            $sql .= ' ORDER BY A.' . $this->table_left;
            if (FALSE === DB_CACHE || FALSE === $cache || 0 == (int)$cache) {
                $res = $this->db->Execute($sql);
            } else {
                $res = $this->db->CacheExecute((int)$cache, $sql);
            }
            if (FALSE === $res) {
                $this->ERRORS[] = array(2, 'SQL query error.', __FILE__ . '::' . __CLASS__ . '::' . __FUNCTION__ . '::' . __LINE__, 'SQL QUERY: ' . $sql, 'SQL ERROR: ' . $this->db->ErrorMsg());
                $this->ERRORS_MES[] = extension_loaded('gettext') ? _('internal_error') : 'internal_error';
                return FALSE;
            }
            if (0 == $res->RecordCount()) {
                $this->ERRORS_MES[] = _('no_element_in_tree');
                return FALSE;
            }
            $alen = $res->RecordCount();
            $i = 0;
            if (is_array($fields)) {
                $fields = implode(', ', $fields);
            } else {
                $fields = '*';
            }
            if (!empty($condition)) {
                $condition1 = $this->_PrepareCondition($condition, FALSE);
            }
            $sql = 'SELECT ' . $fields . ' FROM ' . $this->table . ' WHERE (' . $this->table_level . ' = 1';
            while ($row = $res->FetchRow()) {
                if ((++$i == $alen) && ($row[$this->table_left] + 1) == $row[$this->table_right]) {
                    break;
                }
                $sql .= ' OR (' . $this->table_level . ' = ' . ($row[$this->table_level] + 1)
                . ' AND ' . $this->table_left . ' > ' . $row[$this->table_left]
                . ' AND ' . $this->table_right . ' < ' . $row[$this->table_right] . ')';
            }
            $sql .= ') ' . $condition1;
            $sql .= ' ORDER BY ' . $this->table_left;
            if (FALSE === DB_CACHE || FALSE === $cache || 0 == (int)$cache) {
                $res = $this->db->Execute($sql);
            } else {
                $res = $this->db->CacheExecute($cache, $sql);
            }
            if (FALSE === $res) {
                $this->ERRORS[] = array(2, 'SQL query error.', __FILE__ . '::' . __CLASS__ . '::' . __FUNCTION__ . '::' . __LINE__, 'SQL QUERY: ' . $sql, 'SQL ERROR: ' . $this->db->ErrorMsg());
                $this->ERRORS_MES[] = extension_loaded('gettext') ? _('internal_error') : 'internal_error';
                return FALSE;
            }
            $this->res = $res;
            return TRUE;
        }
    
        /**
        * Returns amount of lines in result.
        *
        * @return integer
        */
        function RecordCount() {
            return $this->res->RecordCount();
        }
    
        /**
        * Returns the current row.
        *
        * @return array
        */
        function NextRow() {
            return $this->res->FetchRow();
        }
    
        /**
        * Transform array with conditions to SQL query
        * Array structure:
        * array('and' => array('id = 0', 'id2 >= 3'), 'or' => array('sec = \'www\'', 'sec2 <> \'erere\'')), etc
        * where array key - condition (AND, OR, etc), value - condition string.
        *
        * @param array $condition
        * @param string $prefix
        * @param bool $where - True - yes, flase - not
        * @return string
        */
        function _PrepareCondition($condition, $where = FALSE, $prefix = '') {
            if (!is_array($condition)) {
                return $condition;
            }
            $sql = ' ';
            if (TRUE === $where) {
                $sql .= 'WHERE ' . $prefix;
            }
            $keys = array_keys($condition);
            for ($i = 0;$i < count($keys);$i++) {
                if (FALSE === $where || (TRUE === $where && $i > 0)) {
                    $sql .= ' ' . strtoupper($keys[$i]) . ' ' . $prefix;
                }
                $sql .= implode(' ' . strtoupper($keys[$i]) . ' ' . $prefix, $condition[$keys[$i]]);
            }
            return $sql;
        }
    }
    ?>
    


    SQL
    -- MySQL dump 10.9
    --
    -- Host: localhost    Database: russofileru_php
    -- ------------------------------------------------------
    -- Server version       4.1.10a-nt
    
    /*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */;
    /*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */;
    /*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */;
    /*!40101 SET NAMES utf8 */;
    /*!40014 SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0 */;
    /*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */;
    /*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */;
    
    --
    -- Table structure for table `test_sections_seq`
    --
    
    DROP TABLE IF EXISTS `test_sections_seq`;
    CREATE TABLE `test_sections_seq` (
      `id` int(11) default NULL
    ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
    
    --
    -- Dumping data for table `test_sections_seq`
    --
    
    
    /*!40000 ALTER TABLE `test_sections_seq` DISABLE KEYS */;
    LOCK TABLES `test_sections_seq` WRITE;
    INSERT INTO `test_sections_seq` VALUES (12);
    UNLOCK TABLES;
    /*!40000 ALTER TABLE `test_sections_seq` ENABLE KEYS */;
    
    --
    -- Table structure for table `test_sections`
    --
    
    DROP TABLE IF EXISTS `test_sections`;
    CREATE TABLE `test_sections` (
      `section_id` bigint(20) NOT NULL default '0',
      `section_left` bigint(20) NOT NULL default '0',
      `section_right` bigint(20) NOT NULL default '0',
      `section_level` int(11) default NULL,
      `section_name` varchar(255) NOT NULL default '',
      PRIMARY KEY  (`section_id`),
      UNIQUE KEY `section_id` (`section_id`)
    ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
    
    --
    -- Dumping data for table `test_sections`
    --
    
    
    /*!40000 ALTER TABLE `test_sections` DISABLE KEYS */;
    LOCK TABLES `test_sections` WRITE;
    INSERT INTO `test_sections` VALUES (1,1,24,0,'Root'),(2,2,3,1,'Node 1'),(3,4,11,1,'Node 2'),(4,12,19,1,'Node 3'),(5,20,21,1,'Node 4'),(6,22,23,1,'Node 5'),(7,5,6,2,'Subnode 1'),(8,7,8,2,'Subnode 2'),(9,9,10,2,'Subnode 3'),(10,13,16,2,'Subnode 1'),(11,17,18,2,'Subnode 2'),(12,14,15,3,'Subsubnode 1');
    UNLOCK TABLES;
    /*!40000 ALTER TABLE `test_sections` ENABLE KEYS */;
    
    /*!40101 SET SQL_MODE=@OLD_SQL_MODE */;
    /*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */;
    /*!40014 SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS */;
    /*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */;
    /*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS */;
    /*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */;
    
    • siyahbeyaz adlı üyenin fotoğrafı siyahbeyaz
      kategori_id | kategori_ust | kategori_adi
      ------------------------------------------------------

      veritabanın bu sekilde olsun...

      function katselect($KatNo, $UstKatNo=0) {
         $result = mysql_query("SELECT kategori_id,kategori_adi FROM kategoriler WHERE ust='".$KatNo."';");
         while ($row = mysql_fetch_array($result)){
             echo "<option value=\"$row[id]\">";
             $cikti= str_repeat('-',$UstKatNo)." ".$row['kategori_adi'];
                 $s = str_replace("-","",$cikti);
              $tane =substr_count($cikti, '-');
              $bosluk= str_repeat(' ',($tane*2));
              echo "$bosluk".$cikti;
             echo "</option>\n";
             katselect($row['id'], $UstKatNo+1);
         }
      


      boyle bir fonksiyona herzaman ihtiyacın olacaktır. bununla selectbox ta kategorileri listelersin... kategori ekleme olayına gelince..

      <form method="post" action="kaydet.php">
      <select name="kid">
      <option value="0">+ En üst Kategori</option>
      <?=katselect()?>
      </select>
      <input type="text" name="kategori_adi">
      <input type="submit" value="kaydet">
      


      kaydet.php dosyan
      $ust=$_POST[kid];
      $kategori_adi = trim($_POST[kategori_adi]);
      
      @mysql_query("insert into kategoriler (kategori_adi,ust) values ('$kategori_adi','$ust') ");
      echo "kategori eklendi..";
      


      kategorileri düzeltmek icin gerekli kod

      duzenle.php diyorum bunada
      <?
      $id=$_GET[kategori_id];
      $ac = mysql_fetch_object($sql=mysql_query("Select * from kategoriler where kategori_id='$id'"));
      ?>
      
      <form method="post" action="guncelle.php?kategori_id=<?=$ac->kategori_id?>">
      <select name="kid">
      <option value="0">+ En üst Kategori</option>
      <?=katselect($ac->ust)?>
      </select>
      <input type="text" name="kategori_adi" value="<?=$ac->kategori_adi">
      <input type="submit" value="Güncelle">
      
      10 yıl önce yazılmış
    • siyahbeyaz adlı üyenin fotoğrafı siyahbeyaz
      kategori_id | kategori_ust | kategori_adi
      bu sekildeolsun demişim.. kategori_ust yerine sadece ust olacak. yani

      kategori_id | ust | kategori_adi seklinde olsun.. yanlıs yazmısım ılkınde :D
      10 yıl önce yazılmış
    • Raks adlı üyenin fotoğrafı Raks
      ilginiz için teşekkür ederim :)

      ancak bu tarz da bir kategori su anda kullanıyorum benim amacım daha iyi ve sorunsuz bir menüye gecmek yapmak istediğim projemde birbirine bağlı yüzlerce alt kategori olacak bu yüzden derinliğine ulaşabildiğim bir kategori kullanmak istiyorum...

      Fonksiyon için çok teşekkür ederim bu arada deneyeceğim...

      Bu tarz bir yapı hakında yardım edebilecek biri yokmu :((
      10 yıl önce yazılmış
    • zyber adlı üyenin fotoğrafı zyber
      siyahbeyaz'ın bahsettiği hierarchical data Raks'ın sorduğu Nested set model...
      Konuyla ilgili bildiğim/gördüğüm en iyi/detaylı bir kaynak vereyim inceleyiniz.

      http://www.2shared.com/file/Pi28T2iR/nested-set-model.html
      10 yıl önce yazılmış
    • Raks adlı üyenin fotoğrafı Raks
      @zyber
      Teşekkür Ederim biraz uykum geldiği için soyle bi göz gezdirdim ancak gercekten de bahsettiğiniz kadar var gibi :) cok fazla ingilizce gerektirmeyecek bi sekilde anlatılmıs gibi görünüyo p.tesi detaylıca inceleyeceğim...

      iyi geceler....
      10 yıl önce yazılmış