Last active
October 7, 2015 07:48
-
-
Save bwaidelich/3130147 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
namespace TYPO3\Form\Factory; | |
/* * | |
* This script belongs to the FLOW3 package "TYPO3.Form". * | |
* * | |
* It is free software; you can redistribute it and/or modify it under * | |
* the terms of the GNU Lesser General Public License, either version 3 * | |
* of the License, or (at your option) any later version. * | |
* * | |
* The TYPO3 project - inspiring people to share! * | |
* */ | |
use TYPO3\FLOW3\Annotations as FLOW3; | |
use TYPO3\Form\Core\Model\FormDefinition; | |
use TYPO3\FLOW3\Validation\Validator as Validator; | |
/** | |
* TODO documentation, @api annotation(?) | |
*/ | |
abstract class AbstractModelFormFactory extends AbstractFormFactory { | |
/** | |
* @FLOW3\Inject | |
* @var \TYPO3\FLOW3\Reflection\ReflectionService | |
*/ | |
protected $reflectionService; | |
/** | |
* @FLOW3\Inject | |
* @var \TYPO3\FLOW3\Validation\ValidatorResolver | |
*/ | |
protected $validatorResolver; | |
/** | |
* @FLOW3\Inject | |
* @var \TYPO3\FLOW3\Persistence\PersistenceManagerInterface | |
*/ | |
protected $persistenceManager; | |
/** | |
* @var FormDefinition | |
*/ | |
protected $formDefinition; | |
/** | |
* @var array | |
*/ | |
protected $configuration = array(); | |
/** | |
* @var string | |
*/ | |
protected $objectPrefix = 'object'; | |
/** | |
* @var object | |
*/ | |
protected $targetObject = NULL; | |
/** | |
* @param array $configuration factory-specific configuration array | |
* @param string $presetName The name of the "Form Preset" to use; it is factory-specific to implement this. | |
* @return \TYPO3\Form\Core\Model\FormDefinition a newly built form definition | |
* @throws \TYPO3\Form\Exception | |
*/ | |
public function build(array $configuration, $presetName) { | |
// merge preset configuration with specified $configuration ("overrideConfiguration" argument of the render ViewHelper) | |
$this->configuration = \TYPO3\FLOW3\Utility\Arrays::arrayMergeRecursiveOverrule($this->getPresetConfiguration($presetName), $configuration); | |
$formIdentifier = sprintf('%sForm', $this->objectPrefix); | |
$this->formDefinition = new FormDefinition($formIdentifier, $this->configuration); | |
$page1 = $this->formDefinition->createPage('page1'); | |
$targetClassName = $this->getTargetClassName(); | |
// set $this->targetObject if specified | |
if (isset($this->configuration['targetObject'])) { | |
if (!$this->configuration['targetObject'] instanceof $targetClassName) { | |
throw new \TYPO3\Form\Exception(sprintf('The specified targetObject must be of type "%s", given: "%s"', $targetClassName, get_class($this->configuration['targetObject'])), 1336394809); | |
} | |
$this->targetObject = $this->configuration['targetObject']; | |
} | |
// set target type for property mapping | |
$this->formDefinition->getProcessingRule($this->objectPrefix)->setDataType($targetClassName); | |
// allow all properties to be mapped | |
$targetObjectPropertyMappingConfiguration = $this->formDefinition->getProcessingRule($this->objectPrefix)->getPropertyMappingConfiguration(); | |
$targetObjectPropertyMappingConfiguration->allowAllProperties(); | |
// set property mapping mode to modification/creation depending on $this->targetObject to be set | |
if ($this->targetObject !== NULL) { | |
$targetObjectPropertyMappingConfiguration->setTypeConverterOption('TYPO3\FLOW3\Property\TypeConverter\PersistentObjectConverter', \TYPO3\FLOW3\Property\TypeConverter\PersistentObjectConverter::CONFIGURATION_MODIFICATION_ALLOWED, TRUE); | |
$identity = $page1->createElement($this->objectPrefix . '.__identity', 'TYPO3.Form:HiddenField'); | |
$identity->setDefaultValue($this->persistenceManager->getIdentifierByObject($this->targetObject)); | |
} else { | |
$targetObjectPropertyMappingConfiguration->setTypeConverterOption('TYPO3\FLOW3\Property\TypeConverter\PersistentObjectConverter', \TYPO3\FLOW3\Property\TypeConverter\PersistentObjectConverter::CONFIGURATION_CREATION_ALLOWED, TRUE); | |
} | |
$this->createFormElements($page1); | |
// set default values and validators from the targetClassName | |
$this->setDefaultValues(); | |
$this->addValidators(); | |
// call postProcessFormValues() upon submission for further processing of the submitted values | |
$self = $this; | |
$this->formDefinition->createFinisher('TYPO3.Form:Closure')->setOption('closure', function(\TYPO3\Form\Core\Model\FinisherContext $context) use ($self) { | |
$self->postProcessFormValues($context->getFormValues()); | |
}); | |
// add more custom finishers if required | |
$this->addFinishers(); | |
return $this->formDefinition; | |
} | |
/** | |
* Implement this method and attach form elements to the $section like: | |
* $name = $section->createElement($this->objectPrefix . '.name', 'TYPO3.Form:SingleLineText'); | |
* $name->setLabel('Name'); | |
* ... | |
* | |
* @param \TYPO3\Form\Core\Model\AbstractSection $section | |
* @return void | |
*/ | |
abstract protected function createFormElements(\TYPO3\Form\Core\Model\AbstractSection $section); | |
/** | |
* Implement this method and return the fully qualified class name of your target object | |
* e.g. return 'My\Package\Domain\Model\SomeModel'; | |
* | |
* @return string | |
*/ | |
abstract protected function getTargetClassName(); | |
/** | |
* Iterates over the form elements and sets default values if possible | |
* | |
* @return void | |
*/ | |
protected function setDefaultValues() { | |
if ($this->targetObject === NULL) { | |
return; | |
} | |
$targetClassName = $this->getTargetClassName(); | |
$object = $this->targetObject !== NULL ? $this->targetObject : new $targetClassName(); | |
foreach ($this->formDefinition->getRenderablesRecursively() as $formElement) { | |
if (!$formElement instanceof FormElementInterface || $formElement->getDefaultValue() !== NULL) { | |
continue; | |
} | |
$propertyPath = substr($formElement->getIdentifier(), strlen($this->objectPrefix) + 1); | |
$formElement->setDefaultValue(ObjectAccess::getPropertyPath($object, $propertyPath)); | |
} | |
} | |
/** | |
* Uses reflection to retrieve base validation rules for the specified targetClassName | |
* | |
* @return void | |
* @throws \TYPO3\FLOW3\Validation\Exception\NoSuchValidatorException | |
*/ | |
protected function addValidators() { | |
$targetClassName = $this->getTargetClassName(); | |
foreach ($this->reflectionService->getClassPropertyNames($targetClassName) as $classPropertyName) { | |
$formElement = $this->formDefinition->getElementByIdentifier($this->objectPrefix . '.' . $classPropertyName); | |
if ($formElement === NULL) { | |
continue; | |
} | |
$validateAnnotations = $this->reflectionService->getPropertyAnnotations($targetClassName, $classPropertyName, 'TYPO3\FLOW3\Annotations\Validate'); | |
foreach ($validateAnnotations as $validateAnnotation) { | |
$newValidator = $this->validatorResolver->createValidator($validateAnnotation->type, $validateAnnotation->options); | |
if ($newValidator === NULL) { | |
throw new \TYPO3\FLOW3\Validation\Exception\NoSuchValidatorException('Invalid validate annotation in ' . $this->targetClassName . '::' . $classPropertyName . ': Could not resolve class name for validator "' . $validateAnnotation->type . '".', 1342536676); | |
} | |
$formElement->addValidator($newValidator); | |
} | |
} | |
} | |
/** | |
* Override this method if you want to post process the (already mapped) $formValue | |
* | |
* @param array $formValues | |
* @return void | |
*/ | |
public function postProcessFormValues(array $formValues) { | |
} | |
/** | |
* Override this method if you want to add custom finishers | |
* | |
* @return void | |
*/ | |
protected function addFinishers() { | |
} | |
} | |
?> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
namespace Test\FormFactories; | |
/* * | |
* This script belongs to the FLOW3 package "Yeebase.Guruhelp". * | |
* * | |
* It is free software; you can redistribute it and/or modify it under * | |
* the terms of the GNU Lesser General Public License, either version 3 * | |
* of the License, or (at your option) any later version. * | |
* * | |
* The TYPO3 project - inspiring people to share! * | |
* */ | |
use TYPO3\FLOW3\Annotations as FLOW3; | |
use TYPO3\FLOW3\Error\Message; | |
class BookFormFactory extends \TYPO3\Form\Factory\AbstractModelFormFactory { | |
/** | |
* @FLOW3\Inject | |
* @var \Test\Domain\Repository\BookRepository | |
*/ | |
protected $bookRepository; | |
/** | |
* @FLOW3\Inject | |
* @var \TYPO3\FLOW3\Mvc\FlashMessageContainer | |
*/ | |
protected $flashMessageContainer; | |
/** | |
* @param \TYPO3\Form\Core\Model\AbstractSection $section | |
* @return void | |
*/ | |
protected function createFormElements(\TYPO3\Form\Core\Model\AbstractSection $section) { | |
$title = $section->createElement($this->objectPrefix . '.title', 'TYPO3.Form:SingleLineText'); | |
$title->setLabel('Title'); | |
$price = $section->createElement($this->objectPrefix . '.price', 'TYPO3.Form:SingleLineText'); | |
$price->setLabel('Price'); | |
} | |
/** | |
* @return string | |
*/ | |
protected function getTargetClassName() { | |
return 'Test\Domain\Model\Book'; | |
} | |
/** | |
* @param array $formValues | |
* @return void | |
*/ | |
public function postProcessFormValues(array $formValues) { | |
if ($this->targetObject !== NULL) { | |
$this->bookRepository->update($formValues[$this->objectPrefix]); | |
} else { | |
$this->bookRepository->add($formValues[$this->objectPrefix]); | |
} | |
} | |
/** | |
* @return void | |
*/ | |
protected function addFinishers() { | |
$flashMessageFinisher = $this->formDefinition->createFinisher('TYPO3.Form:FlashMessage'); | |
if ($this->targetObject === NULL) { | |
$flashMessageFinisher->setOptions( | |
array( | |
'messageBody' => 'Stream "{' . $this->objectPrefix . '.title}" has been created', | |
'messageTitle' => 'Stream created', | |
) | |
); | |
} else { | |
$flashMessageFinisher->setOptions( | |
array( | |
'messageBody' => 'Stream "{' . $this->objectPrefix . '.title}" has been updated', | |
'messageTitle' => 'Stream updated', | |
) | |
); | |
} | |
$redirectFinisher = $this->formDefinition->createFinisher('TYPO3.Form:Redirect'); | |
$redirectFinisher->setOptions( | |
array( | |
'package' => 'Test', | |
'controller' => 'Standard', | |
'action' => 'index' | |
) | |
); | |
} | |
} | |
?> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
{namespace form=TYPO3\Form\ViewHelpers} | |
<h1>Edit book "{book.title}"</h1> | |
<form:render factoryClass="Test\FormFactories\TestFormFactory" overrideConfiguration="{targetObject: book}" /> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<f:flashMessages /> | |
<ul> | |
<f:for each="{books}" as="book"> | |
<li> | |
<f:link.action action="edit" arguments="{book: book}">{book.title}</f:link.action> | |
</li> | |
</f:for> | |
</ul> | |
<f:link.action action="new">Add book</f:link.action> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
{namespace form=TYPO3\Form\ViewHelpers}# | |
<h1>Create new book</h1> | |
<form:render factoryClass="Test\FormFactories\BookFormFactory" /> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
namespace Test\Controller; | |
/* * | |
* This script belongs to the FLOW3 package "Test". * | |
* * | |
* */ | |
use TYPO3\FLOW3\Annotations as FLOW3; | |
/** | |
* Standard controller for the Test package | |
* | |
* @FLOW3\Scope("singleton") | |
*/ | |
class StandardController extends \TYPO3\FLOW3\Mvc\Controller\ActionController { | |
/** | |
* @FLOW3\Inject | |
* @var \Test\Domain\Repository\BookRepository | |
*/ | |
protected $bookRepository; | |
/** | |
* @return void | |
*/ | |
public function indexAction() { | |
$this->view->assign('books', $this->bookRepository->findAll()); | |
} | |
/** | |
* @return void | |
*/ | |
public function newAction() { | |
} | |
/** | |
* @param \Test\Domain\Model\Book $book | |
* @return void | |
*/ | |
public function editAction(\Test\Domain\Model\Book $book) { | |
$this->view->assign('book', $book); | |
} | |
} | |
?> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment