Skip to content
Permalink
Browse files

Add getByProperty and refactor association handling in EntityContext

Add a way to get associations by property name. This allows other parts
of the framework to operate on associations knowing only the property
names.
  • Loading branch information...
markstory committed Feb 1, 2014
1 parent 5cdef0d commit 1532032f6e7834625b06c6ef5cd5cb48ab22fc8e
@@ -62,6 +62,21 @@ public function get($alias) {
return null;
}
/**
* Fetch an association by property name.
*
* @param string $prop The property to find an association by.
* @return Association|null Either the association or null.
*/
public function getByProperty($prop) {
foreach ($this->_items as $assoc) {
if ($assoc->property() === $prop) {
return $assoc;
}
}
return null;
}
/**
* Check for an attached association by name.
*
@@ -17,6 +17,7 @@
use Cake\Network\Request;
use Cake\ORM\Entity;
use Cake\ORM\TableRegistry;
use Cake\Utility\Inflector;
use Cake\Validation\Validator;
use Traversable;
@@ -33,11 +34,10 @@
* from, an array of table instances in the case of an form spanning
* multiple entities, or the name(s) of the table.
* If this is null the table name(s) will be determined using conventions.
* This table object will be used to fetch the schema and
* validation information.
* - `validator` Either the Validation\Validator to use, or the name of the
* validation method to call on the table object. For example 'default'.
* Defaults to 'default'.
* Defaults to 'default'. Can be an array of table alias=>validators when
* dealing with associated forms.
*/
class EntityContext {
@@ -56,19 +56,11 @@ class EntityContext {
protected $_context;
/**
* The plural name of the top level entity/table object.
* The name of the top level entity/table object.
*
* @var string
*/
protected $_pluralName;
/**
* A dictionary of validators and their
* related tables.
*
* @var array
*/
protected $_validators = [];
protected $_rootName;
/**
* A dictionary of tables
@@ -87,9 +79,8 @@ public function __construct(Request $request, array $context) {
$this->_request = $request;
$context += [
'entity' => null,
'schema' => null,
'table' => null,
'validator' => null
'validator' => [],
];
$this->_context = $context;
$this->_prepare();
@@ -101,21 +92,12 @@ public function __construct(Request $request, array $context) {
* @return void
*/
protected function _prepare() {
$table = null;
// TODO handle the other cases (string, array, instance)
if (is_string($this->_context['table'])) {
$plural = $this->_context['table'];
}
$table = TableRegistry::get($plural);
if (is_object($this->_context['validator'])) {
$this->_validators['_default'] = $this->_context['validator'];
} elseif (is_string($this->_context['validator'])) {
$this->_validators['_default'] = $table->validator($this->_context['validator']);
$table = $this->_context['table'];
if (is_string($table)) {
$table = TableRegistry::get($table);
}
$this->_pluralName = $plural;
$this->_tables[$plural] = $table;
$alias = $this->_rootName = $table->alias();
$this->_tables[$alias] = $table;
}
/**
@@ -131,7 +113,7 @@ public function val($field) {
return null;
}
$parts = explode('.', $field);
$entity = $this->_getEntity($parts);
list($entity, $prop) = $this->_getEntity($parts);
if (!$entity) {
return null;
}
@@ -146,31 +128,35 @@ public function val($field) {
* will be returned.
*
* @param array $path The path to traverse to find the leaf entity.
* @return boolean|Entity Either the leaf entity or false.
* @return array
*/
protected function _getEntity($path) {
$entity = $this->_context['entity'];
if (count($path) === 1) {
return $entity;
return [$entity, $this->_rootName];
}
// Remove the Table name if present.
if (count($path) > 1 && $path[0] === $this->_pluralName) {
if (count($path) > 1 && $path[0] === $this->_rootName) {
array_shift($path);
}
$lastProp = $this->_rootName;
foreach ($path as $prop) {
$next = $this->_getProp($entity, $prop);
if (
!is_array($next) &&
!($next instanceof Traversable) &&
!($next instanceof Entity)
) {
return $entity;
return [$entity, $lastProp];
}
if (!is_numeric($prop)) {
$lastProp = $prop;
}
$entity = $next;
}
return false;
return [false, false];
}
/**
@@ -191,7 +177,6 @@ protected function _getProp($target, $field) {
return $target->get($field);
}
/**
* Check if a field should be marked as required.
*
@@ -203,13 +188,17 @@ public function isRequired($field) {
return false;
}
$parts = explode('.', $field);
$entity = $this->_getEntity($parts);
list($entity, $prop) = $this->_getEntity($parts);
if (!$entity) {
return false;
}
$validator = $this->_getValidator($prop);
if (!$validator) {
return false;
}
$field = array_pop($parts);
$validator = $this->_getValidator($entity);
if (!$validator->hasField($field)) {
return false;
}
@@ -221,19 +210,44 @@ public function isRequired($field) {
* Get the validator associated to an entity based on naming
* conventions.
*
* If no match is found the `_root` validator will be used.
*
* @param Cake\ORM\Entity $entity
* @return Validator
* @param string $entity The entity name to get a validator for.
* @return Validator|false
*/
protected function _getValidator($entity) {
list($ns, $entityClass) = namespaceSplit(get_class($entity));
if (isset($this->_validators[$entityClass])) {
return $this->_validators[$entityClass];
$table = $this->_getTable($entity);
$alias = $table->alias();
$method = 'default';
if (is_string($this->_context['validator'])) {
$method = $this->_context['validator'];
} elseif (isset($this->_context['validator'][$alias])){
$method = $this->_context['validator'][$alias];
}
if (isset($this->_validators['_default'])) {
return $this->_validators['_default'];
return $table->validator($method);
}
/**
* Get the table instance
*
* @param string $prop The property name to get a table for.
* @return Cake\ORM\Table The table instance.
*/
protected function _getTable($prop) {
if (isset($this->_tables[$prop])) {
return $this->_tables[$prop];
}
$root = $this->_tables[$this->_rootName];
$assoc = $root->associations()->getByProperty($prop);
// No assoc, use the default table to prevent
// downstream failures.
if (!$assoc) {
return $root;
}
$target = $assoc->target();
$this->_tables[$prop] = $target;
return $target;
}
public function type($field) {
@@ -62,6 +62,20 @@ public function testAddHasRemoveAndGet() {
$this->assertNull($this->associations->get('Users'));
}
/**
* Test getting associations by property.
*
* @return void
*/
public function testGetByProperty() {
$belongsTo = new BelongsTo('Users', []);
$this->assertEquals('user', $belongsTo->property());
$this->associations->add('Users', $belongsTo);
$this->assertNull($this->associations->get('user'));
$this->assertSame($belongsTo, $this->associations->getByProperty('user'));
}
/**
* Test associations with plugin names.
*
Oops, something went wrong.

0 comments on commit 1532032

Please sign in to comment.
You can’t perform that action at this time.