Пример #1
0
 public function afterDelete(Model &$model)
 {
     $class = get_class($model);
     $relations = $class::getRelations();
     foreach ($relations as $name => $relation) {
         switch ($relation['type']) {
             case Model::MANY_TO_MANY:
                 $linkTable = $class::getRelationLinkName($relation);
                 $query = new QueryBuilder();
                 $query->delete()->table($linkTable)->where($class::getManyToManyThisLinkColumnName() . '=:id');
                 $query->params([':id' => $model->getPk()]);
                 $class::getDbConnection()->execute($query);
         }
     }
     return true;
 }
Пример #2
0
 /**
  * @param string|\T4\Dbal\QueryBuilder $query
  * @param array $params
  * @return \T4\Dbal\Statement
  */
 public function query($query, array $params = [])
 {
     if ($query instanceof QueryBuilder) {
         $params = array_merge($params, $query->getParams());
         $query = $query->getQuery($this->getDriver());
     }
     $statement = $this->pdo->prepare($query);
     $statement->execute($params);
     return $statement;
 }
Пример #3
0
 public function actionSetupBlock($sectionId, $blockPath)
 {
     $query = new QueryBuilder();
     $query->select('MAX(' . Block::getDbDriver()->quoteName('order') . ')')->from(Block::getTableName())->where('section=:section')->params([':section' => $sectionId]);
     $maxOrder = (int) $this->app->db->default->query($query)->fetchScalar();
     $block = new Block();
     $block->section = $sectionId;
     $block->path = $blockPath;
     $block->template = '';
     $params = [];
     foreach ($this->app->config->blocks->{$blockPath}->options as $optionName => $options) {
         $params[$optionName] = $options->default;
     }
     $block->options = json_encode($params);
     $block->order = $maxOrder + 10;
     if (false !== $block->save()) {
         $this->data->id = $block->getPK();
         $this->data->result = true;
     } else {
         $this->data->result = false;
     }
 }
Пример #4
0
 /**
  * Создает пустое место в дереве заданной ширины
  * Место создается ВНУТРИ элемента с заданным rgt как ПОСЛЕДНИЙ его потомок
  * @param \T4\Dbal\Connection $connection
  * @param string $table
  * @param int $rgt
  * @param int $width
  */
 protected function expandTreeBeforeRgt(Connection $connection, $table, $rgt, $width)
 {
     $query = new QueryBuilder();
     $query->update()->table($table)->values(['__lft' => 'CASE WHEN __lft>=:rgt THEN __lft + (:width + 1) ELSE __lft END', '__rgt' => 'CASE WHEN __rgt>=:rgt THEN __rgt + (:width + 1) ELSE __rgt END'])->where('__lft>=:rgt OR __rgt>=:rgt')->order('__lft DESC');
     $query->params([':rgt' => $rgt, ':width' => $width]);
     $connection->execute($query);
 }
Пример #5
0
 public function countAllByColumn($class, $column, $value, $options = [])
 {
     $query = new QueryBuilder();
     $query->select('COUNT(*)')->from($class::getTableName())->where('`' . $column . '`=:value')->params([':value' => $value]);
     return $class::getDbConnection()->query($query->getQuery($this), $query->getParams())->fetchScalar();
 }
Пример #6
0
 protected function delete(Migration $migration)
 {
     $query = new QueryBuilder();
     if ($this->app->db->default->getDriverName() == 'mysql') {
         $column = '`time`';
     } else {
         $column = '"time"';
     }
     $query->delete(self::TABLE_NAME)->where($column . '=:time')->params([':time' => $migration->getTimestamp()]);
     $this->app->db->default->execute($query);
 }
Пример #7
0
 /**
  * "Ленивое" получение данных связи для моделей
  * @param string $key
  * @param array $options
  * @return mixed
  * @throws Exception
  */
 public function getRelationLazy($key, $options = [])
 {
     $class = get_class($this);
     $relations = $class::getRelations();
     if (empty($relations[$key])) {
         throw new Exception('No such column or relation: ' . $key . ' in model of ' . $class . ' class');
     }
     $relation = $relations[$key];
     switch ($relation['type']) {
         case $class::BELONGS_TO:
             $relationClass = $relation['model'];
             $link = $class::getRelationLinkName($relation);
             $subModel = $relationClass::findByPK($this->{$link});
             if (empty($subModel)) {
                 return null;
             } else {
                 return $relationClass::findByPK($this->{$link});
             }
             break;
         case $class::HAS_ONE:
             $relationClass = $relation['model'];
             $link = $class::getRelationLinkName($relation);
             return $relationClass::findByColumn($link, $this->getPk(), $options);
             break;
         case $class::HAS_MANY:
             $relationClass = $relation['model'];
             $link = $class::getRelationLinkName($relation);
             return $relationClass::findAllByColumn($link, $this->getPk(), $options);
             break;
         case $class::MANY_TO_MANY:
             $relationClass = $relation['model'];
             $linkTable = $class::getRelationLinkName($relation);
             $pivots = $relationClass::getPivots($class, $key);
             if (!empty($pivots)) {
                 $pivotColumnsSql = ', ' . implode(', ', array_map(function ($x) {
                     return 'j1.' . $x;
                 }, array_keys($pivots)));
             } else {
                 $pivotColumnsSql = '';
             }
             $query = new QueryBuilder();
             $query->select('t1.*' . $pivotColumnsSql)->from($relationClass::getTableName())->join($linkTable, 't1.' . $relationClass::PK . '=j1.' . static::getManyToManyThatLinkColumnName($relation), 'right')->where('(j1.' . static::getManyToManyThisLinkColumnName() . '=:id)' . (isset($options['where']) ? ' AND (' . $options['where'] . ')' : ''));
             if (isset($options['order'])) {
                 $query->order($options['order']);
             }
             $query->params([':id' => $this->getPk()]);
             $result = $relationClass::getDbConnection()->query($query)->fetchAll(\PDO::FETCH_CLASS, $relationClass);
             if (!empty($result)) {
                 $ret = new Collection($result);
                 $ret->setNew(false);
                 return $ret;
             } else {
                 return new Collection();
             }
     }
 }
Пример #8
0
 /**
  * TODO: много лишних isset, которые всегда true по определению
  * Сохранение полей модели без учета связей, требующих ID модели
  * @param Model $model
  * @return Model
  */
 protected function saveColumns(Model $model)
 {
     $class = get_class($model);
     $columns = $class::getColumns();
     $relations = $class::getRelations();
     $cols = [];
     $sets = [];
     $data = [];
     foreach ($columns as $column => $def) {
         if (isset($model->{$column}) && !is_null($model->{$column})) {
             $cols[] = $column;
             $sets[$column] = ':' . $column;
             $data[':' . $column] = $model->{$column};
         } elseif (isset($def['default'])) {
             $sets[$column] = ':' . $column;
             $data[':' . $column] = $def['default'];
         }
     }
     foreach ($relations as $rel => $def) {
         switch ($def['type']) {
             case $class::BELONGS_TO:
                 $column = $class::getRelationLinkName($def);
                 if (!in_array($column, $cols)) {
                     if (isset($model->{$column}) && !is_null($model->{$column})) {
                         $sets[$column] = ':' . $column;
                         $data[':' . $column] = $model->{$column};
                     } elseif (isset($model->{$rel}) && $model->{$rel} instanceof Model) {
                         $sets[$column] = ':' . $column;
                         $data[':' . $column] = $model->{$rel}->getPk();
                     }
                 }
                 break;
         }
     }
     $connection = $class::getDbConnection();
     if ($model->isNew()) {
         $sql = new QueryBuilder();
         $sql->insert($class::getTableName())->values($sets);
         $connection->execute($sql, $data);
         $model->{$class::PK} = $connection->lastInsertId();
     } else {
         $sql = new QueryBuilder();
         $sql->update($class::getTableName())->values($sets)->where($class::PK . '=' . $model->getPk());
         $connection->execute($sql, $data);
     }
     return $model;
 }
Пример #9
0
 public function __call($method, $argv)
 {
     /** @var \T4\Orm\Model $model */
     $model = $argv[0];
     array_shift($argv);
     /* @var \T4\Orm\Model $class */
     $class = get_class($model);
     $tableName = $class::getTableName();
     /** @var \T4\Dbal\Connection $connection */
     $connection = $class::getDbConnection();
     switch ($method) {
         case 'refreshTreeColumns':
             $sql = new QueryBuilder();
             $sql->select(['__lft', '__rgt', '__lvl', '__prt'])->from($tableName)->where('t1.' . $class::PK . '=:id');
             $columns = $connection->query($sql, [':id' => $model->getPk()])->fetch();
             $model->merge($columns);
             return $model;
         case 'getTreeWidth':
             if ($model->isNew()) {
                 return 1;
             } else {
                 return $model->__rgt - $model->__lft;
             }
         case 'findAllParents':
             $query = new QueryBuilder();
             $query->select('*')->from($class::getTableName())->where('__lft<:lft AND __rgt>:rgt')->order('__lft')->params([':lft' => $model->__lft, ':rgt' => $model->__rgt]);
             return $class::findAllByQuery($query);
         case 'findAllChildren':
             $query = new QueryBuilder();
             $query->select('*')->from($class::getTableName())->where('__lft>:lft AND __rgt<:rgt')->order('__lft')->params([':lft' => $model->__lft, ':rgt' => $model->__rgt]);
             return $class::findAllByQuery($query);
         case 'hasChildren':
             $query = new QueryBuilder();
             $query->select('COUNT(*)')->from($class::getTableName())->where('__lft>:lft AND __rgt<:rgt')->order('__lft')->params([':lft' => $model->__lft, ':rgt' => $model->__rgt]);
             return 0 != $connection->query($query)->fetchScalar();
         case 'findSubTree':
             $query = new QueryBuilder();
             $query->select('*')->from($class::getTableName())->where('__lft>=:lft AND __rgt<=:rgt')->order('__lft')->params([':lft' => $model->__lft, ':rgt' => $model->__rgt]);
             return $class::findAllByQuery($query);
         case 'hasPrevSibling':
             $query = new QueryBuilder();
             $query->select('COUNT(*)')->from($class::getTableName())->where('__rgt<:lft AND __prt=:prt')->params([':lft' => $model->__lft, ':prt' => $model->__prt]);
             return 0 != $connection->query($query)->fetchScalar();
         case 'getPrevSibling':
             $query = new QueryBuilder();
             $query->select('*')->from($class::getTableName())->where('__rgt<:lft AND __prt=:prt')->order('__lft DESC')->limit(1)->params([':lft' => $model->__lft, ':prt' => $model->__prt]);
             return $class::findByQuery($query);
         case 'hasNextSibling':
             $query = new QueryBuilder();
             $query->select('COUNT(*)')->from($class::getTableName())->where('__lft>:rgt AND __prt=:prt')->params([':rgt' => $model->__rgt, ':prt' => $model->__prt]);
             return 0 != $connection->query($query)->fetchScalar();
         case 'getNextSibling':
             $query = new QueryBuilder();
             $query->select('*')->from($class::getTableName())->where('__lft>:rgt AND __prt=:prt')->order('__lft')->limit(1)->params([':rgt' => $model->__rgt, ':prt' => $model->__prt]);
             return $class::findByQuery($query);
         case 'insertBefore':
             $element = $argv[0];
             $this->insertModelBeforeElement($model, $element);
             return $model;
             break;
         case 'insertAfter':
             $element = $argv[0];
             $this->insertModelAfterElement($model, $element);
             return $model;
             break;
         case 'moveToFirstPosition':
             $parent = $model->parent;
             if (empty($parent)) {
                 $this->insertModelAsFirstRoot($model);
             } else {
                 $this->insertModelAsFirstChildOf($model, $parent);
             }
             return $model;
         case 'moveToLastPosition':
             $parent = $model->parent;
             if (empty($parent)) {
                 $this->insertModelAsLastRoot($model);
             } else {
                 $this->insertModelAsLastChildOf($model, $parent);
             }
             return $model;
     }
 }
Пример #10
0
 /**
  * Merges queries
  *
  * @param array|QueryBuilder|\T4\Core\IArrayable $prototype
  * @param string $operator AND, OR
  * @return self
  * @throws \InvalidArgumentException
  * @throws \DomainException
  */
 public function merge($prototype, $operator = 'and')
 {
     if ($prototype instanceof QueryBuilder) {
         $params = $prototype->getParams();
         $prototype = $prototype->toArray();
         $prototype['params'] = $params;
     } elseif ($prototype instanceof \T4\Core\IArrayable) {
         $prototype = $prototype->toArray();
     }
     if (!is_array($prototype) && !$prototype instanceof \ArrayAccess) {
         throw new \InvalidArgumentException('Invalid builder type!');
     }
     if (!empty($this->mode) && !empty($prototype['mode']) && $this->mode !== $prototype['mode']) {
         throw new \DomainException('Query mode is not much!');
     }
     if (!empty($prototype['select'])) {
         $this->select($prototype['select']);
     }
     if (!empty($prototype['from'])) {
         $this->from($prototype['from']);
     }
     if (!empty($prototype['where'])) {
         $this->where = empty($this->where) ? $prototype['where'] : "({$this->where}) {$operator} ({$prototype['where']})";
     }
     foreach (['group', 'order', 'limit', 'offset'] as $property) {
         if (!empty($prototype[$property])) {
             $this->{$property} = $prototype[$property];
         }
     }
     foreach (['joins', 'params', 'insertTables', 'updateTables', 'deleteTables', 'values'] as $arrayProperty) {
         if (!empty($prototype[$arrayProperty])) {
             $this->{$arrayProperty} = array_merge($this->{$arrayProperty} ?? [], $prototype[$arrayProperty]);
         }
     }
     return $this;
 }
Пример #11
0
 /**
  * Удаление узла дерева
  * В данном методе удаляются все его подузлы
  * @param \T4\Orm\Model $model
  * @return bool
  */
 public function afterDelete(Model &$model)
 {
     /** @var \T4\Orm\Model $class */
     $class = get_class($model);
     $tableName = $class::getTableName();
     /** @var \T4\Dbal\Connection $connection */
     $connection = $class::getDbConnection();
     $query = new QueryBuilder();
     $query->delete()->table($tableName)->where('__lft>:lft AND __rgt<:rgt');
     $query->params([':lft' => $model->__lft, ':rgt' => $model->__rgt]);
     $connection->execute($query);
     $this->removeFromTreeByLftRgt($connection, $tableName, $model->__lft, $model->__rgt);
     $model->__lft = 0;
     $model->__rgt = 0;
     $model->__lvl = 0;
     $model->__prt = 0;
 }