Tree
[ class tree: Tree ] [ index: Tree ] [ all elements ]

Source for file DBsimple.php

Documentation is available at DBsimple.php

  1. <?php
  2. // +----------------------------------------------------------------------+
  3. // | PHP Version 4                                                        |
  4. // +----------------------------------------------------------------------+
  5. // | Copyright (c) 1997-2003 The PHP Group                                |
  6. // +----------------------------------------------------------------------+
  7. // | This source file is subject to version 2.02 of the PHP license,      |
  8. // | that is bundled with this package in the file LICENSE, and is        |
  9. // | available at through the world-wide-web at                           |
  10. // | http://www.php.net/license/2_02.txt.                                 |
  11. // | If you did not receive a copy of the PHP license and are unable to   |
  12. // | obtain it through the world-wide-web, please send a note to          |
  13. // | license@php.net so we can mail you a copy immediately.               |
  14. // +----------------------------------------------------------------------+
  15. // | Authors: Wolfram Kriesing <wolfram@kriesing.de>                      |
  16. // +----------------------------------------------------------------------+
  17.  
  18. // $Id: DBsimple.php 320703 2011-12-08 22:08:40Z danielc $
  19. require_once 'Tree/OptionsDB.php';
  20. require_once 'Tree/Error.php';
  21.  
  22. /**
  23.  * the DB interface to the tree class
  24.  *
  25.  * @access public
  26.  * @author Wolfram Kriesing <wolfram@kriesing.de>
  27.  * @version 2001/06/27
  28.  * @package Tree
  29.  */
  30. {
  31.     // FIXXME should actually extend Tree_Common, to use the methods provided in there...
  32.     // but we need to connect to the db here, so we extend optionsMDB for now, may be use
  33.     // "aggregate" function to fix that
  34.  
  35.     /**
  36.      * @access public
  37.      * @var array saves the options passed to the constructor. Valid options:
  38.      *       - order: which column to order by when reading the data from the DB,
  39.      *                this sorts the data even inside every level
  40.      *       - whereAddOn: add on for the where clause, this string is simply
  41.      *                     added behind the WHERE in the select, so you better make
  42.      *                     sure its correct SQL :-), i.e. 'uid=3'.
  43.      *                     This is needed i.e. when you are saving many trees for different
  44.      *                     user in one table where each entry has a uid (user id)
  45.      *       - columnNameMaps: the column-name maps are used for the "as" in the select
  46.      *                         queries so you can use any column name in the table and "map"
  47.      *                         it to the name that shall be used in the internal array,
  48.      *                         that is built, see the examples (in comments)
  49.      *       - columnNameMaps: array for id/parentId/prevId/name table column names
  50.      */
  51.     var $options = array('order' => '',
  52.                          'whereAddOn' => '',
  53.                          'table' => '',
  54.                          'columnNameMaps' => array(
  55.                                    /* 'id'       => 'tree_id', // use "tree_id" as "id"
  56.                                       'parentId' => 'parent_id',
  57.                                       'prevId'   => 'previous_id',
  58.                                       'name'     => 'nodeName'
  59.                                    */
  60.                         ),
  61.                     );
  62.  
  63.     /**
  64.      *
  65.      * @access public
  66.      * @var string the table where to read the tree data from
  67.      *                     can also be set using the DSN in the constructor
  68.      */
  69.     var $table;
  70.  
  71.     /**
  72.      *
  73.      * @access private
  74.      * @var object $dbh    the handle to the DB-object
  75.      */
  76.     // var $dbh;
  77.  
  78.     // {{{ Tree_Memory_DBsimple()
  79.  
  80.     /**
  81.      * set up this object
  82.      *
  83.      * @version 2001/06/27
  84.      * @access public
  85.      * @author Wolfram Kriesing <wolfram@kriesing.de>
  86.      * @param string $dsn this is a DSN of the for that PEAR::DB uses it
  87.      *                                 only that additionally you can add parameters like ...?table=test_table
  88.      *                                 to define the table it shall work on
  89.      * @param array $options additional options you can set
  90.      */
  91.     function Tree_Memory_DBsimple($dsn$options = array())
  92.     {
  93.         $this->Tree_OptionsDB($dsn$options)// instanciate DB
  94.         if (is_string($options)) {
  95.             // just to be backward compatible, or to make the second paramter shorter
  96.             $this->setOption('order'$options);
  97.         }
  98.  
  99.         $this->table = $this->getOption('table');
  100.     }
  101.  
  102.     // }}}
  103.     // {{{ setup()
  104.  
  105.     /**
  106.      * retreive all the navigation data from the db and call build to build the
  107.      * tree in the array data and structure
  108.      *
  109.      * @version 2001/11/20
  110.      * @access public
  111.      * @author Wolfram Kriesing <wolfram@kriesing.de>
  112.      * @return boolean true on success
  113.      */
  114.     function setup()
  115.     {
  116.         // TODO sort by prevId (parentId,prevId $addQuery) too if it exists in the table, or the root might be wrong
  117.         // TODO  since the prevId of the root should be 0
  118.  
  119.         $whereAddOn '';
  120.         if ($this->options['whereAddOn']{
  121.             $whereAddOn 'WHERE ' $this->getOption('whereAddOn');
  122.         }
  123.  
  124.         $orderBy '';
  125.         if ($this->options['order']{
  126.             $orderBy ',' $this->options['order'];
  127.         }
  128.  
  129.         $map $this->getOption('columnNameMaps');
  130.         if (isset($map['parentId'])) {
  131.             $orderBy $map['parentId'$orderBy;
  132.         else {
  133.             $orderBy 'parentId' $orderBy;
  134.         }
  135.         // build the query this way, that the root, which has no parent (parentId=0)
  136.         // and no previous (prevId=0) is in first place (in case prevId is given)
  137.         $query sprintf("SELECT * FROM %s %s ORDER BY %s",
  138.             $this->table,
  139.             $whereAddOn,
  140.             $orderBy)//,prevId !!!!
  141.         if (DB::isError($res $this->dbh->getAll($query))) {
  142.             // FIXXME remove print use debug mode instead
  143.             printf("ERROR - Tree::setup - %s - %s<br>"DB::errormessage($res)$query);
  144.             return $this->_throwError($res->getMessage()__LINE__);
  145.         }
  146.         // if the db-column names need to be mapped to different names
  147.         // FIXXME somehow we should be able to do this in the query, but i dont know how to select
  148.         // only those columns, use "as" on them and select the rest, without getting those columns again :-(
  149.         if ($map{
  150.             foreach($res as $id => $aResult// map each result
  151.                 foreach($map as $key => $columnName{
  152.                     $res[$id][$key$res[$id][$columnName];
  153.                     unset($res[$id][$columnName]);
  154.                 }
  155.             }
  156.         }
  157.  
  158.         return $res;
  159.     }
  160.  
  161.     // }}}
  162.     // {{{ add()
  163.  
  164.     /**
  165.      * adds _one_ new element in the tree under the given parent
  166.      * the values' keys given have to match the db-columns, because the
  167.      * value gets inserted in the db directly
  168.      * to add an entire node containing children and so on see 'addNode()'
  169.      *
  170.      * to ba compatible, to the DBnested u can also give the parent and previd as the second and third parameter
  171.      *
  172.      * @see addNode
  173.      * @version 2001/10/09
  174.      * @access public
  175.      * @author Wolfram Kriesing <wolfram@kriesing.de>
  176.      * @param array $newValues this array contains the values that shall be inserted in the db-table
  177.      *                                     the key for each element is the name of the column
  178.      * @return mixed either boolean false on failure or the id of the inserted row
  179.      */
  180.     function add($newValues$parentId = 0)
  181.     {
  182.         // FIXXME use $this->dbh->tableInfo to check which columns exist
  183.         // so only data for which a column exist is inserted
  184.         if ($parentId{
  185.             $newValues['parentId'$parentId;
  186.         }
  187.         $newData = array();
  188.         foreach($newValues as $key => $value// quote the values, as needed for the insert
  189.             $newData[$this->_getColName($key)$this->dbh->quote($value);
  190.         }
  191.         // use sequences to create a new id in the db-table
  192.         $nextId $this->dbh->nextId($this->table);
  193.         $query sprintf("INSERT INTO %s (%s,%s) VALUES (%s,%s)",
  194.                          $this->table ,
  195.                          $this->_getColName('id'),
  196.                          implode(','array_keys($newData)) ,
  197.                          $nextId,
  198.                          implode(','$newData));
  199.         if (DB::isError($res $this->dbh->query($query))) {
  200.             // TODO raise PEAR error
  201.             printf("ERROR - Tree::add - %s - %s<br>"DB::errormessage($res)$query);
  202.             return false;
  203.         }
  204.  
  205.         return $nextId;
  206.     }
  207.  
  208.     // }}}
  209.     // {{{ remove()
  210.  
  211.     /**
  212.      * removes the given node
  213.      *
  214.      * @version 2001/10/09
  215.      * @access public
  216.      * @author Wolfram Kriesing <wolfram@kriesing.de>
  217.      * @param mixed $id the id of the node to be removed, or an array of id's to be removed
  218.      * @return boolean true on success
  219.      */
  220.     function remove($id)
  221.     {
  222.         // if the one to remove has children, get their id's to remove them too
  223.         if ($this->hasChildren($id)) {
  224.             $id $this->walk(array('_remove'$this)$id'array');
  225.         }
  226.         $idColumnName 'id';
  227.         $map $this->getOption('columnNameMaps');
  228.         if (isset($map['id'])) // if there are maps given
  229.             $idColumnName $map['id'];
  230.         }
  231.  
  232.         $whereClause = "WHERE $idColumnName=$id";
  233.         if (is_array($id)) {
  234.             $whereClause = "WHERE $idColumnName in (" . implode(','$id')';
  235.         }
  236.  
  237.         $query = "DELETE FROM {$this->table$whereClause";
  238.         // print("<br>".$query);
  239.         if (DB::isError($res = $this->dbh->query($query))) {
  240.             // TODO raise PEAR error
  241.             printf("ERROR - Tree::remove - %s - %s<br>", DB::errormessage($res), $query);
  242.             return false;
  243.         }
  244.         // TODO if remove succeeded set prevId of the following element properly
  245.         return true;
  246.     }
  247.  
  248.     // }}}
  249.     // {{{ move()
  250.     /**
  251.      * move an entry under a given parent or behind a given entry
  252.      *
  253.      * @version 2001/10/10
  254.      * @access public
  255.      * @author Wolfram Kriesing <wolfram@kriesing.de>
  256.      * @param integer $idToMove the id of the element that shall be moved
  257.      * @param integer $newParentId the id of the element which will be the new parent
  258.      * @param integer $newPrevId if prevId is given the element with the id idToMove
  259.      *                                        shall be moved _behind_ the element with id=prevId
  260.      *                                        if it is 0 it will be put at the beginning
  261.      *                                        if no prevId is in the DB it can be 0 too and won't bother
  262.      *                                        since it is not written in the DB anyway
  263.      * @return boolean true for success
  264.      */
  265.     function move($idToMove, $newParentId, $newPrevId = 0)
  266.     {
  267.         $idColumnName = 'id';
  268.         $parentIdColumnName = 'parentId';
  269.         $map = $this->getOption('columnNameMaps');
  270.         if (isset($map['id'])) {
  271.             $idColumnName = $map['id'];
  272.         }
  273.         if (isset($map['parentId'])) {
  274.             $parentIdColumnName = $map['parentId'];
  275.         }
  276.         // FIXXME todo: previous stuff
  277.         // set the parent in the DB
  278.         $query = "UPDATE $this->table SET $parentIdColumnName=$newParentId WHERE $idColumnName=$idToMove";
  279.         // print($query);
  280.         if (DB::isError($res = $this->dbh->query($query))) {
  281.             // TODO raise PEAR error
  282.             printf("ERROR - Tree::move - %s - %s<br>", DB::errormessage($res), $query);
  283.             return false;
  284.         }
  285.         // FIXXME update the prevId's of the elements where the element was moved away from and moved in
  286.         return true;
  287.     }
  288.  
  289.     // }}}
  290.     // {{{ update()
  291.     /**
  292.      * update an element in the DB
  293.      *
  294.      * @version 2002/01/17
  295.      * @access public
  296.      * @author Wolfram Kriesing <wolfram@kriesing.de>
  297.      * @param array $newData all the new data, the key 'id' is used to
  298.      *                                    build the 'WHERE id=' clause and all the other
  299.      *                                    elements are the data to fill in the DB
  300.      * @return boolean true for success
  301.      */
  302.     function update($id, $newData)
  303.     {
  304.         // FIXXME check $this->dbh->tableInfo to see if all the columns that shall be updated
  305.         // really exist, this will also extract nextId etc. if given before writing it in the DB
  306.         // in case they dont exist in the DB
  307.         $setData = array();
  308.         foreach($newData as $key => $value) { // quote the values, as needed for the insert
  309.             $setData[] = $this->_getColName($key'=' $this->dbh->quote($value);
  310.         }
  311.  
  312.         $query = sprintf('UPDATE %s SET %s WHERE %s=%s',
  313.                          $this->table,
  314.                          implode(','$setData),
  315.                          $this->_getColName('id'),
  316.                          $id
  317.                          );
  318.         if (DB::isError($res $this->dbh->query($query))) {
  319.             // FIXXME raise PEAR error
  320.             printf("ERROR - Tree::update - %s - %s<br>", DB::errormessage($res), $query);
  321.             return false;
  322.         }
  323.  
  324.         return true;
  325.     }
  326.  
  327.     // }}}
  328.     // {{{ _throwError()
  329.     /**
  330.      *
  331.      * @access private
  332.      * @version 2002/03/02
  333.      * @author Wolfram Kriesing <wolfram@kriesing.de>
  334.      */
  335.     function _throwError($msg, $line, $mode = null)
  336.     {
  337.         return new Tree_Error($msg, $line, __FILE__, $mode, $this->db->last_query);
  338.     }
  339.  
  340.     // }}}
  341.     // {{{ _prepareResults()
  342.     /**
  343.      * prepare multiple results
  344.      *
  345.      * @see _prepareResult
  346.      * @access private
  347.      * @version 2002/03/03
  348.      * @author Wolfram Kriesing <wolfram@kriesing.de>
  349.      */
  350.     function _prepareResults($results)
  351.     {
  352.         $newResults = array();
  353.         foreach($results as $aResult)
  354.         $newResults[] = $this->_prepareResult($aResult);
  355.         return $newResults;
  356.     }
  357.  
  358.     // }}}
  359.     // {{{ _prepareResult()
  360.     /**
  361.      * map back the index names to get what is expected
  362.      *
  363.      * @access private
  364.      * @version 2002/03/03
  365.      * @author Wolfram Kriesing <wolfram@kriesing.de>
  366.      */
  367.     function _prepareResult($result)
  368.     {
  369.         $map = $this->getOption('columnNameMaps');
  370.  
  371.         if ($map{
  372.             foreach($map as $key => $columnName) {
  373.                 $result[$key] = $result[$columnName];
  374.                 unset($result[$columnName]);
  375.             }
  376.         }
  377.         return $result;
  378.     }
  379.  
  380.     // }}}
  381.     // {{{ _getColName()
  382.     /**
  383.      * this method retreives the real column name, as used in the DB
  384.      *    since the internal names are fixed, to be portable between different
  385.      *    DB-column namings, we map the internal name to the real column name here
  386.      *
  387.      * @access private
  388.      * @version 2002/03/02
  389.      * @author Wolfram Kriesing <wolfram@kriesing.de>
  390.      */
  391.     function _getColName($internalName)
  392.     {
  393.         if ($map = $this->getOption('columnNameMaps')) {
  394.             if (isset($map[$internalName])) {
  395.                 return $map[$internalName];
  396.             }
  397.         }
  398.         return $internalName;
  399.     }
  400.  
  401.     // }}}

Documentation generated on Mon, 11 Mar 2019 15:47:04 -0400 by phpDocumentor 1.4.4. PEAR Logo Copyright © PHP Group 2004.