/** * @param \Cake\Event\Event $event * @param \Cake\ORM\Query $query * @param \ArrayObject $options * @param bool $primary * @return void */ public function beforeFind(Event $event, Query $query, ArrayObject $options, $primary) { if (!$primary && !$this->_config['recursive']) { return; } $field = $this->_config['field']; if (!$field) { return; } $query->find('hashed'); $idField = $this->_primaryKey; if ($primary && $field === $idField) { $query->traverseExpressions(function ($expression) { if (method_exists($expression, 'getField') && ($expression->getField() === $this->_primaryKey || $expression->getField() === $this->_table->alias() . '.' . $this->_primaryKey)) { $expression->setValue($this->decodeHashid($expression->getValue())); } return $expression; }); } if (!$this->_config['recursive']) { return; } foreach ($this->_table->associations() as $association) { if ($association->target()->hasBehavior('Hashid') && $association->finder() === 'all') { $association->finder('hashed'); } } }
/** * 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); }
public function __construct(Table $table, Entity $entity, $field, array $settings) { $this->setRoot(TMP . 'ProfferTests'); $this->setTable($table->alias()); $this->setField($field); $this->setSeed('proffer_test'); if (isset($settings['thumbnailSizes'])) { $this->setPrefixes($settings['thumbnailSizes']); } $this->setFilename($entity->get($field)); }
/** * Returns the basepath for the current field/data combination. * If a `path` is specified in settings, then that will be used as * the replacement pattern * * @return string * @throws LogicException if a replacement is not valid for the current dataset */ public function basepath() { $defaultPath = 'webroot{DS}files{DS}{model}{DS}{field}{DS}'; $path = Hash::get($this->settings, 'path', $defaultPath); if (strpos($path, '{primaryKey}') !== false) { if ($this->entity->isNew()) { throw new LogicException('{primaryKey} substitution not allowed for new entities'); } if (is_array($this->table->primaryKey())) { throw new LogicException('{primaryKey} substitution not valid for composite primary keys'); } } $replacements = ['{primaryKey}' => $this->entity->get($this->table->primaryKey()), '{model}' => $this->table->alias(), '{relatedModel}' => $this->entity->model, '{table}' => $this->table->table(), '{field}' => $this->field, '{time}' => time(), '{microtime}' => microtime(), '{DS}' => DIRECTORY_SEPARATOR]; return str_replace(array_keys($replacements), array_values($replacements), $path); }
/** * Do some checks on the table which has been passed to make sure that it has what we need * * @param string $table The table * @return void */ protected function checkTable($table) { try { $this->Table = $this->loadModel($table); } catch (Exception $e) { $this->out(__('<error>' . $e->getMessage() . '</error>')); exit; } if (get_class($this->Table) === 'AppModel') { $this->out(__('<error>The table could not be found, instance of AppModel loaded.</error>')); exit; } if (!$this->Table->hasBehavior('Proffer')) { $out = __("<error>The table '" . $this->Table->alias() . "' does not have the Proffer behavior attached.</error>"); $this->out($out); exit; } $config = $this->Table->behaviors()->Proffer->config(); foreach ($config as $field => $settings) { if (!$this->Table->hasField($field)) { $out = __("<error>The table '" . $this->Table->alias() . "' does not have the configured upload field in it's schema.</error>"); $this->out($out); exit; } if (!$this->Table->hasField($settings['dir'])) { $out = __("<error>The table '" . $this->Table->alias() . "' does not have the configured dir field in it's schema.</error>"); $this->out($out); exit; } } }
/** * Modifies the entity before it is saved so that versioned fields are persisted * in the database too. * * @param \Cake\Event\Event $event The beforeSave event that was fired * @param \Cake\ORM\Entity $entity The entity that is going to be saved * @param \ArrayObject $options the options passed to the save method * @return void */ public function beforeSave(Event $event, Entity $entity, ArrayObject $options) { $table = $this->_config['versionTable']; $newOptions = [$table => ['validate' => false]]; $options['associated'] = $newOptions + $options['associated']; $fields = $this->_fields(); $values = $entity->extract($fields); $model = $this->_table->alias(); $primaryKey = (array) $this->_table->primaryKey(); $primaryKey = current($primaryKey); $foreignKey = $entity->get($primaryKey); $versionField = $this->_config['versionField']; $preexistent = TableRegistry::get($table)->find()->select(['version_id'])->where(compact('foreign_key', 'model'))->order(['id desc'])->limit(1)->hydrate(false)->toArray(); $versionId = Hash::get($preexistent, '0.version_id', 0) + 1; $created = new Time(); foreach ($values as $field => $content) { if ($field == $primaryKey || $field == $versionField) { continue; } $data = ['version_id' => $versionId, 'model' => $model, 'foreign_key' => $foreignKey, 'field' => $field, 'content' => $content, 'created' => $created]; $new[$field] = new Entity($data, ['useSetters' => false, 'markNew' => true]); } $entity->set('__version', $new); if (!empty($versionField) && in_array($versionField, $fields)) { $entity->set($this->_config['versionField'], $versionId); } }
/** * 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]; }
/** * Merges `$data` into `$entity` and recursively does the same for each one of * the association names passed in `$include`. When merging associations, if an * entity is not present in the parent entity for a given association, a new one * will be created. * * When merging HasMany or BelongsToMany associations, all the entities in the * `$data` array will appear, those that can be matched by primary key will get * the data merged, but those that cannot, will be discarded. * * @param \Cake\Datasource\EntityInterface $entity the entity that will get the * data merged in * @param array $data key value list of fields to be merged into the entity * @param array $include The list of associations to be merged * @return \Cake\Datasource\EntityInterface */ public function merge(EntityInterface $entity, array $data, array $include = []) { $propertyMap = $this->_buildPropertyMap($include); $tableName = $this->_table->alias(); if (isset($data[$tableName])) { $data = $data[$tableName]; } $schema = $this->_table->schema(); $properties = []; foreach ($data as $key => $value) { $columnType = $schema->columnType($key); $original = $entity->get($key); if (isset($propertyMap[$key])) { $assoc = $propertyMap[$key]['association']; $nested = $propertyMap[$key]['nested']; $value = $this->_mergeAssociation($original, $assoc, $value, $nested); } elseif ($columnType) { $converter = Type::build($columnType); $value = $converter->marshal($value); if ($original == $value) { continue; } } $properties[$key] = $value; } $entity->set($properties); return $entity; }
/** * Replaces existing association links between the source entity and the target * with the ones passed. This method does a smart cleanup, links that are already * persisted and present in `$targetEntities` will not be deleted, new links will * be created for the passed target entities that are not already in the database * and the rest will be removed. * * For example, if an article is linked to tags 'cake' and 'framework' and you pass * to this method an array containing the entities for tags 'cake', 'php' and 'awesome', * only the link for cake will be kept in database, the link for 'framework' will be * deleted and the links for 'php' and 'awesome' will be created. * * Existing links are not deleted and created again, they are either left untouched * or updated so that potential extra information stored in the joint row is not * lost. Updating the link row can be done by making sure the corresponding passed * target entity contains the joint property with its primary key and any extra * information to be stored. * * On success, the passed `$sourceEntity` will contain `$targetEntities` as value * in the corresponding property for this association. * * This method assumes that links between both the source entity and each of the * target entities are unique. That is, for any given row in the source table there * can only be one link in the junction table pointing to any other given row in * the target table. * * Additional options for new links to be saved can be passed in the third argument, * check `Table::save()` for information on the accepted options. * * ### Example: * * ``` * $article->tags = [$tag1, $tag2, $tag3, $tag4]; * $articles->save($article); * $tags = [$tag1, $tag3]; * $articles->association('tags')->replaceLinks($article, $tags); * ``` * * `$article->get('tags')` will contain only `[$tag1, $tag3]` at the end * * @param \Cake\Datasource\EntityInterface $sourceEntity an entity persisted in the source table for * this association * @param array $targetEntities list of entities from the target table to be linked * @param array $options list of options to be passed to the internal `save`/`delete` calls * when persisting/updating new links, or deleting existing ones * @throws \InvalidArgumentException if non persisted entities are passed or if * any of them is lacking a primary key value * @return bool success */ public function replaceLinks(EntityInterface $sourceEntity, array $targetEntities, array $options = []) { $bindingKey = (array) $this->bindingKey(); $primaryValue = $sourceEntity->extract($bindingKey); if (count(array_filter($primaryValue, 'strlen')) !== count($bindingKey)) { $message = 'Could not find primary key value for source entity'; throw new InvalidArgumentException($message); } return $this->junction()->connection()->transactional(function () use($sourceEntity, $targetEntities, $primaryValue, $options) { $foreignKey = (array) $this->foreignKey(); $hasMany = $this->source()->association($this->_junctionTable->alias()); $existing = $hasMany->find('all')->where(array_combine($foreignKey, $primaryValue)); $associationConditions = $this->conditions(); if ($associationConditions) { $existing->contain($this->target()->alias()); $existing->andWhere($associationConditions); } $jointEntities = $this->_collectJointEntities($sourceEntity, $targetEntities); $inserts = $this->_diffLinks($existing, $jointEntities, $targetEntities, $options); if ($inserts && !$this->_saveTarget($sourceEntity, $inserts, $options)) { return false; } $property = $this->property(); if (count($inserts)) { $inserted = array_combine(array_keys($inserts), (array) $sourceEntity->get($property)); $targetEntities = $inserted + $targetEntities; } ksort($targetEntities); $sourceEntity->set($property, array_values($targetEntities)); $sourceEntity->dirty($property, false); return true; }); }
/** * 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 = []; foreach ($row as $key => $value) { $table = $defaultAlias; $field = $key; if (isset($this->_associationMap[$key])) { $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; } unset($presentAliases[$defaultAlias]); $results[$defaultAlias] = $this->_castValues($this->_defaultTable, $results[$defaultAlias]); $options = ['useSetters' => false, 'markClean' => true, 'markNew' => false, 'guard' => false]; foreach (array_reverse($this->_associationMap) 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]); } if ($this->_hydrate && $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]; } $options['source'] = $defaultAlias; $results = $results[$defaultAlias]; if ($this->_hydrate && !$results instanceof Entity) { $results = new $this->_entityClass($results, $options); } return $results; }
/** * Returns default version association name. * * @param string $field Field name. * @return string */ protected function _associationName($field = null) { $alias = Inflector::singularize($this->_table->alias()); if ($field) { $field = Inflector::camelize($field); } return $alias . $field . 'Version'; }
/** * Get comments for the given entity. * * Allows you to get all comments even when this behavior was disabled * using `unbindComments()`. * * ### Usage: * * // in your controller, gets comments for post which id equals 2 * $postComments = $this->Posts->find('comments', ['for' => 2]); * * @param \Cake\ORM\Query $query The query object * @param array $options Additional options as an array * @return \Cake\Datasource\ResultSetDecorator Comments collection * @throws \InvalidArgumentException When the 'for' key is not passed in $options */ public function findComments(Query $query, $options) { $tableAlias = Inflector::underscore($this->_table->alias()); if (empty($options['for'])) { throw new \InvalidArgumentException("The 'for' key is required for find('children')"); } $comments = $this->_table->Comments->find('threaded')->where(['table_alias' => $tableAlias, 'entity_id' => $options['for']])->order($this->config('order'))->all(); return $comments; }
/** * 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(); }
/** * beforeDelete callback * * Prevent delete if the context is not global * * @param \Cake\Event\Event $event The beforeDelete event that was fired. * @param \Cake\ORM\Entity $entity The entity that was saved. * @return void */ public function beforeDelete(Event $event, Entity $entity, $options) { if (MTApp::getContext() == 'tenant') { $field = $this->config('foreign_key_field'); //paranoid check of ownership if ($entity->{$field} != MTApp::tenant()->id) { //current tenant is NOT owner throw new DataScopeViolationException('Tenant->id:' . MTApp::tenant()->id . ' does not own ' . $this->_table->alias() . '->id:' . $entity->id); } } return true; }
/** * Gets table's PK as an array. * * @return array */ protected function _tablePrimaryKey() { $alias = $this->_table->alias(); $pk = $this->_table->primaryKey(); if (!is_array($pk)) { $pk = [$pk]; } $pk = array_map(function ($key) use($alias) { return "{$alias}.{$key}"; }, $pk); return $pk; }
/** * Validation rules. * * @param \Cake\Event\Event $event The event instance. * @return void * @throws \Cake\Network\Exception\ForbiddenException When * - $_manageTable is not defined. * - trait is used in non-controller classes. * - the controller is not a backend controller. */ public function beforeFilter(Event $event) { $requestParams = $event->subject()->request->params; if (empty($this->_manageTable) || !($this->_table = TableRegistry::get($this->_manageTable))) { throw new ForbiddenException(__d('field', 'FieldUIControllerTrait: The property $_manageTable was not found or is empty.')); } elseif (!$this instanceof Controller) { throw new ForbiddenException(__d('field', 'FieldUIControllerTrait: This trait must be used on instances of Cake\\Controller\\Controller.')); } elseif (!isset($requestParams['prefix']) || strtolower($requestParams['prefix']) !== 'admin') { throw new ForbiddenException(__d('field', 'FieldUIControllerTrait: This trait must be used on backend-controllers only.')); } $this->_tableAlias = Inflector::underscore($this->_table->alias()); }
/** * Returns data and options prepared to validate and marshall. * * @param array $data The data to prepare. * @param array $options The options passed to this marshaller. * @return array An array containing prepared data and options. */ protected function _prepareDataAndOptions($data, $options) { $options += ['validate' => true]; $tableName = $this->_table->alias(); if (isset($data[$tableName])) { $data = $data[$tableName]; } $data = new \ArrayObject($data); $options = new \ArrayObject($options); $this->_table->dispatchEvent('Model.beforeMarshal', compact('data', 'options')); return [(array) $data, (array) $options]; }
/** * Find or create new draft database entry and return entity ID * * @param \Cake\ORM\Table $table Table instance * @param array|null $conditions Find conditions * * @return int $id Draft Id */ public function getDraftId(Table $table, $conditions = []) { $conditions = array_merge($this->config[$table->alias()]['conditions'], $conditions); $result = $table->find()->select(['id' => $table->primaryKey()])->andWhere($conditions)->first(); if ($result) { return $result->id; } else { $entity = $table->newEntity($conditions, ['validate' => false]); $entity = $table->save($entity); return $entity->id; } }
/** * 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); }
public function increment(Table $table, $counter, $identifier) { list($alias, $field) = $this->_counterSplit($counter); $key = $table->primaryKey(); if ($table->alias() !== $alias) { $key = $table->{$alias}->bindingKey(); $table = TableRegistry::get($alias); } $expression = new QueryExpression("{$field} = {$field} + " . $this->_offset); $conditions = [$key => $identifier] + $this->_conditions; return $table->updateAll($expression, $conditions); }
/** * Construct the class and setup the defaults * * @param Table $table Instance of the table * @param Entity $entity Instance of the entity data * @param string $field The name of the upload field * @param array $settings Array of settings for the upload field */ public function __construct(Table $table, Entity $entity, $field, array $settings) { if (isset($settings['root'])) { $this->setRoot($settings['root']); } else { $this->setRoot(WWW_ROOT . 'files'); } $this->setTable($table->alias()); $this->setField($field); $this->setSeed($this->generateSeed($entity->get($settings['dir']))); if (isset($settings['thumbnailSizes'])) { $this->setPrefixes($settings['thumbnailSizes']); } $this->setFilename($entity->get($field)); }
/** * Implementation of the beforeSave event, handles uploading / saving and overwriting of image records. * * @param Event $event Event object. * @param Entity $entity Entity object. * @param \ArrayObject $options Options array. * @return void */ public function beforeSave(Event $event, Entity $entity, \ArrayObject $options) { $fields = $this->config('fields'); $alias = $this->_table->alias(); $options['associated'] = [$this->_imagesTable->alias() => ['validate' => false]] + $options['associated']; $entities = []; foreach ($fields as $fieldName => $fieldType) { $uploadedImages = []; $field = $entity->get($fieldName); $field = $fieldType == 'one' ? [$field] : $field; foreach ($field as $image) { $result = array(); if (!empty($image['tmp_name'])) { $result = $this->_upload($image['name'], $image['tmp_name'], false); } elseif (is_string($image)) { $result = $this->_upload($image, $image, true); } if (!empty($result)) { $uploadedImages[] = $result + ['model' => $alias, 'field' => $fieldName]; } } if (!empty($uploadedImages)) { if (!$entity->isNew() && $fieldType == 'one') { $preexisting = $this->_imagesTable->find()->where(['model' => $alias, 'field' => $fieldName, 'foreign_key' => $entity->id])->bufferResults(false); foreach ($preexisting as $index => $image) { $this->_imagesTable->delete($image); } } foreach ($uploadedImages as $image) { $entities[] = $this->_imagesTable->newEntity($image); } } $entity->dirty($fieldName, true); } $entity->set('_images', $entities); }
/** * beforeDelete callback * * Prevent delete if the record is global * Prevent delete if the record belongs to another tenant * * @param \Cake\Event\Event $event The beforeDelete event that was fired. * @param \Cake\ORM\Entity $entity The entity that was saved. * @return void */ public function beforeDelete(Event $event, Entity $entity, $options) { if (MTApp::getContext() == 'tenant') { $field = $this->config('foreign_key_field'); //tenant cannot delete global records if he is not the onwer of the global tenant if ($entity->{$field} == $this->config('global_value') && MTapp::tenant()->id != $this->config('global_value')) { return false; } //paranoid check of ownership if ($entity->{$field} != MTApp::tenant()->id) { //current tenant is NOT owner throw new DataScopeViolationException('Tenant->id:' . MTApp::tenant()->id . ' does not own ' . $this->_table->alias() . '->id:' . $entity->id); } } return true; }
/** * Sets or instantiates the user model class. * * @param mixed $table * @throws \RuntimeException * @return void */ public function setUserTable($table = null) { if ($table === null) { $this->UserTable = $this->_controller->{$this->_controller->modelClass}; } else { if (is_object($table)) { if (!is_a($table, '\\Cake\\ORM\\Table')) { throw new \RuntimeException('Passed object is not of type \\Cake\\ORM\\Table!'); } $this->UserTable = $table->alias(); } if (is_string($table)) { $this->UserTable = TableRegistry::get($table); } } $this->_controller->set('userTable', $this->UserTable->alias()); }
public function increment(Table $table, $counter, $identifier) { list($alias, $field) = $this->_counterSplit($counter); $key = $table->primaryKey(); if ($table->alias() !== $alias) { $key = $table->{$alias}->bindingKey(); $table = TableRegistry::get($alias); } if (!$this->_cache->read($counter)) { $options = ['fields' => [$field]]; $this->_cache->write($counter, $table->get($identifier, $options)->{$field}); } $count = $this->_cache->increment($counter, $this->_offset); if (!($count % $this->_threshold)) { return; } $table->updateAll([$field => $count], [$key => $identifier]); }
/** * Constructor * * @param \Cake\ORM\Query $query Query from where results come * @param \Cake\Database\StatementInterface $statement The statement to fetch from */ public function __construct($query, $statement) { $repository = $query->repository(); $this->_statement = $statement; $this->_driver = $query->connection()->driver(); $this->_defaultTable = $query->repository(); $this->_calculateAssociationMap($query); $this->_hydrate = $query->hydrate(); $this->_entityClass = $repository->entityClass(); $this->_useBuffering = $query->bufferResults(); $this->_defaultAlias = $this->_defaultTable->alias(); $this->_calculateColumnMap($query); $this->_calculateTypeMap(); if ($this->_useBuffering) { $count = $this->count(); $this->_results = new SplFixedArray($count); } }
/** * Generate a mock of the ProfferPath class with various set returns to ensure that the path is always consistent * * @param Table $table Instance of the table * @param Entity $entity Instance of the entity * @return \PHPUnit_Framework_MockObject_MockObject */ private function getProfferPathMock(Table $table, Entity $entity) { $path = $this->getMockBuilder('Proffer\\Lib\\ProfferPath')->setConstructorArgs([$table, $entity, 'photo', $this->config['photo']])->setMethods(['fullPath', 'getFolder'])->getMock(); $path->expects($this->any())->method('fullPath')->with($this->logicalOr($this->equalTo(null), $this->equalTo('square'), $this->equalTo('portrait')))->will($this->returnCallback(function ($param) use($table, $entity) { $filename = ''; if ($param !== null) { $filename = $param . '_'; } $entityFieldData = $entity->get('photo'); if (is_array($entityFieldData)) { $filename .= $entityFieldData['name']; } else { $filename .= $entityFieldData; } return TMP . 'ProfferTests' . DS . $table->alias() . DS . 'photo' . DS . 'proffer_test' . DS . $filename; })); $path->expects($this->any())->method('getFolder')->willReturn(TMP . 'ProfferTests' . DS . $table->alias() . DS . 'photo' . DS . 'proffer_test' . DS); return $path; }
public function findPath(Query $query, array $options) { if (empty($options['for'])) { throw new \InvalidArgumentException("The 'for' key is required for find('path')"); } $for = $options['for']; $ancestor_table = $this->getAncestorTable($this->_table); $model_alias = $this->_table->alias(); $ancestor_table->belongsTo($model_alias, ['className' => $model_alias, 'foreignKey' => 'ancestor_id', 'propertyName' => 'linked_node']); $query = $ancestor_table->find(); $query->contain([$model_alias]); $query->order(['level' => 'asc']); $query->where(['node_id' => $for]); $nodes = []; foreach ($query as $ancestor_entity) { $nodes[] = $ancestor_entity->linked_node; } $nodes_collections = new \Cake\Collection\Collection($nodes); return $nodes_collections; }
/** * Helper method used to generated multiple translated field entities * out of the data found in the `_translations` property in the passed * entity. The result will be put into its `_i18n` property * * @param \Cake\ORM\Entity $entity Entity * @return void */ protected function _bundleTranslatedFields($entity) { $translations = (array) $entity->get('_translations'); if (empty($translations) && !$entity->dirty('_translations')) { return; } $fields = $this->_config['fields']; $primaryKey = (array) $this->_table->primaryKey(); $key = $entity->get(current($primaryKey)); $find = []; foreach ($translations as $lang => $translation) { foreach ($fields as $field) { if (!$translation->dirty($field)) { continue; } $find[] = ['locale' => $lang, 'field' => $field, 'foreign_key' => $key]; $contents[] = new Entity(['content' => $translation->get($field)], ['useSetters' => false]); } } if (empty($find)) { return; } $results = $this->_findExistingTranslations($find); $alias = $this->_table->alias(); foreach ($find as $i => $translation) { if (!empty($results[$i])) { $contents[$i]->set('id', $results[$i], ['setter' => false]); $contents[$i]->isNew(false); } else { $translation['model'] = $alias; $contents[$i]->set($translation, ['setter' => false, 'guard' => false]); $contents[$i]->isNew(true); } } $entity->set('_i18n', $contents); }
/** * Merges `$data` into `$entity` and recursively does the same for each one of * the association names passed in `$options`. When merging associations, if an * entity is not present in the parent entity for a given association, a new one * will be created. * * When merging HasMany or BelongsToMany associations, all the entities in the * `$data` array will appear, those that can be matched by primary key will get * the data merged, but those that cannot, will be discarded. * * ### Options: * * * associated: Associations listed here will be marshalled as well. * * fieldList: A whitelist of fields to be assigned to the entity. If not present * the accessible fields list in the entity will be used. * * @param \Cake\Datasource\EntityInterface $entity the entity that will get the * data merged in * @param array $data key value list of fields to be merged into the entity * @param array $options List of options. * @return \Cake\Datasource\EntityInterface */ public function merge(EntityInterface $entity, array $data, array $options = []) { $propertyMap = $this->_buildPropertyMap($options); $tableName = $this->_table->alias(); if (isset($data[$tableName])) { $data = $data[$tableName]; } $schema = $this->_table->schema(); $properties = []; foreach ($data as $key => $value) { $columnType = $schema->columnType($key); $original = $entity->get($key); if (isset($propertyMap[$key])) { $assoc = $propertyMap[$key]['association']; $value = $this->_mergeAssociation($original, $assoc, $value, $propertyMap[$key]); } elseif ($columnType) { $converter = Type::build($columnType); $value = $converter->marshal($value); $isObject = is_object($value); if (!$isObject && $original === $value || $isObject && $original == $value) { continue; } } $properties[$key] = $value; } if (!isset($options['fieldList'])) { $entity->set($properties); return $entity; } foreach ((array) $options['fieldList'] as $field) { if (isset($properties[$field])) { $entity->set($field, $properties[$field]); } } return $entity; }