Source for file jDaoGenerator.class.php

Documentation is available at jDaoGenerator.class.php

  1. <?php
  2. /**
  3. @package    jelix
  4. @subpackage dao
  5. @author     Croes GĂ©rald, Laurent Jouanneau
  6. @contributor Laurent Jouanneau
  7. @contributor Bastien Jaillot (bug fix)
  8. @contributor Julien Issler
  9. @copyright  2001-2005 CopixTeam, 2005-2011 Laurent Jouanneau
  10. @copyright  2007-2008 Julien Issler
  11. *  This class was get originally from the Copix project (CopixDAOGeneratorV1, Copix 2.3dev20050901, http://www.copix.org)
  12. *  Few lines of code are still copyrighted 2001-2005 CopixTeam (LGPL licence).
  13. *  Initial authors of this Copix class are Gerald Croes and Laurent Jouanneau,
  14. *  and this class was rewrited for Jelix by Laurent Jouanneau
  15. *
  16. @link        http://www.jelix.org
  17. @licence  http://www.gnu.org/licenses/lgpl.html GNU Lesser General Public Licence, see LICENCE file
  18. */
  19.  
  20. /**
  21. * This is a generator which creates php class from dao xml file.
  22. *
  23. * It is called by jDaoCompiler
  24. @package  jelix
  25. @subpackage dao
  26. @see jDaoCompiler
  27. */
  28. class jDaoGenerator {
  29.  
  30.     /**
  31.     * the dao definition.
  32.     * @var jDaoParser 
  33.     */
  34.     protected $_dataParser = null;
  35.  
  36.     /**
  37.     * The DaoRecord ClassName
  38.     * @var string 
  39.     */
  40.     protected $_DaoRecordClassName = null;
  41.  
  42.     /**
  43.     * the DAO classname
  44.     * @var string 
  45.     */
  46.     protected $_DaoClassName = null;
  47.  
  48.     protected $propertiesListForInsert = 'PrimaryTable';
  49.  
  50.     protected $aliasWord = ' AS ';
  51.  
  52.     protected $trueValue = 1;
  53.     protected $falseValue = 0;
  54.  
  55.     /**
  56.     * constructor
  57.     * @param jDaoParser $daoDefinition 
  58.     */
  59.     function __construct($factoryClassName$recordClassName$daoDefinition){
  60.         $this->_dataParser = $daoDefinition;
  61.         $this->_DaoClassName = $factoryClassName;
  62.         $this->_DaoRecordClassName = $recordClassName;
  63.     }
  64.  
  65.     /**
  66.     * build all classes
  67.     */
  68.     public function buildClasses ({
  69.  
  70.         $src array();
  71.         $src[' require_once ( JELIX_LIB_PATH .\'dao/jDaoRecordBase.class.php\');';
  72.         $src[' require_once ( JELIX_LIB_PATH .\'dao/jDaoFactoryBase.class.php\');';
  73.  
  74.         // prepare some values to generate properties and methods
  75.  
  76.         list($sqlFromClause$sqlWhereClause)$this->_getFromClause();
  77.         $tables            $this->_dataParser->getTables();
  78.         $sqlSelectClause   $this->_getSelectClause();
  79.         $pkFields          $this->_getPropertiesBy('PkFields');
  80.         $pTableRealName    $tables[$this->_dataParser->getPrimaryTable()]['realname'];
  81.         $pTableRealNameEsc $this->_encloseName('\'.$this->_conn->prefixTable(\''.$pTableRealName.'\').\'');
  82.         $pkai              $this->_getAutoIncrementPKField();
  83.         $sqlPkCondition    $this->_buildSimpleConditions($pkFields);
  84.         if($sqlPkCondition != ''){
  85.             $sqlPkCondition($sqlWhereClause !='' ' AND ':' WHERE ').$sqlPkCondition;
  86.         }
  87.  
  88.         //-----------------------
  89.         // Build the record class
  90.         //-----------------------
  91.  
  92.         $src["\nclass ".$this->_DaoRecordClassName.' extends jDaoRecordBase {';
  93.  
  94.         $properties=array();
  95.  
  96.         foreach ($this->_dataParser->getProperties(as $id=>$field){
  97.             $properties[$idget_object_vars($field);
  98.             if($field->defaultValue !== null)
  99.                 $src[=' public $'.$id.'='.var_export($field->defaultValuetrue).';';
  100.             else
  101.                 $src[=' public $'.$id.';';
  102.         }
  103.  
  104.         // TODO PHP 5.3 : we could remove that
  105.         $src['   public function getProperties() { return '.$this->_DaoClassName.'::$_properties; }';
  106.         $src['   public function getPrimaryKeyNames() { return '.$this->_DaoClassName.'::$_pkFields; }';
  107.         $src['}';
  108.  
  109.         //--------------------
  110.         // Build the dao class
  111.         //--------------------
  112.  
  113.         $src["\nclass ".$this->_DaoClassName.' extends jDaoFactoryBase {';
  114.         $src['   protected $_tables = '.var_export($tablestrue).';';
  115.         $src['   protected $_primaryTable = \''.$this->_dataParser->getPrimaryTable().'\';';
  116.         $src['   protected $_selectClause=\''.$sqlSelectClause.'\';';
  117.         $src['   protected $_fromClause;';
  118.         $src['   protected $_whereClause=\''.$sqlWhereClause.'\';';
  119.         $src['   protected $_DaoRecordClassName=\''.$this->_DaoRecordClassName.'\';';
  120.         $src['   protected $_daoSelector = \''.jDaoCompiler::$daoId.'\';';
  121.  
  122.         if($this->trueValue != 1){
  123.             $src[]='   protected $trueValue ='.var_export($this->trueValue,true).';';
  124.             $src[]='   protected $falseValue ='.var_export($this->falseValue,true).';';
  125.         }
  126.  
  127.         if($this->_dataParser->hasEvent('deletebefore'|| $this->_dataParser->hasEvent('delete'))
  128.             $src['   protected $_deleteBeforeEvent = true;';
  129.         if ($this->_dataParser->hasEvent('deleteafter'|| $this->_dataParser->hasEvent('delete'))
  130.             $src['   protected $_deleteAfterEvent = true;';
  131.         if ($this->_dataParser->hasEvent('deletebybefore'|| $this->_dataParser->hasEvent('deleteby'))
  132.             $src['   protected $_deleteByBeforeEvent = true;';
  133.         if ($this->_dataParser->hasEvent('deletebyafter'|| $this->_dataParser->hasEvent('deleteby'))
  134.             $src['   protected $_deleteByAfterEvent = true;';
  135.  
  136.         $src['   public static $_properties = '.var_export($propertiestrue).';';
  137.         $src['   public static $_pkFields = array('.$this->_writeFieldNamesWith ($start '\''$end='\''$beetween ','$pkFields).');';
  138.  
  139.         $src[' ';
  140.         $src['public function __construct($conn){';
  141.         $src['   parent::__construct($conn);';
  142.         $src['   $this->_fromClause = \''.$sqlFromClause.'\';';
  143.         $src['}';
  144.  
  145.         // cannot put this methods directly into jDaoBase because of a php bug on static methods/properties
  146.         // TODO PHP 5.3 resolves it
  147.         $src['   public function getProperties() { return self::$_properties; }';
  148.         $src['   public function getPrimaryKeyNames() { return self::$_pkFields;}';
  149.  
  150.         $src[' ';
  151.         $src[' protected function _getPkWhereClauseForSelect($pk){';
  152.         $src['   extract($pk);';
  153.         $src[' return \''.$sqlPkCondition.'\';';
  154.         $src['}';
  155.  
  156.         $src[' ';
  157.         $src['protected function _getPkWhereClauseForNonSelect($pk){';
  158.         $src['   extract($pk);';
  159.         $src['   return \' where '.$this->_buildSimpleConditions($pkFields,'',false).'\';';
  160.         $src['}';
  161.  
  162.         //----- Insert method
  163.         $src['public function insert ($record){';
  164.  
  165.         if($pkai !== null){
  166.             // if there is an autoincrement field as primary key
  167.  
  168.             // if a value is given for the autoincrement field, then with do a full insert
  169.             $src[]=' if($record->'.$pkai->name.' > 0 ){';
  170.             $src['    $query = \'INSERT INTO '.$pTableRealNameEsc.' (';
  171.             $fields $this->_getPropertiesBy('PrimaryTable');
  172.             list($fields$values$this->_prepareValues($fields,'insertPattern''record->');
  173.  
  174.             $src[implode(',',$fields);
  175.             $src[') VALUES (';
  176.             $src[implode(', ',$values);
  177.             $src[")';";
  178.  
  179.             $src['}else{';
  180.  
  181.             $fields $this->_getPropertiesBy($this->propertiesListForInsert);
  182.         }else{
  183.             $fields $this->_getPropertiesBy('PrimaryTable');
  184.         }
  185.  
  186.         if($this->_dataParser->hasEvent('insertbefore'|| $this->_dataParser->hasEvent('insert')){
  187.           $src['   jEvent::notify("daoInsertBefore", array(\'dao\'=>$this->_daoSelector, \'record\'=>$record));';
  188.         }
  189.  
  190.         // if there isn't a autoincrement as primary key, then we do a full insert.
  191.         // if there isn't a value for the autoincrement field and if this is a mysql/sqlserver and pgsql,
  192.         // we do an insert without given primary key. In other case, we do a full insert.
  193.  
  194.         $src['    $query = \'INSERT INTO '.$pTableRealNameEsc.' (';
  195.  
  196.         list($fields$values$this->_prepareValues($fields,'insertPattern''record->');
  197.  
  198.         $src[implode(',',$fields);
  199.         $src[') VALUES (';
  200.         $src[implode(', ',$values);
  201.         $src[")';";
  202.  
  203.         if($pkai !== null)
  204.             $src['}';
  205.  
  206.         $src['   $result = $this->_conn->exec ($query);';
  207.  
  208.         if($pkai !== null){
  209.             $src['   if(!$result)';
  210.             $src['       return false;';
  211.  
  212.             $src['   if($record->'.$pkai->name.' < 1 ) ';
  213.             $src[$this->genUpdateAutoIncrementPK($pkai$pTableRealName);
  214.         }
  215.  
  216.         // we generate a SELECT query to update field on the record object, which are autoincrement or calculated
  217.         $fields $this->_getPropertiesBy('FieldToUpdate');
  218.         if (count($fields)) {
  219.             $result array();
  220.             foreach ($fields as $id=>$prop){
  221.                 $result[]$this->genSelectPattern($prop->selectPattern''$prop->fieldName$prop->name);
  222.             }
  223.  
  224.             $sql 'SELECT '.(implode (', ',$result))' FROM '.$pTableRealNameEsc.' WHERE ';
  225.             $sql.= $this->_buildSimpleConditions($pkFields'record->'false);
  226.  
  227.             $src['  $query =\''.$sql.'\';';
  228.             $src['  $rs  =  $this->_conn->query ($query);';
  229.             $src['  $newrecord =  $rs->fetch ();';
  230.             foreach ($fields as $id=>$prop){
  231.                 $src['  $record->'.$prop->name.' = $newrecord->'.$prop->name.';';
  232.             }
  233.         }
  234.  
  235.         if($this->_dataParser->hasEvent('insertafter'|| $this->_dataParser->hasEvent('insert')){
  236.             $src['   jEvent::notify("daoInsertAfter", array(\'dao\'=>$this->_daoSelector, \'record\'=>$record));';
  237.         }
  238.  
  239.         $src['    return $result;';
  240.         $src['}';
  241.  
  242.         //-----  update method
  243.  
  244.         $src['public function update ($record){';
  245.         list($fields$values$this->_prepareValues($this->_getPropertiesBy('PrimaryFieldsExcludePk'),'updatePattern''record->');
  246.         if(count($fields)){
  247.             if($this->_dataParser->hasEvent('updatebefore'|| $this->_dataParser->hasEvent('update')){
  248.                 $src['   jEvent::notify("daoUpdateBefore", array(\'dao\'=>$this->_daoSelector, \'record\'=>$record));';
  249.             }
  250.  
  251.             $src['   $query = \'UPDATE '.$pTableRealNameEsc.' SET ';
  252.             $sqlSet='';
  253.             foreach($fields as $k=> $fname){
  254.                 $sqlSet.= ', '.$fname'= '$values[$k];
  255.             }
  256.             $src[substr($sqlSet,1);
  257.  
  258.             $sqlCondition $this->_buildSimpleConditions($pkFields'record->'false);
  259.             if($sqlCondition!='')
  260.                 $src[' where '.$sqlCondition;
  261.  
  262.             $src["';";
  263.  
  264.             $src['   $result = $this->_conn->exec ($query);';
  265.  
  266.             // we generate a SELECT query to update field on the record object, which are autoincrement or calculated
  267.             $fields $this->_getPropertiesBy('FieldToUpdateOnUpdate');
  268.             if (count($fields)) {
  269.                 $result array();
  270.                 foreach ($fields as $id=>$prop){
  271.                     $result[]$this->genSelectPattern($prop->selectPattern''$prop->fieldName$prop->name);
  272.                 }
  273.  
  274.                 $sql 'SELECT '.(implode (', ',$result))' FROM '.$pTableRealNameEsc.' WHERE ';
  275.                 $sql.= $this->_buildSimpleConditions($pkFields'record->'false);
  276.  
  277.                 $src['  $query =\''.$sql.'\';';
  278.                 $src['  $rs  =  $this->_conn->query ($query, jDbConnection::FETCH_INTO, $record);';
  279.                 $src['  $record =  $rs->fetch ();';
  280.             }
  281.  
  282.             if($this->_dataParser->hasEvent('updateafter'|| $this->_dataParser->hasEvent('update'))
  283.                 $src['   jEvent::notify("daoUpdateAfter", array(\'dao\'=>$this->_daoSelector, \'record\'=>$record));';
  284.  
  285.             $src['   return $result;';
  286.             $src[' }';//ends the update function
  287.         }else{
  288.             //the dao is mapped on a table which contains only primary key : update is impossible
  289.             // so we will generate an error on update
  290.             $src["     throw new jException('jelix~dao.error.update.impossible',array('".jDaoCompiler::$daoId."','".jDaoCompiler::$daoPath."'));";
  291.             $src[" }";
  292.         }
  293.  
  294.         //----- other user methods
  295.  
  296.         $allField $this->_getPropertiesBy('All');
  297.         $primaryFields $this->_getPropertiesBy('PrimaryTable');
  298.         $ct=null;
  299.  
  300.  
  301.         foreach($this->_dataParser->getMethods(as $name=>$method){
  302.  
  303.             $defval $method->getParametersDefaultValues();
  304.             if(count($defval)){
  305.                 $mparam='';
  306.                 foreach($method->getParameters(as $param){
  307.                     $mparam.=', $'.$param;
  308.                     if(isset($defval[$param]))
  309.                         $mparam.='=\''.str_replace("'","\'",$defval[$param]).'\'';
  310.                 }
  311.                 $mparam substr($mparam,1);
  312.             }else{
  313.                 $mparam=implode(', $',$method->getParameters());
  314.                 if($mparam != ''$mparam ='$'.$mparam;
  315.             }
  316.  
  317.             $src[' function '.$method->name.' ('$mparam.'){';
  318.  
  319.             $limit='';
  320.  
  321.             switch($method->type){
  322.                 case 'delete':
  323.                     $src['    $__query = \'DELETE FROM '.$pTableRealNameEsc.' \';';
  324.                     $glueCondition =' WHERE ';
  325.                     break;
  326.                 case 'update':
  327.                     $src['    $__query = \'UPDATE '.$pTableRealNameEsc.' SET ';
  328.                     $updatefields $this->_getPropertiesBy('PrimaryFieldsExcludePk');
  329.                     $sqlSet='';
  330.                     foreach($method->getValues(as $propname=>$value){
  331.                         if($value[1]){
  332.                             foreach($method->getParameters(as $param){
  333.                                 $value[0str_replace('$'.$param'\'.'.$this->_preparePHPExpr('$'.$param$updatefields[$propname],true).'.\'',$value[0]);
  334.                             }
  335.                             $sqlSet.= ', '.$this->_encloseName($updatefields[$propname]->fieldName)'= '$value[0];
  336.                         }else{
  337.                             $sqlSet.= ', '.$this->_encloseName($updatefields[$propname]->fieldName)'= '.
  338.                                 $this->_preparePHPValue($value[0],$updatefields[$propname]->datatype,false);
  339.                         }
  340.                     }
  341.                     $src[substr($sqlSet,1).'\';';
  342.  
  343.                     $glueCondition =' WHERE ';
  344.                     break;
  345.  
  346.                 case 'php':
  347.                     $src[$method->getBody();
  348.                     $src['}';
  349.                     break;
  350.  
  351.                 case 'count':
  352.                     if($method->distinct !=''){
  353.                         $prop $this->_dataParser->getProperties ();
  354.                         $prop $prop[$method->distinct];
  355.                         $count=' DISTINCT '.$this->_encloseName($tables[$prop->table]['name'].'.'.$this->_encloseName($prop->fieldName);
  356.                     }else{
  357.                         $count='*';
  358.                     }
  359.                     $src['    $__query = \'SELECT COUNT('.$count.') as c \'.$this->_fromClause.$this->_whereClause;';
  360.                     $glueCondition ($sqlWhereClause !='' ' AND ':' WHERE ');
  361.                     break;
  362.                 case 'selectfirst':
  363.                 case 'select':
  364.                 default:
  365.                     if($method->distinct !=''){
  366.                         $select '\''.$this->_getSelectClause($method->distinct).'\'';
  367.                     }else{
  368.                         $select=' $this->_selectClause';
  369.                     }
  370.                     $src['    $__query = '.$select.'.$this->_fromClause.$this->_whereClause;';
  371.                     $glueCondition ($sqlWhereClause !='' ' AND ':' WHERE ');
  372.                     if$method->type == 'select' && ($lim $method->getLimit ()) !==null){
  373.                         $limit=', '.$lim['offset'].', '.$lim['count'];
  374.                     }
  375.             }
  376.  
  377.             if($method->type == 'php')
  378.                 continue;
  379.  
  380.             $cond $method->getConditions();
  381.             $sqlCond '';
  382.             if($cond !== null){
  383.                 if($method->type == 'delete' || $method->type == 'update')
  384.                     $sqlCond $this->_buildConditions($cond$primaryFields$method->getParameters()false);
  385.                 else if($method->type == 'count')
  386.                     $sqlCond $this->_buildConditions($cond$allField$method->getParameters()true);
  387.                 else
  388.                     $sqlCond $this->_buildConditions($cond$allField$method->getParameters()true$method->getGroupBy());
  389.  
  390.             else if(($method->type == 'select' || $method->type == 'selectfirst')) {
  391.                 $sqlCond $this->_buildConditions(null$allField$method->getParameters()true$method->getGroupBy());
  392.             }
  393.  
  394.             if(trim($sqlCond!= '')
  395.                 $src['$__query .=\''.$glueCondition.$sqlCond."';";
  396.  
  397.             switch($method->type){
  398.                 case 'delete':
  399.                 case 'update' :
  400.                     if ($method->eventBeforeEnabled || $method->eventAfterEnabled{
  401.                         $src['   $args = func_get_args();';
  402.                         $methname ($method->type == 'update'?'Update':'Delete');
  403.                         if ($method->eventBeforeEnabled{
  404.                         $src['   jEvent::notify("daoSpecific'.$methname.'Before", array(\'dao\'=>$this->_daoSelector,\'method\'=>\''.
  405.                             $method->name.'\', \'params\'=>$args));';
  406.                         }
  407.                         if ($method->eventAfterEnabled{
  408.                             $src['   $result = $this->_conn->exec ($__query);';
  409.                             $src['   jEvent::notify("daoSpecific'.$methname.'After", array(\'dao\'=>$this->_daoSelector,\'method\'=>\''.
  410.                                 $method->name.'\', \'params\'=>$args));';
  411.                             $src['   return $result;';
  412.                         else {
  413.                             $src['    return $this->_conn->exec ($__query);';
  414.                         }
  415.                     else {
  416.                         $src['    return $this->_conn->exec ($__query);';
  417.                     }
  418.                     break;
  419.                 case 'count':
  420.                     $src['    $__rs = $this->_conn->query($__query);';
  421.                     $src['    $__res = $__rs->fetch();';
  422.                     $src['    return intval($__res->c);';
  423.                     break;
  424.                 case 'selectfirst':
  425.                     $src['    $__rs = $this->_conn->limitQuery($__query,0,1);';
  426.                     $src['    $this->finishInitResultSet($__rs);';
  427.                     $src['    return $__rs->fetch();';
  428.                     break;
  429.                 case 'select':
  430.                 default:
  431.                     if($limit)
  432.                         $src['    $__rs = $this->_conn->limitQuery($__query'.$limit.');';
  433.                     else
  434.                         $src['    $__rs = $this->_conn->query($__query);';
  435.                     $src['    $this->finishInitResultSet($__rs);';
  436.                     $src['    return $__rs;';
  437.             }
  438.             $src['}';
  439.         }
  440.  
  441.         $src[$this->genEndOfClass();
  442.  
  443.         $src['}';//end of class
  444.  
  445.         return implode("\n",$src);
  446.     }
  447.  
  448.     /**
  449.     *  create FROM clause for all SELECT query
  450.     * @return array  FROM string and WHERE string
  451.     */
  452.     protected function _getFromClause(){
  453.  
  454.         $tables $this->_dataParser->getTables();
  455.  
  456.         foreach($tables as $table_name => $table){
  457.             $tables[$table_name]['realname''\'.$this->_conn->prefixTable(\''.$table['realname'].'\').\'';
  458.         }
  459.  
  460.         $primarytable $tables[$this->_dataParser->getPrimaryTable()];
  461.         $ptrealname $this->_encloseName($primarytable['realname']);
  462.         $ptname $this->_encloseName($primarytable['name']);
  463.  
  464.         list($sqlFrom$sqlWhere$this->genOuterJoins($tables$ptname);
  465.  
  466.         if($primarytable['name']!=$primarytable['realname'])
  467.             $sqlFrom =$ptrealname.$this->aliasWord.$ptname.$sqlFrom;
  468.         else
  469.             $sqlFrom =$ptrealname.$sqlFrom;
  470.  
  471.         foreach($this->_dataParser->getInnerJoins(as $tablejoin){
  472.             $table$tables[$tablejoin];
  473.             $tablename $this->_encloseName($table['name']);
  474.             if($table['name']!=$table['realname'])
  475.                 $sqlFrom .=', '.$this->_encloseName($table['realname']).$this->aliasWord.$tablename;
  476.             else
  477.                 $sqlFrom .=', '.$this->_encloseName($table['realname']);
  478.  
  479.             foreach($table['fk'as $k => $fk){
  480.                 $sqlWhere.=' AND '.$ptname.'.'.$this->_encloseName($fk).'='.$tablename.'.'.$this->_encloseName($table['pk'][$k]);
  481.             }
  482.         }
  483.  
  484.         $sqlWhere=($sqlWhere !=''' WHERE '.substr($sqlWhere,4:'';
  485.         return array(' FROM '.$sqlFrom,$sqlWhere);
  486.     }
  487.  
  488.     protected function genOuterJoins(&$tables$primaryTableName){
  489.         $sqlFrom '';
  490.         foreach($this->_dataParser->getOuterJoins(as $tablejoin){
  491.             $table$tables[$tablejoin[0]];
  492.             $tablename $this->_encloseName($table['name']);
  493.  
  494.             if($table['name']!=$table['realname'])
  495.                 $r =$this->_encloseName($table['realname']).$this->aliasWord.$tablename;
  496.             else
  497.                 $r =$this->_encloseName($table['realname']);
  498.  
  499.             $fieldjoin='';
  500.             foreach($table['fk'as $k => $fk){
  501.                 $fieldjoin.=' AND '.$primaryTableName.'.'.$this->_encloseName($fk).'='.$tablename.'.'.$this->_encloseName($table['pk'][$k]);
  502.             }
  503.             $fieldjoin=substr($fieldjoin,4);
  504.  
  505.             if($tablejoin[1== 0){
  506.                 $sqlFrom.=' LEFT JOIN '.$r.' ON ('.$fieldjoin.')';
  507.             }elseif($tablejoin[1== 1){
  508.                 $sqlFrom.=' RIGHT JOIN '.$r.' ON ('.$fieldjoin.')';
  509.             }
  510.         }
  511.         return array($sqlFrom'');
  512.     }
  513.  
  514.     /**
  515.     * build SELECT clause for all SELECT queries
  516.     */
  517.     protected function _getSelectClause ($distinct=false){
  518.         $result array();
  519.  
  520.         $tables $this->_dataParser->getTables();
  521.         foreach ($this->_dataParser->getProperties (as $id=>$prop){
  522.  
  523.             $table $this->_encloseName($tables[$prop->table]['name'].'.';
  524.  
  525.             if ($prop->selectPattern !=''){
  526.                 $result[]$this->genSelectPattern($prop->selectPattern$table$prop->fieldName$prop->name);
  527.             }
  528.         }
  529.  
  530.         return 'SELECT '.($distinct?'DISTINCT ':'').(implode (', ',$result));
  531.     }
  532.  
  533.     protected function genSelectPattern ($pattern$table$fieldname$propname ){
  534.         if ($pattern =='%s'){
  535.             if ($fieldname != $propname){
  536.                 $field $table.$this->_encloseName($fieldname).' as '.$this->_encloseName($propname);
  537.             }else{
  538.                 $field $table.$this->_encloseName($fieldname);
  539.             }
  540.         }else{
  541.             $field str_replace(array("'""%s")array("\\'",$table.$this->_encloseName($fieldname)),$pattern).' as '.$this->_encloseName($propname);
  542.         }
  543.         return $field;
  544.     }
  545.  
  546.     protected function genEndOfClass({
  547.         return '';
  548.     }
  549.  
  550.     /**
  551.     * format field names with start, end and between strings.
  552.     *   will write the field named info.
  553.     *   eg info == name
  554.     *   echo $field->name
  555.     * @param string   $info    property to get from objects in $using
  556.     * @param string   $start   string to add before the info
  557.     * @param string   $end     string to add after the info
  558.     * @param string   $beetween string to add between each info
  559.     * @param array    $using     list of CopixPropertiesForDAO object. if null, get default fields list
  560.     * @see  jDaoProperty
  561.     */
  562.     protected function _writeFieldsInfoWith ($info$start ''$end=''$beetween ''$using null){
  563.         $result array();
  564.         if ($using === null){
  565.             //if no fields are provided, using _dataParser's as default.
  566.             $using $this->_dataParser->getProperties ();
  567.         }
  568.  
  569.         foreach ($using as $id=>$field){
  570.             $result[$start $field->$info $end;
  571.         }
  572.  
  573.         return implode ($beetween,$result);;
  574.     }
  575.  
  576.     /**
  577.     * format field names with start, end and between strings.
  578.     */
  579.     protected function _writeFieldNamesWith ($start ''$end=''$beetween ''$using null){
  580.         return $this->_writeFieldsInfoWith ('name'$start$end$beetween$using);
  581.     }
  582.  
  583.  
  584.     /**
  585.     * gets fields that match a condition returned by the $captureMethod
  586.     * @internal
  587.     */
  588.     protected function _getPropertiesBy ($captureMethod){
  589.         $captureMethod '_capture'.$captureMethod;
  590.         $result array ();
  591.  
  592.         foreach ($this->_dataParser->getProperties(as $field){
  593.             if $this->$captureMethod($field)){
  594.                 $result[$field->name$field;
  595.             }
  596.         }
  597.         return $result;
  598.     }
  599.  
  600.     protected function _capturePkFields(&$field){
  601.         return ($field->table == $this->_dataParser->getPrimaryTable()) && $field->isPK;
  602.     }
  603.  
  604.     protected function _capturePrimaryFieldsExcludeAutoIncrement(&$field){
  605.         return ($field->table == $this->_dataParser->getPrimaryTable()) &&
  606.         ($field->datatype != 'autoincrement'&& ($field->datatype != 'bigautoincrement');
  607.     }
  608.  
  609.     protected function _capturePrimaryFieldsExcludePk(&$field){
  610.         return ($field->table == $this->_dataParser->getPrimaryTable()) && !$field->isPK;
  611.     }
  612.  
  613.     protected function _capturePrimaryTable(&$field){
  614.         return ($field->table == $this->_dataParser->getPrimaryTable());
  615.     }
  616.  
  617.     protected function _captureAll(&$field){
  618.         return true;
  619.     }
  620.  
  621.     protected function _captureFieldToUpdate(&$field){
  622.         return ($field->table == $this->_dataParser->getPrimaryTable()
  623.                 && !$field->isPK
  624.                 && !$field->isFK
  625.                 && $field->datatype == 'autoincrement' || $field->datatype == 'bigautoincrement'
  626.                     || ($field->insertPattern != '%s' && $field->selectPattern != '')));
  627.     }
  628.  
  629.     protected function _captureFieldToUpdateOnUpdate(&$field){
  630.         return ($field->table == $this->_dataParser->getPrimaryTable()
  631.                 && !$field->isPK
  632.                 && !$field->isFK
  633.                 && $field->datatype == 'autoincrement' || $field->datatype == 'bigautoincrement'
  634.                     || ($field->updatePattern != '%s' && $field->selectPattern != '')));
  635.     }
  636.  
  637.     protected function _captureBinaryField(&$field{
  638.         return ($field->datatype == 'varbinary');
  639.     }
  640.  
  641.     /**
  642.     * get autoincrement PK field
  643.     */
  644.     protected function _getAutoIncrementPKField ($using null){
  645.         if ($using === null){
  646.             $using $this->_dataParser->getProperties ();
  647.         }
  648.  
  649.         $tb $this->_dataParser->getTables();
  650.         $tb $tb[$this->_dataParser->getPrimaryTable()]['realname'];
  651.  
  652.         foreach ($using as $id=>$field{
  653.             if(!$field->isPK)
  654.                 continue;
  655.             if ($field->datatype == 'autoincrement' || $field->datatype == 'bigautoincrement'{
  656.                 return $field;
  657.             }
  658.         }
  659.         return null;
  660.     }
  661.  
  662.     /**
  663.      * build a WHERE clause with conditions on given properties : conditions are
  664.      * equality between a variable and the field.
  665.      * the variable name is the name of the property, made with an optional prefix
  666.      * given in $fieldPrefix parameter.
  667.      * This method is called to generate WHERE clause for primary keys.
  668.      * @param array $fields  list of jDaoPropery objects
  669.      * @param string $fieldPrefix  an optional prefix to prefix variable names
  670.      * @param boolean $forSelect  if true, the table name or table alias will prefix
  671.      *                             the field name in the query
  672.      * @return string the WHERE clause (without the WHERE keyword)
  673.      * @internal
  674.      */
  675.     protected function _buildSimpleConditions (&$fields$fieldPrefix=''$forSelect=true){
  676.         $r ' ';
  677.  
  678.         $first true;
  679.         foreach($fields as $field){
  680.             if (!$first){
  681.                 $r .= ' AND ';
  682.             }else{
  683.                 $first false;
  684.             }
  685.  
  686.             if($forSelect){
  687.                 $condition $this->_encloseName($field->table).'.'.$this->_encloseName($field->fieldName);
  688.             }else{
  689.                 $condition $this->_encloseName($field->fieldName);
  690.             }
  691.  
  692.             $var '$'.$fieldPrefix.$field->name;
  693.             $value $this->_preparePHPExpr($var$field!$field->requiredInConditions'=');
  694.  
  695.             $r .= $condition.'\'.'.$value.'.\'';
  696.         }
  697.  
  698.         return $r;
  699.     }
  700.  
  701.  
  702.     protected function _prepareValues ($fieldList$pattern=''$prefixfield=''){
  703.         $values $fields array();
  704.  
  705.         foreach ((array)$fieldList as $fieldName=>$field{
  706.             if ($pattern != '' && $field->$pattern == ''{
  707.                 continue;
  708.             }
  709.  
  710.             $value $this->_preparePHPExpr('$'.$prefixfield.$fieldName$fieldtrue);
  711.  
  712.             if($pattern != ''){
  713.                 $values[$field->namesprintf($field->$pattern,'\'.'.$value.'.\'');
  714.             }else{
  715.                 $values[$field->name'\'.'.$value.'.\'';
  716.             }
  717.  
  718.             $fields[$field->name$this->_encloseName($field->fieldName);
  719.         }
  720.         return array($fields$values);
  721.     }
  722.  
  723.  
  724.     /**
  725.      * build 'where' clause from conditions declared with condition tag in a user method
  726.      * @param jDaoConditions $cond the condition object which contains conditions data
  727.      * @param array $fields  array of jDaoProperty
  728.      * @param array $params  list of parameters name of the method
  729.      * @param boolean $withPrefix true if the field name should be preceded by the table name/table alias
  730.      * @param array $groupby  list of properties to use in a groupby
  731.      * @return string a WHERE clause (without the WHERE keyword) with eventually an ORDER clause
  732.      * @internal
  733.      */
  734.     protected function _buildConditions ($cond$fields$params=array()$withPrefix=true$groupby=null){
  735.         if($cond)
  736.             $sql $this->_buildSQLCondition ($cond->condition$fields$params$withPrefixtrue);
  737.         else
  738.             $sql '';
  739.  
  740.         if($groupby && count($groupby)) {
  741.             if(trim($sql==''{
  742.                 $sql ' 1=1 ';
  743.             }
  744.             foreach($groupby as $k=>$f{
  745.                 if ($withPrefix)
  746.                     $groupby[$k]$this->_encloseName($fields[$f]->table).'.'.$this->_encloseName($fields[$f]->fieldName);
  747.                 else
  748.                     $groupby[$k]$this->_encloseName($fields[$f]->fieldName);
  749.             }
  750.             $sql .= ' GROUP BY '.implode (', '$groupby);
  751.         }
  752.  
  753.         $order array ();
  754.         foreach ($cond->order as $name => $way){
  755.             $ord='';
  756.             if (isset($fields[$name])){
  757.                 if ($withPrefix)
  758.                     $ord $this->_encloseName($fields[$name]->table).'.'.$this->_encloseName($fields[$name]->fieldName);
  759.                 else
  760.                     $ord $this->_encloseName($fields[$name]->fieldName);
  761.             }elseif($name[0== '$'){
  762.                 $ord '\'.'.$name.'.\'';
  763.             }else{
  764.                 continue;
  765.             }
  766.             if($way[0== '$'){
  767.                 $order[]=$ord.' \'.( strtolower('.$way.') ==\'asc\'?\'asc\':\'desc\').\'';
  768.             }else{
  769.                 $order[]=$ord.' '.$way;
  770.             }
  771.         }
  772.         if(count ($order0){
  773.             if(trim($sql==''{
  774.                 $sql ' 1=1 ';
  775.             }
  776.             $sql.=' ORDER BY '.implode (', '$order);
  777.         }
  778.         return $sql;
  779.     }
  780.  
  781.     /**
  782.      * build SQL WHERE clause
  783.      * Used by _buildConditions. And this method call itself recursively
  784.      * @param jDaoCondition $cond a condition object which contains conditions data
  785.      * @param array $fields  array of jDaoProperty
  786.      * @param array $params  list of parameters name of the method
  787.      * @param boolean $withPrefix true if the field name should be preceded by the table name/table alias
  788.      * @param boolean $principal  should be true for the first call, and false for recursive call
  789.      * @return string a WHERE clause (without the WHERE keyword)
  790.      * @see jDaoGenerator::_buildConditions
  791.      * @internal
  792.      */
  793.     protected function _buildSQLCondition ($condition$fields$params$withPrefix$principal=false){
  794.  
  795.         $r ' ';
  796.  
  797.         //direct conditions for the group
  798.         $first true;
  799.         foreach ($condition->conditions as $cond){
  800.             if (!$first){
  801.                 $r .= ' '.$condition->glueOp.' ';
  802.             }
  803.             $first false;
  804.  
  805.             $prop $fields[$cond['field_id']];
  806.  
  807.             if($withPrefix){
  808.                 $f $this->_encloseName($prop->table).'.'.$this->_encloseName($prop->fieldName);
  809.             }else{
  810.                 $f $this->_encloseName($prop->fieldName);
  811.             }
  812.  
  813.             $r .= $f.' ';
  814.  
  815.             if($cond['operator'== 'IN' || $cond['operator'== 'NOT IN'){
  816.                 if($cond['isExpr']){
  817.                     $phpvalue$this->_preparePHPExpr('$__e'$propfalse);
  818.                     if(strpos($phpvalue,'$this->_conn->quote')===0){
  819.                         $phpvalue str_replace('$this->_conn->quote(',"'\''.str_replace('\\'','\\\\\\'',",$phpvalue).".'\''";
  820.                         $phpvalue str_replace('\\','\\\\'$phpvalue);
  821.                         $phpvalue str_replace('\'','\\\''$phpvalue);
  822.                     }
  823.                     $phpvalue 'implode(\',\', array_map( create_function(\'$__e\',\'return '.$phpvalue.';\'), '.$cond['value'].'))';
  824.                     $value'(\'.'.$phpvalue.'.\')';
  825.                 }else{
  826.                     $value'('.$cond['value'].')';
  827.                 }
  828.                 $r.=$cond['operator'].' '.$value;
  829.             }elseif($cond['operator'== 'IS NULL' || $cond['operator'== 'IS NOT NULL'){
  830.                 $r.=$cond['operator'].' ';
  831.             }else{
  832.                 if ($cond['isExpr']{
  833.                     $value=str_replace("'","\\'",$cond['value']);
  834.                     // we need to know if the expression is like "$foo" (1) or a thing like "concat($foo,'bla')" (2)
  835.                     // because of the nullability of the parameter. If the value of the parameter is null and the operator
  836.                     // is = or <>, then we need to generate a thing like :
  837.                     // - in case 1: ($foo === null ? 'IS NULL' : '='.$this->_conn->quote($foo))
  838.                     // - in case 2: '= concat('.($foo === null ? 'NULL' : $this->_conn->quote($foo)).' ,\'bla\')'
  839.                     if(strpos($value'$'=== 0){
  840.                         $value '\'.'.$this->_preparePHPExpr($value$prop!$prop->requiredInConditions,$cond['operator']).'.\'';
  841.                     }else{
  842.                         foreach($params as $param){
  843.                             $value str_replace('$'.$param'\'.'.$this->_preparePHPExpr('$'.$param$prop!$prop->requiredInConditions).'.\'',$value);
  844.                         }
  845.                         $value $cond['operator'].' '.$value;
  846.                     }
  847.                 else {
  848.                     $value $cond['operator'].' ';
  849.                     if ($cond['operator'== 'LIKE' || $cond['operator'== 'NOT LIKE'{
  850.                         $value .= $this->_preparePHPValue($cond['value']'string'false);
  851.                     else {
  852.                         $value .= $this->_preparePHPValue($cond['value']$prop->datatypefalse);
  853.                     }
  854.                 }
  855.                 $r.=$value;
  856.             }
  857.         }
  858.         //sub conditions
  859.         foreach ($condition->group as $conditionDetail){
  860.             if (!$first){
  861.                 $r .= ' '.$condition->glueOp.' ';
  862.             }
  863.             $r .= $this->_buildSQLCondition ($conditionDetail$fields$params$withPrefix);
  864.             $first=false;
  865.         }
  866.  
  867.         //adds parenthesis around the sql if needed (non empty)
  868.         if (strlen (trim ($r)) && (!$principal ||($principal && $condition->glueOp != 'AND'))){
  869.             $r '('.$r.')';
  870.         }
  871.         return $r;
  872.     }
  873.  
  874.     /**
  875.     * prepare a string ready to be included in a PHP script
  876.     * we assume that if the value is "NULL", all things has been take care of
  877.     *   before the call of this method
  878.     * The method generates something like (including quotes) '.some PHP code.'
  879.     *   (we do break "simple quoted strings")
  880.     */
  881.     protected function _preparePHPValue($value$fieldType$checknull=true){
  882.         if($checknull){
  883.             if($value == 'null' || $value == 'NULL' || $value === null)
  884.                 return 'NULL';
  885.         }
  886.         switch(strtolower($fieldType)){
  887.             case 'int':
  888.             case 'integer':
  889.             case 'autoincrement':
  890.                 return intval($value);
  891.             case 'double':
  892.             case 'float':
  893.                 return jDb::floatToStr($value);
  894.             case 'numeric'//usefull for bigint and stuff
  895.             case 'bigautoincrement':
  896.                 if(is_numeric($value))
  897.                     return $value;
  898.                 else
  899.                     return intval($value);
  900.             case 'boolean':
  901.                 return $this->getBooleanValue($value);
  902.             default:
  903.                 if(strpos($value,"'"!== false){
  904.                     return '\'.$this->_conn->quote(\''.str_replace('\'','\\\'',$value).'\''.($fieldType == 'varbinary' ',true,true':'').').\'';
  905.                 }else{
  906.                     return "\\'".$value."\\'";
  907.                 }
  908.         }
  909.     }
  910.  
  911.     protected function _preparePHPExpr($expr$field$checknull=true$forCondition=''){
  912.         $opnull $opval '';
  913.         if($checknull && $forCondition != ''){
  914.             if($forCondition == '=')
  915.                 $opnull 'IS ';
  916.             elseif($forCondition == '<>')
  917.                 $opnull 'IS NOT ';
  918.             else
  919.                 $checknull=false;
  920.         }
  921.         $type '';
  922.         if ($forCondition != 'LIKE' && $forCondition != 'NOT LIKE')
  923.             $type strtolower($field->datatype);
  924.         
  925.         if ($forCondition != '')
  926.             $forCondition '\' '.$forCondition.' \'.'// spaces for operators like LIKE
  927.  
  928.         switch($type){
  929.             case 'int':
  930.             case 'integer':
  931.                 if($checknull){
  932.                     $expr'('.$expr.' === null ? \''.$opnull.'NULL\' : '.$forCondition.'intval('.$expr.'))';
  933.                 }else{
  934.                     $expr$forCondition.'intval('.$expr.')';
  935.                 }
  936.                 break;
  937.             case 'autoincrement':
  938.                 $expr$forCondition.'intval('.$expr.')';
  939.                 break;
  940.             case 'double':
  941.             case 'float':
  942.                 if($checknull){
  943.                     $expr'('.$expr.' === null ? \''.$opnull.'NULL\' : '.$forCondition.'jDb::floatToStr('.$expr.'))';
  944.                 }else{
  945.                     $expr$forCondition.'jDb::floatToStr('.$expr.')';
  946.                 }
  947.                 break;
  948.             case 'numeric'//usefull for bigint and stuff
  949.                 if($checknull){
  950.                     $expr='('.$expr.' === null ? \''.$opnull.'NULL\' : '.$forCondition.'(is_numeric ('.$expr.') ? '.$expr.' : intval('.$expr.')))';
  951.                 }else{
  952.                     $expr=$forCondition.'(is_numeric ('.$expr.') ? '.$expr.' : intval('.$expr.'))';
  953.                 }
  954.                 break;
  955.             case 'bigautoincrement':
  956.                 $expr=$forCondition.'(is_numeric ('.$expr.') ? '.$expr.' : intval('.$expr.'))';
  957.                 break;
  958.             case 'boolean':
  959.                 if($checknull){
  960.                     $expr'('.$expr.' === null ? \''.$opnull.'NULL\' : '.$forCondition.'$this->_prepareValue('.$expr.', "boolean", true))';
  961.                 }else{
  962.                     $expr$forCondition.'$this->_prepareValue('.$expr.', "boolean", true)';
  963.                 }
  964.                 break;
  965.             default:
  966.                 if($checknull){
  967.                     $expr'('.$expr.' === null ? \''.$opnull.'NULL\' : '.$forCondition.'$this->_conn->quote('.$expr.',false'.($type=='varbinary'?',true':'').'))';
  968.                 }else{
  969.                     $expr$forCondition.'$this->_conn->quote('.$expr.($type=='varbinary'?',true,true':'').')';
  970.                 }
  971.         }
  972.         return $expr;
  973.     }
  974.  
  975.     protected function _encloseName($name){
  976.         return $name;
  977.     }
  978.  
  979.     protected function genUpdateAutoIncrementPK($pkai$pTableRealName{
  980.         return '       $record->'.$pkai->name.'= $this->_conn->lastInsertId();';
  981.     }
  982.  
  983.     protected function getBooleanValue($value){
  984.         return ($value === true || $value === 'on' || strtolower($value=='true'|| intval($value== || $value==='t'?$this->trueValue:$this->falseValue);
  985.     }
  986. }

Documentation generated on Thu, 22 Mar 2012 22:14:47 +0100 by phpDocumentor 1.4.3