/** * build the update() method for the final class * @return string the source of the method */ protected function buildUpdateMethod($pkFields) { $src = array(); $src[] = 'public function update ($record){'; list($fields, $values) = $this->_prepareValues($this->_getPropertiesBy('PrimaryFieldsExcludePk'), 'updatePattern', 'record->'); if (count($fields)) { if ($this->_dataParser->hasEvent('updatebefore') || $this->_dataParser->hasEvent('update')) { $src[] = ' jEvent::notify("daoUpdateBefore", array(\'dao\'=>$this->_daoSelector, \'record\'=>$record));'; } $src[] = ' $query = \'UPDATE ' . $this->tableRealNameEsc . ' SET '; $sqlSet = ''; foreach ($fields as $k => $fname) { $sqlSet .= ', ' . $fname . '= ' . $values[$k]; } $src[] = substr($sqlSet, 1); $sqlCondition = $this->buildSimpleConditions($pkFields, 'record->', false); if ($sqlCondition != '') { $src[] = ' where ' . $sqlCondition; } $src[] = "';"; $src[] = ' $result = $this->_conn->exec ($query);'; // we generate a SELECT query to update field on the record object, which are autoincrement or calculated $fields = $this->_getPropertiesBy('FieldToUpdateOnUpdate'); if (count($fields)) { $result = array(); foreach ($fields as $id => $prop) { $result[] = $this->buildSelectPattern($prop->selectPattern, '', $prop->fieldName, $prop->name); } $sql = 'SELECT ' . implode(', ', $result) . ' FROM ' . $this->tableRealNameEsc . ' WHERE '; $sql .= $this->buildSimpleConditions($pkFields, 'record->', false); $src[] = ' $query =\'' . $sql . '\';'; $src[] = ' $rs = $this->_conn->query ($query, jDbConnection::FETCH_INTO, $record);'; $src[] = ' $record = $rs->fetch ();'; } if ($this->_dataParser->hasEvent('updateafter') || $this->_dataParser->hasEvent('update')) { $src[] = ' jEvent::notify("daoUpdateAfter", array(\'dao\'=>$this->_daoSelector, \'record\'=>$record));'; } $src[] = ' return $result;'; } else { //the dao is mapped on a table which contains only primary key : update is impossible // so we will generate an error on update $src[] = " throw new jException('jelix~dao.error.update.impossible',array('" . $this->_daoId . "','" . $this->_daoPath . "'));"; } $src[] = ' }'; //ends the update function return implode("\n", $src); }
/** * build all classes */ public final function buildClasses() { $src = array(); $src[] = ' require_once ( JELIX_LIB_PATH .\'dao/jDaoRecordBase.class.php\');'; $src[] = ' require_once ( JELIX_LIB_PATH .\'dao/jDaoFactoryBase.class.php\');'; // prepare some values to generate properties and methods list($sqlFromClause, $sqlWhereClause) = $this->_getFromClause(); $tables = $this->_dataParser->getTables(); $sqlSelectClause = $this->_getSelectClause(); $pkFields = $this->_getPropertiesBy('PkFields'); $pTableRealName = $tables[$this->_dataParser->getPrimaryTable()]['realname']; $pTableRealNameEsc = $this->_encloseName('\'.$this->_conn->prefixTable(\'' . $pTableRealName . '\').\''); $pkai = $this->_getAutoIncrementPKField(); $sqlPkCondition = $this->_buildSimpleConditions($pkFields); if ($sqlPkCondition != '') { $sqlPkCondition = ($sqlWhereClause != '' ? ' AND ' : ' WHERE ') . $sqlPkCondition; } //----------------------- // Build the record class //----------------------- $src[] = "\nclass " . $this->_DaoRecordClassName . ' extends jDaoRecordBase {'; $properties = array(); foreach ($this->_dataParser->getProperties() as $id => $field) { $properties[$id] = get_object_vars($field); if ($field->defaultValue !== null) { $src[] = ' public $' . $id . '=' . var_export($field->defaultValue, true) . ';'; } else { $src[] = ' public $' . $id . ';'; } } $src[] = ' public function getProperties() { return ' . $this->_DaoClassName . '::$_properties; }'; $src[] = ' public function getPrimaryKeyNames() { return ' . $this->_DaoClassName . '::$_pkFields; }'; $src[] = '}'; //-------------------- // Build the dao class //-------------------- $src[] = "\nclass " . $this->_DaoClassName . ' extends jDaoFactoryBase {'; $src[] = ' protected $_tables = ' . var_export($tables, true) . ';'; $src[] = ' protected $_primaryTable = \'' . $this->_dataParser->getPrimaryTable() . '\';'; $src[] = ' protected $_selectClause=\'' . $sqlSelectClause . '\';'; $src[] = ' protected $_fromClause;'; $src[] = ' protected $_whereClause=\'' . $sqlWhereClause . '\';'; $src[] = ' protected $_DaoRecordClassName=\'' . $this->_DaoRecordClassName . '\';'; $src[] = ' protected $_daoSelector = \'' . jDaoCompiler::$daoId . '\';'; if ($this->trueValue != 1) { $src[] = ' protected $trueValue =' . var_export($this->trueValue, true) . ';'; $src[] = ' protected $falseValue =' . var_export($this->falseValue, true) . ';'; } if ($this->_dataParser->hasEvent('deletebefore') || $this->_dataParser->hasEvent('delete')) { $src[] = ' protected $_deleteBeforeEvent = true;'; } if ($this->_dataParser->hasEvent('deleteafter') || $this->_dataParser->hasEvent('delete')) { $src[] = ' protected $_deleteAfterEvent = true;'; } if ($this->_dataParser->hasEvent('deletebybefore') || $this->_dataParser->hasEvent('deleteby')) { $src[] = ' protected $_deleteByBeforeEvent = true;'; } if ($this->_dataParser->hasEvent('deletebyafter') || $this->_dataParser->hasEvent('deleteby')) { $src[] = ' protected $_deleteByAfterEvent = true;'; } $src[] = ' public static $_properties = ' . var_export($properties, true) . ';'; $src[] = ' public static $_pkFields = array(' . $this->_writeFieldNamesWith($start = '\'', $end = '\'', $beetween = ',', $pkFields) . ');'; $src[] = ' '; $src[] = 'public function __construct($conn){'; $src[] = ' parent::__construct($conn);'; $src[] = ' $this->_fromClause = \'' . $sqlFromClause . '\';'; $src[] = '}'; // cannot put this methods directly into jDaoBase because of a php bug on static methods/properties $src[] = ' public function getProperties() { return self::$_properties; }'; $src[] = ' public function getPrimaryKeyNames() { return self::$_pkFields;}'; $src[] = ' '; $src[] = ' protected function _getPkWhereClauseForSelect($pk){'; $src[] = ' extract($pk);'; $src[] = ' return \'' . $sqlPkCondition . '\';'; $src[] = '}'; $src[] = ' '; $src[] = 'protected function _getPkWhereClauseForNonSelect($pk){'; $src[] = ' extract($pk);'; $src[] = ' return \' where ' . $this->_buildSimpleConditions($pkFields, '', false) . '\';'; $src[] = '}'; //----- Insert method $src[] = 'public function insert ($record){'; if ($pkai !== null) { // if there is an autoincrement field as primary key // if a value is given for the autoincrement field, then with do a full insert $src[] = ' if($record->' . $pkai->name . ' > 0 ){'; $src[] = ' $query = \'INSERT INTO ' . $pTableRealNameEsc . ' ('; $fields = $this->_getPropertiesBy('PrimaryTable'); list($fields, $values) = $this->_prepareValues($fields, 'insertPattern', 'record->'); $src[] = implode(',', $fields); $src[] = ') VALUES ('; $src[] = implode(', ', $values); $src[] = ")';"; $src[] = '}else{'; $fields = $this->_getPropertiesBy($this->propertiesListForInsert); } else { $fields = $this->_getPropertiesBy('PrimaryTable'); } // if there isn't a autoincrement as primary key, then we do a full insert. // if there isn't a value for the autoincrement field and if this is a mysql/sqlserver and pgsql, // we do an insert without given primary key. In other case, we do a full insert. $src[] = ' $query = \'INSERT INTO ' . $pTableRealNameEsc . ' ('; list($fields, $values) = $this->_prepareValues($fields, 'insertPattern', 'record->'); $src[] = implode(',', $fields); $src[] = ') VALUES ('; $src[] = implode(', ', $values); $src[] = ")';"; if ($pkai !== null) { $src[] = '}'; } if ($this->_dataParser->hasEvent('insertbefore') || $this->_dataParser->hasEvent('insert')) { $src[] = ' jEvent::notify("daoInsertBefore", array(\'dao\'=>$this->_daoSelector, \'record\'=>$record));'; } $src[] = ' $result = $this->_conn->exec ($query);'; if ($pkai !== null) { $src[] = ' if(!$result)'; $src[] = ' return false;'; $src[] = ' if($record->' . $pkai->name . ' < 1 ) '; $src[] = $this->genUpdateAutoIncrementPK($pkai, $pTableRealName); } // we generate a SELECT query to update field on the record object, which are autoincrement or calculated $fields = $this->_getPropertiesBy('FieldToUpdate'); if (count($fields)) { $result = array(); foreach ($fields as $id => $prop) { $result[] = $this->genSelectPattern($prop->selectPattern, '', $prop->fieldName, $prop->name); } $sql = 'SELECT ' . implode(', ', $result) . ' FROM ' . $pTableRealNameEsc . ' WHERE '; $sql .= $this->_buildSimpleConditions($pkFields, 'record->', false); $src[] = ' $query =\'' . $sql . '\';'; $src[] = ' $rs = $this->_conn->query ($query);'; $src[] = ' $newrecord = $rs->fetch ();'; foreach ($fields as $id => $prop) { $src[] = ' $record->' . $prop->name . ' = $newrecord->' . $prop->name . ';'; } } if ($this->_dataParser->hasEvent('insertafter') || $this->_dataParser->hasEvent('insert')) { $src[] = ' jEvent::notify("daoInsertAfter", array(\'dao\'=>$this->_daoSelector, \'record\'=>$record));'; } $src[] = ' return $result;'; $src[] = '}'; //----- update method $src[] = 'public function update ($record){'; list($fields, $values) = $this->_prepareValues($this->_getPropertiesBy('PrimaryFieldsExcludePk'), 'updatePattern', 'record->'); if (count($fields)) { $src[] = ' $query = \'UPDATE ' . $pTableRealNameEsc . ' SET '; $sqlSet = ''; foreach ($fields as $k => $fname) { $sqlSet .= ', ' . $fname . '= ' . $values[$k]; } $src[] = substr($sqlSet, 1); $sqlCondition = $this->_buildSimpleConditions($pkFields, 'record->', false); if ($sqlCondition != '') { $src[] = ' where ' . $sqlCondition; } $src[] = "';"; if ($this->_dataParser->hasEvent('updatebefore') || $this->_dataParser->hasEvent('update')) { $src[] = ' jEvent::notify("daoUpdateBefore", array(\'dao\'=>$this->_daoSelector, \'record\'=>$record));'; } $src[] = ' $result = $this->_conn->exec ($query);'; // we generate a SELECT query to update field on the record object, which are autoincrement or calculated $fields = $this->_getPropertiesBy('FieldToUpdateOnUpdate'); if (count($fields)) { $result = array(); foreach ($fields as $id => $prop) { $result[] = $this->genSelectPattern($prop->selectPattern, '', $prop->fieldName, $prop->name); } $sql = 'SELECT ' . implode(', ', $result) . ' FROM ' . $pTableRealNameEsc . ' WHERE '; $sql .= $this->_buildSimpleConditions($pkFields, 'record->', false); $src[] = ' $query =\'' . $sql . '\';'; $src[] = ' $rs = $this->_conn->query ($query, jDbConnection::FETCH_INTO, $record);'; $src[] = ' $record = $rs->fetch ();'; } if ($this->_dataParser->hasEvent('updateafter') || $this->_dataParser->hasEvent('update')) { $src[] = ' jEvent::notify("daoUpdateAfter", array(\'dao\'=>$this->_daoSelector, \'record\'=>$record));'; } $src[] = ' return $result;'; $src[] = ' }'; //ends the update function } else { //the dao is mapped on a table which contains only primary key : update is impossible // so we will generate an error on update $src[] = " throw new jException('jelix~dao.error.update.impossible',array('" . jDaoCompiler::$daoId . "','" . jDaoCompiler::$daoPath . "'));"; $src[] = " }"; } //----- other user methods $allField = $this->_getPropertiesBy('All'); $primaryFields = $this->_getPropertiesBy('PrimaryTable'); $ct = null; foreach ($this->_dataParser->getMethods() as $name => $method) { $defval = $method->getParametersDefaultValues(); if (count($defval)) { $mparam = ''; foreach ($method->getParameters() as $param) { $mparam .= ', $' . $param; if (isset($defval[$param])) { $mparam .= '=\'' . str_replace("'", "\\'", $defval[$param]) . '\''; } } $mparam = substr($mparam, 1); } else { $mparam = implode(', $', $method->getParameters()); if ($mparam != '') { $mparam = '$' . $mparam; } } $src[] = ' function ' . $method->name . ' (' . $mparam . '){'; $limit = ''; switch ($method->type) { case 'delete': $src[] = ' $__query = \'DELETE FROM ' . $pTableRealNameEsc . ' \';'; $glueCondition = ' WHERE '; break; case 'update': $src[] = ' $__query = \'UPDATE ' . $pTableRealNameEsc . ' SET '; $updatefields = $this->_getPropertiesBy('PrimaryFieldsExcludePk'); $sqlSet = ''; foreach ($method->getValues() as $propname => $value) { if ($value[1]) { foreach ($method->getParameters() as $param) { $value[0] = str_replace('$' . $param, '\'.' . $this->_preparePHPExpr('$' . $param, $updatefields[$propname], true) . '.\'', $value[0]); } $sqlSet .= ', ' . $this->_encloseName($updatefields[$propname]->fieldName) . '= ' . $value[0]; } else { $sqlSet .= ', ' . $this->_encloseName($updatefields[$propname]->fieldName) . '= ' . $this->_preparePHPValue($value[0], $updatefields[$propname]->datatype, false); } } $src[] = substr($sqlSet, 1) . '\';'; $glueCondition = ' WHERE '; break; case 'php': $src[] = $method->getBody(); $src[] = '}'; break; case 'count': if ($method->distinct != '') { $prop = $this->_dataParser->getProperties(); $prop = $prop[$method->distinct]; $count = ' DISTINCT ' . $this->_encloseName($tables[$prop->table]['name']) . '.' . $this->_encloseName($prop->fieldName); } else { $count = '*'; } $src[] = ' $__query = \'SELECT COUNT(' . $count . ') as c \'.$this->_fromClause.$this->_whereClause;'; $glueCondition = $sqlWhereClause != '' ? ' AND ' : ' WHERE '; break; case 'selectfirst': case 'select': default: if ($method->distinct != '') { $select = '\'' . $this->_getSelectClause($method->distinct) . '\''; } else { $select = ' $this->_selectClause'; } $src[] = ' $__query = ' . $select . '.$this->_fromClause.$this->_whereClause;'; $glueCondition = $sqlWhereClause != '' ? ' AND ' : ' WHERE '; if ($method->type == 'select' && ($lim = $method->getLimit()) !== null) { $limit = ', ' . $lim['offset'] . ', ' . $lim['count']; } } if ($method->type == 'php') { continue; } $cond = $method->getConditions(); $sqlCond = ''; if ($cond !== null) { if ($method->type == 'delete' || $method->type == 'update') { $sqlCond = $this->_buildConditions($cond, $primaryFields, $method->getParameters(), false); } else { if ($method->type == 'count') { $sqlCond = $this->_buildConditions($cond, $allField, $method->getParameters(), true); } else { $sqlCond = $this->_buildConditions($cond, $allField, $method->getParameters(), true, $method->getGroupBy()); } } } else { if ($method->type == 'select' || $method->type == 'selectfirst') { $sqlCond = $this->_buildConditions(null, $allField, $method->getParameters(), true, $method->getGroupBy()); } } if (trim($sqlCond) != '') { $src[] = '$__query .=\'' . $glueCondition . $sqlCond . "';"; } switch ($method->type) { case 'delete': case 'update': if ($method->eventBeforeEnabled || $method->eventAfterEnabled) { $src[] = ' $args = func_get_args();'; $methname = $method->type == 'update' ? 'Update' : 'Delete'; if ($method->eventBeforeEnabled) { $src[] = ' jEvent::notify("daoSpecific' . $methname . 'Before", array(\'dao\'=>$this->_daoSelector,\'method\'=>\'' . $method->name . '\', \'params\'=>$args));'; } if ($method->eventAfterEnabled) { $src[] = ' $result = $this->_conn->exec ($__query);'; $src[] = ' jEvent::notify("daoSpecific' . $methname . 'After", array(\'dao\'=>$this->_daoSelector,\'method\'=>\'' . $method->name . '\', \'params\'=>$args));'; $src[] = ' return $result;'; } else { $src[] = ' return $this->_conn->exec ($__query);'; } } else { $src[] = ' return $this->_conn->exec ($__query);'; } break; case 'count': $src[] = ' $__rs = $this->_conn->query($__query);'; $src[] = ' $__res = $__rs->fetch();'; $src[] = ' return intval($__res->c);'; break; case 'selectfirst': $src[] = ' $__rs = $this->_conn->limitQuery($__query,0,1);'; $src[] = ' $__rs->setFetchMode(8,\'' . $this->_DaoRecordClassName . '\');'; $src[] = ' return $__rs->fetch();'; break; case 'select': default: if ($limit) { $src[] = ' $__rs = $this->_conn->limitQuery($__query' . $limit . ');'; } else { $src[] = ' $__rs = $this->_conn->query($__query);'; } $src[] = ' $__rs->setFetchMode(8,\'' . $this->_DaoRecordClassName . '\');'; $src[] = ' return $__rs;'; } $src[] = '}'; } $src[] = '}'; //end of class return implode("\n", $src); }