protected function makeResrictionForAsscotion(array &$arrDataRow, $sFromTableName = null, array $arrFromKeys, $sToTableName = null, array $arrToKeys) { $aRestriction = new Restriction(); foreach ($arrFromKeys as $nIdx => $sFromKey) { if ($sFromTableName) { $sFromKey = $sFromTableName . '.' . $sFromKey; } $aRestriction->expression(array(SQL::createRawColumn($sToTableName, $arrToKeys[$nIdx]), '=', SQL::transValue($arrDataRow[$sFromKey])), true, true); } return $aRestriction; }
public function setData($sColumnName, $value = null, $bValueExpr = false) { list($sTableName, $sColumnName) = SQL::splitColumn($sColumnName); $arrRawSet =& $this->rawClause(SQL::CLAUSE_SET); if (!isset($arrRawSet['subtree'][$sColumnName]) and !empty($arrRawSet['subtree'])) { $arrRawSet['subtree'][] = ','; } $arrRawSet['subtree'][$sColumnName] = array('expr_type' => 'assignment', 'pretree' => array(SQL::createRawColumn($sTableName, $sColumnName), '=')); if ($bValueExpr) { $arrRawSet['subtree'][$sColumnName]['subtree'] =& SQL::parseSql($value, 'values', true); } else { $arrRawSet['subtree'][$sColumnName]['subtree'] = array(SQL::transValue($value)); } }
public function execute(DB $aDB, Model $aModel) { $aPrototype = $aModel->prototype(); $aDelete = new Delete($aPrototype->tableName()); // 设置limit $aDelete->criteria()->setLimit(1); // delete 当前model foreach ($aPrototype->keys() as $sClmName) { if ($aModel->changed($sClmName)) { //主键发生修改 throw new ORMException('org\\jecat\\framework\\mvc\\model\\db\\orm\\Updater : Key 有修改,无法进行Delete操作'); } else { //用主键作为查询条件 $aDelete->criteria()->where()->expression(array(SQL::createRawColumn(null, $sClmName), '=', SQL::transValue($aModel->data($sClmName))), true, true); } } $aDB->execute($aDelete); // 仅delete hasAndBelongsTo的桥表 foreach ($aPrototype->associations() as $aAssociation) { $aAssociatedModel = $aModel->child($aAssociation->name()); if (!$aAssociatedModel) { continue; } switch ($aAssociation->type()) { case Association::hasOne: $this->setAssociatedModelData($aModel, $aAssociatedModel, $aAssociation->fromKeys(), $aAssociation->toKeys()); if (!$aAssociatedModel->delete()) { return false; } break; case Association::belongsTo: // nothing todo ... break; case Association::hasMany: $this->setAssociatedModelData($aModel, $aAssociatedModel, $aAssociation->fromKeys(), $aAssociation->toKeys()); if (!$aAssociatedModel->delete()) { return false; } break; case Association::hasAndBelongsToMany: // delete bridge table foreach ($aAssociatedModel->childIterator() as $aOneChildModel) { $this->deleteBridge($aDB, $aAssociation, $aModel, $aOneChildModel); } break; } } return true; }
/** * * @return string */ public function toString(SqlCompiler $aSqlCompiler = null) { ksort($this->arrRawSql['subtree'][SQL::CLAUSE_INSERT]['subtree']); return parent::toString($aSqlCompiler); }
/** * 以sql表达式的形式,向select对像添加一个或多个返回字段。 */ public function addColumnsExpr($sExpression) { $arrSubTree =& SQL::parseSql($sExpression, 'select', true); if (!empty($arrSubTree)) { $arrRawColumns =& $this->rawClause(self::CLAUSE_SELECT); if ($arrRawColumns['subtree']) { $arrRawColumns['subtree'][] = ','; } $arrRawColumns['subtree'] = array_merge($arrRawColumns['subtree'], $arrSubTree); } return $this; }
/** * @return Select */ public static function make($sSql, $factors = null) { $factors = func_get_args(); $sSql = array_shift($factors); if (!($arrRawSqls = self::parseSql($sSql)) or empty($arrRawSqls[0])) { return; } if (isset($arrRawSqls[0]['command'])) { switch ($arrRawSqls[0]['command']) { case 'SELECT': $aSql = new Select(); case 'INSERT': $aSql = new Insert(); case 'UPDATE': $aSql = new Update(); case 'DELETE': $aSql = new Delete(); break; default: $aSql = new SQL(); break; } } else { $aSql = new SQL(); } $aSql->setRawSql($arrRawSqls[0]); if ($factors) { $aSql->addFactors($factors); } return $aSql; }
/** * @wiki /MVC模式/数据库模型/数据表关联 * ==Bean配置数组== * type string 指定关系类型 * fromkeys array 起始表列名 * tokeys array 目标表列名 * frombridgekeys array 起始桥接表列名 * tobridgekeys array 起始桥接表列名 * bridge string 桥接表名 * fromPrototype string 指定起源原型配置 * on string */ public function buildBean(array &$arrConfig, $sNamespace = '*', \org\jecat\framework\bean\BeanFactory $aBeanFactory = null) { if (!$this->aDB) { $this->aDB = DB::singleton(); } $arrConfigForToPrototype = $arrConfig; $arrConfigForToPrototype['class'] = 'prototype'; $this->aToPrototype = BeanFactory::singleton()->createBean($arrConfigForToPrototype, $sNamespace); $this->aToPrototype->setassociatedBy($this); if (!empty($arrConfig['type'])) { $this->nType = $arrConfig['type']; } if (!empty($arrConfig['fromkeys'])) { $this->setFromKeys($arrConfig['fromkeys']); } if (!empty($arrConfig['tokeys'])) { $this->setToKeys($arrConfig['tokeys']); } if (!empty($arrConfig['tobridgekeys'])) { $this->setToBridgeKeys($arrConfig['tobridgekeys']); } if (!empty($arrConfig['frombridgekeys'])) { $this->setFromBridgeKeys($arrConfig['frombridgekeys']); } if (!empty($arrConfig['bridge'])) { $this->sBridgeTable = $arrConfig['bridge']; } if (!empty($arrConfig['fromPrototype'])) { $this->aFromPrototype = $arrConfig['fromPrototype']; } if (!empty($arrConfig['on'])) { if (is_array($arrConfig['on'])) { $arrOnFactors = $arrConfig['on']; $this->arrOnRawSql['expr_type'] = 'clause_on'; $this->arrOnRawSql['subtree'] =& SQL::parseSql(array_shift($arrOnFactors), 'on', true); $aOnClause = new SQL($this->arrOnRawSql); $aOnClause->addFactors($arrOnFactors); } else { $this->arrOnRawSql['expr_type'] = 'clause_on'; $this->arrOnRawSql['subtree'] =& SQL::parseSql($arrConfig['on'], 'on', true); } } if (!empty($arrConfig['join'])) { $this->sJoinType = strtoupper($arrConfig['join']); } $this->done(); $this->arrBeanConfig = $arrConfig; }
private static function &makeResrictionForForeignKey($sFromTableName = null, $sToTableName = null, array &$arrFromKeys, array &$arrToKeys, array &$arrConditions = null) { $arrTokens = array('ON', '('); foreach ($arrFromKeys as $nIdx => $sFromKey) { if ($nIdx) { $arrTokens[] = 'AND'; } $arrTokens[] = SQL::createRawColumn($sFromTableName, $sFromKey); $arrTokens[] = '='; $arrTokens[] = SQL::createRawColumn($sToTableName, $arrToKeys[$nIdx]); } if ($arrConditions) { $arrTokens[] = 'AND'; $arrTokens[] = $arrConditions; } $arrTokens[] = ')'; return $arrTokens; }
/** * @wiki /MVC模式/数据库模型/模型的基本操作(新建、保存、删除、加载) * ==模型的创建== * 模型的创建有两中方式,基于bean的创建以及基于原型(ProtoType)的直接创建,两中方式的创建原理其实都是基于原型的创建. * * * =Bean配置数组= * {| * !属性 * !类型 * !默认值 * !可选 * !说明 * |-- -- * |model-class * |string * |无 * |可选 * |用哪个类来实现模型对象 * |-- -- * |table * |string * |无 * |可选 * |对应的数据库表 * |-- -- * |name * |string * |无 * |可选 * |在原型关系中的名字,用来区分不同的原型 * |-- -- * |columns * |array * |无 * |可选 * |需要表中哪些列的数据 * |-- -- * |keys * |array * |无 * |可选 * |指定表中哪些列为主键,若指定了主键则使用这里的主键而忽略数据库主键,如果未指定则使用数据库指定的主键 * |-- -- * |alias * |string * |无 * |可选 * |别名 * |-- -- * |limit * |int * |无 * |可选 * |设置读取条目数目的上限,下限为0 * |-- -- * |limitLen * |int * |无 * |可选 * |设置读取条目数目的上限 * |-- -- * |limitFrom * |int * |无 * |可选 * |设置读取条目数目的下限 * |-- -- * |order * |array * |无 * |可选 * |指定依据某一列来排序,同时设置正序排列 * |-- -- * |orderAsc * |string * |无 * |可选 * |指定依据某一列正序排序 * |-- -- * |orderDesc * |string * |无 * |可选 * |指定依据某一列反序排序 * |-- -- * |orderRand * |bool * |无 * |可选 * |随机排列结果 * |-- -- * |where * |array * |无 * |可选 * |where条件(where的格式很有趣,是对Lisp风格的尝试) * |-- -- * |hasOne * |array * |无 * |可选 * |配置hasone关系 * |-- -- * |belongsTo * |array * |无 * |可选 * |配置belongsTo关系 * |-- -- * |hasMany * |array * |无 * |可选 * |配置hasMany关系 * |-- -- * |hasAndBelongsToMany * |array * |无 * |可选 * |配置hasAndBelongsToMany关系 * |} * [example title="/MVC模式/数据库模型/模型的基本操作(新建、保存、删除、加载)/新建(Bean)"] */ public function buildBean(array &$arrConfig, $sNamespace = '*', \org\jecat\framework\bean\BeanFactory $aBeanFactory = null) { if (!empty($arrConfig['model-class'])) { $this->sModelClass = $arrConfig['model-class']; } // table if (!empty($arrConfig['table'])) { $this->setTableName($arrConfig['table']); } else { if (!empty($arrConfig['name'])) { $this->setTableName($arrConfig['name']); } } if (!empty($arrConfig['forceIndex'])) { $this->sForceIndex = $arrConfig['forceIndex']; } // name if (!empty($arrConfig['name'])) { $this->setName($arrConfig['name']); } else { if (!empty($arrConfig['table'])) { $this->setName($arrConfig['table']); } } // columns if (key_exists('columns', $arrConfig)) { call_user_func(array($this, 'addColumns'), $arrConfig['columns']); } // keys if (!empty($arrConfig['keys'])) { $this->setKeys($arrConfig['keys']); } // alias if (!empty($arrConfig['alias'])) { $this->addColumnAlias($arrConfig['alias']); } // limit ---------------- if (!empty($arrConfig['limit'])) { $this->nLimitLen = $arrConfig['limit']; } // limitLen if (!empty($arrConfig['limitLen'])) { $this->nLimitLen = $arrConfig['limitLen']; } // limitFrom if (!empty($arrConfig['limitFrom'])) { $this->limitFrom = $arrConfig['limitFrom']; } if ($this->nLimitLen === -1) { $this->criteria()->clearLimit(); } else { $this->criteria()->setLimit($this->nLimitLen, $this->limitFrom); } // order ---------------- if (!empty($arrConfig['order'])) { foreach ((array) $arrConfig['order'] as $sColumn) { list($sTable, $sColumn) = SQL::splitColumn($sColumn); $this->criteria()->addOrderBy($sColumn, true, $sTable); } } // orderDesc if (!empty($arrConfig['orderDesc'])) { foreach ((array) $arrConfig['orderDesc'] as $sColumn) { list($sTable, $sColumn) = SQL::splitColumn($sColumn); $this->criteria()->addOrderBy($sColumn, true, $sTable); } } // orderAsc if (!empty($arrConfig['orderAsc'])) { foreach ((array) $arrConfig['orderAsc'] as $sColumn) { list($sTable, $sColumn) = SQL::splitColumn($sColumn); $this->criteria()->addOrderBy($sColumn, false, $sTable); } } // orderRand if (!empty($arrConfig['orderRand']) && ($arrConfig['orderRand'] = true)) { $this->criteria()->orders()->add(null, Order::rand); } // groupby if (!empty($arrConfig['groupby'])) { foreach ((array) $arrConfig['groupby'] as $sColumn) { $this->criteria()->addGroupBy($sColumn); } } // where if (!empty($arrConfig['where'])) { $arrRawWhere =& $this->criteria()->rawClause(SQL::CLAUSE_WHERE); if (is_array($arrConfig['where'])) { $arrOnFactors = $arrConfig['where']; $arrRawWhere['subtree'] =& SQL::parseSql(array_shift($arrOnFactors), 'where', true); if ($arrOnFactors) { $this->criteria()->where()->addFactors($arrOnFactors); } } else { $arrRawWhere['subtree'] =& SQL::parseSql($arrConfig['where'], 'where', true); } // self::buildBeanRestriction($arrConfig['where'],$this->criteria()->where()->createRestriction()) ; } // associations $aBeanFactory = BeanFactory::singleton(); foreach ($arrConfig as $sConfigKey => &$item) { if (strpos($sConfigKey, 'hasOne:') === 0) { $item['type'] = Association::hasOne; $item['name'] = substr($sConfigKey, 7); } else { if (strpos($sConfigKey, 'belongsTo:') === 0) { $item['type'] = Association::belongsTo; $item['name'] = substr($sConfigKey, 10); } else { if (strpos($sConfigKey, 'hasMany:') === 0) { $item['type'] = Association::hasMany; $item['name'] = substr($sConfigKey, 8); } else { if (strpos($sConfigKey, 'hasAndBelongsToMany:') === 0) { $item['type'] = Association::hasAndBelongsToMany; $item['name'] = substr($sConfigKey, 20); } else { continue; } } } } if (empty($item['class'])) { $item['class'] = 'association'; } $item['fromPrototype'] = $this; $aAssociation = $aBeanFactory->createBean($item, $sNamespace, $aBeanFactory); unset($item['fromPrototype']); $aAssociation->setDB($this->db()); $this->arrAssociations[] = $aAssociation; } $this->done(); $this->arrBeanConfig = $arrConfig; }
public function execute(DB $aDB, Model $aModel) { $aPrototype = $aModel->prototype(); $aUpdate = $aPrototype->sharedStatementUpdate(); // 从 belongs to model 中设置外键值 foreach ($aPrototype->associations() as $aAssociation) { if ($aAssociation->isType(Association::belongsTo)) { if (!($aAssociatedModel = $aModel->child($aAssociation->name()))) { continue; } if (!$aAssociatedModel->save()) { return false; } $this->setAssociatedModelData($aAssociatedModel, $aModel, $aAssociation->toKeys(), $aAssociation->fromKeys()); } } // 产生一个criteria并设置给$aUpdate //$aCriteria = StatementFactory::singleton()->createCriteria() ; //$aUpdate->setCriteria($aCriteria); // 处理主键 $aUpdate->where()->clear(); foreach ($aPrototype->keys() as $sKey) { //主键发生修改 if ($aModel->changed($sKey)) { throw new ORMException('org\\jecat\\framework\\mvc\\model\\db\\orm\\Updater : Key 有修改,无法进行Update操作'); } else { $aUpdate->where()->expression(array(SQL::createRawColumn(null, $sKey), '=', SQL::transValue($aModel->data($sKey))), true, true); } } $aUpdate->clearData(); $bFlagChanged = false; //当前表是否有修改 foreach ($aPrototype->columns() as $sClmName) { //只update发生修改的项 if ($aModel->changed($sClmName)) { $aUpdate->setData($sClmName, $aModel->data($sClmName), false); $bFlagChanged = true; } } //只有当有修改的时候才发生更新 if ($bFlagChanged) { $aDB->execute($aUpdate); } // update关联model foreach ($aPrototype->associations() as $aAssociation) { $aAssociatedModel = $aModel->child($aAssociation->name()); if (!$aAssociatedModel) { continue; } switch ($aAssociation->type()) { case Association::hasOne: $this->setAssociatedModelData($aModel, $aAssociatedModel, $aAssociation->fromKeys(), $aAssociation->toKeys()); if (!$aAssociatedModel->save()) { return false; } break; case Association::belongsTo: // nothing todo ... break; case Association::hasMany: $this->setAssociatedModelData($aModel, $aAssociatedModel, $aAssociation->fromKeys(), $aAssociation->toKeys()); if (!$aAssociatedModel->save()) { return false; } break; case Association::hasAndBelongsToMany: if (!$aAssociatedModel->save()) { return false; } // update bridge table foreach ($aAssociatedModel->childIterator() as $aOneChildModel) { $this->buildBridge($aDB, $aAssociation, $aModel, $aOneChildModel); } break; } } return true; }
private function makeSql($inputSql, $factors = null, SqlCompiler $aSqlCompiler = null) { if (is_string($inputSql)) { $aSql = SQL::make($inputSql, $factors); } else { if ($inputSql instanceof SQL) { $aSql = $inputSql; if ($factors) { $aSql->addFactors($factors); } } else { throw new ExecuteException($this, null, 0, "DB::query() 输入的参数 \$sql 类型无效。"); } } if ($aSql) { return $aSql->toString($aSqlCompiler); } else { return $inputSql; } }
public static function buildRestriction(Prototype $aPrototype, $values = null, $keys = null) { if ($values === null) { return null; } $keys = $keys ? (array) $keys : $aPrototype->keys(); if ($values instanceof Restriction) { return $values; } else { $aRestriction = new Restriction(); $sSqlTableAlias = $aPrototype->sqlTableAlias(); $values = array_values((array) $values); foreach ($keys as $nIdx => $sKey) { list($sTable, $sColumn) = SQL::splitColumn($sKey); $aRestriction->expression(array(SQL::createRawColumn($sTable, $sColumn), '=', SQL::transValue($values[$nIdx])), true, true); } return $aRestriction; } }