Exemplo n.º 1
0
 /**
  * Retrieves all virtual values of all the entities within the given result-set.
  *
  * @param \Cake\Collection\CollectionInterface $entities Set of entities
  * @param array $args Contains two keys: "options" and "primary" given to the
  *  originating beforeFind(), and "selectedVirtual" a list of virtual columns
  *  selected in the originating find query
  * @return array Virtual values indexed by entity ID
  */
 protected function _prepareSetValues(CollectionInterface $entities, array $args)
 {
     $entityIds = $this->_toolbox->extractEntityIds($entities);
     if (empty($entityIds)) {
         return [];
     }
     $selectedVirtual = $args['selectedVirtual'];
     $bundle = $args['options']['bundle'];
     $validColumns = array_values($selectedVirtual);
     $validNames = array_intersect($this->_toolbox->getAttributeNames($bundle), $validColumns);
     $attrsById = [];
     foreach ($this->_toolbox->attributes($bundle) as $name => $attr) {
         if (in_array($name, $validNames)) {
             $attrsById[$attr['id']] = $attr;
         }
     }
     if (empty($attrsById)) {
         return [];
     }
     return TableRegistry::get('Eav.EavValues')->find('all')->bufferResults(false)->where(['EavValues.eav_attribute_id IN' => array_keys($attrsById), 'EavValues.entity_id IN' => $entityIds])->all()->map(function ($value) use($attrsById, $selectedVirtual) {
         $attrName = $attrsById[$value->get('eav_attribute_id')]->get('name');
         $attrType = $attrsById[$value->get('eav_attribute_id')]->get('type');
         $alias = array_search($attrName, $selectedVirtual);
         return ['entity_id' => $value->get('entity_id'), 'property_name' => is_string($alias) ? $alias : $attrName, 'value' => $this->_toolbox->marshal($value->get("value_{$attrType}"), $attrType)];
     })->groupBy('entity_id')->toArray();
 }
Exemplo n.º 2
0
 /**
  * {@inheritDoc}
  *
  * Look for virtual columns in query's WHERE clause.
  *
  * @param \Cake\ORM\Query $query The query to scope
  * @param string|null $bundle Consider attributes only for a specific bundle
  * @return \Cake\ORM\Query The modified query object
  */
 public function scope(Query $query, $bundle = null)
 {
     $orderClause = $query->clause('order');
     if (!$orderClause) {
         return $query;
     }
     $class = new \ReflectionClass($orderClause);
     $property = $class->getProperty('_conditions');
     $property->setAccessible(true);
     $conditions = $property->getValue($orderClause);
     foreach ($conditions as $column => $direction) {
         if (empty($column) || in_array($column, (array) $this->_table->schema()->columns()) || !in_array($column, $this->_toolbox->getAttributeNames())) {
             continue;
         }
         $conditions['(' . $this->_subQuery($column, $bundle) . ')'] = $direction;
         unset($conditions[$column]);
     }
     $property->setValue($orderClause, $conditions);
     return $query;
 }
Exemplo n.º 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;
 }