association() public method

Returns an association object configured for the specified alias if any
public association ( string $name ) : Cake\ORM\Association | null
$name string the alias used for the association.
return Cake\ORM\Association | null Either the association or null.
 /**
  * Method that renders Entity values through Field Handler Factory.
  *
  * @param  Cake\ORM\Entity       $entity    Entity instance
  * @param  Cake\ORM\Table|string $table     Table instance
  * @param  array                 $fields    Fields to prettify
  * @return void
  */
 protected function _prettify(Entity $entity, $table, array $fields = [])
 {
     if (!$this->__fhf instanceof FieldHandlerFactory) {
         $this->__fhf = new FieldHandlerFactory();
     }
     if (empty($fields)) {
         $fields = array_keys($entity->toArray());
     }
     foreach ($fields as $field) {
         // handle belongsTo associated data
         if ($entity->{$field} instanceof Entity) {
             $tableName = $table->association($entity->{$field}->source())->className();
             $this->_prettify($entity->{$field}, $tableName);
         }
         // handle hasMany associated data
         if (is_array($entity->{$field})) {
             if (empty($entity->{$field})) {
                 continue;
             }
             foreach ($entity->{$field} as $associatedEntity) {
                 if (!$associatedEntity instanceof Entity) {
                     continue;
                 }
                 $tableName = $table->association($associatedEntity->source())->className();
                 $this->_prettify($associatedEntity, $tableName);
             }
         }
         $renderOptions = ['entity' => $entity];
         $entity->{$field} = $this->__fhf->renderValue($table instanceof Table ? $table->registryAlias() : $table, $field, $entity->{$field}, $renderOptions);
     }
 }
Example #2
0
 /**
  * Build the map of property => marshalling callable.
  *
  * @param array $data The data being marshalled.
  * @param array $options List of options containing the 'associated' key.
  * @throws \InvalidArgumentException When associations do not exist.
  * @return array
  */
 protected function _buildPropertyMap($data, $options)
 {
     $map = [];
     $schema = $this->_table->schema();
     // Is a concrete column?
     foreach (array_keys($data) as $prop) {
         $columnType = $schema->columnType($prop);
         if ($columnType) {
             $map[$prop] = function ($value, $entity) use($columnType) {
                 return Type::build($columnType)->marshal($value);
             };
         }
     }
     // Map associations
     if (!isset($options['associated'])) {
         $options['associated'] = [];
     }
     $include = $this->_normalizeAssociations($options['associated']);
     foreach ($include as $key => $nested) {
         if (is_int($key) && is_scalar($nested)) {
             $key = $nested;
             $nested = [];
         }
         $assoc = $this->_table->association($key);
         // If the key is not a special field like _ids or _joinData
         // it is a missing association that we should error on.
         if (!$assoc) {
             if (substr($key, 0, 1) !== '_') {
                 throw new \InvalidArgumentException(sprintf('Cannot marshal data for "%s" association. It is not associated with "%s".', $key, $this->_table->alias()));
             }
             continue;
         }
         if (isset($options['forceNew'])) {
             $nested['forceNew'] = $options['forceNew'];
         }
         if (isset($options['isMerge'])) {
             $callback = function ($value, $entity) use($assoc, $nested) {
                 $options = $nested + ['associated' => []];
                 return $this->_mergeAssociation($entity->get($assoc->property()), $assoc, $value, $options);
             };
         } else {
             $callback = function ($value, $entity) use($assoc, $nested) {
                 $options = $nested + ['associated' => []];
                 return $this->_marshalAssociation($assoc, $value, $options);
             };
         }
         $map[$assoc->property()] = $callback;
     }
     $behaviors = $this->_table->behaviors();
     foreach ($behaviors->loaded() as $name) {
         $behavior = $behaviors->get($name);
         if ($behavior instanceof PropertyMarshalInterface) {
             $map += $behavior->buildMarshalMap($this, $map, $options);
         }
     }
     return $map;
 }
Example #3
0
 /**
  * Build the map of property => association names.
  *
  * @param array $include The array of included associations.
  * @return array
  */
 protected function _buildPropertyMap($include)
 {
     $map = [];
     foreach ($include as $key => $nested) {
         if (is_int($key) && is_scalar($nested)) {
             $key = $nested;
             $nested = [];
         }
         $nested = isset($nested['associated']) ? $nested['associated'] : [];
         $assoc = $this->_table->association($key);
         if ($assoc) {
             $map[$assoc->property()] = ['association' => $assoc, 'nested' => $nested];
         }
     }
     return $map;
 }
 /**
  * Build the map of property => association names.
  *
  * @param array $include The array of included associations.
  * @return array
  */
 protected function _buildPropertyMap($include)
 {
     if (empty($include['associated'])) {
         return [];
     }
     foreach ($include['associated'] as $key => $options) {
         if (is_int($key) && is_scalar($options)) {
             $key = $options;
             $options = [];
         }
         $options += ['validate' => true, 'associated' => []];
         $assoc = $this->_table->association($key);
         if ($assoc) {
             $map[$assoc->property()] = ['association' => $assoc, 'options' => $options];
         }
     }
     return $map;
 }
 /**
  * Build the map of property => association names.
  *
  * @param array $options List of options containing the 'associated' key.
  * @return array
  */
 protected function _buildPropertyMap($options)
 {
     if (empty($options['associated'])) {
         return [];
     }
     $include = $options['associated'];
     $map = [];
     $include = $this->_normalizeAssociations($include);
     foreach ($include as $key => $nested) {
         if (is_int($key) && is_scalar($nested)) {
             $key = $nested;
             $nested = [];
         }
         $assoc = $this->_table->association($key);
         if ($assoc) {
             $map[$assoc->property()] = ['association' => $assoc] + $nested + ['associated' => []];
         }
     }
     return $map;
 }
Example #6
0
 /**
  * Returns the ids found for each of the condition arrays passed for the translations
  * table. Each records is indexed by the corresponding position to the conditions array
  *
  * @param array $ruleSet an array of arary of conditions to be used for finding each
  * @return array
  */
 protected function _findExistingTranslations($ruleSet)
 {
     $association = $this->_table->association($this->_translationTable->alias());
     $query = $association->find()->select(['id', 'num' => 0])->where(current($ruleSet))->hydrate(false)->bufferResults(false);
     unset($ruleSet[0]);
     foreach ($ruleSet as $i => $conditions) {
         $q = $association->find()->select(['id', 'num' => $i])->where($conditions);
         $query->unionAll($q);
     }
     return $query->combine('num', 'id')->toArray();
 }
 /**
  * Returns association object for all versions or single field version.
  *
  * @param string|null $field Field name for per-field association.
  * @param array $options Association options.
  * @return \Cake\ORM\Association
  */
 public function versionAssociation($field = null, $options = [])
 {
     $name = $this->_associationName($field);
     if (!$this->_table->associations()->has($name)) {
         $model = $this->_config['referenceName'];
         if ($field) {
             $this->_table->hasOne($name, $options + ['className' => $this->_config['versionTable'], 'foreignKey' => $this->_config['foreignKey'], 'joinType' => 'LEFT', 'conditions' => [$name . '.model' => $model, $name . '.field' => $field], 'propertyName' => $field . '_version']);
         } else {
             $this->_table->hasMany($name, $options + ['className' => $this->_config['versionTable'], 'foreignKey' => $this->_config['foreignKey'], 'strategy' => 'subquery', 'conditions' => ["{$name}.model" => $model], 'propertyName' => '__version', 'dependent' => true]);
         }
     }
     return $this->_table->association($name);
 }
Example #8
0
 /**
  * Build the map of property => association names.
  *
  * @param array $options List of options containing the 'associated' key.
  * @throws \RuntimeException When associations do not exist.
  * @return array
  */
 protected function _buildPropertyMap($options)
 {
     if (empty($options['associated'])) {
         return [];
     }
     $include = $options['associated'];
     $map = [];
     $include = $this->_normalizeAssociations($include);
     foreach ($include as $key => $nested) {
         if (is_int($key) && is_scalar($nested)) {
             $key = $nested;
             $nested = [];
         }
         if ($key === '_joinData') {
             continue;
         }
         $assoc = $this->_table->association($key);
         if (!$assoc) {
             throw new RuntimeException(sprintf('Cannot marshal data for "%s" association. It is not associated with "%s".', $key, $this->_table->alias()));
         }
         $map[$assoc->property()] = ['association' => $assoc] + $nested + ['associated' => []];
     }
     return $map;
 }
 /**
  * @param \ArrayObject $data
  * @param \Cake\ORM\Table $table
  * @return \ArrayObject
  */
 protected function _process($data, Table $table)
 {
     $associations = [];
     /* @var \Cake\ORM\Association $association */
     foreach ($table->associations() as $association) {
         $associations[$association->property()] = $association->name();
     }
     foreach ($data as $key => $value) {
         if (array_key_exists($key, $associations)) {
             $data[$key] = $this->_process($data[$key], $table->association($associations[$key])->target());
             continue;
         }
         $nullable = Hash::get((array) $table->schema()->column($key), 'null');
         if ($nullable !== true) {
             continue;
         }
         if ($value !== '') {
             continue;
         }
         $default = Hash::get((array) $table->schema()->column($key), 'default');
         $data[$key] = $default;
     }
     return $data;
 }
Example #10
0
 /**
  * Auxiliary function responsible for fully normalizing deep associations defined
  * using `contain()`
  *
  * @param Table $parent owning side of the association
  * @param string $alias name of the association to be loaded
  * @param array $options list of extra options to use for this association
  * @param array $paths An array with two values, the first one is a list of dot
  * separated strings representing associations that lead to this `$alias` in the
  * chain of associations to be loaded. The second value is the path to follow in
  * entities' properties to fetch a record of the corresponding association.
  * @return array normalized associations
  * @throws \InvalidArgumentException When containments refer to associations that do not exist.
  */
 protected function _normalizeContain(Table $parent, $alias, $options, $paths)
 {
     $defaults = $this->_containOptions;
     $instance = $parent->association($alias);
     if (!$instance) {
         throw new InvalidArgumentException(sprintf('%s is not associated with %s', $parent->alias(), $alias));
     }
     if ($instance->alias() !== $alias) {
         throw new InvalidArgumentException(sprintf("You have contained '%s' but that association was bound as '%s'.", $alias, $instance->alias()));
     }
     $paths += ['aliasPath' => '', 'propertyPath' => '', 'root' => $alias];
     $paths['aliasPath'] .= '.' . $alias;
     $paths['propertyPath'] .= '.' . $instance->property();
     $table = $instance->target();
     $extra = array_diff_key($options, $defaults);
     $config = ['associations' => [], 'instance' => $instance, 'config' => array_diff_key($options, $extra), 'aliasPath' => trim($paths['aliasPath'], '.'), 'propertyPath' => trim($paths['propertyPath'], '.')];
     $config['canBeJoined'] = $instance->canBeJoined($config['config']);
     $eagerLoadable = new EagerLoadable($alias, $config);
     if ($config['canBeJoined']) {
         $this->_aliasList[$paths['root']][$alias][] = $eagerLoadable;
     } else {
         $paths['root'] = $config['aliasPath'];
     }
     foreach ($extra as $t => $assoc) {
         $eagerLoadable->addAssociation($t, $this->_normalizeContain($table, $t, $assoc, $paths));
     }
     return $eagerLoadable;
 }
Example #11
0
 /**
  * Generate associations on the junction table as necessary
  *
  * Generates the following associations:
  *
  * - junction belongsTo source e.g. ArticlesTags belongsTo Tags
  * - junction belongsTo target e.g. ArticlesTags belongsTo Articles
  *
  * You can override these generated associations by defining associations
  * with the correct aliases.
  *
  * @param \Cake\ORM\Table $junction The junction table.
  * @param \Cake\ORM\Table $source The source table.
  * @param \Cake\ORM\Table $target The target table.
  * @return void
  */
 protected function _generateJunctionAssociations($junction, $source, $target)
 {
     $tAlias = $target->alias();
     $sAlias = $source->alias();
     if (!$junction->association($tAlias)) {
         $junction->belongsTo($tAlias, ['foreignKey' => $this->targetForeignKey(), 'targetTable' => $target]);
     }
     if (!$junction->association($sAlias)) {
         $junction->belongsTo($sAlias, ['foreignKey' => $this->foreignKey(), 'targetTable' => $source]);
     }
 }
Example #12
0
 /**
  * Used to recursively add contained association column types to
  * the query.
  *
  * @param \Cake\ORM\Table $table The table instance to pluck associations from.
  * @param \Cake\Database\TypeMap $typeMap The typemap to check for columns in.
  *   This typemap is indirectly mutated via Cake\ORM\Query::addDefaultTypes()
  * @param array $associations The nested tree of associations to walk.
  * @return void
  */
 protected function _addAssociationsToTypeMap($table, $typeMap, $associations)
 {
     $typeMap = $this->typeMap();
     foreach ($associations as $name => $nested) {
         $association = $table->association($name);
         if (!$association) {
             continue;
         }
         $target = $association->target();
         $primary = (array) $target->primaryKey();
         if (empty($primary) || $typeMap->type($target->aliasField($primary[0])) === null) {
             $this->addDefaultTypes($target);
         }
         if (!empty($nested)) {
             $this->_addAssociationsToTypeMap($target, $typeMap, $nested);
         }
     }
 }
Example #13
0
 /**
  * Test that save has append as the default save strategy
  *
  * @return void
  */
 public function testSaveDefaultSaveStrategy()
 {
     $authors = new Table(['table' => 'authors', 'alias' => 'Authors', 'connection' => $this->connection, 'entityClass' => 'Cake\\ORM\\Entity']);
     $authors->hasMany('Articles', ['saveStrategy' => 'append']);
     $this->assertEquals('append', $authors->association('articles')->saveStrategy());
 }
 /**
  * Tests that BelongsToMany() creates and configures correctly the association
  *
  * @return void
  */
 public function testBelongsToMany()
 {
     $options = ['foreignKey' => 'thing_id', 'joinTable' => 'things_tags', 'conditions' => ['b' => 'c'], 'sort' => ['foo' => 'asc']];
     $table = new Table(['table' => 'authors', 'connection' => $this->connection]);
     $belongsToMany = $table->belongsToMany('tag', $options);
     $this->assertInstanceOf('Cake\\ORM\\Association\\BelongsToMany', $belongsToMany);
     $this->assertSame($belongsToMany, $table->association('tag'));
     $this->assertEquals('tag', $belongsToMany->name());
     $this->assertEquals('thing_id', $belongsToMany->foreignKey());
     $this->assertEquals(['b' => 'c'], $belongsToMany->conditions());
     $this->assertEquals(['foo' => 'asc'], $belongsToMany->sort());
     $this->assertSame($table, $belongsToMany->source());
     $this->assertSame('things_tags', $belongsToMany->junction()->table());
 }
 /**
  * Iterate all associations and update counter caches.
  *
  * @param Event $event
  * @param Entity $entity
  * @return void
  */
 protected function _processAssociations(Event $event, Entity $entity)
 {
     foreach ($this->_config as $assoc => $settings) {
         $assoc = $this->_table->association($assoc);
         $this->_processAssociation($event, $entity, $assoc, $settings);
     }
 }
Example #16
0
 /**
  * Auxiliary function responsible for fully normalizing deep associations defined
  * using `contain()`
  *
  * @param Table $parent owning side of the association
  * @param string $alias name of the association to be loaded
  * @param array $options list of extra options to use for this association
  * @param array $paths An array with to values, the first one is a list of dot
  * separated strings representing associations that lead to this `$alias` in the
  * chain of associaitons to be loaded. The second value is the path to follow in
  * entities' properties to fetch a record of the corresponding association.
  * @return array normalized associations
  * @throws \InvalidArgumentException When containments refer to associations that do not exist.
  */
 protected function _normalizeContain(Table $parent, $alias, $options, $paths)
 {
     $defaults = $this->_containOptions;
     $instance = $parent->association($alias);
     if (!$instance) {
         throw new \InvalidArgumentException(sprintf('%s is not associated with %s', $parent->alias(), $alias));
     }
     $paths += ['aliasPath' => '', 'propertyPath' => '', 'root' => $alias];
     $paths['aliasPath'] .= '.' . $alias;
     $paths['propertyPath'] .= '.' . $instance->property();
     $table = $instance->target();
     $extra = array_diff_key($options, $defaults);
     $config = ['associations' => [], 'instance' => $instance, 'config' => array_diff_key($options, $extra), 'aliasPath' => trim($paths['aliasPath'], '.'), 'propertyPath' => trim($paths['propertyPath'], '.')];
     $config['canBeJoined'] = $instance->canBeJoined($config['config']);
     $config = $this->_correctStrategy($alias, $config, $paths['root']);
     if ($config['canBeJoined']) {
         $this->_aliasList[$paths['root']][$alias] = true;
     } else {
         $paths['root'] = $config['aliasPath'];
     }
     foreach ($extra as $t => $assoc) {
         $config['associations'][$t] = $this->_normalizeContain($table, $t, $assoc, $paths);
     }
     return $config;
 }