Example #1
1
 /**
  * Generates a SQL sub-query for replacing in ORDER BY clause.
  *
  * @param string $column Name of the column being replaced by this sub-query
  * @param string|null $bundle Consider attributes only for a specific bundle
  * @return string SQL sub-query statement
  */
 protected function _subQuery($column, $bundle = null)
 {
     $alias = $this->_table->alias();
     $pk = $this->_table->primaryKey();
     $type = $this->_toolbox->getType($column);
     $subConditions = ['EavAttribute.table_alias' => $this->_table->table(), 'EavValues.entity_id' => "{$alias}.{$pk}", 'EavAttribute.name' => $column];
     if (!empty($bundle)) {
         $subConditions['EavAttribute.bundle'] = $bundle;
     }
     $subQuery = TableRegistry::get('Eav.EavValues')->find()->contain(['EavAttribute'])->select(["EavValues.value_{$type}"])->where($subConditions)->sql();
     return str_replace([':c0', ':c1', ':c2', ':c3'], ['"' . $this->_table->table() . '"', "{$alias}.{$pk}", '"' . $column . '"', '"' . $bundle . '"'], $subQuery);
 }
Example #2
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];
 }
Example #3
0
 /**
  * After an entity was removed from database. Here is when EAV values are
  * removed from DB.
  *
  * @param \Cake\Event\Event $event The event that was triggered
  * @param \Cake\Datasource\EntityInterface $entity The entity that was deleted
  * @param \ArrayObject $options Additional options given as an array
  * @throws \Cake\Error\FatalErrorException When using this behavior in non-atomic mode
  * @return void
  */
 public function afterDelete(Event $event, EntityInterface $entity, ArrayObject $options)
 {
     if (!$options['atomic']) {
         throw new FatalErrorException(__d('eav', 'Entities in fieldable tables can only be deleted using transactions. Set [atomic = true]'));
     }
     $valuesToDelete = TableRegistry::get('Eav.EavValues')->find()->contain('EavAttribute')->where(['EavAttribute.table_alias' => $this->_table->table(), 'EavValues.entity_id' => $this->_toolbox->getEntityId($entity)]);
     foreach ($valuesToDelete as $value) {
         TableRegistry::get('Eav.EavValues')->delete($value);
     }
 }
Example #4
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;
 }