/** * 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); } }
/** * Hydrate one entity and its associated data. * * ### Options: * * - validate: Set to false to disable validation. Can also be a string of the validator ruleset to be applied. * Defaults to true/default. * - associated: Associations listed here will be marshalled as well. Defaults to null. * - fieldList: A whitelist of fields to be assigned to the entity. If not present, * the accessible fields list in the entity will be used. Defaults to null. * - accessibleFields: A list of fields to allow or deny in entity accessible fields. Defaults to null * - forceNew: When enabled, belongsToMany associations will have 'new' entities created * when primary key values are set, and a record does not already exist. Normally primary key * on missing entities would be ignored. Defaults to false. * * The above options can be used in each nested `associated` array. In addition to the above * options you can also use the `onlyIds` option for HasMany and BelongsToMany associations. * When true this option restricts the request data to only be read from `_ids`. * * ``` * $result = $marshaller->one($data, [ * 'associated' => ['Tags' => ['onlyIds' => true]] * ]); * ``` * * @param array $data The data to hydrate. * @param array $options List of options * @return \Cake\ORM\Entity * @see \Cake\ORM\Table::newEntity() */ public function one(array $data, array $options = []) { list($data, $options) = $this->_prepareDataAndOptions($data, $options); $propertyMap = $this->_buildPropertyMap($options); $schema = $this->_table->schema(); $primaryKey = (array) $this->_table->primaryKey(); $entityClass = $this->_table->entityClass(); $entity = new $entityClass(); $entity->source($this->_table->registryAlias()); if (isset($options['accessibleFields'])) { foreach ((array) $options['accessibleFields'] as $key => $value) { $entity->accessible($key, $value); } } $marshallOptions = []; if (isset($options['forceNew'])) { $marshallOptions['forceNew'] = $options['forceNew']; } $errors = $this->_validate($data, $options, true); $properties = []; foreach ($data as $key => $value) { if (!empty($errors[$key])) { if ($entity instanceof InvalidPropertyInterface) { $entity->invalid($key, $value); } continue; } $columnType = $schema->columnType($key); if (isset($propertyMap[$key])) { $assoc = $propertyMap[$key]['association']; $value = $this->_marshalAssociation($assoc, $value, $propertyMap[$key] + $marshallOptions); } elseif ($value === '' && in_array($key, $primaryKey, true)) { // Skip marshalling '' for pk fields. continue; } elseif ($columnType) { $converter = Type::build($columnType); $value = $converter->marshal($value); } $properties[$key] = $value; } if (!isset($options['fieldList'])) { $entity->set($properties); $entity->errors($errors); return $entity; } foreach ((array) $options['fieldList'] as $field) { if (array_key_exists($field, $properties)) { $entity->set($field, $properties[$field]); } } $entity->errors($errors); return $entity; }
/** * Constructor * * @param \Cake\ORM\Table $table Table instance * @param array $config Configuration */ public function __construct(Table $table, array $config = []) { $tableAlias = $table->alias(); list($plugin) = pluginSplit($table->registryAlias(), true); if (isset($config['referenceName'])) { $tableReferenceName = $config['referenceName']; } else { $tableReferenceName = $this->_referenceName($table); } $config += ['mainTableAlias' => $tableAlias, 'translationTable' => $plugin . $tableReferenceName . 'Translations', 'hasOneAlias' => $tableAlias . 'Translation']; parent::__construct($table, $config); }
/** * Hydrate one entity and its associated data. * * ### Options: * * - validate: Set to false to disable validation. Can also be a string of the validator ruleset to be applied. * Defaults to true/default. * - associated: Associations listed here will be marshalled as well. Defaults to null. * - fieldList: A whitelist of fields to be assigned to the entity. If not present, * the accessible fields list in the entity will be used. Defaults to null. * - accessibleFields: A list of fields to allow or deny in entity accessible fields. Defaults to null * - forceNew: When enabled, belongsToMany associations will have 'new' entities created * when primary key values are set, and a record does not already exist. Normally primary key * on missing entities would be ignored. Defaults to false. * * The above options can be used in each nested `associated` array. In addition to the above * options you can also use the `onlyIds` option for HasMany and BelongsToMany associations. * When true this option restricts the request data to only be read from `_ids`. * * ``` * $result = $marshaller->one($data, [ * 'associated' => ['Tags' => ['onlyIds' => true]] * ]); * ``` * * @param array $data The data to hydrate. * @param array $options List of options * @return \Cake\ORM\Entity * @see \Cake\ORM\Table::newEntity() */ public function one(array $data, array $options = []) { list($data, $options) = $this->_prepareDataAndOptions($data, $options); $primaryKey = (array) $this->_table->primaryKey(); $entityClass = $this->_table->entityClass(); $entity = new $entityClass(); $entity->source($this->_table->registryAlias()); if (isset($options['accessibleFields'])) { foreach ((array) $options['accessibleFields'] as $key => $value) { $entity->accessible($key, $value); } } $errors = $this->_validate($data, $options, true); $options['isMerge'] = false; $propertyMap = $this->_buildPropertyMap($data, $options); $properties = []; foreach ($data as $key => $value) { if (!empty($errors[$key])) { if ($entity instanceof InvalidPropertyInterface) { $entity->invalid($key, $value); } continue; } if ($value === '' && in_array($key, $primaryKey, true)) { // Skip marshalling '' for pk fields. continue; } elseif (isset($propertyMap[$key])) { $properties[$key] = $propertyMap[$key]($value, $entity); } else { $properties[$key] = $value; } } if (!isset($options['fieldList'])) { $entity->set($properties); $entity->errors($errors); return $entity; } foreach ((array) $options['fieldList'] as $field) { if (array_key_exists($field, $properties)) { $entity->set($field, $properties[$field]); } } $entity->errors($errors); return $entity; }
/** * Correctly nests results keys including those coming from associations * * @param mixed $row Array containing columns and values or false if there is no results * @return array Results */ protected function _groupResult($row) { $defaultAlias = $this->_defaultAlias; $results = $presentAliases = []; $options = ['useSetters' => false, 'markClean' => true, 'markNew' => false, 'guard' => false]; foreach ($this->_matchingMapColumns as $alias => $keys) { $matching = $this->_matchingMap[$alias]; $results['_matchingData'][$alias] = $this->_castValues($alias, array_combine($keys, array_intersect_key($row, $keys))); if ($this->_hydrate) { $options['source'] = $alias; $entity = new $matching['entityClass']($results['_matchingData'][$alias], $options); $entity->clean(); $results['_matchingData'][$alias] = $entity; } } foreach ($this->_map as $table => $keys) { $results[$table] = array_combine($keys, array_intersect_key($row, $keys)); $presentAliases[$table] = true; } if (isset($presentAliases[$defaultAlias])) { $results[$defaultAlias] = $this->_castValues($defaultAlias, $results[$defaultAlias]); } unset($presentAliases[$defaultAlias]); foreach ($this->_containMap as $assoc) { $alias = $assoc['nestKey']; if ($assoc['canBeJoined'] && empty($this->_map[$alias])) { continue; } $instance = $assoc['instance']; if (!$assoc['canBeJoined'] && !isset($row[$alias])) { $results = $instance->defaultRowValue($results, $assoc['canBeJoined']); continue; } if (!$assoc['canBeJoined']) { $results[$alias] = $row[$alias]; } $target = $instance->target(); $options['source'] = $target->alias(); unset($presentAliases[$alias]); if ($assoc['canBeJoined']) { $results[$alias] = $this->_castValues($assoc['alias'], $results[$alias]); $hasData = false; foreach ($results[$alias] as $v) { if ($v !== null && $v !== []) { $hasData = true; break; } } if (!$hasData) { $results[$alias] = null; } } if ($this->_hydrate && $results[$alias] !== null && $assoc['canBeJoined']) { $entity = new $assoc['entityClass']($results[$alias], $options); $entity->clean(); $results[$alias] = $entity; } $results = $instance->transformRow($results, $alias, $assoc['canBeJoined']); } foreach ($presentAliases as $alias => $present) { if (!isset($results[$alias])) { continue; } $results[$defaultAlias][$alias] = $results[$alias]; } if (isset($results['_matchingData'])) { $results[$defaultAlias]['_matchingData'] = $results['_matchingData']; } $options['source'] = $this->_defaultTable->registryAlias(); if (isset($results[$defaultAlias])) { $results = $results[$defaultAlias]; } if ($this->_hydrate && !$results instanceof EntityInterface) { $results = new $this->_entityClass($results, $options); } return $results; }
/** * Correctly nests results keys including those coming from associations * * @param mixed $row Array containing columns and values or false if there is no results * @return array Results */ protected function _groupResult($row) { $defaultAlias = $this->_defaultTable->alias(); $results = $presentAliases = []; $options = ['useSetters' => false, 'markClean' => true, 'markNew' => false, 'guard' => false]; foreach ($this->_matchingMap as $matching) { foreach ($row as $key => $value) { if (strpos($key, $matching['alias'] . '__') !== 0) { continue; } list($table, $field) = explode('__', $key); $results['_matchingData'][$table][$field] = $value; if (!isset($this->_containMap[$table])) { unset($row[$key]); } } if (empty($results['_matchingData'][$matching['alias']])) { continue; } $results['_matchingData'][$matching['alias']] = $this->_castValues($matching['instance']->target(), $results['_matchingData'][$matching['alias']]); if ($this->_hydrate) { $options['source'] = $matching['alias']; $entity = new $matching['entityClass']($results['_matchingData'][$matching['alias']], $options); $entity->clean(); $results['_matchingData'][$matching['alias']] = $entity; } } foreach ($row as $key => $value) { $table = $defaultAlias; $field = $key; if ($value !== null && !is_scalar($value)) { $results[$key] = $value; continue; } if (empty($this->_map[$key])) { $parts = explode('__', $key); if (count($parts) > 1) { $this->_map[$key] = $parts; } } if (!empty($this->_map[$key])) { list($table, $field) = $this->_map[$key]; } $presentAliases[$table] = true; $results[$table][$field] = $value; } if (isset($presentAliases[$defaultAlias])) { $results[$defaultAlias] = $this->_castValues($this->_defaultTable, $results[$defaultAlias]); } unset($presentAliases[$defaultAlias]); foreach ($this->_containMap as $assoc) { $alias = $assoc['nestKey']; $instance = $assoc['instance']; if (!isset($results[$alias])) { $results = $instance->defaultRowValue($results, $assoc['canBeJoined']); continue; } $target = $instance->target(); $options['source'] = $target->alias(); unset($presentAliases[$alias]); if ($assoc['canBeJoined']) { $results[$alias] = $this->_castValues($target, $results[$alias]); $hasData = false; foreach ($results[$alias] as $v) { if ($v !== null && $v !== []) { $hasData = true; break; } } if (!$hasData) { $results[$alias] = null; } } if ($this->_hydrate && $results[$alias] !== null && $assoc['canBeJoined']) { $entity = new $assoc['entityClass']($results[$alias], $options); $entity->clean(); $results[$alias] = $entity; } $results = $instance->transformRow($results, $alias, $assoc['canBeJoined']); } foreach ($presentAliases as $alias => $present) { if (!isset($results[$alias])) { continue; } $results[$defaultAlias][$alias] = $results[$alias]; } if (isset($results['_matchingData'])) { $results[$defaultAlias]['_matchingData'] = $results['_matchingData']; } $options['source'] = $this->_defaultTable->registryAlias(); $results = $results[$defaultAlias]; if ($this->_hydrate && !$results instanceof Entity) { $results = new $this->_entityClass($results, $options); } return $results; }
/** * Method that passes csv defined Table fields to the View * * @return void */ protected function _setTableFields() { $result = []; $pathFinder = new ViewPathFinder(); $path = $pathFinder->find($this->request->controller, $this->request->action); $result = $this->_getFieldsFromCsv($path); list($plugin, $model) = pluginSplit($this->_tableInstance->registryAlias()); /* add plugin and model names to each of the fields */ $result = $this->_setFieldPluginAndModel($result, $model, $plugin); /* If action requires panels, arrange the fields into the panels */ if (in_array($this->request->action, $this->_panelActions)) { $result = $this->_arrangePanels($result); } $this->_controllerInstance->set('fields', $result); $this->_controllerInstance->set('_serialize', ['fields']); }