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

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