Skip to content

Commit

Permalink
Start to implement isRequired for the EntityContext.
Browse files Browse the repository at this point in the history
Do some refactoring around entity location and validator handling.
  • Loading branch information
markstory committed Feb 2, 2014
1 parent 20b9b01 commit ccd4b8c
Show file tree
Hide file tree
Showing 2 changed files with 137 additions and 11 deletions.
104 changes: 93 additions & 11 deletions src/View/Form/EntityContext.php
Expand Up @@ -54,8 +54,21 @@ class EntityContext {
*/ */
protected $_context; protected $_context;


/**
* The plural name of the top level entity/table object.
*
* @var string
*/
protected $_pluralName; protected $_pluralName;


/**
* A dictionary of validators and their
* related tables.
*
* @var array
*/
protected $_validators = [];

/** /**
* Constructor. * Constructor.
* *
Expand All @@ -80,11 +93,16 @@ public function __construct(Request $request, array $context) {
* @return void * @return void
*/ */
protected function _prepare() { protected function _prepare() {
$table = null;
// TODO handle the other cases (string, array, instance) // TODO handle the other cases (string, array, instance)
if (is_string($this->_context['table'])) { if (is_string($this->_context['table'])) {
$plural = $this->_context['table']; $plural = $this->_context['table'];
} }
$this->_pluralName = $plural; $this->_pluralName = $plural;

if (is_object($this->_context['validator'])) {
$this->_validators['_default'] = $this->_context['validator'];
}
} }


/** /**
Expand All @@ -100,24 +118,46 @@ public function val($field) {
return null; return null;
} }
$parts = explode('.', $field); $parts = explode('.', $field);
$entity = $this->_getEntity($parts);
if (!$entity) {
return null;
}
return $entity->get(array_pop($parts));
}

/**
* Fetch the leaf entity for the given path.
*
* This method will traverse the given path and find the leaf
* entity. If the path does not contain a leaf entity false
* will be returned.
*
* @param array $path The path to traverse to find the leaf entity.
* @return boolean|Entity Either the leaf entity or false.
*/
protected function _getEntity($path) {
$entity = $this->_context['entity'];
if (count($path) === 1) {
return $entity;
}


// Remove the model name if present. // Remove the Table name if present.
if (count($parts) > 1 && $parts[0] === $this->_pluralName) { if (count($path) > 1 && $path[0] === $this->_pluralName) {
array_shift($parts); array_shift($path);
} }


$val = $this->_context['entity']; foreach ($path as $prop) {
foreach ($parts as $prop) { $next = $this->_getProp($entity, $prop);
$val = $this->_getProp($val, $prop);
if ( if (
!is_array($val) && !is_array($next) &&
!($val instanceof Traversable) && !($next instanceof Traversable) &&
!($val instanceof Entity) !($next instanceof Entity)
) { ) {
return $val; return $entity;
} }
$entity = $next;
} }
return $val; return false;
} }


/** /**
Expand All @@ -138,7 +178,49 @@ protected function _getProp($target, $field) {
return $target->get($field); return $target->get($field);
} }



/**
* Check if a field should be marked as required.
*
* @param string $field The dot separated path to the field you want to check.
* @return boolean
*/
public function isRequired($field) { public function isRequired($field) {
if (empty($this->_context['validator'])) {
return false;
}
$parts = explode('.', $field);
$entity = $this->_getEntity($parts);
if (!$entity) {
return false;
}

$field = array_pop($parts);
$validator = $this->_getValidator($entity);
if (!$validator->hasField($field)) {
return false;
}
$allowed = $validator->isEmptyAllowed($field, $entity->isNew());
return $allowed === false;
}

/**
* 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
*/
protected function _getValidator($entity) {
list($ns, $entityClass) = namespaceSplit(get_class($entity));
if (isset($this->_validators[$entityClass])) {
return $this->_validators[$entityClass];
}
if (isset($this->_validators['_default'])) {
return $this->_validators['_default'];
}
} }


public function type($field) { public function type($field) {
Expand Down
44 changes: 44 additions & 0 deletions tests/TestCase/View/Form/EntityContextTest.php
Expand Up @@ -16,6 +16,7 @@


use Cake\ORM\Entity; use Cake\ORM\Entity;
use Cake\ORM\Table; use Cake\ORM\Table;
use Cake\ORM\TableRegistry;
use Cake\Network\Request; use Cake\Network\Request;
use Cake\TestSuite\TestCase; use Cake\TestSuite\TestCase;
use Cake\View\Form\EntityContext; use Cake\View\Form\EntityContext;
Expand Down Expand Up @@ -122,4 +123,47 @@ public function testValAssociated() {
$this->assertNull($result); $this->assertNull($result);
} }


/**
* Test isRequired in basic scenarios.
*
* @return void
*/
public function testIsRequired() {
$articles = TableRegistry::get('Articles');

$validator = $articles->validator();
$validator->add('title', 'minlength', [
'rule' => ['minlength', 10]
])
->add('body', 'maxlength', [
'rule' => ['maxlength', 1000]
])->allowEmpty('body');

$context = new EntityContext($this->request, [
'entity' => new Entity(),
'table' => 'Articles',
'validator' => $validator
]);

$this->assertTrue($context->isRequired('Articles.title'));
$this->assertTrue($context->isRequired('title'));
$this->assertFalse($context->isRequired('Articles.body'));
$this->assertFalse($context->isRequired('body'));

$this->assertFalse($context->isRequired('Herp.derp.derp'));
$this->assertFalse($context->isRequired('nope'));
}

public function testIsRequiredCustomValidationMethod() {
$this->markTestIncomplete();
}

public function testIsRequiredAssociated() {
$this->markTestIncomplete();
}

public function testIsRequiredAssociatedValidator() {
$this->markTestIncomplete();
}

} }

0 comments on commit ccd4b8c

Please sign in to comment.