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

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