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

Source for file Query.php

Documentation is available at Query.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. // | Author:  Wolfram Kriesing, Paolo Panto, vision:produktion <wk@visionp.de>
  16. // +----------------------------------------------------------------------+
  17. //
  18. // $Id: Query.php,v 1.52 2004/10/13 16:24:47 quipo Exp $
  19. //
  20.  
  21. require_once 'PEAR.php';
  22. require_once 'DB.php';
  23.  
  24.  
  25. /**
  26.  * this class should be extended
  27.  *
  28.  * @package    DB_QueryTool
  29.  * @version    2002/04/02
  30.  * @access     public
  31.  * @author     Wolfram Kriesing <wk@visionp.de>
  32.  */
  33. {
  34.     // {{{ class vars
  35.  
  36.     /**
  37.      * @var string  the name of the primary column
  38.      */
  39.     var $primaryCol = 'id';
  40.  
  41.     /**
  42.      * @var string  the current table the class works on
  43.      */
  44.     var $table      = '';
  45.  
  46.     /**
  47.      * @var string  the name of the sequence for this table
  48.      */
  49.     var $sequenceName = null;
  50.  
  51.     /**
  52.      * @var object  the db-object, a PEAR::Db-object instance
  53.      */
  54.     var $db = null;
  55.  
  56.     /**
  57.      * @var string  the where condition
  58.      * @access private
  59.      */
  60.     var $_where '';
  61.  
  62.     /**
  63.      * @var string  the order condition
  64.      * @access private
  65.      */
  66.     var $_order '';
  67.  
  68.     /**
  69.      * @var    string  the having definition
  70.      * @access private
  71.      */
  72.     var $_having '';
  73.  
  74.     /**
  75.      * @var array   contains the join content
  76.      *               the key is the join type, for now we have 'default' and 'left'
  77.      *               inside each key 'table' contains the table
  78.      *                           key 'where' contains the where clause for the join
  79.      * @access private
  80.      */
  81.     var $_join = array();
  82.  
  83.     /**
  84.      * @var    string  which column to index the result by
  85.      * @access private
  86.      */
  87.     var $_index = null;
  88.  
  89.     /**
  90.      * @var    string  the group-by clause
  91.      * @access private
  92.      */
  93.     var $_group '';
  94.  
  95.     /**
  96.      * @var    array   the limit
  97.      * @access private
  98.      */
  99.     var $_limit = array();
  100.  
  101.     /**
  102.      * @var    string  type of result to return
  103.      * @access private
  104.      */
  105.     var $_resultType 'none';
  106.  
  107.     /**
  108.      * @var    array   the metadata temporary saved
  109.      * @access private
  110.      */
  111.     var $_metadata = array();
  112.  
  113.     /**
  114.      * @var    string 
  115.      * @access private
  116.      */
  117.     var $_lastQuery = null;
  118.  
  119.     /**
  120.      * @var    string   the rows that shall be selected
  121.      * @access private
  122.      */
  123.     var $_select '*';
  124.  
  125.     /**
  126.      * @var    string   the rows that shall not be selected
  127.      * @access private
  128.      */
  129.     var $_dontSelect '';
  130.  
  131.     /**
  132.      * @var array  this array saves different modes in which this class works
  133.      *              i.e. 'raw' means no quoting before saving/updating data
  134.      * @access private
  135.      */
  136.     var $options = array(
  137.         'raw'      =>  false,
  138.         'verbose'  =>  true,    // set this to false in a productive environment
  139.                                 // it will produce error-logs if set to true
  140.         'useCache' =>  false,
  141.         'logFile'  =>  false,
  142.     );
  143.  
  144.     /**
  145.      * this array contains information about the tables
  146.      * those are
  147.      * - 'name' => the real table name
  148.      * - 'shortName' => the short name used, so that when moving the table i.e.
  149.      *                  onto a provider's db and u have to rename the tables to
  150.      *                  longer names this name will be relevant, i.e. when
  151.      *                  autoJoining, i.e. a table name on your local machine is:
  152.      *                  'user' but online it has to be 'applName_user' then the
  153.      *                  shortName will be used to determine if a column refers to
  154.      *                  another table, if the colName is 'user_id', it knows the
  155.      *                  shortName 'user' refers to the table 'applName_user'
  156.      */
  157.     var $tableSpec = array();
  158.  
  159.     /**
  160.      * this is the regular expression that shall be used to find a table's shortName
  161.      * in a column name, the string found by using this regular expression will be removed
  162.      * from the column name and it will be checked if it is a table name
  163.      * i.e. the default '/_id$/' would find the table name 'user' from the column name 'user_id'
  164.      */
  165.     var $_tableNameToShortNamePreg '/^.*_/';
  166.  
  167.     /**
  168.      * @var array this array caches queries that have already been built once
  169.      *             to reduce the execution time
  170.      */
  171.     var $_queryCache = array();
  172.  
  173.     /**
  174.      * The object that contains the log-instance
  175.      */
  176.     var $_logObject = null;
  177.  
  178.     /**
  179.      * Some internal data the logging needs
  180.      */
  181.     var $_logData = array();
  182.  
  183.     // }}}
  184.     // {{{ __construct()
  185.  
  186.     /**
  187.      * this is the constructor, as it will be implemented in ZE2 (php5)
  188.      *
  189.      * @version    2002/04/02
  190.      * @access     public
  191.      * @author     Wolfram Kriesing <wk@visionp.de>
  192.      * @param      object  db-object 
  193.      */
  194. /*
  195.     function __construct($dsn=false, $options=array())
  196.     {
  197.         if (!isset($options['autoConnect'])) {
  198.             $autoConnect = true;
  199.         } else {
  200.             $autoConnect = $options['autoConnect'];
  201.         }
  202.         if (isset($options['errorCallback'])) {
  203.             $this->setErrorCallback($options['errorCallback']);
  204.         }
  205.         if (isset($options['errorSetCallback'])) {
  206.             $this->setErrorSetCallback($options['errorSetCallback']);
  207.         }
  208.         if (isset($options['errorLogCallback'])) {
  209.             $this->setErrorLogCallback($options['errorLogCallback']);
  210.         }
  211.  
  212.         if ($autoConnect && $dsn) {
  213.             $this->connect($dsn, $options);
  214.         }
  215.         //we would need to parse the dsn first ... i dont feel like now :-)
  216.         // oracle has all column names in upper case
  217. //FIXXXME make the class work only with upper case when we work with oracle
  218.         //if ($this->db->phptype=='oci8' && !$this->primaryCol) {
  219.         //    $this->primaryCol = 'ID';
  220.         //}
  221.  
  222.         if ($this->sequenceName == null) {
  223.             $this->sequenceName = $this->table;
  224.         }
  225.     }
  226. */
  227.  
  228.     // }}}
  229.     // {{{ DB_QueryTool_Query()
  230.  
  231.     /**
  232.      * @version    2002/04/02
  233.      * @access     public
  234.      * @author     Wolfram Kriesing <wk@visionp.de>
  235.      * @param mixed $dsn DSN string, DSN array or DB object
  236.      * @param array $options 
  237.      */
  238.     function DB_QueryTool_Query($dsn=false$options=array())
  239.     {
  240.         //$this->__construct($dsn, $options);
  241.         if (!isset($options['autoConnect'])) {
  242.             $autoConnect = true;
  243.         else {
  244.             $autoConnect $options['autoConnect'];
  245.             unset($options['autoConnect']);
  246.         }
  247.         if (isset($options['errorCallback'])) {
  248.             $this->setErrorCallback($options['errorCallback']);
  249.             unset($options['errorCallback']);
  250.         }
  251.         if (isset($options['errorSetCallback'])) {
  252.             $this->setErrorSetCallback($options['errorSetCallback']);
  253.             unset($options['errorSetCallback']);
  254.         }
  255.         if (isset($options['errorLogCallback'])) {
  256.             $this->setErrorLogCallback($options['errorLogCallback']);
  257.             unset($options['errorLogCallback']);
  258.         }
  259.         if ($autoConnect && $dsn{
  260.             $this->connect($dsn$options);
  261.         }
  262.         if (is_null($this->sequenceName)) {
  263.             $this->sequenceName = $this->table;
  264.         }
  265.     }
  266.  
  267.     // }}}
  268.     // {{{ connect()
  269.  
  270.     /**
  271.      * use this method if you want to connect manually
  272.      * @param mixed $dsn DSN string, DSN array or MDB object
  273.      * @param array $options 
  274.      */
  275.     function connect($dsn$options=array())
  276.     {
  277.         if (is_object($dsn)) {
  278.             $res $this->db =$dsn;
  279.         else {
  280.             $res $this->db = DB::connect($dsn$options);
  281.         }
  282.         if (DB::isError($res)) {
  283. // FIXXME what shall we do here?
  284.             $this->_errorLog($res->getUserInfo());
  285.         else {
  286.             $this->db->setFetchMode(DB_FETCHMODE_ASSOC);
  287.         }
  288.     }
  289.  
  290.     // }}}
  291.     // {{{ getDbInstance()
  292.  
  293.     /**
  294.      * @return reference to current DB instance
  295.      */
  296.     function &getDbInstance()
  297.     {
  298.         return $this->db;
  299.     }
  300.  
  301.     // }}}
  302.     // {{{ setDbInstance()
  303.  
  304.     /**
  305.      * Setup using an existing connection.
  306.      * this also sets the DB_FETCHMODE_ASSOC since this class
  307.      * needs this to be set!
  308.      *
  309.      * @param object reference to an existing DB-object
  310.      * @return void 
  311.      */
  312.     function setDbInstance(&$dbh)
  313.     {
  314.         $this->db =$dbh;
  315.         $this->db->setFetchMode(DB_FETCHMODE_ASSOC);
  316.     }
  317.  
  318.     // }}}
  319.     // {{{ get()
  320.  
  321.     /**
  322.      * get the data of a single entry
  323.      * if the second parameter is only one column the result will be returned
  324.      * directly not as an array!
  325.      *
  326.      * @version    2002/03/05
  327.      * @access     public
  328.      * @author     Wolfram Kriesing <wk@visionp.de>
  329.      * @param      integer the id of the element to retreive
  330.      * @param      string  if this is given only one row shall be returned, directly, not an array
  331.      * @return     mixed   (1) an array of the retreived data
  332.      *                      (2) if the second parameter is given and its only one column,
  333.      *                          only this column's data will be returned
  334.      *                      (3) false in case of failure
  335.      */
  336.     function get($id$column='')
  337.     {
  338.         $table $this->table;
  339.         $getMethod 'getRow';
  340.         if ($column && !strpos($column',')) {   // if only one column shall be selected
  341.             $getMethod 'getOne';
  342.         }
  343.         // we dont use 'setSelect' here, since this changes the setup of the class, we
  344.         // build the query directly
  345.         // if $column is '' then _buildSelect selects '*' anyway, so that's the same behaviour as before
  346.         $query['select'$this->_buildSelect($column);
  347.         $query['where']  $this->_buildWhere($this->table.'.'.$this->primaryCol.'='.$id);
  348.         $queryString $this->_buildSelectQuery($query);
  349.  
  350.         return $this->returnResult($this->execute($queryString,$getMethod));
  351.     }
  352.  
  353.     // }}}
  354.     // {{{ getMultiple()
  355.  
  356.     /**
  357.      * gets the data of the given ids
  358.      *
  359.      * @version    2002/04/23
  360.      * @access     public
  361.      * @author     Wolfram Kriesing <wk@visionp.de>
  362.      * @param      array   this is an array of ids to retreive
  363.      * @param      string  the column to search in for
  364.      * @return     mixed   an array of the retreived data, or false in case of failure
  365.      *                        when failing an error is set in $this->_error
  366.      */
  367.     function getMultiple($ids$column='')
  368.     {
  369.         $col $this->primaryCol;
  370.         if ($column{
  371.             $col $column;
  372.         }
  373. // FIXXME if $ids has no table.col syntax and we are using joins, the table better be put in front!!!
  374.         $ids $this->_quoteArray($ids);
  375.  
  376.         $query['where'$this->_buildWhere($col.' IN ('.implode(','$ids).')');
  377.         $queryString $this->_buildSelectQuery($query);
  378.  
  379.         return $this->returnResult($this->execute($queryString));
  380.     }
  381.  
  382.     // }}}
  383.     // {{{ getAll()
  384.  
  385.     /**
  386.      * get all entries from the DB
  387.      * for sorting use setOrder!!!, the last 2 parameters are deprecated
  388.      *
  389.      * @version    2002/03/05
  390.      * @access     public
  391.      * @author     Wolfram Kriesing <wk@visionp.de>
  392.      * @param      int     to start from
  393.      * @param      int     the number of rows to show
  394.      * @param      string  the DB-method to use, i dont know if we should leave this param here ...
  395.      * @return     mixed   an array of the retreived data, or false in case of failure
  396.      *                        when failing an error is set in $this->_error
  397.      */
  398.     function getAll($from=0,$count=0,$method='getAll')
  399.     {
  400.         $query = array();
  401.         if ($count{
  402.             $query = array('limit' => array($from$count));
  403.         }
  404.         return $this->returnResult($this->execute($this->_buildSelectQuery($query)$method));
  405.     }
  406.  
  407.     // }}}
  408.     // {{{ getCol()
  409.  
  410.     /**
  411.      * this method only returns one column, so the result will be a one dimensional array
  412.      * this does also mean that using setSelect() should be set to *one* column, the one you want to
  413.      * have returned a most common use case for this could be:
  414.      *      $table->setSelect('id');
  415.      *      $ids = $table->getCol();
  416.      * OR
  417.      *      $ids = $table->getCol('id');
  418.      * so ids will ba an array with all the id's
  419.      *
  420.      * @version    2003/02/25
  421.      * @access     public
  422.      * @author     Wolfram Kriesing <wk@visionp.de>
  423.      * @param      string  the column that shall be retreived
  424.      * @param      int     to start from
  425.      * @param      int     the number of rows to show
  426.      * @return     mixed   an array of the retreived data, or false in case of failure
  427.      *                      when failing an error is set in $this->_error
  428.      */
  429.     function getCol($column=null$from=0$count=0)
  430.     {
  431.         $query = array();
  432.         if (!is_null($column)) {
  433.             // by using _buildSelect() i can be sure that the table name will not be ambigious
  434.             // i.e. in a join, where all the joined tables have a col 'id'
  435.             // _buildSelect() will put the proper table name in front in case there is none
  436.             $query['select'$this->_buildSelect($column);
  437.         }
  438.         if ($count{
  439.             $query['limit'= array($from,$count);
  440.         }
  441.         return $this->returnResult($this->execute($this->_buildSelectQuery($query)'getCol'));
  442.     }
  443.  
  444.     // }}}
  445.     // {{{ getCount()
  446.  
  447.     /**
  448.      * get the number of entries
  449.      *
  450.      * @version    2002/04/02
  451.      * @access     public
  452.      * @author     Wolfram Kriesing <wk@visionp.de>
  453.      * @param 
  454.      * @return     mixed   an array of the retreived data, or false in case of failure
  455.      *                        when failing an error is set in $this->_error
  456.      */
  457.     function getCount()
  458.     {
  459. /* the following query works on mysql
  460. SELECT count(DISTINCT image.id) FROM image2tree
  461. RIGHT JOIN image ON image.id = image2tree.image_id
  462. the reason why this is needed - i just wanted to get the number of rows that do exist if the result is grouped by image.id
  463. the following query is what i tried first, but that returns the number of rows that have been grouped together
  464. for each image.id
  465. SELECT count(*) FROM image2tree
  466. RIGHT JOIN image ON image.id = image2tree.image_id GROUP BY image.id
  467.  
  468. so that's why we do the following, i am not sure if that is standard SQL and absolutley correct!!!
  469. */
  470.  
  471. //FIXXME see comment above if this is absolutely correct!!!
  472.         if ($group $this->_buildGroup()) {
  473.             $query['select''COUNT(DISTINCT '.$group.')';
  474.             $query['group''';
  475.         else {
  476.             $query['select''COUNT(*)';
  477.         }
  478.  
  479.         $query['order''';   // order is not of importance and might freak up the special group-handling up there, since the order-col is not be known
  480. /*# FIXXME use the following line, but watch out, then it has to be used in every method, or this
  481. # value will be used always, simply try calling getCount and getAll afterwards, getAll will return the count :-)
  482. # if getAll doenst use setSelect!!!
  483. */
  484.         //$this->setSelect('count(*)');
  485.         $queryString $this->_buildSelectQuery($query);
  486.  
  487.         return ($res $this->execute($queryString'getOne')) $res : 0;
  488.     }
  489.  
  490.     // }}}
  491.     // {{{ getDefaultValues()
  492.  
  493.     /**
  494.      * return an empty element where all the array elements do already exist
  495.      * corresponding to the columns in the DB
  496.      *
  497.      * @version    2002/04/05
  498.      * @access     public
  499.      * @author     Wolfram Kriesing <wk@visionp.de>
  500.      * @return     array   an empty, or pre-initialized element
  501.      */
  502.     function getDefaultValues()
  503.     {
  504.         $ret = array();
  505.         // here we read all the columns from the DB and initialize them
  506.         // with '' to prevent PHP-warnings in case we use error_reporting=E_ALL
  507.         foreach ($this->metadata(as $aCol=>$x{
  508.             $ret[$aCol'';
  509.         }
  510.         return $ret;
  511.     }
  512.  
  513.     // }}}
  514.     // {{{ getEmptyElement()
  515.  
  516.     /**
  517.      * this is just for BC
  518.      * @deprecated
  519.      */
  520.     function getEmptyElement()
  521.     {
  522.         $this->getDefaultValues();
  523.     }
  524.  
  525.     // }}}
  526.     // {{{ getQueryString()
  527.  
  528.     /**
  529.      * Render the current query and return it as a string.
  530.      *
  531.      * @return string the current query
  532.      */
  533.     function getQueryString()
  534.     {
  535.         $ret $this->_buildSelectQuery();
  536.         if (is_string($ret)) {
  537.             $ret trim($ret);
  538.         }
  539.         return $ret;
  540.     }
  541.  
  542.     // }}}
  543.     // {{{ save()
  544.  
  545.     /**
  546.      * save data, calls either update or add
  547.      * if the primaryCol is given in the data this method knows that the
  548.      * data passed to it are meant to be updated (call 'update'), otherwise it will
  549.      * call the method 'add'.
  550.      * If you dont like this behaviour simply stick with the methods 'add'
  551.      * and 'update' and ignore this one here.
  552.      * This method is very useful when you have validation checks that have to
  553.      * be done for both adding and updating, then you can simply overwrite this
  554.      * method and do the checks in here, and both cases will be validated first.
  555.      *
  556.      * @version    2002/03/11
  557.      * @access     public
  558.      * @author     Wolfram Kriesing <wk@visionp.de>
  559.      * @param      array   contains the new data that shall be saved in the DB
  560.      * @return     mixed   the data returned by either add or update-method
  561.      */
  562.     function save($data)
  563.     {
  564.         if (!empty($data[$this->primaryCol])) {
  565.             return $this->update($data);
  566.         }
  567.         return $this->add($data);
  568.     }
  569.  
  570.     // }}}
  571.     // {{{ update()
  572.  
  573.     /**
  574.      * update the member data of a data set
  575.      *
  576.      * @version    2002/03/06
  577.      * @access     public
  578.      * @author     Wolfram Kriesing <wk@visionp.de>
  579.      * @param      array   contains the new data that shall be saved in the DB
  580.      *                      the id has to be given in the field with the key 'ID'
  581.      * @return     mixed   true on success, or false otherwise
  582.      */
  583.     function update($newData)
  584.     {
  585.         $query = array();
  586.         // do only set the 'where' part in $query, if a primary column is given
  587.         // if not the default 'where' clause is used
  588.         if (isset($newData[$this->primaryCol])) {
  589.             $query['where'$this->primaryCol.'='.$newData[$this->primaryCol];
  590.         }
  591.         $newData $this->_checkColumns($newData'update');
  592.         $values = array();
  593.         $raw $this->getOption('raw');
  594.         foreach ($newData as $key => $aData{         // quote the data
  595.             //$values[] = "{$this->table}.$key=". ($raw ? $aData : $this->db->quote($aData));
  596.             $values[= "$key=". ($raw $aData $this->db->quote($aData));
  597.         }
  598.  
  599.         $query['set'implode(','$values);
  600. //FIXXXME _buildUpdateQuery() seems to take joins into account, whcih is bullshit here
  601.         $updateString $this->_buildUpdateQuery($query);
  602. #print '$updateString = '.$updateString;
  603.         return $this->execute($updateString'query'? true : false;
  604.     }
  605.  
  606.     // }}}
  607.     // {{{ add()
  608.  
  609.     /**
  610.      * add a new member in the DB
  611.      *
  612.      * @version    2002/04/02
  613.      * @access     public
  614.      * @author     Wolfram Kriesing <wk@visionp.de>
  615.      * @param      array   contains the new data that shall be saved in the DB
  616.      * @return     mixed   the inserted id on success, or false otherwise
  617.      */
  618.     function add($newData)
  619.     {
  620.         // if no primary col is given, get next sequence value
  621.         if (empty($newData[$this->primaryCol])) {
  622.             if ($this->primaryCol{    // do only use the sequence if a primary column is given
  623.                                         // otherwise the data are written as given
  624.                 $id $this->db->nextId($this->sequenceName);
  625.                 $newData[$this->primaryCol= (int)$id;
  626.             else {
  627.                 // if no primary col is given return true on success
  628.                 $id = true;
  629.             }
  630.         else {
  631.             $id $newData[$this->primaryCol];
  632.         }
  633.  
  634.         //unset($newData[$this->primaryCol]);
  635.  
  636.         $newData $this->_checkColumns($newData'add');
  637.         $newData $this->_quoteArray($newData);
  638.  
  639.         $query sprintf(   'INSERT INTO %s (%s) VALUES (%s)',
  640.                             $this->table,
  641.                             implode(', 'array_keys($newData)),
  642.                             implode(', '$newData)
  643.                        );
  644.         return $this->execute($query'query'$id : false;
  645.     }
  646.  
  647.     // }}}
  648.     // {{{ addMultiple()
  649.  
  650.     /**
  651.      * adds multiple new members in the DB
  652.      *
  653.      * @version    2002/07/17
  654.      * @access     public
  655.      * @author     Wolfram Kriesing <wk@visionp.de>
  656.      * @param      array   contains an array of new data that shall be saved in the DB
  657.      *                      the key-value pairs have to be the same for all the data!!!
  658.      * @return     mixed   the inserted ids on success, or false otherwise
  659.      */
  660.     function addMultiple($data)
  661.     {
  662.         if (!sizeof($data)) {
  663.             return false;
  664.         }
  665.         // the inserted ids which will be returned or if no primaryCol is given
  666.         // we return true by default
  667.         $retIds $this->primaryCol ? array(: true;
  668.         $allData = array();     // each row that will be inserted
  669.         foreach ($data as $key => $aData{
  670.             $aData $this->_checkColumns($aData'add');
  671.             $aData $this->_quoteArray($aData);
  672.  
  673.             if (empty($aData[$this->primaryCol])) {
  674.                 if ($this->primaryCol{    // do only use the sequence if a primary column is given
  675.                                             // otherwise the data are written as given
  676.                     $retIds[$id = (int)$this->db->nextId($this->sequenceName);
  677.                     $aData[$this->primaryCol$id;
  678.                 }
  679.             else {
  680.                 $retIds[$aData[$this->primaryCol];
  681.             }
  682.             $allData['('.implode(', '$aData).')';
  683.         }
  684.  
  685.         $query sprintf(   'INSERT INTO %s (%s) VALUES %s',
  686.                             $this->table,
  687.                             implode(', 'array_keys($aData))// use the keys of the last element built
  688.                             implode(', '$allData)
  689.                         );
  690.         return $this->execute($query'query'$retIds : false;
  691.     }
  692.  
  693.     // }}}
  694.     // {{{ remove()
  695.  
  696.    /**
  697.      * removes a member from the DB
  698.      *
  699.      * @version    2002/04/08
  700.      * @access     public
  701.      * @author     Wolfram Kriesing <wk@visionp.de>
  702.      * @param      mixed   integer/string - the value of the column that shall be removed
  703.      *                        array   - multiple columns that shall be matched, the second parameter will be ommited
  704.      * @param      string  the column to match the data against, only if $data is not an array
  705.      * @return     boolean 
  706.      */
  707.     function remove($data$whereCol='')
  708.     {
  709.         $raw $this->getOption('raw');
  710.  
  711.         if (is_array($data)) {
  712. //FIXXME check $data if it only contains columns that really exist in the table
  713.             $wheres = array();
  714.             foreach ($data as $key => $val{
  715.                 $wheres[$key.'='($raw $val $this->db->quote($val));
  716.             }
  717.             $whereClause implode(' AND ',$wheres);
  718.         else {
  719.             if (empty($whereCol)) {
  720.                 $whereCol $this->primaryCol;
  721.             }
  722.             $whereClause $whereCol.'='($raw $data $this->db->quote($data));
  723.         }
  724.  
  725.         $query sprintf(   'DELETE FROM %s WHERE %s',
  726.                             $this->table,
  727.                             $whereClause
  728.                             );
  729.         return $this->execute($query'query'? true : false;
  730. // i think this method should return the ID's that it removed, this way we could simply use the result
  731. // for further actions that depend on those id ... or? make stuff easier, see ignaz::imail::remove
  732.     }
  733.  
  734.     // }}}
  735.     // {{{ removeAll()
  736.  
  737.     /**
  738.      * empty a table
  739.      *
  740.      * @version    2002/06/17
  741.      * @access     public
  742.      * @author     Wolfram Kriesing <wk@visionp.de>
  743.      * @return 
  744.      */
  745.     function removeAll()
  746.     {
  747.         $query 'DELETE FROM '.$this->table;
  748.         return $this->execute($query'query'? true : false;
  749.     }
  750.  
  751.     // }}}
  752.     // {{{ removeMultiple()
  753.  
  754.     /**
  755.      * remove the datasets with the given ids
  756.      *
  757.      * @version    2002/04/24
  758.      * @access     public
  759.      * @author     Wolfram Kriesing <wk@visionp.de>
  760.      * @param      array   the ids to remove
  761.      * @return 
  762.      */
  763.     function removeMultiple($ids$colName='')
  764.     {
  765.         if (empty($colName)) {
  766.             $colName $this->primaryCol;
  767.         }
  768.         $ids $this->_quoteArray($ids);
  769.  
  770.         $query sprintf(   'DELETE FROM %s WHERE %s IN (%s)',
  771.                             $this->table,
  772.                             $colName,
  773.                             implode(','$ids)
  774.                         );
  775.         return $this->execute($query'query'? true : false;
  776.     }
  777.  
  778.     // }}}
  779.     // {{{ removePrimary()
  780.  
  781.     /**
  782.      * removes a member from the DB and calls the remove methods of the given objects
  783.      * so all rows in another table that refer to this table are erased too
  784.      *
  785.      * @version    2002/04/08
  786.      * @access     public
  787.      * @author     Wolfram Kriesing <wk@visionp.de>
  788.      * @param      integer the value of the primary key
  789.      * @param      string  the column name of the tables with the foreign keys
  790.      * @param      object  just for convinience, so nobody forgets to call this method
  791.      *                        with at least one object as a parameter
  792.      * @return     boolean 
  793.      */
  794.     function removePrimary($id$colName$atLeastOneObject)
  795.     {
  796.         $argCounter = 2;    // we have 2 parameters that need to be given at least
  797.         // func_get_arg returns false and a warning if there are no more parameters, so
  798.         // we suppress the warning and check for false
  799.         while ($object @func_get_arg($argCounter++)) {
  800. //FIXXXME let $object also simply be a table name
  801.             if (!$object->remove($id$colName)) {
  802. //FIXXXME do this better
  803.                 $this->_errorSet("Error removing '$colName=$id' from table {$object->table}.");
  804.                return false;
  805.             }
  806.         }
  807.  
  808.         return ($this->remove($id? true : false);
  809.     }
  810.  
  811.     // }}}
  812.     // {{{ setLimit()
  813.  
  814.     /**
  815.      * @param integer $from 
  816.      * @param integer $count 
  817.      */
  818.     function setLimit($from=0$count=0)
  819.     {
  820.         if ($from==0 && $count==0{
  821.             $this->_limit = array();
  822.         else {
  823.             $this->_limit = array($from$count);
  824.         }
  825.     }
  826.  
  827.     // }}}
  828.     // {{{ getLimit()
  829.  
  830.     /**
  831.      * @return array 
  832.      */
  833.     function getLimit()
  834.     {
  835.         return $this->_limit;
  836.     }
  837.  
  838.     // }}}
  839.     // {{{ setWhere()
  840.  
  841.     /**
  842.      * sets the where condition which is used for the current instance
  843.      *
  844.      * @version    2002/04/16
  845.      * @access     public
  846.      * @author     Wolfram Kriesing <wk@visionp.de>
  847.      * @param      string  the where condition, this can be complete like 'X=7 AND Y=8'
  848.      */
  849.     function setWhere($whereCondition='')
  850.     {
  851.         $this->_where $whereCondition;
  852. //FIXXME parse the where condition and replace ambigious column names, such as "name='Deutschland'" with "country.name='Deutschland'"
  853. // then the users dont have to write that explicitly and can use the same name as in the setOrder i.e. setOrder('name,_net_name,_netPrefix_prefix');
  854.     }
  855.  
  856.     // }}}
  857.     // {{{ getWhere()
  858.  
  859.     /**
  860.      * gets the where condition which is used for the current instance
  861.      *
  862.      * @version    2002/04/22
  863.      * @access     public
  864.      * @author     Wolfram Kriesing <wk@visionp.de>
  865.      * @return     string  the where condition, this can be complete like 'X=7 AND Y=8'
  866.      */
  867.     function getWhere()
  868.     {
  869.         return $this->_where;
  870.     }
  871.  
  872.     // }}}
  873.     // {{{ addWhere()
  874.  
  875.     /**
  876.      * only adds a string to the where clause
  877.      *
  878.      * @version    2002/07/22
  879.      * @access     public
  880.      * @author     Wolfram Kriesing <wk@visionp.de>
  881.      * @param      string  the where clause to add to the existing one
  882.      * @param      string  the condition for how to concatenate the new where clause
  883.      *                        to the existing one
  884.      */
  885.     function addWhere($where$condition='AND')
  886.     {
  887.         if ($this->getWhere()) {
  888.             $where $this->getWhere().' '.$condition.' '.$where;
  889.         }
  890.         $this->setWhere($where);
  891.     }
  892.  
  893.     // }}}
  894.     // {{{ addWhere()
  895.  
  896.     /**
  897.      * add a where-like clause which works like a search for the given string
  898.      * i.e. calling it like this:
  899.      *     $this->addWhereSearch('name', 'otto hans')
  900.      * produces a where clause like this one
  901.      *     LOWER(name) LIKE "%otto%hans%"
  902.      * so the search finds the given string
  903.      *
  904.      * @version    2002/08/14
  905.      * @access     public
  906.      * @author     Wolfram Kriesing <wk@visionp.de>
  907.      * @param      string  the column to search in for
  908.      * @param      string  the string to search for
  909.      */
  910.     function addWhereSearch($column$string$condition='AND')
  911.     {
  912.         // if the column doesnt contain a tablename use the current table name in case it is a defined column
  913.         // to prevent ambigious rows
  914.         if (strpos($column'.'=== false{
  915.             $meta $this->metadata();
  916.             if (isset($meta[$column])) {
  917.                 $column $this->table.".$column";
  918.             }
  919.         }
  920.  
  921.         $string $this->db->quote('%'.str_replace(' ''%'strtolower($string)).'%');
  922.         $this->addWhere("LOWER($column) LIKE $string"$condition);
  923.     }
  924.  
  925.     // }}}
  926.     // {{{ setOrder()
  927.  
  928.     /**
  929.      * sets the order condition which is used for the current instance
  930.      *
  931.      * @version    2002/05/16
  932.      * @access     public
  933.      * @author     Wolfram Kriesing <wk@visionp.de>
  934.      * @param      string  the where condition, this can be complete like 'X=7 AND Y=8'
  935.      * @param      boolean sorting order (TRUE => ASC, FALSE => DESC)
  936.      */
  937.     function setOrder($orderCondition=''$desc=false)
  938.     {
  939.         $this->_order $orderCondition .($desc ' DESC' '');
  940.     }
  941.  
  942.     // }}}
  943.     // {{{ addOrder()
  944.  
  945.     /**
  946.      * Add a order parameter to the query.
  947.      *
  948.      * @version    2003/05/28
  949.      * @access     public
  950.      * @author     Wolfram Kriesing <wk@visionp.de>
  951.      * @param      string  the where condition, this can be complete like 'X=7 AND Y=8'
  952.      * @param      boolean sorting order (TRUE => ASC, FALSE => DESC)
  953.      */
  954.     function addOrder($orderCondition=''$desc=false)
  955.     {
  956.         $order $orderCondition .($desc ' DESC' '');
  957.         if ($this->_order{
  958.             $this->_order $this->_order.','.$order;
  959.         else {
  960.             $this->_order $order;
  961.         }
  962.     }
  963.  
  964.     // }}}
  965.     // {{{ getOrder()
  966.  
  967.     /**
  968.      * gets the order condition which is used for the current instance
  969.      *
  970.      * @version    2002/05/16
  971.      * @access     public
  972.      * @author     Wolfram Kriesing <wk@visionp.de>
  973.      * @return     string  the order condition, this can be complete like 'ID,TIMESTAMP DESC'
  974.      */
  975.     function getOrder()
  976.     {
  977.         return $this->_order;
  978.     }
  979.  
  980.     // }}}
  981.     // {{{ setHaving()
  982.  
  983.     /**
  984.      * sets the having definition
  985.      *
  986.      * @version    2003/06/05
  987.      * @access     public
  988.      * @author     Johannes Schaefer <johnschaefer@gmx.de>
  989.      * @param      string  the having definition
  990.      */
  991.     function setHaving($having='')
  992.     {
  993.         $this->_having $having;
  994.     }
  995.  
  996.     // }}}
  997.     // {{{ getHaving()
  998.  
  999.     /**
  1000.      * gets the having definition which is used for the current instance
  1001.      *
  1002.      * @version    2003/06/05
  1003.      * @access     public
  1004.      * @author     Johannes Schaefer <johnschaefer@gmx.de>
  1005.      * @return     string  the having definition
  1006.      */
  1007.     function getHaving()
  1008.     {
  1009.         return $this->_having;
  1010.     }
  1011.  
  1012.     // }}}
  1013.     // {{{ addHaving()
  1014.  
  1015.     /**
  1016.      * Extend the current having clause. This is very useful, when you are building
  1017.      * this clause from different places and dont want to overwrite the currently
  1018.      * set having clause, but extend it.
  1019.      *
  1020.      * @param string this is a having clause, i.e. 'column' or 'table.column' or 'MAX(column)'
  1021.      * @param string the connection string, which usually stays the default, which is ',' (a comma)
  1022.      */
  1023.     function addHaving($what='*'$connectString=' AND ')
  1024.     {
  1025.         if ($this->_having{
  1026.             $this->_having $this->_having.$connectString.$what;
  1027.         else {
  1028.             $this->_having $what;
  1029.         }
  1030.     }
  1031.  
  1032.     // }}}
  1033.     // {{{ setJoin()
  1034.  
  1035.     /**
  1036.      * sets a join-condition
  1037.      *
  1038.      * @version    2002/06/10
  1039.      * @access     public
  1040.      * @author     Wolfram Kriesing <wk@visionp.de>
  1041.      * @param      mixed   either a string or an array that contains
  1042.      *                        the table(s) to join on the current table
  1043.      * @param      string  the where clause for the join
  1044.      */
  1045.     function setJoin($table=null$where=null$joinType='default')
  1046.     {
  1047. //FIXXME make it possible to pass a table name as a string like this too 'user u'
  1048. // where u is the string that can be used to refer to this table in a where/order
  1049. // or whatever condition
  1050. // this way it will be possible to join tables with itself, like setJoin(array('user u','user u1'))
  1051. // this wouldnt work yet, but for doing so we would need to change the _build methods too!!!
  1052. // because they use getJoin('tables') and this simply returns all the tables in use
  1053. // but don't take care of the mentioned syntax
  1054.  
  1055.         if (is_null($table|| is_null($where)) {   // remove the join if not sufficient parameters are given
  1056.             $this->_join[$joinType= array();
  1057.             return;
  1058.         }
  1059. /* this causes problems if we use the order-by, since it doenst know the name to order it by ... :-)
  1060.         // replace the table names with the internal name used for the join
  1061.         // this way we can also join one table multiple times if it will be implemented one day
  1062.         $this->_join[$table] = preg_replace('/'.$table.'/','j1',$where);
  1063. */
  1064.         $this->_join[$joinType][$table$where;
  1065.     }
  1066.  
  1067.     // }}}
  1068.     // {{{ setJoin()
  1069.  
  1070.     /**
  1071.      * if you do a left join on $this->table you will get all entries
  1072.      * from $this->table, also if there are no entries for them in the joined table
  1073.      * if both parameters are not given the left-join will be removed
  1074.      * NOTE: be sure to only use either a right or a left join
  1075.      *
  1076.      * @version    2002/07/22
  1077.      * @access     public
  1078.      * @author     Wolfram Kriesing <wk@visionp.de>
  1079.      * @param      string  the table(s) to be left-joined
  1080.      * @param      string  the where clause for the join
  1081.      */
  1082.     function setLeftJoin($table=null$where=null)
  1083.     {
  1084.         $this->setJoin($table$where'left');
  1085.     }
  1086.  
  1087.     // }}}
  1088.     // {{{ addLeftJoin()
  1089.  
  1090.     /**
  1091.      * @param string the table to be left-joined
  1092.      * @param string the where clause for the join
  1093.      * @param string the join type
  1094.      */
  1095.     function addLeftJoin($table$where$type='left')
  1096.     {
  1097.         // init value, to prevent E_ALL-warning
  1098.         if (!isset($this->_join[$type]|| !$this->_join[$type]{
  1099.             $this->_join[$type= array();
  1100.         }
  1101.         $this->_join[$type][$table$where;
  1102.     }
  1103.  
  1104.     // }}}
  1105.     // {{{ setRightJoin()
  1106.  
  1107.     /**
  1108.      * see setLeftJoin for further explaination on what a left/right join is
  1109.      * NOTE: be sure to only use either a right or a left join
  1110. //FIXXME check if the above sentence is necessary and if sql doesnt allow the use of both
  1111.      *
  1112.      * @see        setLeftJoin()
  1113.      * @version    2002/09/04
  1114.      * @access     public
  1115.      * @author     Wolfram Kriesing <wk@visionp.de>
  1116.      * @param      string  the table(s) to be right-joined
  1117.      * @param      string  the where clause for the join
  1118.      */
  1119.     function setRightJoin($table=null$where=null)
  1120.     {
  1121.         $this->setJoin($table$where'right');
  1122.     }
  1123.  
  1124.     // }}}
  1125.     // {{{ getJoin()
  1126.  
  1127.     /**
  1128.      * gets the join-condition
  1129.      *
  1130.      * @access public
  1131.      * @param  string  [null|''|'table'|'tables'|'right'|'left']
  1132.      * @return array   gets the join parameters
  1133.      */
  1134.     function getJoin($what=null)
  1135.     {
  1136.         // if the user requests all the join data or if the join is empty, return it
  1137.         if (is_null($what|| empty($this->_join)) {
  1138.             return $this->_join;
  1139.         }
  1140.  
  1141.         $ret = array();
  1142.         switch (strtolower($what)) {
  1143.             case 'table':
  1144.             case 'tables':
  1145.                 foreach ($this->_join as $aJoin{
  1146.                     if (count($aJoin)) {
  1147.                         $ret array_merge($retarray_keys($aJoin));
  1148.                     }
  1149.                 }
  1150.                 break;
  1151.             case 'right':   // return right-join data only
  1152.             case 'left':    // return left join data only
  1153.                 if (count($this->_join[$what])) {
  1154.                     $ret array_merge($ret$this->_join[$what]);
  1155.                 }
  1156.                 break;
  1157.         }
  1158.         return $ret;
  1159.     }
  1160.  
  1161.     // }}}
  1162.     // {{{ addJoin()
  1163.  
  1164.     /**
  1165.      *   adds a table and a where clause that shall be used for the join
  1166.      *   instead of calling
  1167.      *       setJoin(array(table1,table2),'<where clause1> AND <where clause2>')
  1168.      *   you can also call
  1169.      *       setJoin(table1,'<where clause1>')
  1170.      *       addJoin(table2,'<where clause2>')
  1171.      *   or where it makes more sense is to build a query which is made out of a
  1172.      *   left join and a standard join
  1173.      *       setLeftJoin(table1,'<where clause1>')
  1174.      *       // results in ... FROM $this->table LEFT JOIN table ON <where clause1>
  1175.      *       addJoin(table2,'<where clause2>')
  1176.      *       // results in ...  FROM $this->table,table2 LEFT JOIN table ON <where clause1> WHERE <where clause2>
  1177.      *
  1178.      * @access     public
  1179.      * @param      string the table to be joined
  1180.      * @param      string the where clause for the join
  1181.      * @param      string the join type
  1182.      */
  1183.     function addJoin($table$where$type='default')
  1184.     {
  1185.         if ($table == $this->table{
  1186.             return;  //skip. Self joins are not supported.
  1187.         }
  1188.         // init value, to prevent E_ALL-warning
  1189.         if (!isset($this->_join[$type]|| !$this->_join[$type]{
  1190.             $this->_join[$type= array();
  1191.         }
  1192.         $this->_join[$type][$table$where;
  1193.     }
  1194.  
  1195.     // }}}
  1196.     // {{{ setTable()
  1197.  
  1198.     /**
  1199.      * sets the table this class is currently working on
  1200.      *
  1201.      * @version    2002/07/11
  1202.      * @access     public
  1203.      * @author     Wolfram Kriesing <wk@visionp.de>
  1204.      * @param      string  the table name
  1205.      */
  1206.     function setTable($table)
  1207.     {
  1208.         $this->table = $table;
  1209.     }
  1210.  
  1211.     // }}}
  1212.     // {{{ getTable()
  1213.  
  1214.     /**
  1215.      * gets the table this class is currently working on
  1216.      *
  1217.      * @version    2002/07/11
  1218.      * @access     public
  1219.      * @author     Wolfram Kriesing <wk@visionp.de>
  1220.      * @return     string  the table name
  1221.      */
  1222.     function getTable()
  1223.     {
  1224.         return $this->table;
  1225.     }
  1226.  
  1227.     // }}}
  1228.     // {{{ setGroup()
  1229.  
  1230.     /**
  1231.      * sets the group-by condition
  1232.      *
  1233.      * @version    2002/07/22
  1234.      * @access     public
  1235.      * @author     Wolfram Kriesing <wk@visionp.de>
  1236.      * @param      string  the group condition
  1237.      */
  1238.     function setGroup($group='')
  1239.     {
  1240.         $this->_group $group;
  1241. //FIXXME parse the condition and replace ambigious column names, such as "name='Deutschland'" with "country.name='Deutschland'"
  1242. // then the users dont have to write that explicitly and can use the same name as in the setOrder i.e. setOrder('name,_net_name,_netPrefix_prefix');
  1243.     }
  1244.  
  1245.     // }}}
  1246.     // {{{ getGroup()
  1247.  
  1248.     /**
  1249.      *   gets the group condition which is used for the current instance
  1250.      *
  1251.      * @version    2002/07/22
  1252.      * @access     public
  1253.      * @author     Wolfram Kriesing <wk@visionp.de>
  1254.      * @return     string  the group condition
  1255.      */
  1256.     function getGroup()
  1257.     {
  1258.         return $this->_group;
  1259.     }
  1260.  
  1261.     // }}}
  1262.     // {{{ setSelect()
  1263.  
  1264.     /**
  1265.      * limit the result to return only the columns given in $what
  1266.      * @param string fields that shall be selected
  1267.      */
  1268.     function setSelect($what='*')
  1269.     {
  1270.         $this->_select $what;
  1271.     }
  1272.  
  1273.     // }}}
  1274.     // {{{ addSelect()
  1275.  
  1276.     /**
  1277.      * add a string to the select part of the query
  1278.      *
  1279.      * add a string to the select-part of the query and connects it to an existing
  1280.      * string using the $connectString, which by default is a comma.
  1281.      * (SELECT xxx FROM - xxx is the select-part of a query)
  1282.      *
  1283.      * @version    2003/01/08
  1284.      * @access     public
  1285.      * @author     Wolfram Kriesing <wk@visionp.de>
  1286.      * @param      string  the string that shall be added to the select-part
  1287.      * @param      string  the string to connect the new string with the existing one
  1288.      * @return     void 
  1289.      */
  1290.     function addSelect($what='*'$connectString=',')
  1291.     {
  1292.         // if the select string is not empty add the string, otherwise simply set it
  1293.         if ($this->_select{
  1294.             $this->_select $this->_select.$connectString.$what;
  1295.         else {
  1296.             $this->_select $what;
  1297.         }
  1298.     }
  1299.  
  1300.     // }}}
  1301.     // {{{ getSelect()
  1302.  
  1303.     /**
  1304.      * @return     string 
  1305.      */
  1306.     function getSelect()
  1307.     {
  1308.         return $this->_select;
  1309.     }
  1310.  
  1311.     // }}}
  1312.     // {{{ setDontSelect()
  1313.  
  1314.     /**
  1315.      * @param     string 
  1316.      */
  1317.     function setDontSelect($what='')
  1318.     {
  1319.         $this->_dontSelect $what;
  1320.     }
  1321.  
  1322.     // }}}
  1323.     // {{{ getDontSelect()
  1324.  
  1325.     /**
  1326.      * @return     string 
  1327.      */
  1328.     function getDontSelect()
  1329.     {
  1330.         return $this->_dontSelect;
  1331.     }
  1332.  
  1333.     // }}}
  1334.     // {{{ reset()
  1335.  
  1336.     /**
  1337.      * reset all the set* settings; with no parameter given, it resets them all
  1338.      *
  1339.      * @version    2002/09/16
  1340.      * @access     public
  1341.      * @author     Wolfram Kriesing <wk@visionp.de>
  1342.      * @return     void 
  1343.      */
  1344.     function reset($what=array())
  1345.     {
  1346.         if (!sizeof($what)) {
  1347.             $what = array(
  1348.                 'select',
  1349.                 'dontSelect',
  1350.                 'group',
  1351.                 'having',
  1352.                 'limit',
  1353.                 'where',
  1354.                 'index',
  1355.                 'order',
  1356.                 'join',
  1357.                 'leftJoin',
  1358.                 'rightJoin'
  1359.             );
  1360.         }
  1361.  
  1362.         foreach ($what as $aReset{
  1363.             $this->{'set'.ucfirst($aReset)}();
  1364.         }
  1365.     }
  1366.  
  1367.     // }}}
  1368.     // {{{ setOption()
  1369.  
  1370.     /**
  1371.      * set mode the class shall work in
  1372.      * currently we have the modes:
  1373.      * 'raw'   does not quote the data before building the query
  1374.      *
  1375.      * @version    2002/09/17
  1376.      * @access     public
  1377.      * @author     Wolfram Kriesing <wk@visionp.de>
  1378.      * @param      string      the mode to be set
  1379.      * @param      mixed       the value of the mode
  1380.      * @return     void 
  1381.      */
  1382.     function setOption($option$value)
  1383.     {
  1384.         $this->options[strtolower($option)$value;
  1385.     }
  1386.  
  1387.     // }}}
  1388.     // {{{ getOption()
  1389.  
  1390.     /**
  1391.      * @return     string 
  1392.      */
  1393.     function getOption($option)
  1394.     {
  1395.         return $this->options[strtolower($option)];
  1396.     }
  1397.  
  1398.     // }}}
  1399.     // {{{ _quoteArray()
  1400.  
  1401.     /**
  1402.      * quotes all the data in this array if we are not in raw mode!
  1403.      * @param array 
  1404.      */
  1405.     function _quoteArray($data)
  1406.     {
  1407.         if (!$this->getOption('raw')) {
  1408.             foreach ($data as $key => $val{
  1409.                 $data[$key$this->db->quote($val);
  1410.             }
  1411.         }
  1412.         return $data;
  1413.     }
  1414.  
  1415.     // }}}
  1416.     // {{{ _checkColumns()
  1417.  
  1418.     /**
  1419.      * checks if the columns which are given as the array's indexes really exist
  1420.      * if not it will be unset anyway
  1421.      *
  1422.      * @version    2002/04/16
  1423.      * @access     public
  1424.      * @author     Wolfram Kriesing <wk@visionp.de>
  1425.      * @param      string  the actual message, first word should always be the method name,
  1426.      *                        to build the message like this: className::methodname
  1427.      * @param      integer the line number
  1428.      */
  1429.     function _checkColumns($newData$method='unknown')
  1430.     {
  1431.         if (!$meta $this->metadata()) {   // if no metadata available, return data as given
  1432.             return $newData;
  1433.         }
  1434.  
  1435.         foreach ($newData as $colName => $x{
  1436.             if (!isset($meta[$colName])) {
  1437.                 $this->_errorLog("$method, column {$this->table}.$colName doesnt exist, value was removed before '$method'",__LINE__);
  1438.                 unset($newData[$colName]);
  1439.             } else {
  1440.                 // if the current column exists, check the length too, not to write content that is too long
  1441.                 // prevent DB-errors here
  1442.                 // do only check the data length if this field is given
  1443. // FIXXME use PEAR-defined field for 'DATA_LENGTH'
  1444.                 if (isset($meta[$colName]['DATA_LENGTH']) &&
  1445.                     ($oldLength=strlen($newData[$colName])) > $meta[$colName]['DATA_LENGTH']) {
  1446.  
  1447.                     $this->_errorLog("_checkColumns, had to trim column '$colName' from $oldLength to ".
  1448.                                         $meta[$colName]['DATA_LENGTH'].' characters.', __LINE__);
  1449.                     $newData[$colName] = substr($newData[$colName], 0, $meta[$colName]['DATA_LENGTH']);
  1450.                 }
  1451.             }
  1452.         }
  1453.         return $newData;
  1454.     }
  1455.  
  1456.     // }}}
  1457.     // {{{ debug()
  1458.     /**
  1459.      * overwrite this method and i.e. print the query $string
  1460.      * to see the final query
  1461.      *
  1462.      * @param      string  the query mostly
  1463.      */
  1464.     function debug($string){}
  1465.  
  1466.     //
  1467.     //
  1468.     //  ONLY ORACLE SPECIFIC, not very nice since it is DB dependent, but we need it!!!
  1469.     //
  1470.     //
  1471.     // }}}
  1472.     // {{{ metadata()
  1473.     /**
  1474.      * !!!! query COPIED FROM db_oci8.inc - from PHPLIB !!!!
  1475.      *
  1476.      * @access   public
  1477.      * @see
  1478.      * @version  2001/09
  1479.      * @author   PHPLIB
  1480.      * @param
  1481.      * @return
  1482.      */
  1483.     function metadata($table='')
  1484.     {
  1485.         // is there an alias in the table name, then we have something like this: 'user ua'
  1486.         // cut of the alias and return the table name
  1487.         if (strpos($table, ' ') !== false) {
  1488.             $split = explode(' ', trim($table));
  1489.             $table = $split[0];
  1490.         }
  1491.  
  1492.         $full = false;
  1493.         if (empty($table)) {
  1494.             $table = $this->table;
  1495.         }
  1496.         // to prevent multiple selects for the same metadata
  1497.         if (isset($this->_metadata[$table])) {
  1498.             return $this->_metadata[$table];
  1499.         }
  1500.  
  1501. // FIXXXME use oci8 implementation of newer PEAR::DB-version
  1502.         if ($this->db->phptype == 'oci8'{
  1503.             $count = 0;
  1504.             $id    = 0;
  1505.             $res   = array();
  1506.  
  1507.             //# This is a RIGHT OUTER JOIN: "(+)", if you want to see, what
  1508.             //# this query results try the following:
  1509.             //// $table = new Table; $this->db = new my_DB_Sql; // you have to make
  1510.             ////                                          // your own class
  1511.             //// $table->show_results($this->db->query(see query vvvvvv))
  1512.             ////
  1513.             $res = $this->db->getAll("SELECT T.column_name,T.table_name,T.data_type,".
  1514.                 "T.data_length,T.data_precision,T.data_scale,T.nullable,".
  1515.                 "T.char_col_decl_length,I.index_name".
  1516.                 " FROM ALL_TAB_COLUMNS T,ALL_IND_COLUMNS I".
  1517.                 " WHERE T.column_name=I.column_name (+)".
  1518.                 " AND T.table_name=I.table_name (+)".
  1519.                 " AND T.table_name=UPPER('$table') ORDER BY T.column_id");
  1520.  
  1521.             if (DB::isError($res)) {
  1522.                 //$this->_errorSet($res->getMessage());
  1523.                 // i think we only need to log here, since this method is never used
  1524.                 // directly for the user's functionality, which means if it fails it
  1525.                 // is most probably an appl error
  1526.                 $this->_errorLog($res->getUserInfo());
  1527.                 return false;
  1528.             }
  1529.             foreach ($res as $key=>$val) {
  1530.                 $res[$key]['name'] = $val['COLUMN_NAME'];
  1531.             }
  1532.         } else {
  1533.             if (!is_object($this->db)) {
  1534.                 return false;
  1535.             }
  1536.             $res = $this->db->tableinfo($table);
  1537.             if (DB::isError($res)) {
  1538.                 $this->_errorSet($res->getUserInfo());
  1539.                 return false;
  1540.             }
  1541.         }
  1542.  
  1543.         $ret = array();
  1544.         foreach ($res as $key => $val) {
  1545.             $ret[$val['name']] = $val;
  1546.         }
  1547.         $this->_metadata[$table$ret;
  1548.         return $ret;
  1549.     }
  1550.  
  1551.  
  1552.  
  1553.     //
  1554.     //  methods for building the query
  1555.     //
  1556.     // }}}
  1557.     // {{{ _buildFrom()
  1558.     /**
  1559.      * build the from string
  1560.      *
  1561.      * @access     private
  1562.      * @return     string  the string added after FROM
  1563.      */
  1564.     function _buildFrom()
  1565.     {
  1566.         $from = $this->table;
  1567.         $join $this->getJoin();
  1568.  
  1569.         if (!$join{  // no join set
  1570.             return $from;
  1571.         }
  1572.         // handle the standard join thingy
  1573.         if (isset($join['default']) && count($join['default'])) {
  1574.             $from .= ','.implode(',',array_keys($join['default']));
  1575.         }
  1576.  
  1577.         // handle left/right joins
  1578.         foreach (array('left', 'right') as $joinType) {
  1579.             if (isset($join[$joinType]) && count($join[$joinType])) {
  1580.                 foreach($join[$joinType] as $table => $condition) {
  1581.                     // replace the _TABLENAME_COLUMNNAME by TABLENAME.COLUMNNAME
  1582.                     // since oracle doesnt work with the _TABLENAME_COLUMNNAME which i think is strange
  1583. // FIXXME i think this should become deprecated since the setWhere should not be used like this: '_table_column' but 'table.column'
  1584.                     $regExp = '/_('.$table.')_([^\s]+)/';
  1585.                     $where = preg_replace($regExp, '$1.$2', $condition);
  1586.  
  1587.                     // add the table name before any column that has no table prefix
  1588.                     // since this might cause "unambiguous column" errors
  1589.                     if ($meta = $this->metadata()) {
  1590.                         foreach ($meta as $aCol=>$x) {
  1591.                             // this covers the LIKE,IN stuff: 'name LIKE "%you%"'  'id IN (2,3,4,5)'
  1592.                             $condition = preg_replace('/\s'.$aCol.'\s/', " {$this->table}.$aCol ", $condition);
  1593.                             // replace also the column names which are behind a '='
  1594.                             // and do this also if the aCol is at the end of the where clause
  1595.                             // that's what the $ is for
  1596.                             $condition = preg_replace('/=\s*'.$aCol.'(\s|$)/', "={$this->table}.$aCol ", $condition);
  1597.                             // replace if colName is first and possibly also if at the beginning of the where-string
  1598.                             $condition = preg_replace('/(^\s*|\s+)'.$aCol.'\s*=/', "$1{$this->table}.$aCol=", $condition);
  1599.                         }
  1600.                     }
  1601.                     $from .= ' '.strtoupper($joinType).' JOIN '.$table.' ON '.$condition;
  1602.                 }
  1603.             }
  1604.         }
  1605.         return $from;
  1606.     }
  1607.  
  1608.     // }}}
  1609.     // {{{ getTableShortName()
  1610.     /**
  1611.      *   this method gets the short name for a table
  1612.      *
  1613.      *   get the short name for a table, this is needed to properly build the
  1614.      *   'AS' parts in the select query
  1615.      * @param  string  the real table name
  1616.      * @return string  the table's short name
  1617.      */
  1618.     function getTableShortName($table)
  1619.     {
  1620.         $tableSpec = $this->getTableSpec(false);
  1621.         if (isset($tableSpec[$table]['shortName']&& $tableSpec[$table]['shortName']{
  1622. //print "$table ... ".$tableSpec[$table]['shortName'].'<br>';
  1623.             return $tableSpec[$table]['shortName'];
  1624.         }
  1625.  
  1626.         $possibleTableShortName = preg_replace($this->_tableNameToShortNamePreg''$table);
  1627. //print "$table ... $possibleTableShortName<br>";
  1628.         return $possibleTableShortName;
  1629.     }
  1630.  
  1631.     // }}}
  1632.     // {{{ getTableSpec()
  1633.     /**
  1634.      * gets the tableSpec either indexed by the short name or the name
  1635.      * returns the array for the tables given as parameter or if no
  1636.      * parameter given for all tables that exist in the tableSpec
  1637.      *
  1638.      * @param      array   table names (not the short names!)
  1639.      * @param      boolean if true the table is returned indexed by the shortName
  1640.      *                       otherwise indexed by the name
  1641.      * @return     array   the tableSpec indexed
  1642.      */
  1643.     function getTableSpec($shortNameIndexed=true, $tables=array())
  1644.     {
  1645.         $newSpec = array();
  1646.         foreach ($this->tableSpec as $aSpec{
  1647.             if (sizeof($tables)==0 || in_array($aSpec['name'],$tables)) {
  1648.                 if ($shortNameIndexed) {
  1649.                     $newSpec[$aSpec['shortName']] = $aSpec;
  1650.                 } else {
  1651.                     $newSpec[$aSpec['name']] = $aSpec;
  1652.                 }
  1653.             }
  1654.         }
  1655.         return $newSpec;
  1656.     }
  1657.  
  1658.     // }}}
  1659.     // {{{ _buildSelect()
  1660.     /**
  1661.      *   build the 'SELECT <what> FROM ... 'for a select
  1662.      *
  1663.      * @version    2002/07/11
  1664.      * @access     public
  1665.      * @author     Wolfram Kriesing <wk@visionp.de>
  1666.      * @param      string      if given use this string
  1667.      * @return     string      the what-clause
  1668.      */
  1669.     function _buildSelect($what=null)
  1670.     {
  1671.         // what has preference, that means if what is set it is used
  1672.         // this is only because the methods like 'get' pass an individually built value, which
  1673.         // is supposed to be used, but usually it's generically build using the 'getSelect' values
  1674.         if (empty($what) && $this->getSelect()) {
  1675.             $what = $this->getSelect();
  1676.         }
  1677.  
  1678.         //
  1679.         // replace all the '*' by the real column names, and take care of the dontSelect-columns!
  1680.         //
  1681.         $dontSelect = $this->getDontSelect();
  1682.         $dontSelect $dontSelect ? explode(','$dontSelect: array()// make sure dontSelect is an array
  1683.  
  1684.         // here we will replace all the '*' and 'table.*' by all the columns that this table
  1685.         // contains. we do this so we can easily apply the 'dontSelect' values.
  1686.         // and so we can also handle queries like: 'SELECT *,count() FROM ' and 'SELECT table.*,x FROM ' too
  1687.         if (strpos($what'*'!== false{
  1688.             // subpattern 1 get all the table names, that are written like this: 'table.*' including '*'
  1689.             // for '*' the tablename will be ''
  1690.             preg_match_all('/([^,]*)(\.)?\*\s*(,|$)/U', $what, $res);
  1691. //print "$what ... ";print_r($res);print "<br>";
  1692.             $selectAllFromTables = array_unique($res[1])// make the table names unique, so we do it all just once for each table
  1693.             $tables = array();
  1694.             if (in_array('', $selectAllFromTables)) { // was there a '*' ?
  1695.                 // get all the tables that we need to process, depending on if joined or not
  1696.                 $tables = $this->getJoin(?
  1697.                                 array_merge($this->getJoin('tables')array($this->table)) // get the joined tables and this->table
  1698.                                 array($this->table);        // create an array with only this->table
  1699.             } else {
  1700.                 $tables = $selectAllFromTables;
  1701.             }
  1702.  
  1703.             $cols = array();
  1704.             foreach ($tables as $aTable) {      // go thru all the tables and get all columns for each, and handle 'dontSelect'
  1705.                 if ($meta = $this->metadata($aTable)) {
  1706.                     foreach ($meta as $colName => $x) {
  1707.                         // handle the dontSelect's
  1708.                         if (in_array($colName, $dontSelect) || in_array("$aTable.$colName", $dontSelect)) {
  1709.                             continue;
  1710.                         }
  1711.  
  1712.                         // build the AS clauses
  1713.                         // put " around them to enable use of reserved words, i.e. SELECT table.option as option FROM...
  1714.                         // and 'option' actually is a reserved word, at least in mysql
  1715.                         // put double quotes around them, since pgsql doesnt work with single quotes
  1716.                         if ($aTable == $this->table{
  1717.                             $cols[$aTable][] = $this->table.".$colName AS \"$colName\"";
  1718.                         } else {
  1719.                             $cols[$aTable][] = "$aTable.$colName AS \"_".$this->getTableShortName($aTable)."_$colName\"";
  1720.                         }
  1721.                     }
  1722.                 }
  1723.             }
  1724.  
  1725.             // put the extracted select back in the $what
  1726.             // that means replace 'table.*' by the i.e. 'table.id AS _table_id'
  1727.             // or if it is the table of this class replace 'table.id AS id'
  1728.             if (in_array('', $selectAllFromTables)) {
  1729.                 $allCols = array();
  1730.                 foreach ($cols as $aTable) {
  1731.                     $allCols[] = implode(',', $aTable);
  1732.                 }
  1733.                 $what = preg_replace('/(^|,)\*($|,)/', '$1'.implode(',',$allCols).'$2', $what);
  1734.                 // remove all the 'table.*' since we have selected all anyway (because there was a '*' in the select)
  1735.                 $what = preg_replace('/[^,]*(\.)?\*\s*(,|$)/U', '', $what);
  1736.             } else {
  1737.                 foreach ($cols as $tableName => $aTable) {
  1738.                     if (is_array($aTable) && sizeof($aTable)) {
  1739.                         // replace all the 'table.*' by their select of each column
  1740.                         $what = preg_replace('/(^|,)\s*'.$tableName.'\.\*\s*($|,)/', '$1'.implode(',',$aTable).'$2', $what);
  1741.                     }
  1742.                 }
  1743.             }
  1744.         }
  1745.  
  1746.         if ($this->getJoin()) {
  1747.             // replace all 'column' by '$this->table.column' to prevent ambigious errors
  1748.             $metadata = $this->metadata();
  1749.             if (is_array($metadata)) {
  1750.                 foreach ($metadata as $aCol => $x) {
  1751.                     // handle ',id as xid,MAX(id),id' etc.
  1752. // FIXXME do this better!!!
  1753.                     $what = preg_replace(  "/(^|,|\()(\s*)$aCol(\)|\s|,|as|$)/i",
  1754.                                             // $2 is actually just to keep the spaces, is not really
  1755.                                             // necessary, but this way the test works independent of this functionality here
  1756.                                             "$1$2{$this->table}.$aCol$3",
  1757.                                             $what);
  1758.                 }
  1759.             }
  1760.             // replace all 'joinedTable.columnName' by '_joinedTable_columnName'
  1761.             // this actually only has an effect if there was no 'table.*' for 'table'
  1762.             // if that was there, then it has already been done before
  1763.             foreach ($this->getJoin('tables'as $aTable{
  1764.                 if ($meta = $this->metadata($aTable)) {
  1765.                     foreach ($meta as $aCol=>$x) {
  1766.                         // dont put the 'AS' behind it if there is already one
  1767.                         if (preg_match("/$aTable.$aCol\s*as/i",$what)) {
  1768.                             continue;
  1769.                         }
  1770.                         // this covers a ' table.colName ' surrounded by spaces, and replaces it by ' table.colName AS _table_colName'
  1771.                         $what = preg_replace('/\s'.$aTable.'.'.$aCol.'\s/', " $aTable.$aCol AS _".$this->getTableShortName($aTable)."_$aCol ", $what);
  1772.                         // replace also the column names which are behind a ','
  1773.                         // and do this also if the aCol is at the end that's what the $ is for
  1774.                         $what = preg_replace('/,\s*'.$aTable.'.'.$aCol.'(,|\s|$)/', ",$aTable.$aCol AS _".$this->getTableShortName($aTable)."_$aCol$1", $what);
  1775.                         // replace if colName is first and possibly also if at the beginning of the where-string
  1776.                         $what = preg_replace('/(^\s*|\s+)'.$aTable.'.'.$aCol.'\s*,/', "$1$aTable.$aCol AS _".$this->getTableShortName($aTable)."_$aCol,", $what);
  1777.                     }
  1778.                 }
  1779.             }
  1780.         }
  1781.         return $what;
  1782.     }
  1783.  
  1784.     // }}}
  1785.     // {{{ _buildWhere()
  1786.     /**
  1787.      * Build WHERE clause
  1788.      *
  1789.      * @param  string $where WHERE clause
  1790.      * @return string $where WHERE clause after processing
  1791.      * @access private
  1792.      */
  1793.     function _buildWhere($where='')
  1794.     {
  1795.         $where = trim($where);
  1796.         $originalWhere = $this->getWhere();
  1797.         if ($originalWhere{
  1798.             if (!empty($where)) {
  1799.                 $where = $originalWhere.' AND '.$where;
  1800.             } else {
  1801.                 $where = $originalWhere;
  1802.             }
  1803.         }
  1804.         $where = trim($where);
  1805.  
  1806.         if ($join = $this->getJoin()) {     // is join set?
  1807.             // only those where conditions in the default-join have to be added here
  1808.             // left-join conditions are added behind 'ON', the '_buildJoin()' does that
  1809.             if (isset($join['default']) && count($join['default'])) {
  1810.                 // we have to add this join-where clause here
  1811.                 // since at least in mysql a query like: select * from tableX JOIN tableY ON ...
  1812.                 // doesnt work, may be that's even SQL-standard...
  1813.                 if (!empty($where)) {
  1814.                     $where = implode(' AND ', $join['default']).' AND '.$where;
  1815.                 } else {
  1816.                     $where = implode(' AND ', $join['default']);
  1817.                 }
  1818.             }
  1819.             // replace the _TABLENAME_COLUMNNAME by TABLENAME.COLUMNNAME
  1820.             // since oracle doesnt work with the _TABLENAME_COLUMNNAME which i think is strange
  1821. // FIXXME i think this should become deprecated since the setWhere should not be used like this: '_table_column' but 'table.column'
  1822.             $regExp = '/_('.implode('|', $this->getJoin('tables')).')_([^\s]+)/';
  1823.             $where = preg_replace($regExp'$1.$2'$where);
  1824.             // add the table name before any column that has no table prefix
  1825.             // since this might cause "unambigious column" errors
  1826.             if ($meta $this->metadata()) {
  1827.                 foreach ($meta as $aCol => $x) {
  1828.                     // this covers the LIKE,IN stuff: 'name LIKE "%you%"'  'id IN (2,3,4,5)'
  1829.                     $where = preg_replace('/\s'.$aCol.'\s/', " {$this->table}.$aCol ", $where);
  1830.                     // replace also the column names which are behind a '='
  1831.                     // and do this also if the aCol is at the end of the where clause
  1832.                     // that's what the $ is for
  1833.                     $where = preg_replace('/([=<>])\s*'.$aCol.'(\s|$)/', "$1{$this->table}.$aCol ", $where);
  1834.                     // replace if colName is first and possibly also if at the beginning of the where-string
  1835.                     $where = preg_replace('/(^\s*|\s+)'.$aCol.'\s*([=<>])/', "$1{$this->table}.$aCol$2", $where);
  1836.                 }
  1837.             }
  1838.         }
  1839.         return $where;
  1840.     }
  1841.  
  1842.     // }}}
  1843.     // {{{ _buildOrder()
  1844.     /**
  1845.      *
  1846.      *
  1847.      * @version    2002/07/11
  1848.      * @access     public
  1849.      * @author     Wolfram Kriesing <wk@visionp.de>
  1850.      * @param
  1851.      * @return
  1852.      */
  1853.     function _buildOrder()
  1854.     {
  1855.         $order = $this->getOrder();
  1856.         // replace 'column' by '$this->table.column' if the column is defined for $this->table
  1857.         if ($meta $this->metadata()) {
  1858.             foreach ($meta as $aCol=>$x) {
  1859.                 $order = preg_replace('/(^\s*|\s+|,)'.$aCol.'\s*(,)?/U', "$1{$this->table}.$aCol$2", $order);
  1860.             }
  1861.         }
  1862.         return $order;
  1863.     }
  1864.  
  1865.     // }}}
  1866.     // {{{ _buildGroup()
  1867.     /**
  1868.      *   Build the group-clause, replace 'column' by 'table.column'.
  1869.      *
  1870.      * @access public
  1871.      * @param void
  1872.      * @return string the rendered group clause
  1873.      */
  1874.     function _buildGroup()
  1875.     {
  1876.         $group = $this->getGroup();
  1877.         // replace 'column' by '$this->table.column' if the column is defined for $this->table
  1878.         if ($meta $this->metadata()) {
  1879.             foreach ($meta as $aCol => $x) {
  1880.                 $group = preg_replace('/(^\s*|\s+|,)'.$aCol.'\s*(,)?/U', "$1{$this->table}.$aCol$2", $group);
  1881.             }
  1882.         }
  1883.         return $group;
  1884.     }
  1885.  
  1886.     // }}}
  1887.     // {{{ _buildHaving()
  1888.     /**
  1889.      *
  1890.      * @version    2003/06/05
  1891.      * @access     public
  1892.      * @author     Johannes Schaefer <johnschaefer@gmx.de>
  1893.      * @param
  1894.      * @return string the having clause
  1895.      */
  1896.     function _buildHaving()
  1897.     {
  1898.         $having = $this->getHaving();
  1899.         // replace 'column' by '$this->table.column' if the column is defined for $this->table
  1900.         if ($meta $this->metadata()) {
  1901.             foreach ($meta as $aCol => $x) {
  1902.                 $having = preg_replace('/(^\s*|\s+|,)'.$aCol.'\s*(,)?/U',"$1{$this->table}.$aCol$2",$having);
  1903.             }
  1904.         }
  1905.         return $having;
  1906.     }
  1907.  
  1908.     // }}}
  1909.     // {{{ _buildHaving()
  1910.     /**
  1911.      *
  1912.      * @version    2002/07/11
  1913.      * @access     public
  1914.      * @author     Wolfram Kriesing <wk@visionp.de>
  1915.      * @param      array   this array contains the elements of the query,
  1916.      *                       indexed by their key, which are: 'select','from','where', etc.
  1917.      * @return
  1918.      */
  1919.     function _buildSelectQuery($query=array())
  1920.     {
  1921. /*FIXXXME finish this
  1922.         $cacheKey = md5(serialize(????));
  1923.         if (isset($this->_queryCache[$cacheKey])) {
  1924.             $this->_errorLog('using cached query',__LINE__);
  1925.             return $this->_queryCache[$cacheKey];
  1926.         }
  1927. */
  1928.         $where = isset($query['where']) ? $query['where'] : $this->_buildWhere();
  1929.         if ($where{
  1930.             $where = 'WHERE '.$where;
  1931.         }
  1932.         $order = isset($query['order']) ? $query['order'] : $this->_buildOrder();
  1933.         if ($order{
  1934.             $order = 'ORDER BY '.$order;
  1935.         }
  1936.         $group = isset($query['group']) ? $query['group'] : $this->_buildGroup();
  1937.         if ($group{
  1938.             $group = 'GROUP BY '.$group;
  1939.         }
  1940.         $having = isset($query['having']) ? $query['having'] : $this->_buildHaving();
  1941.         if ($having{
  1942.             $having = 'HAVING '.$having;
  1943.         }
  1944.         $queryString = sprintf( 'SELECT %s FROM %s %s %s %s %s',
  1945.                                 isset($query['select']) ? $query['select'] : $this->_buildSelect(),
  1946.                                 isset($query['from']$query['from'$this->_buildFrom(),
  1947.                                 $where,
  1948.                                 $group,
  1949.                                 $order,
  1950.                                 $having
  1951.                                 );
  1952.         // $query['limit'] has preference!
  1953.         $limit = isset($query['limit']$query['limit'$this->_limit;
  1954.         if (@$limit[1]{    // is there a count set?
  1955.             $queryString=$this->db->modifyLimitQuery($queryString,$limit[0],$limit[1]);
  1956.             if (DB::isError($queryString)) {
  1957.                 $this->_errorSet('DB_QueryTool::db::modifyLimitQuery failed '.$queryString->getMessage());
  1958.                 $this->_errorLog($queryString->getUserInfo());
  1959.                 return false;
  1960.             }
  1961.         }
  1962. //        $this->_queryCache[$cacheKey] = $queryString;
  1963.         return $queryString;
  1964.     }
  1965.  
  1966.     // }}}
  1967.     // {{{ _buildUpdateQuery()
  1968.     /**
  1969.      * this simply builds an update query.
  1970.      *
  1971.      * @param  array   the parameter array might contain the following indexes
  1972.      *         'where'     the where clause to be added, i.e.
  1973.      *                     UPDATE table SET x=1 WHERE y=0
  1974.      *                     here the 'where' part simply would be 'y=0'
  1975.      *         'set'       the actual data to be updated
  1976.      *                     in the example above, that would be 'x=1'
  1977.      * @return string the resulting query
  1978.      */
  1979.     function _buildUpdateQuery($query=array())
  1980.     {
  1981.         $where = isset($query['where']) ? $query['where'] : $this->_buildWhere();
  1982.         if ($where{
  1983.             $where = 'WHERE '.$where;
  1984.         }
  1985.  
  1986.         $updateString = sprintf('UPDATE %s SET %s %s',
  1987.                                 $this->table,
  1988.                                 $query['set'],
  1989.                                 $where
  1990.                             );
  1991.         return $updateString;
  1992.     }
  1993.  
  1994.     // }}}
  1995.     // {{{ execute()
  1996.     /**
  1997.      *
  1998.      * @version    2002/07/11
  1999.      * @access     public
  2000.      * @author     Wolfram Kriesing <wk@visionp.de>
  2001.      * @param
  2002.      * @param      string  query method
  2003.      * @return     boolean
  2004.      */
  2005.     function execute($query=null, $method='getAll')
  2006.     {
  2007.         $this->writeLog();
  2008.         if (is_null($query)) {
  2009.             $query = $this->_buildSelectQuery();
  2010.         }
  2011.         $this->writeLog('query built: '.$query);
  2012.  
  2013. // FIXXME on ORACLE this doesnt work, since we return joined columns as _TABLE_COLNAME and the _ in front
  2014. // doesnt work on oracle, add a letter before it!!!
  2015.         $this->_lastQuery = $query;
  2016.  
  2017.         $this->debug($query);
  2018.         $this->writeLog('start query');
  2019.         if (DB::isError($res $this->db->$method($query))) {
  2020.             $this->writeLog('end query (failed)');
  2021.             if ($this->getOption('verbose')) {
  2022.                 $this->_errorSet($res->getMessage());
  2023.             } else {
  2024.                 $this->_errorLog($res->getMessage());
  2025.             }
  2026.             $this->_errorLog($res->getUserInfo()__LINE__);
  2027.             return false;
  2028.         } else {
  2029.             $this->writeLog('end query');
  2030.         }
  2031.         $res = $this->_makeIndexed($res);
  2032.         return $res;
  2033.     }
  2034.  
  2035.     // }}}
  2036.     // {{{ writeLog()
  2037.     /**
  2038.      *   Write events to the logfile.
  2039.      *
  2040.      *   It does some additional work, like time measuring etc. to
  2041.      *   see some additional info
  2042.      *
  2043.      */
  2044.     function writeLog($text='START')
  2045.     {
  2046. //its still really a quicky.... 'refactor' (nice word) that
  2047.         if (!isset($this->options['logfile'])) {
  2048.             return;
  2049.         }
  2050.  
  2051.         include_once 'Log.php';
  2052.         if (!class_exists('Log')) {
  2053.             return;
  2054.         }
  2055.         if (!$this->_logObject{
  2056.             $this->_logObject =Log::factory('file'$this->options['logfile']);
  2057.         }
  2058.  
  2059.         if ($text==='start query' || $text==='end query') {
  2060.             $bytesSent = $this->db->getAll("SHOW STATUS like 'Bytes_sent'");
  2061.             $bytesSent $bytesSent[0]['Value'];
  2062.         }
  2063.         if ($text==='START') {
  2064.             $startTime = split(' ', microtime());
  2065.             $this->_logData['startTime'$startTime[1$startTime[0];
  2066.         }
  2067.         if ($text==='start query') {
  2068.             $this->_logData['startBytesSent'$bytesSent;
  2069.             $startTime = split(' 'microtime());
  2070.             $this->_logData['startQueryTime'$startTime[1$startTime[0];
  2071.             return;
  2072.         }
  2073.         if ($text==='end query') {
  2074.             $text .= ' result size: '.((int)$bytesSent-(int)$this->_logData['startBytesSent']).' bytes';
  2075.             $endTime = split(' 'microtime());
  2076.             $endTime $endTime[1$endTime[0];
  2077.             $text .= ', took: '.(($endTime $this->_logData['startQueryTime'])).' seconds';
  2078.         }
  2079.         if (strpos($text, 'query built')===0) {
  2080.             $endTime = split(' ', microtime());
  2081.             $endTime = $endTime[1] + $endTime[0];
  2082.             $this->writeLog('query building took: '.(($endTime $this->_logData['startTime'])).' seconds');
  2083.         }
  2084.         $this->_logObject->log($text);
  2085.  
  2086.         if (strpos($text'end query')===0{
  2087.             $endTime = split(' ', microtime());
  2088.             $endTime = $endTime[1] + $endTime[0];
  2089.             $text = 'time over all: '.(($endTime - $this->_logData['startTime'])).' seconds';
  2090.             $this->_logObject->log($text);
  2091.         }
  2092.     }
  2093.  
  2094.     // }}}
  2095.     // {{{ returnResult()
  2096.     /**
  2097.      * Return the chosen result type
  2098.      *
  2099.      * @version    2004/04/28
  2100.      * @access     public
  2101.      * @param object reference
  2102.      * @return mixed
  2103.      */
  2104.     function returnResult(&$result)
  2105.     {
  2106.         if ($this->_resultType == 'none'{
  2107.             return $result;
  2108.         }
  2109.         if ($result === false) {
  2110.             return false;
  2111.         }
  2112.         //what about allowing other (custom) result types?
  2113.         switch (strtolower($this->_resultType)) {
  2114.             case 'object':  return new DB_QueryTool_Result_Object($result);
  2115.             case 'array':
  2116.             default:        return new DB_QueryTool_Result($result);
  2117.         }
  2118.     }
  2119.  
  2120.     // }}}
  2121.     // {{{ _makeIndexed()
  2122.     /**
  2123.      *
  2124.      * @version    2002/07/11
  2125.      * @access     public
  2126.      * @author     Wolfram Kriesing <wk@visionp.de>
  2127.      * @param      mixed
  2128.      * @return     mixed
  2129.      */
  2130.     function &_makeIndexed(&$data)
  2131.     {
  2132.         // we can only return an indexed result if the result has a number of columns
  2133.         if (is_array($data) && sizeof($data) && $key = $this->getIndex()) {
  2134.             // build the string to evaluate which might be made up out of multiple indexes of a result-row
  2135.             $evalString = '$val[\''.implode('\'].\',\'.$val[\'',explode(',',$key)).'\']';   //"
  2136.             $indexedData = array();
  2137. //FIXXME actually we also need to check ONCE if $val is an array, so to say if $data is 2-dimensional
  2138.             foreach ($data as $val) {
  2139.                 eval("\$keyValue = $evalString;");  // get the actual real (string-)key (string if multiple cols are used as index)
  2140.                 $indexedData[$keyValue] = $val;
  2141.             }
  2142.             unset($data);
  2143.             return $indexedData;
  2144.         }
  2145.  
  2146.         return $data;
  2147.     }
  2148.  
  2149.     // }}}
  2150.     // {{{ setIndex()
  2151.     /**
  2152.      * format the result to be indexed by $key
  2153.      * NOTE: be careful, when using this you should be aware, that if you
  2154.      * use an index which's value appears multiple times you may loose data
  2155.      * since a key cant exist multiple times!!
  2156.      * the result for a result to be indexed by a key(=columnName)
  2157.      * (i.e. 'relationtoMe') which's values are 'brother' and 'sister'
  2158.      * or alike normally returns this:
  2159.      *     $res['brother'] = array('name'=>'xxx')
  2160.      *     $res['sister'] = array('name'=>'xxx')
  2161.      * but if the column 'relationtoMe' contains multiple entries for 'brother'
  2162.      * then the returned dataset will only contain one brother, since the
  2163.      * value from the column 'relationtoMe' is used
  2164.      * and which 'brother' you get depends on a lot of things, like the sortorder,
  2165.      * how the db saves the data, and whatever else
  2166.      *
  2167.      * you can also set indexes which depend on 2 columns, simply pass the parameters like
  2168.      * 'table1.id,table2.id' it will be used as a string for indexing the result
  2169.      * and the index will be built using the 2 values given, so a possible
  2170.      * index might be '1,2' or '2108,29389' this way you can access data which
  2171.      * have 2 primary keys. Be sure to remember that the index is a string!
  2172.      *
  2173.      * @version    2002/07/11
  2174.      * @access     public
  2175.      * @author     Wolfram Kriesing <wk@visionp.de>
  2176.      * @param
  2177.      * @return
  2178.      */
  2179.     function setIndex($key=null)
  2180.     {
  2181.         if ($this->getJoin()) { // is join set?
  2182.             // replace TABLENAME.COLUMNNAME by _TABLENAME_COLUMNNAME
  2183.             // since this is only the result-keys can be used for indexing :-)
  2184.             $regExp = '/('.implode('|', $this->getJoin('tables')).')\.([^\s]+)/';
  2185.             $key = preg_replace($regExp'_$1_$2'$key);
  2186.  
  2187.             // remove the table name if it is in front of '<$this->table>.columnname'
  2188.             // since the key doesnt contain it neither
  2189.             if ($meta $this->metadata()) {
  2190.                 foreach ($meta as $aCol => $x) {
  2191.                     $key = preg_replace('/'.$this->table.'\.'.$aCol.'/'$aCol$key);
  2192.                 }
  2193.             }
  2194.         }
  2195.         $this->_index = $key;
  2196.     }
  2197.  
  2198.     // }}}
  2199.     // {{{ getIndex()
  2200.     /**
  2201.      *
  2202.      * @version    2002/07/11
  2203.      * @access     public
  2204.      * @author     Wolfram Kriesing <wk@visionp.de>
  2205.      * @param
  2206.      * @return
  2207.      */
  2208.     function getIndex()
  2209.     {
  2210.         return $this->_index;
  2211.     }
  2212.  
  2213.     // }}}
  2214.     // {{{ useResult()
  2215.     /**
  2216.      * Choose the type of the returned result
  2217.      *
  2218.      * @version    2004/04/28
  2219.      * @access     public
  2220.      * @param string $type  ['array' | 'object' | 'none']
  2221.      *             For BC reasons, $type=true is equal to 'array',
  2222.      *             $type=false is equal to 'none'
  2223.      */
  2224.     function useResult($type='array')
  2225.     {
  2226.         if ($type === true) {
  2227.             $type = 'array';
  2228.         } elseif ($type === false) {
  2229.             $type = 'none';
  2230.         }
  2231.         switch (strtolower($type)) {
  2232.             case 'array':
  2233.                 $this->_resultType = 'array';
  2234.                 require_once 'DB/QueryTool/Result.php';
  2235.                 break;
  2236.             case 'object':
  2237.                 $this->_resultType = 'object';
  2238.                 require_once 'DB/QueryTool/Result/Object.php';
  2239.                 break;
  2240.             default:
  2241.                 $this->_resultType = 'none';
  2242.         }
  2243.     }
  2244.  
  2245.     // }}}
  2246.     // {{{ setErrorCallback()
  2247.     /**
  2248.      * set both callbacks
  2249.      * @param string
  2250.      */
  2251.     function setErrorCallback($param='')
  2252.     {
  2253.         $this->setErrorLogCallback($param);
  2254.         $this->setErrorSetCallback($param);
  2255.     }
  2256.  
  2257.     // }}}
  2258.     // {{{ setErrorLogCallback()
  2259.     /**
  2260.      * @param string
  2261.      */
  2262.     function setErrorLogCallback($param='')
  2263.     {
  2264.         $errorLogCallback = &PEAR::getStaticProperty('DB_QueryTool','_errorLogCallback');
  2265.         $errorLogCallback = $param;
  2266.     }
  2267.  
  2268.     // }}}
  2269.     // {{{ setErrorSetCallback()
  2270.     /**
  2271.      * @param string
  2272.      */
  2273.     function setErrorSetCallback($param='')
  2274.     {
  2275.         $errorSetCallback = &PEAR::getStaticProperty('DB_QueryTool','_errorSetCallback');
  2276.         $errorSetCallback = $param;
  2277.     }
  2278.  
  2279.     // }}}
  2280.     // {{{ _errorLog()
  2281.     /**
  2282.      * sets error log and adds additional info
  2283.      *
  2284.      * @version    2002/04/16
  2285.      * @access     public
  2286.      * @author     Wolfram Kriesing <wk@visionp.de>
  2287.      * @param      string  the actual message, first word should always be the method name,
  2288.      *                     to build the message like this: className::methodname
  2289.      * @param      integer the line number
  2290.      */
  2291.     function _errorLog($msg, $line='unknown')
  2292.     {
  2293.         $this->_errorHandler('log'$msg$line);
  2294. /*
  2295.         if ($this->getOption('verbose') == true)
  2296.         {
  2297.             $this->_errorLog(get_class($this)."::$msg ($line)");
  2298.             return;
  2299.         }
  2300.  
  2301.         if ($this->_errorLogCallback)
  2302.             call_user_func($this->_errorLogCallback, $msg);
  2303. */
  2304.     }
  2305.  
  2306.     // }}}
  2307.     // {{{ _errorSet()
  2308.     /**
  2309.      * @param      string
  2310.      * @param      string
  2311.      */
  2312.     function _errorSet($msg, $line='unknown')
  2313.     {
  2314.         $this->_errorHandler('set'$msg$line);
  2315.     }
  2316.  
  2317.     // }}}
  2318.     // {{{ _errorHandler()
  2319.     /**
  2320.      * @param
  2321.      * @param      string
  2322.      * @param      string
  2323.      */
  2324.     function _errorHandler($logOrSet, $msg, $line='unknown')
  2325.     {
  2326. /* what did i do this for?
  2327.         if ($this->getOption('verbose') == true)
  2328.         {
  2329.             $this->_errorHandler($logOrSet, get_class($this)."::$msg ($line)");
  2330.             return;
  2331.         }
  2332. */
  2333.  
  2334.         $msg = get_class($this)."::$msg ($line)";
  2335.  
  2336.         $logOrSet = ucfirst($logOrSet);
  2337.         $callback = &PEAR::getStaticProperty('DB_QueryTool','_error'.$logOrSet.'Callback');
  2338.         if ($callback)
  2339.             call_user_func($callback, $msg);
  2340. //        else
  2341. //          ?????
  2342.     }
  2343.  
  2344.     // }}}
  2345. }

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