Skip to content

Commit

Permalink
Implement a FormHelper context class for Form\Form.
Browse files Browse the repository at this point in the history
This allows FormHelper to work with Form instances.
  • Loading branch information
markstory committed Dec 20, 2014
1 parent 278a40b commit d43ac71
Show file tree
Hide file tree
Showing 2 changed files with 340 additions and 0 deletions.
136 changes: 136 additions & 0 deletions src/View/Form/FormContext.php
@@ -0,0 +1,136 @@
<?php
/**
* CakePHP(tm) : Rapid Development Framework (http://cakephp.org)
* Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
*
* Licensed under The MIT License
* For full copyright and license information, please see the LICENSE.txt
* Redistributions of files must retain the above copyright notice.
*
* @copyright Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
* @link http://cakephp.org CakePHP(tm) Project
* @since 3.0.0
* @license http://www.opensource.org/licenses/mit-license.php MIT License
*/
namespace Cake\View\Form;

use Cake\Form\Form;
use Cake\Network\Request;
use Cake\View\Form\ContextInterface;

/**
* Provides a context provider for Cake\Form\Form instances.
*
* This context provider simply fulfils the interface requirements
* that FormHelper has and allows access to the request data.
*/
class FormContext implements ContextInterface {

/**
* The request object.
*
* @var \Cake\Network\Request
*/
protected $_request;

/**
* Constructor.
*
* @param \Cake\Network\Request $request The request object.
* @param array $context Context info.
*/
public function __construct(Request $request, array $context) {
$this->_request = $request;
$context += [
'entity' => null,
];
$this->_form = $context['entity'];
}

/**
* {@inheritDoc}
*/
public function primaryKey() {
return [];
}

/**
* {@inheritDoc}
*/
public function isPrimaryKey($field) {
return false;
}

/**
* {@inheritDoc}
*/
public function isCreate() {
return true;
}

/**
* {@inheritDoc}
*/
public function val($field) {
return $this->_request->data($field);
}

/**
* {@inheritDoc}
*/
public function isRequired($field) {
$validator = $this->_form->validator();
if (!$validator->hasField($field)) {
return false;
}
if ($this->type($field) !== 'boolean') {
return $validator->isEmptyAllowed($field, true) === false;
}
return false;
}

/**
* {@inheritDoc}
*/
public function fieldNames() {
$schema = $this->_form->schema();
return $schema->fields();
}

/**
* {@inheritDoc}
*/
public function type($field) {
$schema = $this->_form->schema();
return $schema->fieldType($field);
}

/**
* {@inheritDoc}
*/
public function attributes($field) {
$column = (array)$this->_form->schema()->field($field);
$whitelist = ['length' => null, 'precision' => null];
return array_intersect_key($column, $whitelist);
}

/**
* {@inheritDoc}
*/
public function hasError($field) {
$errors = $this->error($field);
return count($errors) > 0;
}

/**
* {@inheritDoc}
*/
public function error($field) {
$errors = $this->_form->errors();
if (isset($errors[$field])) {
return array_values($errors[$field]);
}
return [];
}

}
204 changes: 204 additions & 0 deletions tests/TestCase/View/Form/FormContextTest.php
@@ -0,0 +1,204 @@
<?php
/**
* CakePHP(tm) : Rapid Development Framework (http://cakephp.org)
* Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
*
* Licensed under The MIT License
* For full copyright and license information, please see the LICENSE.txt
* Redistributions of files must retain the above copyright notice.
*
* @copyright Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
* @link http://cakephp.org CakePHP(tm) Project
* @since 3.0.0
* @license http://www.opensource.org/licenses/mit-license.php MIT License
*/
namespace Cake\Test\TestCase\View\Form;

use Cake\Form\Form;
use Cake\Network\Request;
use Cake\TestSuite\TestCase;
use Cake\View\Form\FormContext;

/**
* Form context test case.
*/
class FormContextTest extends TestCase {

/**
* setup method.
*
* @return void
*/
public function setUp() {
parent::setUp();
$this->request = new Request();
}

/**
* Test getting the primary key.
*
* @return void
*/
public function testPrimaryKey() {
$context = new FormContext($this->request, ['entity' => new Form()]);
$this->assertEquals([], $context->primaryKey());
}

/**
* Test isPrimaryKey.
*
* @return void
*/
public function testIsPrimaryKey() {
$context = new FormContext($this->request, ['entity' => new Form()]);
$this->assertFalse($context->isPrimaryKey('id'));
}

/**
* Test the isCreate method.
*
* @return void
*/
public function testIsCreate() {
$context = new FormContext($this->request, ['entity' => new Form()]);
$this->assertTrue($context->isCreate());
}

/**
* Test reading values from the request & defaults.
*/
public function testValPresent() {
$this->request->data = [
'Articles' => [
'title' => 'New title',
'body' => 'My copy',
]
];
$context = new FormContext($this->request, ['entity' => new Form()]);
$this->assertEquals('New title', $context->val('Articles.title'));
$this->assertEquals('My copy', $context->val('Articles.body'));
$this->assertNull($context->val('Articles.nope'));
}

/**
* Test getting values when the request and defaults are missing.
*
* @return void
*/
public function testValMissing() {
$context = new FormContext($this->request, ['entity' => new Form()]);
$this->assertNull($context->val('Comments.field'));
}

/**
* Test isRequired
*
* @return void
*/
public function testIsRequired() {
$form = new Form();
$form->validator()
->requirePresence('name')
->add('email', 'format', ['rule' => 'email']);

$context = new FormContext($this->request, [
'entity' => $form
]);
$this->assertTrue($context->isRequired('name'));
$this->assertTrue($context->isRequired('email'));
$this->assertFalse($context->isRequired('body'));
$this->assertFalse($context->isRequired('Prefix.body'));
}

/**
* Test the type method.
*
* @return void
*/
public function testType() {
$form = new Form();
$form->schema()
->addField('email', 'string')
->addField('user_id', 'integer');

$context = new FormContext($this->request, [
'entity' => $form
]);
$this->assertNull($context->type('undefined'));
$this->assertEquals('integer', $context->type('user_id'));
$this->assertEquals('string', $context->type('email'));
$this->assertNull($context->type('Prefix.email'));
}

/**
* Test fetching attributes.
*
* @return void
*/
public function testAttributes() {
$form = new Form();
$form->schema()
->addField('email', [
'type' => 'string',
'length' => 10,
])
->addField('amount', [
'type' => 'decimal',
'length' => 5,
'precision' => 2,
]);
$context = new FormContext($this->request, [
'entity' => $form
]);
$this->assertEquals([], $context->attributes('id'));
$this->assertEquals(['length' => 10, 'precision' => null], $context->attributes('email'));
$this->assertEquals(['precision' => 2, 'length' => 5], $context->attributes('amount'));
}

/**
* Test fetching errors.
*
* @return void
*/
public function testError() {
$form = new Form();
$form->validator()
->add('email', 'format', ['rule' => 'email'])
->add('name', 'length', ['rule' => ['minLength', 10]]);
$form->validate([
'email' => 'derp',
'name' => 'derp'
]);

$context = new FormContext($this->request, ['entity' => $form]);
$this->assertEquals([], $context->error('empty'));
$this->assertEquals(['The provided value is invalid'], $context->error('email'));
$this->assertEquals(['The provided value is invalid'], $context->error('name'));

$this->assertEquals([], $context->error('Alias.name'));
$this->assertEquals([], $context->error('nope.nope'));
}

/**
* Test checking errors.
*
* @return void
*/
public function testHasError() {
$form = new Form();
$form->validator()
->add('email', 'format', ['rule' => 'email'])
->add('name', 'length', ['rule' => ['minLength', 10]]);
$form->validate([
'email' => 'derp',
'name' => 'derp'
]);

$context = new FormContext($this->request, ['entity' => $form]);
$this->assertTrue($context->hasError('email'));
$this->assertTrue($context->hasError('name'));
$this->assertFalse($context->hasError('nope'));
$this->assertFalse($context->hasError('nope.nope'));
}

}

0 comments on commit d43ac71

Please sign in to comment.