Skip to content

Commit

Permalink
Added virtual Element - TODO: clean all this up
Browse files Browse the repository at this point in the history
  • Loading branch information
Gary Tierney committed Jun 19, 2014
1 parent 1d77ce1 commit cc22c57
Show file tree
Hide file tree
Showing 4 changed files with 132 additions and 13 deletions.
3 changes: 2 additions & 1 deletion composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
},

"require": {
"symfony/Validator" : "*"
"symfony/Validator" : "2.2.*"
},

"require-dev": {
Expand All @@ -14,3 +14,4 @@

"minimum-stability": "dev"
}

11 changes: 7 additions & 4 deletions src/Element/Element.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
namespace PPI\Form\Element;

use Symfony\Component\Validator\Constraint;
use Symfony\Component\Validator\Validator\ValidatorInterface;
use Symfony\Component\Validator\ValidatorInterface;

abstract class Element implements ElementInterface
{
Expand Down Expand Up @@ -175,12 +175,13 @@ public function getConstraints()
* @todo garyttierney - do we want the Form to handle validation for every input or should that be left to an element?
* if the latter, we should share a single Validator object between all of them.
*
* @param $input string|array
* @return ElementValidationResult
*/
public function validate(ValidatorInterface $validator)
public function validate($input, ValidatorInterface $validator)
{
// @todo - note, this will be removed in Symfony 3.0 and there's currently no way around that
$validatorResult = $validator->validateValue($this->getValue(), $this->getConstraints());
$validatorResult = $validator->validateValue($input, $this->getConstraints());
if(count($validatorResult) === 0) {
return new ElementValidationResult(true);
} else {
Expand All @@ -192,10 +193,12 @@ public function validate(ValidatorInterface $validator)
}
}

/**
/*
*
* Set element options
*
* @param array $options
*
*/
public function setOptions($options)
{
Expand Down
54 changes: 54 additions & 0 deletions src/Element/Virtual.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
<?php


namespace PPI\Form\Element;

/**
* An abstract Element which encapsulates the rendering of several inputs and transforms the independent data into something
* suitable for validation.
*
* Class Virtual
* @package PPI\Form\Element
*/
abstract class Virtual extends Element
{
protected $elements = array();

public function addElement(Element $element)
{
$this->elements[] = $element;
}

public function __construct($options = array())
{
parent::__construct($options);
}

/**
* Render the tag
*
* @return string
*/
public function render()
{
$parts = array();

foreach($this->elements as $element) {
$parts[] = $element->render();
}

return implode("\n", $parts);
}

/**
* Takes an array of input and returns a string. Should be used when you have 2 elements which should be concatenated into 1 variable.
*
* For example, if you want a TimeElement which allows the user to choose hours via a select element, and minutes via a select element
* then you should get the input as an array (input_x[0] -- hours, input_x[1] -- minutes) and implement this method
* to join both of those inputs.
*
* @param array $data
* @return string
*/
public abstract function transformInput(array $data);
}
77 changes: 69 additions & 8 deletions src/Form.php
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@

use PPI\Form\Element\Element;
use PPI\Form\Element\ElementInterface;
use PPI\Form\Element\Label;
use PPI\Form\Element\Virtual;
use Symfony\Component\Validator\Validation;

class Form
Expand Down Expand Up @@ -132,7 +134,7 @@ public function submit($name, $value = 'Submit', array $options = array())
*/
public function hidden($name, array $options = array())
{
return $this->add($name, 'hidden', $options);
return $this->add('hidden', 'hidden', $options);
}

/**
Expand Down Expand Up @@ -342,28 +344,87 @@ public function end()
return '</form>';
}


/**
* Validates all input elements within a form with their constraints. Returns a hashtable of element names mapped
* to an array of their error messages as described in {@link ElementValidationResult::getErrorMessages}
*
* @return array
* @param array $input The clients POST data
*
* @return array An array of error messages keyed by element name
*/
public function validate()
public function validate(array $input)
{
$validator = Validation::createValidator();
$errors = array();

/**
* @var $element Element
*/
foreach($this->elements as $elementName => $element) {
$validationResult = $element->validate($validator);
if($validationResult->isSuccessful()) {
foreach($this->elements as $key => $element) {
if($element instanceof Label) {
continue;
}

$errors[$elementName] = $validationResult->getErrorMessages();
if(substr($key, -2) == "[]") {
$elementName = substr($key, 0, -2);
} else {
$elementName = $key;
}

if(count($element->getConstraints()) > 0) {
$value = array_key_exists($elementName, $input) ? $input[$elementName] : null; // map elements with no value to null
if(is_array($value) && $element instanceof Virtual) {
$value = $element->transformData($value);
}

$validationResult = $element->validate($value, $validator);

if ($validationResult->isSuccessful()) {
continue;
}

$errors[$elementName] = $validationResult->getErrorMessages();
}
}
return $errors;

$this->errorMessages = $errors;

return count($errors) == 0;
}

protected $errorMessages = array();

public function getErrorsForElement(Element $element)
{
return $this->errorMessages[$element->getName()];
}

public function hasErrorsForElement(Element $element)
{
return array_key_exists($element->getName(), $this->errorMessages);
}

/**
* Takes an $input an array and checks if the input key corresponds to a Virtual element, if it does then it calls
* the {@see Virtual::transformInput} function to make the input value good for validation.
*
* @param array $input An array of $_POSTed variables.
*/
public function transformInput(array $input)
{
$output = array();

foreach($input as $key => $val) {
if(array_key_exists($key, $this->elements) && $this->elements[$key] instanceof Virtual) {
if (is_array($input)) {
$output[$key] = $this->elements[$key]->transformInput($val);
}
} else {
$output[$key] = $val;
}
}

return $output;
}
}

0 comments on commit cc22c57

Please sign in to comment.