Пример #1
0
 /**
  * Gets a list of all virtual columns present in given $query's SELECT clause.
  *
  * This method will alter the given Query object removing any virtual column
  * present in its SELECT clause in order to avoid incorrect SQL statements.
  * Selected virtual columns should be fetched after query is executed using
  * mapReduce or similar.
  *
  * @param \Cake\ORM\Query $query The query object to be scoped
  * @param string|null $bundle Consider attributes only for a specific bundle
  * @return array List of virtual columns names
  */
 public function getVirtualColumns(Query $query, $bundle = null)
 {
     static $selectedVirtual = [];
     $cacheKey = md5($query->sql()) . '_' . $bundle;
     if (isset($selectedVirtual[$cacheKey])) {
         return $selectedVirtual[$cacheKey];
     }
     $selectClause = (array) $query->clause('select');
     if (empty($selectClause)) {
         $selectedVirtual[$cacheKey] = array_keys($this->_toolbox->attributes($bundle));
         return $selectedVirtual[$cacheKey];
     }
     $selectedVirtual[$cacheKey] = [];
     $virtualColumns = array_keys($this->_toolbox->attributes($bundle));
     foreach ($selectClause as $index => $column) {
         list($table, $column) = pluginSplit($column);
         if ((empty($table) || $table == $this->_table->alias()) && in_array($column, $virtualColumns)) {
             $selectedVirtual[$cacheKey][$index] = $column;
             unset($selectClause[$index]);
         }
     }
     if (empty($selectClause) && !empty($selectedVirtual[$cacheKey])) {
         $selectClause[] = $this->_table->primaryKey();
     }
     $query->select($selectClause, true);
     return $selectedVirtual[$cacheKey];
 }
Пример #2
0
 /**
  * Save virtual values after an entity's real values were saved.
  *
  * @param \Cake\Event\Event $event The event that was triggered
  * @param \Cake\Datasource\EntityInterface $entity The entity that was saved
  * @param \ArrayObject $options Additional options given as an array
  * @return bool True always
  */
 public function afterSave(Event $event, EntityInterface $entity, ArrayObject $options)
 {
     $attrsById = [];
     $updatedAttrs = [];
     $valuesTable = TableRegistry::get('Eav.EavValues');
     foreach ($this->_toolbox->attributes() as $name => $attr) {
         if (!$this->_toolbox->propertyExists($entity, $name)) {
             continue;
         }
         $attrsById[$attr->get('id')] = $attr;
     }
     if (empty($attrsById)) {
         return true;
         // nothing to do
     }
     $values = $valuesTable->find()->where(['eav_attribute_id IN' => array_keys($attrsById), 'entity_id' => $this->_toolbox->getEntityId($entity)]);
     foreach ($values as $value) {
         $updatedAttrs[] = $value->get('eav_attribute_id');
         $info = $attrsById[$value->get('eav_attribute_id')];
         $type = $this->_toolbox->getType($info->get('name'));
         $marshaledValue = $this->_toolbox->marshal($entity->get($info->get('name')), $type);
         $value->set("value_{$type}", $marshaledValue);
         $entity->set($info->get('name'), $marshaledValue);
         $valuesTable->save($value);
     }
     foreach ($this->_toolbox->attributes() as $name => $attr) {
         if (!$this->_toolbox->propertyExists($entity, $name)) {
             continue;
         }
         if (!in_array($attr->get('id'), $updatedAttrs)) {
             $type = $this->_toolbox->getType($name);
             $value = $valuesTable->newEntity(['eav_attribute_id' => $attr->get('id'), 'entity_id' => $this->_toolbox->getEntityId($entity)]);
             $marshaledValue = $this->_toolbox->marshal($entity->get($name), $type);
             $value->set("value_{$type}", $marshaledValue);
             $entity->set($name, $marshaledValue);
             $valuesTable->save($value);
         }
     }
     if ($this->config('cacheMap')) {
         $this->updateEavCache($entity);
     }
     return true;
 }
Пример #3
0
 /**
  * Analyzes the given unary expression and alters it according.
  *
  * @param \Cake\Database\Expression\UnaryExpression $expression Unary expression
  * @param string $bundle Consider attributes only for a specific bundle
  * @param \Cake\ORM\Query $query The query instance this expression comes from
  * @return \Cake\Database\Expression\UnaryExpression Scoped expression (or not)
  */
 protected function _inspectUnaryExpression(UnaryExpression $expression, $bundle, Query $query)
 {
     $class = new \ReflectionClass($expression);
     $property = $class->getProperty('_value');
     $property->setAccessible(true);
     $value = $property->getValue($expression);
     if ($value instanceof IdentifierExpression) {
         $field = $value->getIdentifier();
         $column = is_string($field) ? $this->_toolbox->columnName($field) : '';
         if (empty($column) || in_array($column, (array) $this->_table->schema()->columns()) || !in_array($column, $this->_toolbox->getAttributeNames($bundle)) || !$this->_toolbox->isSearchable($column)) {
             // nothing to alter
             return $expression;
         }
         $pk = $this->_tablePrimaryKey();
         $driverClass = $this->_driverClass($query);
         switch ($driverClass) {
             case 'sqlite':
                 $concat = implode(' || ', $pk);
                 $field = "({$concat} || '')";
                 break;
             case 'mysql':
             case 'postgres':
             case 'sqlserver':
             default:
                 $concat = implode(', ', $pk);
                 $field = "CONCAT({$concat}, '')";
                 break;
         }
         $attr = $this->_toolbox->attributes($bundle)[$column];
         $type = $this->_toolbox->getType($column);
         $subQuery = TableRegistry::get('Eav.EavValues')->find()->select("EavValues.value_{$type}")->where(['EavValues.entity_id' => $field, 'EavValues.eav_attribute_id' => $attr['id']])->sql();
         $subQuery = str_replace([':c0', ':c1'], [$field, $attr['id']], $subQuery);
         $property->setValue($expression, "({$subQuery})");
     }
     return $expression;
 }