Skip to content

Instantly share code, notes, and snippets.

@VaclavSir
Created February 14, 2013 11:50
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save VaclavSir/4952313 to your computer and use it in GitHub Desktop.
Save VaclavSir/4952313 to your computer and use it in GitHub Desktop.
EntityFormBuilder
<?php
namespace VS\UI;
/**
* Simple form generator for plain old data objects.
*
* Creates a field for each scalar setter. Nothing more.
*
* @author Václav Šír
*/
class EntityFormBuilder extends \Nette\Object
{
/**
* @param \Nette\Forms\Form $form
* @param object $entity
*/
public function build(\Nette\Forms\Form $form, $entity)
{
$classType = \Nette\Reflection\ClassType::from($entity);
$methods = $classType->getMethods(\ReflectionMethod::IS_PUBLIC);
$fieldNames = array();
foreach ($methods as $method) {
if ($this->isSuitableSetter($method)) {
// Field creation
$fieldName = substr($method->name, 3);
$type = $this->getFirstParameterType($method);
$caption = "$fieldName: ";
switch ($type) {
case 'bool':
case 'boolean':
$form->addCheckbox($fieldName, $caption);
break;
default:
$form->addTextArea($fieldName, $caption, 40, 3);
break;
}
$fieldNames[] = $fieldName;
// Assign default value
$getterName = 'get' . $fieldName;
$defaultValue = $classType->hasMethod($getterName)
? $classType->getMethod($getterName)->invoke($entity)
: null;
$form[$fieldName]->setDefaultValue($defaultValue);
}
}
$form->onSuccess[] = new EntityFormBuilder_OnSuccessCallback($entity, $fieldNames);
}
private function isSuitableSetter(\Nette\Reflection\Method $method)
{
$parameters = $method->getParameters();
$typeOfTheParameter = $this->getFirstParameterType($method);
return substr($method->name, 0, 3) === 'set'
&& count($parameters) === 1
&& $parameters[0]->getClass() === null
&& $typeOfTheParameter !== 'array'
&& $typeOfTheParameter !== 'object'
&& !\Nette\Utils\Strings::endsWith($typeOfTheParameter, '[]')
&& !class_exists($typeOfTheParameter);
}
private function getFirstParameterType(\Nette\Reflection\Method $method)
{
$parameters = $method->getParameters();
if (empty($parameters)) { return null; }
if ($typehintedClass = $parameters[0]->getClassName()) { return $typehintedClass; }
if ($parameters[0]->isArray()) { return 'array'; }
if ($annotation = $method->getAnnotation('param')) {
$splits = preg_split('~[|\s]+~', $annotation, 2);
return array_shift($splits);
}
return 'mixed';
}
}
<?php
namespace VS\UI;
/**
* @author Václav Šír
*/
class EntityFormBuilder_OnSuccessCallback extends \Nette\Object
{
private $entity;
private $fieldNames;
public function __construct($entity, $fieldNames)
{
$this->entity = $entity;
$this->fieldNames = $fieldNames;
}
public function __invoke(\Nette\Forms\Form $form)
{
$values = $form->getValues();
foreach ($this->fieldNames as $fieldName) {
$setterName = "set$fieldName";
try {
$this->entity->$setterName($values[$fieldName]);
} catch (\Exception $e) {
$form[$fieldName]->addError(get_class($e) . ': ' . $e->getMessage());
}
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment