Source for file jDaoFactoryBase.class.php

Documentation is available at jDaoFactoryBase.class.php

  1. <?php
  2. /**
  3.  * @package     jelix
  4.  * @subpackage  dao
  5.  * @author      Laurent Jouanneau
  6.  * @contributor Loic Mathaud
  7.  * @contributor Julien Issler
  8.  * @contributor Michael Fradin
  9.  * @copyright   2005-2009 Laurent Jouanneau
  10.  * @copyright   2007 Loic Mathaud
  11.  * @copyright   2007-2008 Julien Issler
  12.  * @copyright   2009 Mickael Fradin
  13.  * @link        http://www.jelix.org
  14.  * @licence     http://www.gnu.org/licenses/lgpl.html GNU Lesser General Public Licence, see LICENCE file
  15.  */
  16.  
  17. /**
  18.  * base class for all factory classes generated by the dao compiler
  19.  * @package  jelix
  20.  * @subpackage dao
  21.  */
  22. abstract class jDaoFactoryBase  {
  23.     /**
  24.      * informations on tables
  25.      *
  26.      * Keys of elements are the alias of the table. values are arrays like that :
  27.      * <pre> array (
  28.      *   'name' => ' the table alias',
  29.      *   'realname' => 'the real name of the table',
  30.      *   'pk' => array ( list of primary keys name ),
  31.      *   'fields' => array ( list of property name attached to this table )
  32.      * )
  33.      * </pre>
  34.      * @var array 
  35.      */
  36.     protected $_tables;
  37.     /**
  38.      * the id of the primary table
  39.      * @var string 
  40.      */
  41.     protected $_primaryTable;
  42.     /**
  43.      * the database connector
  44.      * @var jDbConnection 
  45.      */
  46.     protected $_conn;
  47.     /**
  48.      * the select clause you can reuse for a specific SELECT query
  49.      * @var string 
  50.      */
  51.     protected $_selectClause;
  52.     /**
  53.      * the from clause you can reuse for a specific SELECT query
  54.      * @var string 
  55.      */
  56.     protected $_fromClause;
  57.     /**
  58.      * the where clause you can reuse for a specific SELECT query
  59.      * @var string 
  60.      */
  61.     protected $_whereClause;
  62.     /**
  63.      * the class name of a dao record for this dao factory
  64.      * @var string 
  65.      */
  66.     protected $_DaoRecordClassName;
  67.  
  68.     /**
  69.      * the selector of the dao, to be sent with events
  70.      * @var string 
  71.      */
  72.     protected $_daoSelector;
  73.  
  74.     /**
  75.      * @since 1.0
  76.      */
  77.     protected $_deleteBeforeEvent = false;
  78.     /**
  79.      * @since 1.0
  80.      */
  81.     protected $_deleteAfterEvent = false;
  82.     /**
  83.      * @since 1.0
  84.      */
  85.     protected $_deleteByBeforeEvent = false;
  86.     /**
  87.      * @since 1.0
  88.      */
  89.     protected $_deleteByAfterEvent = false;
  90.  
  91.     /**
  92.      * @since 1.0
  93.      */
  94.     protected $trueValue = 1;
  95.     /**
  96.      * @since 1.0
  97.      */
  98.     protected $falseValue = 0;
  99.     /**
  100.      * @param jDbConnection $conn the database connection
  101.      */
  102.     function  __construct($conn){
  103.         $this->_conn = $conn;
  104.  
  105.         if($this->_conn->hasTablePrefix()){
  106.             foreach($this->_tables as $table_name=>$table){
  107.                 $this->_tables[$table_name]['realname'$this->_conn->prefixTable($table['realname']);
  108.             }
  109.         }
  110.     }
  111.  
  112.     /**
  113.      * informations on all properties
  114.      * 
  115.      * keys are property name, and values are an array like that :
  116.      * <pre> array (
  117.      *  'name' => 'name of property',
  118.      *  'fieldName' => 'name of fieldname',
  119.      *  'regExp' => NULL, // or the regular expression to test the value
  120.      *  'required' => true/false,
  121.      *  'isPK' => true/false, //says if it is a primary key
  122.      *  'isFK' => true/false, //says if it is a foreign key
  123.      *  'datatype' => '', // type of data : string
  124.      *  'table' => 'grp', // alias of the table the property is attached to
  125.      *  'updatePattern' => '%s',
  126.      *  'insertPattern' => '%s',
  127.      *  'selectPattern' => '%s',
  128.      *  'sequenceName' => '', // name of the sequence when type is autoincrement
  129.      *  'maxlength' => NULL, // or a number
  130.      *  'minlength' => NULL, // or a number
  131.      *  'ofPrimaryTable' => true/false,
  132.      *  'needsQuotes' => tree/false, // says if the value need to enclosed between quotes
  133.      * ) </pre>
  134.      * @return array informations on all properties
  135.      * @since 1.0beta3
  136.      */
  137.     abstract public function getProperties();
  138.  
  139.     /**
  140.      * list of id of primary properties
  141.      * @return array list of properties name which contains primary keys
  142.      * @since 1.0beta3
  143.      */
  144.     abstract public function getPrimaryKeyNames();
  145.  
  146.     /**
  147.      * return all records
  148.      * @return jDbResultSet 
  149.      */
  150.     public function findAll(){
  151.         $rs $this->_conn->query ($this->_selectClause.$this->_fromClause.$this->_whereClause);
  152.         $rs->setFetchMode(8,$this->_DaoRecordClassName);
  153.         return $rs;
  154.     }
  155.  
  156.     /**
  157.      * return the number of all records
  158.      * @return int the count
  159.      */
  160.     public function countAll(){
  161.         $query 'SELECT COUNT(*) as c '.$this->_fromClause.$this->_whereClause;
  162.         $rs  $this->_conn->query ($query);
  163.         $res $rs->fetch ();
  164.         return intval($res->c);
  165.     }
  166.  
  167.     /**
  168.      * return the record corresponding to the given key
  169.      * @param string  one or more primary key
  170.      * @return jDaoRecordBase 
  171.      */
  172.     final public function get(){
  173.         $args=func_get_args();
  174.         if(count($args)==&& is_array($args[0])){
  175.             $args=$args[0];
  176.         }
  177.         $keys array_combine($this->getPrimaryKeyNames(),$args );
  178.  
  179.         if($keys === false){
  180.             throw new jException('jelix~dao.error.keys.missing');
  181.         }
  182.  
  183.         $q $this->_selectClause.$this->_fromClause.$this->_whereClause;
  184.         $q .= $this->_getPkWhereClauseForSelect($keys);
  185.  
  186.         $rs $this->_conn->query ($q);
  187.         $rs->setFetchMode(8,$this->_DaoRecordClassName);
  188.         $record =  $rs->fetch ();
  189.         return $record;
  190.     }
  191.  
  192.     /**
  193.      * delete a record corresponding to the given key
  194.      * @param string  one or more primary key
  195.      * @return int the number of deleted record
  196.      */
  197.     final public function delete(){
  198.         $args=func_get_args();
  199.         if(count($args)==&& is_array($args[0])){
  200.             $args=$args[0];
  201.         }
  202.         $keys array_combine($this->getPrimaryKeyNames()$args);
  203.         if($keys === false){
  204.             throw new jException('jelix~dao.error.keys.missing');
  205.         }
  206.         $q 'DELETE FROM '.$this->_tables[$this->_primaryTable]['realname'].' ';
  207.         $q.= $this->_getPkWhereClauseForNonSelect($keys);
  208.  
  209.         if ($this->_deleteBeforeEvent{
  210.             jEvent::notify("daoDeleteBefore"array('dao'=>$this->_daoSelector'keys'=>$keys));
  211.         }
  212.         $result $this->_conn->exec ($q);
  213.         if ($this->_deleteAfterEvent{
  214.             jEvent::notify("daoDeleteAfter"array('dao'=>$this->_daoSelector'keys'=>$keys'result'=>$result));
  215.         }
  216.         return $result;
  217.     }
  218.  
  219.     /**
  220.      * save a new record into the database
  221.      * if the dao record has an autoincrement key, its corresponding property is updated
  222.      * @param jDaoRecordBase $record the record to save
  223.      */
  224.     abstract public function insert ($record);
  225.  
  226.     /**
  227.      * save a modified record into the database
  228.      * @param jDaoRecordBase $record the record to save
  229.      */
  230.     abstract public function update ($record);
  231.  
  232.     /**
  233.      * return all record corresponding to the conditions stored into the
  234.      * jDaoConditions object.
  235.      * you can limit the number of results by given an offset and a count
  236.      * @param jDaoConditions $searchcond 
  237.      * @param int $limitOffset 
  238.      * @param int $limitCount 
  239.      * @return jDbResultSet 
  240.      */
  241.     final public function findBy ($searchcond$limitOffset=0$limitCount=0){
  242.         $query $this->_selectClause.$this->_fromClause.$this->_whereClause;
  243.         if ($searchcond->hasConditions ()){
  244.             $query .= ($this->_whereClause !='' ' AND ' ' WHERE ');
  245.             $query .= $this->_createConditionsClause($searchcond);
  246.         }
  247.         $query.= $this->_createOrderClause($searchcond);
  248.  
  249.         if($limitCount != 0){
  250.             $rs $this->_conn->limitQuery ($query$limitOffset$limitCount);
  251.         }else{
  252.             $rs $this->_conn->query ($query);
  253.         }
  254.         $rs->setFetchMode(8,$this->_DaoRecordClassName);
  255.         return $rs;
  256.     }
  257.  
  258.     /**
  259.      * return the number of records corresponding to the conditions stored into the
  260.      * jDaoConditions object.
  261.      * @author Loic Mathaud
  262.      * @copyright 2007 Loic Mathaud
  263.      * @since 1.0b2
  264.      * @param jDaoConditions $searchcond 
  265.      * @return int the count
  266.      */
  267.     final public function countBy($searchcond{
  268.         $query 'SELECT COUNT(*) as c '.$this->_fromClause.$this->_whereClause;
  269.         if ($searchcond->hasConditions ()){
  270.             $query .= ($this->_whereClause !='' ' AND ' ' WHERE ');
  271.             $query .= $this->_createConditionsClause($searchcond);
  272.         }
  273.         $rs  $this->_conn->query ($query);
  274.         $res $rs->fetch();
  275.         return intval($res->c);
  276.     }
  277.  
  278.     /**
  279.      * delete all record corresponding to the conditions stored into the
  280.      * jDaoConditions object.
  281.      * @param jDaoConditions $searchcond 
  282.      * @return number of deleted rows
  283.      * @since 1.0beta3
  284.      */
  285.     final public function deleteBy ($searchcond){
  286.         if ($searchcond->isEmpty ()){
  287.             return;
  288.         }
  289.  
  290.         $query 'DELETE FROM '.$this->_tables[$this->_primaryTable]['realname'].' WHERE ';
  291.         $query .= $this->_createConditionsClause($searchcondfalse);
  292.  
  293.         if ($this->_deleteByBeforeEvent{
  294.             jEvent::notify("daoDeleteByBefore"array('dao'=>$this->_daoSelector'criterias'=>$searchcond));
  295.         }
  296.         $result $this->_conn->exec($query);
  297.         if ($this->_deleteByAfterEvent{
  298.             jEvent::notify("daoDeleteByAfter"array('dao'=>$this->_daoSelector'criterias'=>$searchcond'result'=>$result));
  299.         }
  300.         return $result;
  301.     }
  302.  
  303.     /**
  304.      * create a WHERE clause with conditions on primary keys with given value. This method
  305.      * should be used for SELECT queries. You haven't to escape values.
  306.      *
  307.      * @param array $pk  associated array : keys = primary key name, values : value of a primary key
  308.      * @return string a 'where' clause (WHERE mypk = 'myvalue' ...)
  309.      */
  310.     abstract protected function _getPkWhereClauseForSelect($pk);
  311.  
  312.     /**
  313.      * create a WHERE clause with conditions on primary keys with given value. This method
  314.      * should be used for DELETE and UPDATE queries.
  315.      * @param array $pk  associated array : keys = primary key name, values : value of a primary key
  316.      * @return string a 'where' clause (WHERE mypk = 'myvalue' ...)
  317.      */
  318.     abstract protected function _getPkWhereClauseForNonSelect($pk);
  319.  
  320.     /**
  321.     * @internal
  322.     */
  323.     final protected function _createConditionsClause($daocond$forSelect=true){
  324.         $props $this->getProperties();
  325.         return $this->_generateCondition ($daocond->condition$props$forSelecttrue);
  326.     }
  327.  
  328.     /**
  329.      * @internal
  330.      */
  331.     final protected function _createOrderClause($daocond{
  332.         $order array ();
  333.         $props =$this->getProperties();
  334.         foreach ($daocond->order as $name => $way){
  335.             if (isset($props[$name])){
  336.                 $order[$name.' '.$way;
  337.             }
  338.         }
  339.  
  340.         if(count ($order)){
  341.             return ' ORDER BY '.implode (', '$order);
  342.         }
  343.         return '';
  344.     }
  345.  
  346.     /**
  347.      * @internal it don't support isExpr property of a condition because of security issue (SQL injection)
  348.      *  because the value could be provided by a form, it is escaped in any case
  349.      */
  350.     final protected function _generateCondition($condition&$fields$forSelect$principal=true){
  351.         $r ' ';
  352.         $notfirst false;
  353.         foreach ($condition->conditions as $cond){
  354.             if ($notfirst){
  355.                 $r .= ' '.$condition->glueOp.' ';
  356.             }else
  357.                 $notfirst true;
  358.  
  359.             $prop=$fields[$cond['field_id']];
  360.  
  361.             if($forSelect)
  362.                 $prefixNoCondition $this->_tables[$prop['table']]['name'].'.'.$prop['fieldName'];
  363.             else
  364.                 $prefixNoCondition $prop['fieldName'];
  365.  
  366.             $op strtoupper($cond['operator']);
  367.             $prefix $prefixNoCondition.' '.$op.' '// ' ' for LIKE
  368.  
  369.             if ($op == 'IN' || $op == 'NOT IN'{
  370.                 if (is_array($cond['value'])) {
  371.                     $values array();
  372.                     foreach($cond['value'as $value)
  373.                         $values[$this->_prepareValue($value$prop['datatype']);
  374.                     $values join(','$values);
  375.                 }
  376.                 else
  377.                     $values $cond['value'];
  378.  
  379.                 $r .= $prefix.'('.$values.')';
  380.             }
  381.             else {
  382.                 if ($op == 'LIKE' || $op == 'NOT LIKE'{
  383.                     $type 'varchar';
  384.                 }
  385.                 else {
  386.                     $type $prop['datatype'];
  387.                 }
  388.                 if (!is_array ($cond['value'])){
  389.                     $value $this->_prepareValue($cond['value']$type);
  390.                     if ($cond['value'=== null{
  391.                         if (in_array($oparray('=','LIKE','IS','IS NULL'))) {
  392.                             $r .= $prefixNoCondition.' IS NULL';
  393.                         else {
  394.                             $r .= $prefixNoCondition.' IS NOT NULL';
  395.                         }
  396.                     else {
  397.                         $r .= $prefix.$value;
  398.                     }
  399.                 else {
  400.                     $r .= ' ( ';
  401.                     $firstCV true;
  402.                     foreach ($cond['value'as $conditionValue{
  403.                         if (!$firstCV{
  404.                             $r .= ' or ';
  405.                         }
  406.                         $value $this->_prepareValue($conditionValue$type);
  407.                         if ($conditionValue === null{
  408.                             if (in_array($oparray('=','LIKE','IS','IS NULL'))) {
  409.                                 $r .= $prefixNoCondition.' IS NULL';
  410.                             else {
  411.                                 $r .= $prefixNoCondition.' IS NOT NULL';
  412.                             }
  413.                         else {
  414.                             $r .= $prefix.$value;
  415.                         }
  416.                         $firstCV false;
  417.                     }
  418.                     $r .= ' ) ';
  419.                 }
  420.             }
  421.         }
  422.         //sub conditions
  423.         foreach ($condition->group as $conditionDetail){
  424.             if ($notfirst){
  425.                 $r .= ' '.$condition->glueOp.' ';
  426.             }else{
  427.                 $notfirst true;
  428.             }
  429.             $r .= $this->_generateCondition($conditionDetail$fields$forSelectfalse);
  430.         }
  431.  
  432.         //adds parenthesis around the sql if needed (non empty)
  433.         if (strlen (trim ($r)) && !$principal){
  434.             $r '('.$r.')';
  435.         }
  436.         return $r;
  437.     }
  438.  
  439.     /**
  440.      * prepare the value ready to be used in a dynamic evaluation
  441.      */
  442.     final protected function _prepareValue($value$fieldType$notNull false){
  443.         if (!$notNull && $value === null)
  444.             return 'NULL';
  445.         switch(strtolower($fieldType)){
  446.             case 'int':
  447.             case 'integer':
  448.             case 'autoincrement':
  449.                 $value intval($value);
  450.                 break;
  451.             case 'double':
  452.             case 'float':
  453.                 $value doubleval($value);
  454.                 break;
  455.             case 'numeric'://usefull for bigint and stuff
  456.             case 'bigautoincrement':
  457.                 if (is_numeric ($value)){
  458.                     //was numeric, we can sends it as is
  459.                     // no cast with intval else overflow
  460.                     return $value;
  461.                 }else{
  462.                     //not a numeric, nevermind, casting it
  463.                     return intval ($value);
  464.                 }
  465.                 break;
  466.             case 'boolean':
  467.                 if ($value === true|| strtolower($value)=='true'|| $value =='1' || $value ==='t')
  468.                     $value =  $this->trueValue;
  469.                 else
  470.                     $value =  $this->falseValue;
  471.                 break;
  472.             default:
  473.                 $value $this->_conn->quote ($value);
  474.         }
  475.         return $value;
  476.     }
  477. }
  478. ?>

Documentation generated on Wed, 07 Sep 2011 13:46:55 +0200 by phpDocumentor 1.4.3