around the original implementation, he can simply call the
// widget() function again to render the block for the parent type.
//
// The second kind is implemented in the following blocks.
if (!isset($this->blockNameHierarchyMap[$viewAndSuffixCacheKey])) {
// INITIAL CALL
// Calculate the hierarchy of template blocks and start on
// the bottom level of the hierarchy (= "_
_" block)
$blockNameHierarchy = array();
foreach ($view->vars['block_prefixes'] as $blockNamePrefix) {
$blockNameHierarchy[] = $blockNamePrefix.'_'.$blockNameSuffix;
}
$hierarchyLevel = count($blockNameHierarchy) - 1;
$hierarchyInit = true;
} else {
// RECURSIVE CALL
// If a block recursively calls searchAndRenderBlock() again, resume rendering
// using the parent type in the hierarchy.
$blockNameHierarchy = $this->blockNameHierarchyMap[$viewAndSuffixCacheKey];
$hierarchyLevel = $this->hierarchyLevelMap[$viewAndSuffixCacheKey] - 1;
$hierarchyInit = false;
}
// The variables are cached globally for a view (instead of for the
// current suffix)
if (!isset($this->variableStack[$viewCacheKey])) {
$this->variableStack[$viewCacheKey] = array();
// The default variable scope contains all view variables, merged with
// the variables passed explicitly to the helper
$scopeVariables = $view->vars;
$varInit = true;
} else {
// Reuse the current scope and merge it with the explicitly passed variables
$scopeVariables = end($this->variableStack[$viewCacheKey]);
$varInit = false;
}
// Load the resource where this block can be found
$resource = $this->engine->getResourceForBlockNameHierarchy($view, $blockNameHierarchy, $hierarchyLevel);
// Update the current hierarchy level to the one at which the resource was
// found. For example, if looking for "choice_widget", but only a resource
// is found for its parent "form_widget", then the level is updated here
// to the parent level.
$hierarchyLevel = $this->engine->getResourceHierarchyLevel($view, $blockNameHierarchy, $hierarchyLevel);
// The actually existing block name in $resource
$blockName = $blockNameHierarchy[$hierarchyLevel];
// Escape if no resource exists for this block
if (!$resource) {
throw new LogicException(sprintf(
'Unable to render the form as none of the following blocks exist: "%s".',
implode('", "', array_reverse($blockNameHierarchy))
));
}
// Merge the passed with the existing attributes
if (isset($variables['attr']) && isset($scopeVariables['attr'])) {
$variables['attr'] = array_replace($scopeVariables['attr'], $variables['attr']);
}
// Merge the passed with the exist *label* attributes
if (isset($variables['label_attr']) && isset($scopeVariables['label_attr'])) {
$variables['label_attr'] = array_replace($scopeVariables['label_attr'], $variables['label_attr']);
}
// Do not use array_replace_recursive(), otherwise array variables
// cannot be overwritten
$variables = array_replace($scopeVariables, $variables);
// In order to make recursive calls possible, we need to store the block hierarchy,
// the current level of the hierarchy and the variables so that this method can
// resume rendering one level higher of the hierarchy when it is called recursively.
//
// We need to store these values in maps (associative arrays) because within a
// call to widget() another call to widget() can be made, but for a different view
// object. These nested calls should not override each other.
$this->blockNameHierarchyMap[$viewAndSuffixCacheKey] = $blockNameHierarchy;
$this->hierarchyLevelMap[$viewAndSuffixCacheKey] = $hierarchyLevel;
// We also need to store the variables for the view so that we can render other
// blocks for the same view using the same variables as in the outer block.
$this->variableStack[$viewCacheKey][] = $variables;
// Do the rendering
$html = $this->engine->renderBlock($view, $resource, $blockName, $variables);
// Clear the stack
array_pop($this->variableStack[$viewCacheKey]);
// Clear the caches if they were filled for the first time within
// this function call
if ($hierarchyInit) {
unset($this->blockNameHierarchyMap[$viewAndSuffixCacheKey]);
unset($this->hierarchyLevelMap[$viewAndSuffixCacheKey]);
}
if ($varInit) {
unset($this->variableStack[$viewCacheKey]);
}
if ($renderOnlyOnce) {
$view->setRendered();
}
return $html;
}
/**
* {@inheritdoc}
*/
public function humanize($text)
{
return ucfirst(trim(strtolower(preg_replace(array('/([A-Z])/', '/[_\s]+/'), array('_$1', ' '), $text))));
}
}
PK ! C ButtonTypeInterface.phpnu [
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Form;
/**
* A type that should be converted into a {@link Button} instance.
*
* @author Bernhard Schussek
*/
interface ButtonTypeInterface extends FormTypeInterface
{
}
PK ! K'$ FormBuilder.phpnu [
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Form;
use Symfony\Component\Form\Exception\BadMethodCallException;
use Symfony\Component\Form\Exception\InvalidArgumentException;
use Symfony\Component\Form\Exception\UnexpectedTypeException;
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
/**
* A builder for creating {@link Form} instances.
*
* @author Bernhard Schussek
*/
class FormBuilder extends FormConfigBuilder implements \IteratorAggregate, FormBuilderInterface
{
/**
* The children of the form builder.
*
* @var FormBuilderInterface[]
*/
private $children = array();
/**
* The data of children who haven't been converted to form builders yet.
*
* @var array
*/
private $unresolvedChildren = array();
/**
* Creates a new form builder.
*
* @param string $name
* @param string $dataClass
* @param EventDispatcherInterface $dispatcher
* @param FormFactoryInterface $factory
* @param array $options
*/
public function __construct($name, $dataClass, EventDispatcherInterface $dispatcher, FormFactoryInterface $factory, array $options = array())
{
parent::__construct($name, $dataClass, $dispatcher, $options);
$this->setFormFactory($factory);
}
/**
* {@inheritdoc}
*/
public function add($child, $type = null, array $options = array())
{
if ($this->locked) {
throw new BadMethodCallException('FormBuilder methods cannot be accessed anymore once the builder is turned into a FormConfigInterface instance.');
}
if ($child instanceof self) {
$this->children[$child->getName()] = $child;
// In case an unresolved child with the same name exists
unset($this->unresolvedChildren[$child->getName()]);
return $this;
}
if (!is_string($child) && !is_int($child)) {
throw new UnexpectedTypeException($child, 'string, integer or Symfony\Component\Form\FormBuilder');
}
if (null !== $type && !is_string($type) && !$type instanceof FormTypeInterface) {
throw new UnexpectedTypeException($type, 'string or Symfony\Component\Form\FormTypeInterface');
}
// Add to "children" to maintain order
$this->children[$child] = null;
$this->unresolvedChildren[$child] = array(
'type' => $type,
'options' => $options,
);
return $this;
}
/**
* {@inheritdoc}
*/
public function create($name, $type = null, array $options = array())
{
if ($this->locked) {
throw new BadMethodCallException('FormBuilder methods cannot be accessed anymore once the builder is turned into a FormConfigInterface instance.');
}
if (null === $type && null === $this->getDataClass()) {
$type = 'text';
}
if (null !== $type) {
return $this->getFormFactory()->createNamedBuilder($name, $type, null, $options);
}
return $this->getFormFactory()->createBuilderForProperty($this->getDataClass(), $name, null, $options);
}
/**
* {@inheritdoc}
*/
public function get($name)
{
if ($this->locked) {
throw new BadMethodCallException('FormBuilder methods cannot be accessed anymore once the builder is turned into a FormConfigInterface instance.');
}
if (isset($this->unresolvedChildren[$name])) {
return $this->resolveChild($name);
}
if (isset($this->children[$name])) {
return $this->children[$name];
}
throw new InvalidArgumentException(sprintf('The child with the name "%s" does not exist.', $name));
}
/**
* {@inheritdoc}
*/
public function remove($name)
{
if ($this->locked) {
throw new BadMethodCallException('FormBuilder methods cannot be accessed anymore once the builder is turned into a FormConfigInterface instance.');
}
unset($this->unresolvedChildren[$name]);
if (array_key_exists($name, $this->children)) {
unset($this->children[$name]);
}
return $this;
}
/**
* {@inheritdoc}
*/
public function has($name)
{
if ($this->locked) {
throw new BadMethodCallException('FormBuilder methods cannot be accessed anymore once the builder is turned into a FormConfigInterface instance.');
}
if (isset($this->unresolvedChildren[$name])) {
return true;
}
if (isset($this->children[$name])) {
return true;
}
return false;
}
/**
* {@inheritdoc}
*/
public function all()
{
if ($this->locked) {
throw new BadMethodCallException('FormBuilder methods cannot be accessed anymore once the builder is turned into a FormConfigInterface instance.');
}
$this->resolveChildren();
return $this->children;
}
/**
* {@inheritdoc}
*/
public function count()
{
if ($this->locked) {
throw new BadMethodCallException('FormBuilder methods cannot be accessed anymore once the builder is turned into a FormConfigInterface instance.');
}
return count($this->children);
}
/**
* {@inheritdoc}
*/
public function getFormConfig()
{
$config = parent::getFormConfig();
$config->children = array();
$config->unresolvedChildren = array();
return $config;
}
/**
* {@inheritdoc}
*/
public function getForm()
{
if ($this->locked) {
throw new BadMethodCallException('FormBuilder methods cannot be accessed anymore once the builder is turned into a FormConfigInterface instance.');
}
$this->resolveChildren();
$form = new Form($this->getFormConfig());
foreach ($this->children as $child) {
// Automatic initialization is only supported on root forms
$form->add($child->setAutoInitialize(false)->getForm());
}
if ($this->getAutoInitialize()) {
// Automatically initialize the form if it is configured so
$form->initialize();
}
return $form;
}
/**
* {@inheritdoc}
*/
public function getIterator()
{
if ($this->locked) {
throw new BadMethodCallException('FormBuilder methods cannot be accessed anymore once the builder is turned into a FormConfigInterface instance.');
}
return new \ArrayIterator($this->children);
}
/**
* Converts an unresolved child into a {@link FormBuilder} instance.
*
* @param string $name The name of the unresolved child.
*
* @return FormBuilder The created instance.
*/
private function resolveChild($name)
{
$info = $this->unresolvedChildren[$name];
$child = $this->create($name, $info['type'], $info['options']);
$this->children[$name] = $child;
unset($this->unresolvedChildren[$name]);
return $child;
}
/**
* Converts all unresolved children into {@link FormBuilder} instances.
*/
private function resolveChildren()
{
foreach ($this->unresolvedChildren as $name => $info) {
$this->children[$name] = $this->create($name, $info['type'], $info['options']);
}
$this->unresolvedChildren = array();
}
}
PK ! &"̰T T FormConfigBuilder.phpnu [
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Form;
use Symfony\Component\Form\Exception\BadMethodCallException;
use Symfony\Component\Form\Exception\InvalidArgumentException;
use Symfony\Component\Form\Exception\UnexpectedTypeException;
use Symfony\Component\PropertyAccess\PropertyPath;
use Symfony\Component\PropertyAccess\PropertyPathInterface;
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Symfony\Component\EventDispatcher\ImmutableEventDispatcher;
/**
* A basic form configuration.
*
* @author Bernhard Schussek
*/
class FormConfigBuilder implements FormConfigBuilderInterface
{
/**
* Caches a globally unique {@link NativeRequestHandler} instance.
*
* @var NativeRequestHandler
*/
private static $nativeRequestProcessor;
/**
* The accepted request methods.
*
* @var array
*/
private static $allowedMethods = array(
'GET',
'PUT',
'POST',
'DELETE',
'PATCH'
);
/**
* @var Boolean
*/
protected $locked = false;
/**
* @var EventDispatcherInterface
*/
private $dispatcher;
/**
* @var string
*/
private $name;
/**
* @var PropertyPathInterface
*/
private $propertyPath;
/**
* @var Boolean
*/
private $mapped = true;
/**
* @var Boolean
*/
private $byReference = true;
/**
* @var Boolean
*/
private $inheritData = false;
/**
* @var Boolean
*/
private $compound = false;
/**
* @var ResolvedFormTypeInterface
*/
private $type;
/**
* @var array
*/
private $viewTransformers = array();
/**
* @var array
*/
private $modelTransformers = array();
/**
* @var DataMapperInterface
*/
private $dataMapper;
/**
* @var Boolean
*/
private $required = true;
/**
* @var Boolean
*/
private $disabled = false;
/**
* @var Boolean
*/
private $errorBubbling = false;
/**
* @var mixed
*/
private $emptyData;
/**
* @var array
*/
private $attributes = array();
/**
* @var mixed
*/
private $data;
/**
* @var string
*/
private $dataClass;
/**
* @var Boolean
*/
private $dataLocked;
/**
* @var FormFactoryInterface
*/
private $formFactory;
/**
* @var string
*/
private $action;
/**
* @var string
*/
private $method = 'POST';
/**
* @var RequestHandlerInterface
*/
private $requestHandler;
/**
* @var Boolean
*/
private $autoInitialize = false;
/**
* @var array
*/
private $options;
/**
* Creates an empty form configuration.
*
* @param string|integer $name The form name
* @param string $dataClass The class of the form's data
* @param EventDispatcherInterface $dispatcher The event dispatcher
* @param array $options The form options
*
* @throws InvalidArgumentException If the data class is not a valid class or if
* the name contains invalid characters.
*/
public function __construct($name, $dataClass, EventDispatcherInterface $dispatcher, array $options = array())
{
self::validateName($name);
if (null !== $dataClass && !class_exists($dataClass)) {
throw new InvalidArgumentException(sprintf('The data class "%s" is not a valid class.', $dataClass));
}
$this->name = (string) $name;
$this->dataClass = $dataClass;
$this->dispatcher = $dispatcher;
$this->options = $options;
}
/**
* {@inheritdoc}
*/
public function addEventListener($eventName, $listener, $priority = 0)
{
if ($this->locked) {
throw new BadMethodCallException('FormConfigBuilder methods cannot be accessed anymore once the builder is turned into a FormConfigInterface instance.');
}
$this->dispatcher->addListener($eventName, $listener, $priority);
return $this;
}
/**
* {@inheritdoc}
*/
public function addEventSubscriber(EventSubscriberInterface $subscriber)
{
if ($this->locked) {
throw new BadMethodCallException('FormConfigBuilder methods cannot be accessed anymore once the builder is turned into a FormConfigInterface instance.');
}
$this->dispatcher->addSubscriber($subscriber);
return $this;
}
/**
* {@inheritdoc}
*/
public function addViewTransformer(DataTransformerInterface $viewTransformer, $forcePrepend = false)
{
if ($this->locked) {
throw new BadMethodCallException('FormConfigBuilder methods cannot be accessed anymore once the builder is turned into a FormConfigInterface instance.');
}
if ($forcePrepend) {
array_unshift($this->viewTransformers, $viewTransformer);
} else {
$this->viewTransformers[] = $viewTransformer;
}
return $this;
}
/**
* {@inheritdoc}
*/
public function resetViewTransformers()
{
if ($this->locked) {
throw new BadMethodCallException('FormConfigBuilder methods cannot be accessed anymore once the builder is turned into a FormConfigInterface instance.');
}
$this->viewTransformers = array();
return $this;
}
/**
* {@inheritdoc}
*/
public function addModelTransformer(DataTransformerInterface $modelTransformer, $forceAppend = false)
{
if ($this->locked) {
throw new BadMethodCallException('FormConfigBuilder methods cannot be accessed anymore once the builder is turned into a FormConfigInterface instance.');
}
if ($forceAppend) {
$this->modelTransformers[] = $modelTransformer;
} else {
array_unshift($this->modelTransformers, $modelTransformer);
}
return $this;
}
/**
* {@inheritdoc}
*/
public function resetModelTransformers()
{
if ($this->locked) {
throw new BadMethodCallException('FormConfigBuilder methods cannot be accessed anymore once the builder is turned into a FormConfigInterface instance.');
}
$this->modelTransformers = array();
return $this;
}
/**
* {@inheritdoc}
*/
public function getEventDispatcher()
{
if ($this->locked && !$this->dispatcher instanceof ImmutableEventDispatcher) {
$this->dispatcher = new ImmutableEventDispatcher($this->dispatcher);
}
return $this->dispatcher;
}
/**
* {@inheritdoc}
*/
public function getName()
{
return $this->name;
}
/**
* {@inheritdoc}
*/
public function getPropertyPath()
{
return $this->propertyPath;
}
/**
* {@inheritdoc}
*/
public function getMapped()
{
return $this->mapped;
}
/**
* {@inheritdoc}
*/
public function getByReference()
{
return $this->byReference;
}
/**
* {@inheritdoc}
*/
public function getInheritData()
{
return $this->inheritData;
}
/**
* Alias of {@link getInheritData()}.
*
* @return FormConfigBuilder The configuration object.
*
* @deprecated Deprecated since version 2.3, to be removed in 3.0. Use
* {@link getInheritData()} instead.
*/
public function getVirtual()
{
// Uncomment this as soon as the deprecation note should be shown
// trigger_error('getVirtual() is deprecated since version 2.3 and will be removed in 3.0. Use getInheritData() instead.', E_USER_DEPRECATED);
return $this->getInheritData();
}
/**
* {@inheritdoc}
*/
public function getCompound()
{
return $this->compound;
}
/**
* {@inheritdoc}
*/
public function getType()
{
return $this->type;
}
/**
* {@inheritdoc}
*/
public function getViewTransformers()
{
return $this->viewTransformers;
}
/**
* {@inheritdoc}
*/
public function getModelTransformers()
{
return $this->modelTransformers;
}
/**
* {@inheritdoc}
*/
public function getDataMapper()
{
return $this->dataMapper;
}
/**
* {@inheritdoc}
*/
public function getRequired()
{
return $this->required;
}
/**
* {@inheritdoc}
*/
public function getDisabled()
{
return $this->disabled;
}
/**
* {@inheritdoc}
*/
public function getErrorBubbling()
{
return $this->errorBubbling;
}
/**
* {@inheritdoc}
*/
public function getEmptyData()
{
return $this->emptyData;
}
/**
* {@inheritdoc}
*/
public function getAttributes()
{
return $this->attributes;
}
/**
* {@inheritdoc}
*/
public function hasAttribute($name)
{
return array_key_exists($name, $this->attributes);
}
/**
* {@inheritdoc}
*/
public function getAttribute($name, $default = null)
{
return array_key_exists($name, $this->attributes) ? $this->attributes[$name] : $default;
}
/**
* {@inheritdoc}
*/
public function getData()
{
return $this->data;
}
/**
* {@inheritdoc}
*/
public function getDataClass()
{
return $this->dataClass;
}
/**
* {@inheritdoc}
*/
public function getDataLocked()
{
return $this->dataLocked;
}
/**
* {@inheritdoc}
*/
public function getFormFactory()
{
return $this->formFactory;
}
/**
* {@inheritdoc}
*/
public function getAction()
{
return $this->action;
}
/**
* {@inheritdoc}
*/
public function getMethod()
{
return $this->method;
}
/**
* {@inheritdoc}
*/
public function getRequestHandler()
{
if (null === $this->requestHandler) {
if (null === self::$nativeRequestProcessor) {
self::$nativeRequestProcessor = new NativeRequestHandler();
}
$this->requestHandler = self::$nativeRequestProcessor;
}
return $this->requestHandler;
}
/**
* {@inheritdoc}
*/
public function getAutoInitialize()
{
return $this->autoInitialize;
}
/**
* {@inheritdoc}
*/
public function getOptions()
{
return $this->options;
}
/**
* {@inheritdoc}
*/
public function hasOption($name)
{
return array_key_exists($name, $this->options);
}
/**
* {@inheritdoc}
*/
public function getOption($name, $default = null)
{
return array_key_exists($name, $this->options) ? $this->options[$name] : $default;
}
/**
* {@inheritdoc}
*/
public function setAttribute($name, $value)
{
if ($this->locked) {
throw new BadMethodCallException('FormConfigBuilder methods cannot be accessed anymore once the builder is turned into a FormConfigInterface instance.');
}
$this->attributes[$name] = $value;
return $this;
}
/**
* {@inheritdoc}
*/
public function setAttributes(array $attributes)
{
if ($this->locked) {
throw new BadMethodCallException('FormConfigBuilder methods cannot be accessed anymore once the builder is turned into a FormConfigInterface instance.');
}
$this->attributes = $attributes;
return $this;
}
/**
* {@inheritdoc}
*/
public function setDataMapper(DataMapperInterface $dataMapper = null)
{
if ($this->locked) {
throw new BadMethodCallException('FormConfigBuilder methods cannot be accessed anymore once the builder is turned into a FormConfigInterface instance.');
}
$this->dataMapper = $dataMapper;
return $this;
}
/**
* {@inheritdoc}
*/
public function setDisabled($disabled)
{
if ($this->locked) {
throw new BadMethodCallException('FormConfigBuilder methods cannot be accessed anymore once the builder is turned into a FormConfigInterface instance.');
}
$this->disabled = (Boolean) $disabled;
return $this;
}
/**
* {@inheritdoc}
*/
public function setEmptyData($emptyData)
{
if ($this->locked) {
throw new BadMethodCallException('FormConfigBuilder methods cannot be accessed anymore once the builder is turned into a FormConfigInterface instance.');
}
$this->emptyData = $emptyData;
return $this;
}
/**
* {@inheritdoc}
*/
public function setErrorBubbling($errorBubbling)
{
if ($this->locked) {
throw new BadMethodCallException('FormConfigBuilder methods cannot be accessed anymore once the builder is turned into a FormConfigInterface instance.');
}
$this->errorBubbling = null === $errorBubbling ? null : (Boolean) $errorBubbling;
return $this;
}
/**
* {@inheritdoc}
*/
public function setRequired($required)
{
if ($this->locked) {
throw new BadMethodCallException('FormConfigBuilder methods cannot be accessed anymore once the builder is turned into a FormConfigInterface instance.');
}
$this->required = (Boolean) $required;
return $this;
}
/**
* {@inheritdoc}
*/
public function setPropertyPath($propertyPath)
{
if ($this->locked) {
throw new BadMethodCallException('FormConfigBuilder methods cannot be accessed anymore once the builder is turned into a FormConfigInterface instance.');
}
if (null !== $propertyPath && !$propertyPath instanceof PropertyPathInterface) {
$propertyPath = new PropertyPath($propertyPath);
}
$this->propertyPath = $propertyPath;
return $this;
}
/**
* {@inheritdoc}
*/
public function setMapped($mapped)
{
if ($this->locked) {
throw new BadMethodCallException('FormConfigBuilder methods cannot be accessed anymore once the builder is turned into a FormConfigInterface instance.');
}
$this->mapped = $mapped;
return $this;
}
/**
* {@inheritdoc}
*/
public function setByReference($byReference)
{
if ($this->locked) {
throw new BadMethodCallException('FormConfigBuilder methods cannot be accessed anymore once the builder is turned into a FormConfigInterface instance.');
}
$this->byReference = $byReference;
return $this;
}
/**
* {@inheritdoc}
*/
public function setInheritData($inheritData)
{
if ($this->locked) {
throw new BadMethodCallException('FormConfigBuilder methods cannot be accessed anymore once the builder is turned into a FormConfigInterface instance.');
}
$this->inheritData = $inheritData;
return $this;
}
/**
* Alias of {@link setInheritData()}.
*
* @param Boolean $inheritData Whether the form should inherit its parent's data.
*
* @return FormConfigBuilder The configuration object.
*
* @deprecated Deprecated since version 2.3, to be removed in 3.0. Use
* {@link setInheritData()} instead.
*/
public function setVirtual($inheritData)
{
// Uncomment this as soon as the deprecation note should be shown
// trigger_error('setVirtual() is deprecated since version 2.3 and will be removed in 3.0. Use setInheritData() instead.', E_USER_DEPRECATED);
$this->setInheritData($inheritData);
}
/**
* {@inheritdoc}
*/
public function setCompound($compound)
{
if ($this->locked) {
throw new BadMethodCallException('FormConfigBuilder methods cannot be accessed anymore once the builder is turned into a FormConfigInterface instance.');
}
$this->compound = $compound;
return $this;
}
/**
* {@inheritdoc}
*/
public function setType(ResolvedFormTypeInterface $type)
{
if ($this->locked) {
throw new BadMethodCallException('FormConfigBuilder methods cannot be accessed anymore once the builder is turned into a FormConfigInterface instance.');
}
$this->type = $type;
return $this;
}
/**
* {@inheritdoc}
*/
public function setData($data)
{
if ($this->locked) {
throw new BadMethodCallException('FormConfigBuilder methods cannot be accessed anymore once the builder is turned into a FormConfigInterface instance.');
}
$this->data = $data;
return $this;
}
/**
* {@inheritdoc}
*/
public function setDataLocked($locked)
{
if ($this->locked) {
throw new BadMethodCallException('FormConfigBuilder methods cannot be accessed anymore once the builder is turned into a FormConfigInterface instance.');
}
$this->dataLocked = $locked;
return $this;
}
/**
* {@inheritdoc}
*/
public function setFormFactory(FormFactoryInterface $formFactory)
{
if ($this->locked) {
throw new BadMethodCallException('FormConfigBuilder methods cannot be accessed anymore once the builder is turned into a FormConfigInterface instance.');
}
$this->formFactory = $formFactory;
return $this;
}
/**
* {@inheritdoc}
*/
public function setAction($action)
{
if ($this->locked) {
throw new BadMethodCallException('The config builder cannot be modified anymore.');
}
$this->action = $action;
return $this;
}
/**
* {@inheritdoc}
*/
public function setMethod($method)
{
if ($this->locked) {
throw new BadMethodCallException('The config builder cannot be modified anymore.');
}
$upperCaseMethod = strtoupper($method);
if (!in_array($upperCaseMethod, self::$allowedMethods)) {
throw new InvalidArgumentException(sprintf(
'The form method is "%s", but should be one of "%s".',
$method,
implode('", "', self::$allowedMethods)
));
}
$this->method = $upperCaseMethod;
return $this;
}
/**
* {@inheritdoc}
*/
public function setRequestHandler(RequestHandlerInterface $requestHandler)
{
if ($this->locked) {
throw new BadMethodCallException('The config builder cannot be modified anymore.');
}
$this->requestHandler = $requestHandler;
return $this;
}
/**
* {@inheritdoc}
*/
public function setAutoInitialize($initialize)
{
$this->autoInitialize = (Boolean) $initialize;
return $this;
}
/**
* {@inheritdoc}
*/
public function getFormConfig()
{
if ($this->locked) {
throw new BadMethodCallException('FormConfigBuilder methods cannot be accessed anymore once the builder is turned into a FormConfigInterface instance.');
}
// This method should be idempotent, so clone the builder
$config = clone $this;
$config->locked = true;
return $config;
}
/**
* Validates whether the given variable is a valid form name.
*
* @param string|integer $name The tested form name.
*
* @throws UnexpectedTypeException If the name is not a string or an integer.
* @throws InvalidArgumentException If the name contains invalid characters.
*/
public static function validateName($name)
{
if (null !== $name && !is_string($name) && !is_int($name)) {
throw new UnexpectedTypeException($name, 'string, integer or null');
}
if (!self::isValidName($name)) {
throw new InvalidArgumentException(sprintf(
'The name "%s" contains illegal characters. Names should start with a letter, digit or underscore and only contain letters, digits, numbers, underscores ("_"), hyphens ("-") and colons (":").',
$name
));
}
}
/**
* Returns whether the given variable contains a valid form name.
*
* A name is accepted if it
*
* * is empty
* * starts with a letter, digit or underscore
* * contains only letters, digits, numbers, underscores ("_"),
* hyphens ("-") and colons (":")
*
* @param string $name The tested form name.
*
* @return Boolean Whether the name is valid.
*/
public static function isValidName($name)
{
return '' === $name || null === $name || preg_match('/^[a-zA-Z0-9_][a-zA-Z0-9_\-:]*$/D', $name);
}
}
PK ! E1' SubmitButtonTypeInterface.phpnu [
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Form;
/**
* A type that should be converted into a {@link SubmitButton} instance.
*
* @author Bernhard Schussek
*/
interface SubmitButtonTypeInterface extends FormTypeInterface
{
}
PK ! d FormRegistry.phpnu [
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Form;
use Symfony\Component\Form\Exception\ExceptionInterface;
use Symfony\Component\Form\Exception\UnexpectedTypeException;
use Symfony\Component\Form\Exception\InvalidArgumentException;
/**
* The central registry of the Form component.
*
* @author Bernhard Schussek
*/
class FormRegistry implements FormRegistryInterface
{
/**
* Extensions
*
* @var FormExtensionInterface[] An array of FormExtensionInterface
*/
private $extensions = array();
/**
* @var array
*/
private $types = array();
/**
* @var FormTypeGuesserInterface|false|null
*/
private $guesser = false;
/**
* @var ResolvedFormTypeFactoryInterface
*/
private $resolvedTypeFactory;
/**
* Constructor.
*
* @param FormExtensionInterface[] $extensions An array of FormExtensionInterface
* @param ResolvedFormTypeFactoryInterface $resolvedTypeFactory The factory for resolved form types.
*
* @throws UnexpectedTypeException if any extension does not implement FormExtensionInterface
*/
public function __construct(array $extensions, ResolvedFormTypeFactoryInterface $resolvedTypeFactory)
{
foreach ($extensions as $extension) {
if (!$extension instanceof FormExtensionInterface) {
throw new UnexpectedTypeException($extension, 'Symfony\Component\Form\FormExtensionInterface');
}
}
$this->extensions = $extensions;
$this->resolvedTypeFactory = $resolvedTypeFactory;
}
/**
* {@inheritdoc}
*/
public function getType($name)
{
if (!is_string($name)) {
throw new UnexpectedTypeException($name, 'string');
}
if (!isset($this->types[$name])) {
/** @var FormTypeInterface $type */
$type = null;
foreach ($this->extensions as $extension) {
/* @var FormExtensionInterface $extension */
if ($extension->hasType($name)) {
$type = $extension->getType($name);
break;
}
}
if (!$type) {
throw new InvalidArgumentException(sprintf('Could not load type "%s"', $name));
}
$this->resolveAndAddType($type);
}
return $this->types[$name];
}
/**
* Wraps a type into a ResolvedFormTypeInterface implementation and connects
* it with its parent type.
*
* @param FormTypeInterface $type The type to resolve.
*
* @return ResolvedFormTypeInterface The resolved type.
*/
private function resolveAndAddType(FormTypeInterface $type)
{
$parentType = $type->getParent();
if ($parentType instanceof FormTypeInterface) {
$this->resolveAndAddType($parentType);
$parentType = $parentType->getName();
}
$typeExtensions = array();
foreach ($this->extensions as $extension) {
/* @var FormExtensionInterface $extension */
$typeExtensions = array_merge(
$typeExtensions,
$extension->getTypeExtensions($type->getName())
);
}
$this->types[$type->getName()] = $this->resolvedTypeFactory->createResolvedType(
$type,
$typeExtensions,
$parentType ? $this->getType($parentType) : null
);
}
/**
* {@inheritdoc}
*/
public function hasType($name)
{
if (isset($this->types[$name])) {
return true;
}
try {
$this->getType($name);
} catch (ExceptionInterface $e) {
return false;
}
return true;
}
/**
* {@inheritdoc}
*/
public function getTypeGuesser()
{
if (false === $this->guesser) {
$guessers = array();
foreach ($this->extensions as $extension) {
/* @var FormExtensionInterface $extension */
$guesser = $extension->getTypeGuesser();
if ($guesser) {
$guessers[] = $guesser;
}
}
$this->guesser = !empty($guessers) ? new FormTypeGuesserChain($guessers) : null;
}
return $this->guesser;
}
/**
* {@inheritdoc}
*/
public function getExtensions()
{
return $this->extensions;
}
}
PK ! ÊM'% % FormConfigInterface.phpnu [
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Form;
/**
* The configuration of a {@link Form} object.
*
* @author Bernhard Schussek
*/
interface FormConfigInterface
{
/**
* Returns the event dispatcher used to dispatch form events.
*
* @return \Symfony\Component\EventDispatcher\EventDispatcherInterface The dispatcher.
*/
public function getEventDispatcher();
/**
* Returns the name of the form used as HTTP parameter.
*
* @return string The form name.
*/
public function getName();
/**
* Returns the property path that the form should be mapped to.
*
* @return null|\Symfony\Component\PropertyAccess\PropertyPathInterface The property path.
*/
public function getPropertyPath();
/**
* Returns whether the form should be mapped to an element of its
* parent's data.
*
* @return Boolean Whether the form is mapped.
*/
public function getMapped();
/**
* Returns whether the form's data should be modified by reference.
*
* @return Boolean Whether to modify the form's data by reference.
*/
public function getByReference();
/**
* Returns whether the form should read and write the data of its parent.
*
* @return Boolean Whether the form should inherit its parent's data.
*/
public function getInheritData();
/**
* Returns whether the form is compound.
*
* This property is independent of whether the form actually has
* children. A form can be compound and have no children at all, like
* for example an empty collection form.
*
* @return Boolean Whether the form is compound.
*/
public function getCompound();
/**
* Returns the form types used to construct the form.
*
* @return ResolvedFormTypeInterface The form's type.
*/
public function getType();
/**
* Returns the view transformers of the form.
*
* @return DataTransformerInterface[] An array of {@link DataTransformerInterface} instances.
*/
public function getViewTransformers();
/**
* Returns the model transformers of the form.
*
* @return DataTransformerInterface[] An array of {@link DataTransformerInterface} instances.
*/
public function getModelTransformers();
/**
* Returns the data mapper of the form.
*
* @return DataMapperInterface The data mapper.
*/
public function getDataMapper();
/**
* Returns whether the form is required.
*
* @return Boolean Whether the form is required.
*/
public function getRequired();
/**
* Returns whether the form is disabled.
*
* @return Boolean Whether the form is disabled.
*/
public function getDisabled();
/**
* Returns whether errors attached to the form will bubble to its parent.
*
* @return Boolean Whether errors will bubble up.
*/
public function getErrorBubbling();
/**
* Returns the data that should be returned when the form is empty.
*
* @return mixed The data returned if the form is empty.
*/
public function getEmptyData();
/**
* Returns additional attributes of the form.
*
* @return array An array of key-value combinations.
*/
public function getAttributes();
/**
* Returns whether the attribute with the given name exists.
*
* @param string $name The attribute name.
*
* @return Boolean Whether the attribute exists.
*/
public function hasAttribute($name);
/**
* Returns the value of the given attribute.
*
* @param string $name The attribute name.
* @param mixed $default The value returned if the attribute does not exist.
*
* @return mixed The attribute value.
*/
public function getAttribute($name, $default = null);
/**
* Returns the initial data of the form.
*
* @return mixed The initial form data.
*/
public function getData();
/**
* Returns the class of the form data or null if the data is scalar or an array.
*
* @return string The data class or null.
*/
public function getDataClass();
/**
* Returns whether the form's data is locked.
*
* A form with locked data is restricted to the data passed in
* this configuration. The data can only be modified then by
* submitting the form.
*
* @return Boolean Whether the data is locked.
*/
public function getDataLocked();
/**
* Returns the form factory used for creating new forms.
*
* @return FormFactoryInterface The form factory.
*/
public function getFormFactory();
/**
* Returns the target URL of the form.
*
* @return string The target URL of the form.
*/
public function getAction();
/**
* Returns the HTTP method used by the form.
*
* @return string The HTTP method of the form.
*/
public function getMethod();
/**
* Returns the request handler used by the form.
*
* @return RequestHandlerInterface The request handler.
*/
public function getRequestHandler();
/**
* Returns whether the form should be initialized upon creation.
*
* @return Boolean Returns true if the form should be initialized
* when created, false otherwise.
*/
public function getAutoInitialize();
/**
* Returns all options passed during the construction of the form.
*
* @return array The passed options.
*/
public function getOptions();
/**
* Returns whether a specific option exists.
*
* @param string $name The option name,
*
* @return Boolean Whether the option exists.
*/
public function hasOption($name);
/**
* Returns the value of a specific option.
*
* @param string $name The option name.
* @param mixed $default The value returned if the option does not exist.
*
* @return mixed The option value.
*/
public function getOption($name, $default = null);
}
PK ! @ @ FormTypeGuesserChain.phpnu [
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Form;
use Symfony\Component\Form\Guess\Guess;
use Symfony\Component\Form\Exception\UnexpectedTypeException;
class FormTypeGuesserChain implements FormTypeGuesserInterface
{
private $guessers = array();
/**
* Constructor.
*
* @param FormTypeGuesserInterface[] $guessers Guessers as instances of FormTypeGuesserInterface
*
* @throws UnexpectedTypeException if any guesser does not implement FormTypeGuesserInterface
*/
public function __construct(array $guessers)
{
foreach ($guessers as $guesser) {
if (!$guesser instanceof FormTypeGuesserInterface) {
throw new UnexpectedTypeException($guesser, 'Symfony\Component\Form\FormTypeGuesserInterface');
}
if ($guesser instanceof self) {
$this->guessers = array_merge($this->guessers, $guesser->guessers);
} else {
$this->guessers[] = $guesser;
}
}
}
/**
* {@inheritDoc}
*/
public function guessType($class, $property)
{
return $this->guess(function ($guesser) use ($class, $property) {
return $guesser->guessType($class, $property);
});
}
/**
* {@inheritDoc}
*/
public function guessRequired($class, $property)
{
return $this->guess(function ($guesser) use ($class, $property) {
return $guesser->guessRequired($class, $property);
});
}
/**
* {@inheritDoc}
*/
public function guessMaxLength($class, $property)
{
return $this->guess(function ($guesser) use ($class, $property) {
return $guesser->guessMaxLength($class, $property);
});
}
/**
* {@inheritDoc}
*/
public function guessPattern($class, $property)
{
return $this->guess(function ($guesser) use ($class, $property) {
return $guesser->guessPattern($class, $property);
});
}
/**
* Executes a closure for each guesser and returns the best guess from the
* return values
*
* @param \Closure $closure The closure to execute. Accepts a guesser
* as argument and should return a Guess instance
*
* @return Guess|null The guess with the highest confidence
*/
private function guess(\Closure $closure)
{
$guesses = array();
foreach ($this->guessers as $guesser) {
if ($guess = $closure($guesser)) {
$guesses[] = $guess;
}
}
return Guess::getBestGuess($guesses);
}
}
PK ! R Guess/ValueGuess.phpnu [
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Form\Guess;
/**
* Contains a guessed value
*
* @author Bernhard Schussek
*/
class ValueGuess extends Guess
{
/**
* The guessed value
* @var array
*/
private $value;
/**
* Constructor
*
* @param string $value The guessed value
* @param integer $confidence The confidence that the guessed class name
* is correct
*/
public function __construct($value, $confidence)
{
parent::__construct($confidence);
$this->value = $value;
}
/**
* Returns the guessed value
*
* @return mixed
*/
public function getValue()
{
return $this->value;
}
}
PK ! 51 1 Guess/Guess.phpnu [
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Form\Guess;
use Symfony\Component\Form\Exception\InvalidArgumentException;
/**
* Base class for guesses made by TypeGuesserInterface implementation
*
* Each instance contains a confidence value about the correctness of the guess.
* Thus an instance with confidence HIGH_CONFIDENCE is more likely to be
* correct than an instance with confidence LOW_CONFIDENCE.
*
* @author Bernhard Schussek
*/
abstract class Guess
{
/**
* Marks an instance with a value that is extremely likely to be correct
* @var integer
*/
const VERY_HIGH_CONFIDENCE = 3;
/**
* Marks an instance with a value that is very likely to be correct
* @var integer
*/
const HIGH_CONFIDENCE = 2;
/**
* Marks an instance with a value that is likely to be correct
* @var integer
*/
const MEDIUM_CONFIDENCE = 1;
/**
* Marks an instance with a value that may be correct
* @var integer
*/
const LOW_CONFIDENCE = 0;
/**
* The confidence about the correctness of the value
*
* One of VERY_HIGH_CONFIDENCE, HIGH_CONFIDENCE, MEDIUM_CONFIDENCE
* and LOW_CONFIDENCE.
*
* @var integer
*/
private $confidence;
/**
* Returns the guess most likely to be correct from a list of guesses.
*
* If there are multiple guesses with the same, highest confidence, the
* returned guess is any of them.
*
* @param Guess[] $guesses An array of guesses
*
* @return Guess|null The guess with the highest confidence
*/
public static function getBestGuess(array $guesses)
{
$result = null;
$maxConfidence = -1;
foreach ($guesses as $guess) {
if ($maxConfidence < $confidence = $guess->getConfidence()) {
$maxConfidence = $confidence;
$result = $guess;
}
}
return $result;
}
/**
* Constructor.
*
* @param integer $confidence The confidence
*
* @throws InvalidArgumentException if the given value of confidence is unknown
*/
public function __construct($confidence)
{
if (self::VERY_HIGH_CONFIDENCE !== $confidence && self::HIGH_CONFIDENCE !== $confidence &&
self::MEDIUM_CONFIDENCE !== $confidence && self::LOW_CONFIDENCE !== $confidence) {
throw new InvalidArgumentException('The confidence should be one of the constants defined in Guess.');
}
$this->confidence = $confidence;
}
/**
* Returns the confidence that the guessed value is correct.
*
* @return integer One of the constants VERY_HIGH_CONFIDENCE,
* HIGH_CONFIDENCE, MEDIUM_CONFIDENCE and LOW_CONFIDENCE
*/
public function getConfidence()
{
return $this->confidence;
}
}
PK ! Guess/TypeGuess.phpnu [
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Form\Guess;
/**
* Contains a guessed class name and a list of options for creating an instance
* of that class
*
* @author Bernhard Schussek
*/
class TypeGuess extends Guess
{
/**
* The guessed field type
* @var string
*/
private $type;
/**
* The guessed options for creating an instance of the guessed class
* @var array
*/
private $options;
/**
* Constructor
*
* @param string $type The guessed field type
* @param array $options The options for creating instances of the
* guessed class
* @param integer $confidence The confidence that the guessed class name
* is correct
*/
public function __construct($type, array $options, $confidence)
{
parent::__construct($confidence);
$this->type = $type;
$this->options = $options;
}
/**
* Returns the guessed field type
*
* @return string
*/
public function getType()
{
return $this->type;
}
/**
* Returns the guessed options for creating instances of the guessed type
*
* @return array
*/
public function getOptions()
{
return $this->options;
}
}
PK ! 0\Z Z CallbackTransformer.phpnu [
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Form;
use Symfony\Component\Form\Exception\UnexpectedTypeException;
use Symfony\Component\Form\Exception\TransformationFailedException;
class CallbackTransformer implements DataTransformerInterface
{
/**
* The callback used for forward transform
* @var \Closure
*/
private $transform;
/**
* The callback used for reverse transform
* @var \Closure
*/
private $reverseTransform;
/**
* Constructor.
*
* @param \Closure $transform The forward transform callback
* @param \Closure $reverseTransform The reverse transform callback
*/
public function __construct(\Closure $transform, \Closure $reverseTransform)
{
$this->transform = $transform;
$this->reverseTransform = $reverseTransform;
}
/**
* Transforms a value from the original representation to a transformed representation.
*
* @param mixed $data The value in the original representation
*
* @return mixed The value in the transformed representation
*
* @throws UnexpectedTypeException when the argument is not a string
* @throws TransformationFailedException when the transformation fails
*/
public function transform($data)
{
return call_user_func($this->transform, $data);
}
/**
* Transforms a value from the transformed representation to its original
* representation.
*
* @param mixed $data The value in the transformed representation
*
* @return mixed The value in the original representation
*
* @throws UnexpectedTypeException when the argument is not of the expected type
* @throws TransformationFailedException when the transformation fails
*/
public function reverseTransform($data)
{
return call_user_func($this->reverseTransform, $data);
}
}
PK ! 4Nz" z"
Button.phpnu [
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Form;
use Symfony\Component\Form\Exception\AlreadySubmittedException;
use Symfony\Component\Form\Exception\BadMethodCallException;
/**
* A form button.
*
* @author Bernhard Schussek
*/
class Button implements \IteratorAggregate, FormInterface
{
/**
* @var FormInterface|null
*/
private $parent;
/**
* @var FormConfigInterface
*/
private $config;
/**
* @var Boolean
*/
private $submitted = false;
/**
* Creates a new button from a form configuration.
*
* @param FormConfigInterface $config The button's configuration.
*/
public function __construct(FormConfigInterface $config)
{
$this->config = $config;
}
/**
* Unsupported method.
*
* @param mixed $offset
*
* @return Boolean Always returns false.
*/
public function offsetExists($offset)
{
return false;
}
/**
* Unsupported method.
*
* This method should not be invoked.
*
* @param mixed $offset
*
* @throws BadMethodCallException
*/
public function offsetGet($offset)
{
throw new BadMethodCallException('Buttons cannot have children.');
}
/**
* Unsupported method.
*
* This method should not be invoked.
*
* @param mixed $offset
* @param mixed $value
*
* @throws BadMethodCallException
*/
public function offsetSet($offset, $value)
{
throw new BadMethodCallException('Buttons cannot have children.');
}
/**
* Unsupported method.
*
* This method should not be invoked.
*
* @param mixed $offset
*
* @throws BadMethodCallException
*/
public function offsetUnset($offset)
{
throw new BadMethodCallException('Buttons cannot have children.');
}
/**
* {@inheritdoc}
*/
public function setParent(FormInterface $parent = null)
{
$this->parent = $parent;
}
/**
* {@inheritdoc}
*/
public function getParent()
{
return $this->parent;
}
/**
* Unsupported method.
*
* This method should not be invoked.
*
* @param int|string|FormInterface $child
* @param null $type
* @param array $options
*
* @throws BadMethodCallException
*/
public function add($child, $type = null, array $options = array())
{
throw new BadMethodCallException('Buttons cannot have children.');
}
/**
* Unsupported method.
*
* This method should not be invoked.
*
* @param string $name
*
* @throws BadMethodCallException
*/
public function get($name)
{
throw new BadMethodCallException('Buttons cannot have children.');
}
/**
* Unsupported method.
*
* @param string $name
*
* @return Boolean Always returns false.
*/
public function has($name)
{
return false;
}
/**
* Unsupported method.
*
* This method should not be invoked.
*
* @param string $name
*
* @throws BadMethodCallException
*/
public function remove($name)
{
throw new BadMethodCallException('Buttons cannot have children.');
}
/**
* {@inheritdoc}
*/
public function all()
{
return array();
}
/**
* {@inheritdoc}
*/
public function getErrors()
{
return array();
}
/**
* Unsupported method.
*
* This method should not be invoked.
*
* @param string $modelData
*
* @throws BadMethodCallException
*/
public function setData($modelData)
{
// called during initialization of the form tree
// noop
}
/**
* Unsupported method.
*
* @return null Always returns null.
*/
public function getData()
{
return null;
}
/**
* Unsupported method.
*
* @return null Always returns null.
*/
public function getNormData()
{
return null;
}
/**
* Unsupported method.
*
* @return null Always returns null.
*/
public function getViewData()
{
return null;
}
/**
* Unsupported method.
*
* @return array Always returns an empty array.
*/
public function getExtraData()
{
return array();
}
/**
* Returns the button's configuration.
*
* @return FormConfigInterface The configuration.
*/
public function getConfig()
{
return $this->config;
}
/**
* Returns whether the button is submitted.
*
* @return Boolean true if the button was submitted.
*/
public function isSubmitted()
{
return $this->submitted;
}
/**
* Returns the name by which the button is identified in forms.
*
* @return string The name of the button.
*/
public function getName()
{
return $this->config->getName();
}
/**
* Unsupported method.
*
* @return null Always returns null.
*/
public function getPropertyPath()
{
return null;
}
/**
* Unsupported method.
*
* @param FormError $error
*
* @throws BadMethodCallException
*/
public function addError(FormError $error)
{
throw new BadMethodCallException('Buttons cannot have errors.');
}
/**
* Unsupported method.
*
* @return Boolean Always returns true.
*/
public function isValid()
{
return true;
}
/**
* Unsupported method.
*
* @return Boolean Always returns false.
*/
public function isRequired()
{
return false;
}
/**
* {@inheritdoc}
*/
public function isDisabled()
{
return $this->config->getDisabled();
}
/**
* Unsupported method.
*
* @return Boolean Always returns true.
*/
public function isEmpty()
{
return true;
}
/**
* Unsupported method.
*
* @return Boolean Always returns true.
*/
public function isSynchronized()
{
return true;
}
/**
* Unsupported method.
*
* @throws BadMethodCallException
*/
public function initialize()
{
throw new BadMethodCallException('Buttons cannot be initialized. Call initialize() on the root form instead.');
}
/**
* Unsupported method.
*
* @param mixed $request
*
* @throws BadMethodCallException
*/
public function handleRequest($request = null)
{
throw new BadMethodCallException('Buttons cannot handle requests. Call handleRequest() on the root form instead.');
}
/**
* Submits data to the button.
*
* @param null|string $submittedData The data.
* @param Boolean $clearMissing Not used.
*
* @return Button The button instance
*
* @throws Exception\AlreadySubmittedException If the button has already been submitted.
*/
public function submit($submittedData, $clearMissing = true)
{
if ($this->submitted) {
throw new AlreadySubmittedException('A form can only be submitted once');
}
$this->submitted = true;
return $this;
}
/**
* {@inheritdoc}
*/
public function getRoot()
{
return $this->parent ? $this->parent->getRoot() : $this;
}
/**
* {@inheritdoc}
*/
public function isRoot()
{
return null === $this->parent;
}
/**
* {@inheritdoc}
*/
public function createView(FormView $parent = null)
{
if (null === $parent && $this->parent) {
$parent = $this->parent->createView();
}
$type = $this->config->getType();
$options = $this->config->getOptions();
$view = $type->createView($this, $parent);
$type->buildView($view, $this, $options);
$type->finishView($view, $this, $options);
return $view;
}
/**
* Unsupported method.
*
* @return integer Always returns 0.
*/
public function count()
{
return 0;
}
/**
* Unsupported method.
*
* @return \EmptyIterator Always returns an empty iterator.
*/
public function getIterator()
{
return new \EmptyIterator();
}
}
PK ! -9N N autoloader.phpnu [
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Form;
/**
* @author Bernhard Schussek
*/
final class FormEvents
{
const PRE_SUBMIT = 'form.pre_bind';
const SUBMIT = 'form.bind';
const POST_SUBMIT = 'form.post_bind';
const PRE_SET_DATA = 'form.pre_set_data';
const POST_SET_DATA = 'form.post_set_data';
/**
* @deprecated Deprecated since version 2.3, to be removed in 3.0. Use
* {@link PRE_SUBMIT} instead.
*/
const PRE_BIND = 'form.pre_bind';
/**
* @deprecated Deprecated since version 2.3, to be removed in 3.0. Use
* {@link SUBMIT} instead.
*/
const BIND = 'form.bind';
/**
* @deprecated Deprecated since version 2.3, to be removed in 3.0. Use
* {@link POST_SUBMIT} instead.
*/
const POST_BIND = 'form.post_bind';
private function __construct()
{
}
}
PK ! FormTypeInterface.phpnu [
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Form;
use Symfony\Component\OptionsResolver\OptionsResolverInterface;
/**
* @author Bernhard Schussek
*/
interface FormTypeInterface
{
/**
* Builds the form.
*
* This method is called for each type in the hierarchy starting form the
* top most type. Type extensions can further modify the form.
*
* @see FormTypeExtensionInterface::buildForm()
*
* @param FormBuilderInterface $builder The form builder
* @param array $options The options
*/
public function buildForm(FormBuilderInterface $builder, array $options);
/**
* Builds the form view.
*
* This method is called for each type in the hierarchy starting form the
* top most type. Type extensions can further modify the view.
*
* A view of a form is built before the views of the child forms are built.
* This means that you cannot access child views in this method. If you need
* to do so, move your logic to {@link finishView()} instead.
*
* @see FormTypeExtensionInterface::buildView()
*
* @param FormView $view The view
* @param FormInterface $form The form
* @param array $options The options
*/
public function buildView(FormView $view, FormInterface $form, array $options);
/**
* Finishes the form view.
*
* This method gets called for each type in the hierarchy starting form the
* top most type. Type extensions can further modify the view.
*
* When this method is called, views of the form's children have already
* been built and finished and can be accessed. You should only implement
* such logic in this method that actually accesses child views. For everything
* else you are recommended to implement {@link buildView()} instead.
*
* @see FormTypeExtensionInterface::finishView()
*
* @param FormView $view The view
* @param FormInterface $form The form
* @param array $options The options
*/
public function finishView(FormView $view, FormInterface $form, array $options);
/**
* Sets the default options for this type.
*
* @param OptionsResolverInterface $resolver The resolver for the options.
*/
public function setDefaultOptions(OptionsResolverInterface $resolver);
/**
* Returns the name of the parent type.
*
* You can also return a type instance from this method, although doing so
* is discouraged because it leads to a performance penalty. The support
* for returning type instances may be dropped from future releases.
*
* @return string|null|FormTypeInterface The name of the parent type if any, null otherwise.
*/
public function getParent();
/**
* Returns the name of this type.
*
* @return string The name of this type
*/
public function getName();
}
PK ! > FormRegistryInterface.phpnu [
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Form;
/**
* The central registry of the Form component.
*
* @author Bernhard Schussek
*/
interface FormRegistryInterface
{
/**
* Returns a form type by name.
*
* This methods registers the type extensions from the form extensions.
*
* @param string $name The name of the type
*
* @return ResolvedFormTypeInterface The type
*
* @throws Exception\UnexpectedTypeException if the passed name is not a string
* @throws Exception\InvalidArgumentException if the type can not be retrieved from any extension
*/
public function getType($name);
/**
* Returns whether the given form type is supported.
*
* @param string $name The name of the type
*
* @return Boolean Whether the type is supported
*/
public function hasType($name);
/**
* Returns the guesser responsible for guessing types.
*
* @return FormTypeGuesserInterface|null
*/
public function getTypeGuesser();
/**
* Returns the extensions loaded by the framework.
*
* @return FormExtensionInterface[]
*/
public function getExtensions();
}
PK ! ?z z FormTypeGuesserInterface.phpnu [
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Form;
/**
* @author Bernhard Schussek
*/
interface FormTypeGuesserInterface
{
/**
* Returns a field guess for a property name of a class
*
* @param string $class The fully qualified class name
* @param string $property The name of the property to guess for
*
* @return Guess\TypeGuess|null A guess for the field's type and options
*/
public function guessType($class, $property);
/**
* Returns a guess whether a property of a class is required
*
* @param string $class The fully qualified class name
* @param string $property The name of the property to guess for
*
* @return Guess\ValueGuess A guess for the field's required setting
*/
public function guessRequired($class, $property);
/**
* Returns a guess about the field's maximum length
*
* @param string $class The fully qualified class name
* @param string $property The name of the property to guess for
*
* @return Guess\ValueGuess|null A guess for the field's maximum length
*/
public function guessMaxLength($class, $property);
/**
* Returns a guess about the field's pattern
*
* - When you have a min value, you guess a min length of this min (LOW_CONFIDENCE) , lines below
* - If this value is a float type, this is wrong so you guess null with MEDIUM_CONFIDENCE to override the previous guess.
* Example:
* You want a float greater than 5, 4.512313 is not valid but length(4.512314) > length(5)
* @link https://github.com/symfony/symfony/pull/3927
*
* @param string $class The fully qualified class name
* @param string $property The name of the property to guess for
*
* @return Guess\ValueGuess|null A guess for the field's required pattern
*/
public function guessPattern($class, $property);
}
PK ! * ResolvedFormType.phpnu [
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Form;
use Symfony\Component\Form\Exception\InvalidArgumentException;
use Symfony\Component\Form\Exception\UnexpectedTypeException;
use Symfony\Component\EventDispatcher\EventDispatcher;
use Symfony\Component\OptionsResolver\OptionsResolver;
/**
* A wrapper for a form type and its extensions.
*
* @author Bernhard Schussek
*/
class ResolvedFormType implements ResolvedFormTypeInterface
{
/**
* @var FormTypeInterface
*/
private $innerType;
/**
* @var FormTypeExtensionInterface[]
*/
private $typeExtensions;
/**
* @var ResolvedFormTypeInterface|null
*/
private $parent;
/**
* @var OptionsResolver
*/
private $optionsResolver;
public function __construct(FormTypeInterface $innerType, array $typeExtensions = array(), ResolvedFormTypeInterface $parent = null)
{
if (!preg_match('/^[a-z0-9_]*$/i', $innerType->getName())) {
throw new InvalidArgumentException(sprintf(
'The "%s" form type name ("%s") is not valid. Names must only contain letters, numbers, and "_".',
get_class($innerType),
$innerType->getName()
));
}
foreach ($typeExtensions as $extension) {
if (!$extension instanceof FormTypeExtensionInterface) {
throw new UnexpectedTypeException($extension, 'Symfony\Component\Form\FormTypeExtensionInterface');
}
}
$this->innerType = $innerType;
$this->typeExtensions = $typeExtensions;
$this->parent = $parent;
}
/**
* {@inheritdoc}
*/
public function getName()
{
return $this->innerType->getName();
}
/**
* {@inheritdoc}
*/
public function getParent()
{
return $this->parent;
}
/**
* {@inheritdoc}
*/
public function getInnerType()
{
return $this->innerType;
}
/**
* {@inheritdoc}
*/
public function getTypeExtensions()
{
// BC
if ($this->innerType instanceof AbstractType) {
return $this->innerType->getExtensions();
}
return $this->typeExtensions;
}
/**
* {@inheritdoc}
*/
public function createBuilder(FormFactoryInterface $factory, $name, array $options = array())
{
$options = $this->getOptionsResolver()->resolve($options);
// Should be decoupled from the specific option at some point
$dataClass = isset($options['data_class']) ? $options['data_class'] : null;
$builder = $this->newBuilder($name, $dataClass, $factory, $options);
$builder->setType($this);
return $builder;
}
/**
* {@inheritdoc}
*/
public function createView(FormInterface $form, FormView $parent = null)
{
return $this->newView($parent);
}
/**
* Configures a form builder for the type hierarchy.
*
* @param FormBuilderInterface $builder The builder to configure.
* @param array $options The options used for the configuration.
*/
public function buildForm(FormBuilderInterface $builder, array $options)
{
if (null !== $this->parent) {
$this->parent->buildForm($builder, $options);
}
$this->innerType->buildForm($builder, $options);
foreach ($this->typeExtensions as $extension) {
/* @var FormTypeExtensionInterface $extension */
$extension->buildForm($builder, $options);
}
}
/**
* Configures a form view for the type hierarchy.
*
* This method is called before the children of the view are built.
*
* @param FormView $view The form view to configure.
* @param FormInterface $form The form corresponding to the view.
* @param array $options The options used for the configuration.
*/
public function buildView(FormView $view, FormInterface $form, array $options)
{
if (null !== $this->parent) {
$this->parent->buildView($view, $form, $options);
}
$this->innerType->buildView($view, $form, $options);
foreach ($this->typeExtensions as $extension) {
/* @var FormTypeExtensionInterface $extension */
$extension->buildView($view, $form, $options);
}
}
/**
* Finishes a form view for the type hierarchy.
*
* This method is called after the children of the view have been built.
*
* @param FormView $view The form view to configure.
* @param FormInterface $form The form corresponding to the view.
* @param array $options The options used for the configuration.
*/
public function finishView(FormView $view, FormInterface $form, array $options)
{
if (null !== $this->parent) {
$this->parent->finishView($view, $form, $options);
}
$this->innerType->finishView($view, $form, $options);
foreach ($this->typeExtensions as $extension) {
/* @var FormTypeExtensionInterface $extension */
$extension->finishView($view, $form, $options);
}
}
/**
* Returns the configured options resolver used for this type.
*
* @return \Symfony\Component\OptionsResolver\OptionsResolverInterface The options resolver.
*/
public function getOptionsResolver()
{
if (null === $this->optionsResolver) {
if (null !== $this->parent) {
$this->optionsResolver = clone $this->parent->getOptionsResolver();
} else {
$this->optionsResolver = new OptionsResolver();
}
$this->innerType->setDefaultOptions($this->optionsResolver);
foreach ($this->typeExtensions as $extension) {
/* @var FormTypeExtensionInterface $extension */
$extension->setDefaultOptions($this->optionsResolver);
}
}
return $this->optionsResolver;
}
/**
* Creates a new builder instance.
*
* Override this method if you want to customize the builder class.
*
* @param string $name The name of the builder.
* @param string $dataClass The data class.
* @param FormFactoryInterface $factory The current form factory.
* @param array $options The builder options.
*
* @return FormBuilderInterface The new builder instance.
*/
protected function newBuilder($name, $dataClass, FormFactoryInterface $factory, array $options)
{
if ($this->innerType instanceof ButtonTypeInterface) {
return new ButtonBuilder($name, $options);
}
if ($this->innerType instanceof SubmitButtonTypeInterface) {
return new SubmitButtonBuilder($name, $options);
}
return new FormBuilder($name, $dataClass, new EventDispatcher(), $factory, $options);
}
/**
* Creates a new view instance.
*
* Override this method if you want to customize the view class.
*
* @param FormView|null $parent The parent view, if available.
*
* @return FormView A new view instance.
*/
protected function newView(FormView $parent = null)
{
return new FormView($parent);
}
}
PK ! ObXq q SubmitButton.phpnu [
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Form;
/**
* A button that submits the form.
*
* @author Bernhard Schussek
*/
class SubmitButton extends Button implements ClickableInterface
{
/**
* @var Boolean
*/
private $clicked = false;
/**
* {@inheritdoc}
*/
public function isClicked()
{
return $this->clicked;
}
/**
* Submits data to the button.
*
* @param null|string $submittedData The data.
* @param Boolean $clearMissing Not used.
*
* @return SubmitButton The button instance
*
* @throws Exception\AlreadySubmittedException If the form has already been submitted.
*/
public function submit($submittedData, $clearMissing = true)
{
parent::submit($submittedData, $clearMissing);
$this->clicked = null !== $submittedData;
return $this;
}
}
PK ! p AbstractRendererEngine.phpnu [
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Form;
/**
* Default implementation of {@link FormRendererEngineInterface}.
*
* @author Bernhard Schussek
*/
abstract class AbstractRendererEngine implements FormRendererEngineInterface
{
/**
* The variable in {@link FormView} used as cache key.
*/
const CACHE_KEY_VAR = 'cache_key';
/**
* @var array
*/
protected $defaultThemes;
/**
* @var array
*/
protected $themes = array();
/**
* @var array
*/
protected $resources = array();
/**
* @var array
*/
private $resourceHierarchyLevels = array();
/**
* Creates a new renderer engine.
*
* @param array $defaultThemes The default themes. The type of these
* themes is open to the implementation.
*/
public function __construct(array $defaultThemes = array())
{
$this->defaultThemes = $defaultThemes;
}
/**
* {@inheritdoc}
*/
public function setTheme(FormView $view, $themes)
{
$cacheKey = $view->vars[self::CACHE_KEY_VAR];
// Do not cast, as casting turns objects into arrays of properties
$this->themes[$cacheKey] = is_array($themes) ? $themes : array($themes);
// Unset instead of resetting to an empty array, in order to allow
// implementations (like TwigRendererEngine) to check whether $cacheKey
// is set at all.
unset($this->resources[$cacheKey]);
unset($this->resourceHierarchyLevels[$cacheKey]);
}
/**
* {@inheritdoc}
*/
public function getResourceForBlockName(FormView $view, $blockName)
{
$cacheKey = $view->vars[self::CACHE_KEY_VAR];
if (!isset($this->resources[$cacheKey][$blockName])) {
$this->loadResourceForBlockName($cacheKey, $view, $blockName);
}
return $this->resources[$cacheKey][$blockName];
}
/**
* {@inheritdoc}
*/
public function getResourceForBlockNameHierarchy(FormView $view, array $blockNameHierarchy, $hierarchyLevel)
{
$cacheKey = $view->vars[self::CACHE_KEY_VAR];
$blockName = $blockNameHierarchy[$hierarchyLevel];
if (!isset($this->resources[$cacheKey][$blockName])) {
$this->loadResourceForBlockNameHierarchy($cacheKey, $view, $blockNameHierarchy, $hierarchyLevel);
}
return $this->resources[$cacheKey][$blockName];
}
/**
* {@inheritdoc}
*/
public function getResourceHierarchyLevel(FormView $view, array $blockNameHierarchy, $hierarchyLevel)
{
$cacheKey = $view->vars[self::CACHE_KEY_VAR];
$blockName = $blockNameHierarchy[$hierarchyLevel];
if (!isset($this->resources[$cacheKey][$blockName])) {
$this->loadResourceForBlockNameHierarchy($cacheKey, $view, $blockNameHierarchy, $hierarchyLevel);
}
// If $block was previously rendered loaded with loadTemplateForBlock(), the template
// is cached but the hierarchy level is not. In this case, we know that the block
// exists at this very hierarchy level, so we can just set it.
if (!isset($this->resourceHierarchyLevels[$cacheKey][$blockName])) {
$this->resourceHierarchyLevels[$cacheKey][$blockName] = $hierarchyLevel;
}
return $this->resourceHierarchyLevels[$cacheKey][$blockName];
}
/**
* Loads the cache with the resource for a given block name.
*
* @see getResourceForBlock()
*
* @param string $cacheKey The cache key of the form view.
* @param FormView $view The form view for finding the applying themes.
* @param string $blockName The name of the block to load.
*
* @return Boolean True if the resource could be loaded, false otherwise.
*/
abstract protected function loadResourceForBlockName($cacheKey, FormView $view, $blockName);
/**
* Loads the cache with the resource for a specific level of a block hierarchy.
*
* @see getResourceForBlockHierarchy()
*
* @param string $cacheKey The cache key used for storing the
* resource.
* @param FormView $view The form view for finding the applying
* themes.
* @param array $blockNameHierarchy The block hierarchy, with the most
* specific block name at the end.
* @param integer $hierarchyLevel The level in the block hierarchy that
* should be loaded.
*
* @return Boolean True if the resource could be loaded, false otherwise.
*/
private function loadResourceForBlockNameHierarchy($cacheKey, FormView $view, array $blockNameHierarchy, $hierarchyLevel)
{
$blockName = $blockNameHierarchy[$hierarchyLevel];
// Try to find a template for that block
if ($this->loadResourceForBlockName($cacheKey, $view, $blockName)) {
// If loadTemplateForBlock() returns true, it was able to populate the
// cache. The only missing thing is to set the hierarchy level at which
// the template was found.
$this->resourceHierarchyLevels[$cacheKey][$blockName] = $hierarchyLevel;
return true;
}
if ($hierarchyLevel > 0) {
$parentLevel = $hierarchyLevel - 1;
$parentBlockName = $blockNameHierarchy[$parentLevel];
// The next two if statements contain slightly duplicated code. This is by intention
// and tries to avoid execution of unnecessary checks in order to increase performance.
if (isset($this->resources[$cacheKey][$parentBlockName])) {
// It may happen that the parent block is already loaded, but its level is not.
// In this case, the parent block must have been loaded by loadResourceForBlock(),
// which does not check the hierarchy of the block. Subsequently the block must have
// been found directly on the parent level.
if (!isset($this->resourceHierarchyLevels[$cacheKey][$parentBlockName])) {
$this->resourceHierarchyLevels[$cacheKey][$parentBlockName] = $parentLevel;
}
// Cache the shortcuts for further accesses
$this->resources[$cacheKey][$blockName] = $this->resources[$cacheKey][$parentBlockName];
$this->resourceHierarchyLevels[$cacheKey][$blockName] = $this->resourceHierarchyLevels[$cacheKey][$parentBlockName];
return true;
}
if ($this->loadResourceForBlockNameHierarchy($cacheKey, $view, $blockNameHierarchy, $parentLevel)) {
// Cache the shortcuts for further accesses
$this->resources[$cacheKey][$blockName] = $this->resources[$cacheKey][$parentBlockName];
$this->resourceHierarchyLevels[$cacheKey][$blockName] = $this->resourceHierarchyLevels[$cacheKey][$parentBlockName];
return true;
}
}
// Cache the result for further accesses
$this->resources[$cacheKey][$blockName] = false;
$this->resourceHierarchyLevels[$cacheKey][$blockName] = false;
return false;
}
}
PK ! DjN AbstractExtension.phpnu [
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Form;
use Symfony\Component\Form\Exception\InvalidArgumentException;
use Symfony\Component\Form\Exception\UnexpectedTypeException;
/**
* @author Bernhard Schussek
*/
abstract class AbstractExtension implements FormExtensionInterface
{
/**
* The types provided by this extension
* @var FormTypeInterface[] An array of FormTypeInterface
*/
private $types;
/**
* The type extensions provided by this extension
* @var FormTypeExtensionInterface[] An array of FormTypeExtensionInterface
*/
private $typeExtensions;
/**
* The type guesser provided by this extension
* @var FormTypeGuesserInterface
*/
private $typeGuesser;
/**
* Whether the type guesser has been loaded
* @var Boolean
*/
private $typeGuesserLoaded = false;
/**
* {@inheritdoc}
*/
public function getType($name)
{
if (null === $this->types) {
$this->initTypes();
}
if (!isset($this->types[$name])) {
throw new InvalidArgumentException(sprintf('The type "%s" can not be loaded by this extension', $name));
}
return $this->types[$name];
}
/**
* {@inheritdoc}
*/
public function hasType($name)
{
if (null === $this->types) {
$this->initTypes();
}
return isset($this->types[$name]);
}
/**
* {@inheritdoc}
*/
public function getTypeExtensions($name)
{
if (null === $this->typeExtensions) {
$this->initTypeExtensions();
}
return isset($this->typeExtensions[$name])
? $this->typeExtensions[$name]
: array();
}
/**
* {@inheritdoc}
*/
public function hasTypeExtensions($name)
{
if (null === $this->typeExtensions) {
$this->initTypeExtensions();
}
return isset($this->typeExtensions[$name]) && count($this->typeExtensions[$name]) > 0;
}
/**
* {@inheritdoc}
*/
public function getTypeGuesser()
{
if (!$this->typeGuesserLoaded) {
$this->initTypeGuesser();
}
return $this->typeGuesser;
}
/**
* Registers the types.
*
* @return FormTypeInterface[] An array of FormTypeInterface instances
*/
protected function loadTypes()
{
return array();
}
/**
* Registers the type extensions.
*
* @return FormTypeExtensionInterface[] An array of FormTypeExtensionInterface instances
*/
protected function loadTypeExtensions()
{
return array();
}
/**
* Registers the type guesser.
*
* @return FormTypeGuesserInterface|null A type guesser
*/
protected function loadTypeGuesser()
{
return null;
}
/**
* Initializes the types.
*
* @throws UnexpectedTypeException if any registered type is not an instance of FormTypeInterface
*/
private function initTypes()
{
$this->types = array();
foreach ($this->loadTypes() as $type) {
if (!$type instanceof FormTypeInterface) {
throw new UnexpectedTypeException($type, 'Symfony\Component\Form\FormTypeInterface');
}
$this->types[$type->getName()] = $type;
}
}
/**
* Initializes the type extensions.
*
* @throws UnexpectedTypeException if any registered type extension is not
* an instance of FormTypeExtensionInterface
*/
private function initTypeExtensions()
{
$this->typeExtensions = array();
foreach ($this->loadTypeExtensions() as $extension) {
if (!$extension instanceof FormTypeExtensionInterface) {
throw new UnexpectedTypeException($extension, 'Symfony\Component\Form\FormTypeExtensionInterface');
}
$type = $extension->getExtendedType();
$this->typeExtensions[$type][] = $extension;
}
}
/**
* Initializes the type guesser.
*
* @throws UnexpectedTypeException if the type guesser is not an instance of FormTypeGuesserInterface
*/
private function initTypeGuesser()
{
$this->typeGuesserLoaded = true;
$this->typeGuesser = $this->loadTypeGuesser();
if (null !== $this->typeGuesser && !$this->typeGuesser instanceof FormTypeGuesserInterface) {
throw new UnexpectedTypeException($this->typeGuesser, 'Symfony\Component\Form\FormTypeGuesserInterface');
}
}
}
PK ! f#jK FormRendererEngineInterface.phpnu [
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Form;
/**
* Adapter for rendering form templates with a specific templating engine.
*
* @author Bernhard Schussek
*/
interface FormRendererEngineInterface
{
/**
* Sets the theme(s) to be used for rendering a view and its children.
*
* @param FormView $view The view to assign the theme(s) to.
* @param mixed $themes The theme(s). The type of these themes
* is open to the implementation.
*/
public function setTheme(FormView $view, $themes);
/**
* Returns the resource for a block name.
*
* The resource is first searched in the themes attached to $view, then
* in the themes of its parent view and so on, until a resource was found.
*
* The type of the resource is decided by the implementation. The resource
* is later passed to {@link renderBlock()} by the rendering algorithm.
*
* @param FormView $view The view for determining the used themes.
* First the themes attached directly to the
* view with {@link setTheme()} are considered,
* then the ones of its parent etc.
* @param string $blockName The name of the block to render.
*
* @return mixed The renderer resource or false, if none was found.
*/
public function getResourceForBlockName(FormView $view, $blockName);
/**
* Returns the resource for a block hierarchy.
*
* A block hierarchy is an array which starts with the root of the hierarchy
* and continues with the child of that root, the child of that child etc.
* The following is an example for a block hierarchy:
*
*
* form_widget
* text_widget
* url_widget
*
*
* In this example, "url_widget" is the most specific block, while the other
* blocks are its ancestors in the hierarchy.
*
* The second parameter $hierarchyLevel determines the level of the hierarchy
* that should be rendered. For example, if $hierarchyLevel is 2 for the
* above hierarchy, the engine will first look for the block "url_widget",
* then, if that does not exist, for the block "text_widget" etc.
*
* The type of the resource is decided by the implementation. The resource
* is later passed to {@link renderBlock()} by the rendering algorithm.
*
* @param FormView $view The view for determining the
* used themes. First the themes
* attached directly to the view
* with {@link setTheme()} are
* considered, then the ones of
* its parent etc.
* @param array $blockNameHierarchy The block name hierarchy, with
* the root block at the beginning.
* @param integer $hierarchyLevel The level in the hierarchy at
* which to start looking. Level 0
* indicates the root block, i.e.
* the first element of
* $blockNameHierarchy.
*
* @return mixed The renderer resource or false, if none was found.
*/
public function getResourceForBlockNameHierarchy(FormView $view, array $blockNameHierarchy, $hierarchyLevel);
/**
* Returns the hierarchy level at which a resource can be found.
*
* A block hierarchy is an array which starts with the root of the hierarchy
* and continues with the child of that root, the child of that child etc.
* The following is an example for a block hierarchy:
*
*
* form_widget
* text_widget
* url_widget
*
*
* The second parameter $hierarchyLevel determines the level of the hierarchy
* that should be rendered.
*
* If we call this method with the hierarchy level 2, the engine will first
* look for a resource for block "url_widget". If such a resource exists,
* the method returns 2. Otherwise it tries to find a resource for block
* "text_widget" (at level 1) and, again, returns 1 if a resource was found.
* The method continues to look for resources until the root level was
* reached and nothing was found. In this case false is returned.
*
* The type of the resource is decided by the implementation. The resource
* is later passed to {@link renderBlock()} by the rendering algorithm.
*
* @param FormView $view The view for determining the
* used themes. First the themes
* attached directly to the view
* with {@link setTheme()} are
* considered, then the ones of
* its parent etc.
* @param array $blockNameHierarchy The block name hierarchy, with
* the root block at the beginning.
* @param integer $hierarchyLevel The level in the hierarchy at
* which to start looking. Level 0
* indicates the root block, i.e.
* the first element of
* $blockNameHierarchy.
*
* @return integer|Boolean The hierarchy level or false, if no resource was found.
*/
public function getResourceHierarchyLevel(FormView $view, array $blockNameHierarchy, $hierarchyLevel);
/**
* Renders a block in the given renderer resource.
*
* The resource can be obtained by calling {@link getResourceForBlock()}
* or {@link getResourceForBlockHierarchy()}. The type of the resource is
* decided by the implementation.
*
* @param FormView $view The view to render.
* @param mixed $resource The renderer resource.
* @param string $blockName The name of the block to render.
* @param array $variables The variables to pass to the template.
*
* @return string The HTML markup.
*/
public function renderBlock(FormView $view, $resource, $blockName, array $variables = array());
}
PK ! 1 1 Form.phpnu [
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Form;
use Symfony\Component\Form\Exception\RuntimeException;
use Symfony\Component\Form\Exception\UnexpectedTypeException;
use Symfony\Component\Form\Exception\AlreadySubmittedException;
use Symfony\Component\Form\Exception\TransformationFailedException;
use Symfony\Component\Form\Exception\LogicException;
use Symfony\Component\Form\Exception\OutOfBoundsException;
use Symfony\Component\Form\Util\FormUtil;
use Symfony\Component\Form\Util\InheritDataAwareIterator;
use Symfony\Component\Form\Util\OrderedHashMap;
use Symfony\Component\PropertyAccess\PropertyPath;
/**
* Form represents a form.
*
* To implement your own form fields, you need to have a thorough understanding
* of the data flow within a form. A form stores its data in three different
* representations:
*
* (1) the "model" format required by the form's object
* (2) the "normalized" format for internal processing
* (3) the "view" format used for display
*
* A date field, for example, may store a date as "Y-m-d" string (1) in the
* object. To facilitate processing in the field, this value is normalized
* to a DateTime object (2). In the HTML representation of your form, a
* localized string (3) is presented to and modified by the user.
*
* In most cases, format (1) and format (2) will be the same. For example,
* a checkbox field uses a Boolean value for both internal processing and
* storage in the object. In these cases you simply need to set a value
* transformer to convert between formats (2) and (3). You can do this by
* calling addViewTransformer().
*
* In some cases though it makes sense to make format (1) configurable. To
* demonstrate this, let's extend our above date field to store the value
* either as "Y-m-d" string or as timestamp. Internally we still want to
* use a DateTime object for processing. To convert the data from string/integer
* to DateTime you can set a normalization transformer by calling
* addNormTransformer(). The normalized data is then converted to the displayed
* data as described before.
*
* The conversions (1) -> (2) -> (3) use the transform methods of the transformers.
* The conversions (3) -> (2) -> (1) use the reverseTransform methods of the transformers.
*
* @author Fabien Potencier
* @author Bernhard Schussek
*/
class Form implements \IteratorAggregate, FormInterface
{
/**
* The form's configuration
* @var FormConfigInterface
*/
private $config;
/**
* The parent of this form
* @var FormInterface
*/
private $parent;
/**
* The children of this form
* @var FormInterface[] A map of FormInterface instances
*/
private $children;
/**
* The errors of this form
* @var FormError[] An array of FormError instances
*/
private $errors = array();
/**
* Whether this form was submitted
* @var Boolean
*/
private $submitted = false;
/**
* The button that was used to submit the form
* @var Button
*/
private $clickedButton;
/**
* The form data in model format
* @var mixed
*/
private $modelData;
/**
* The form data in normalized format
* @var mixed
*/
private $normData;
/**
* The form data in view format
* @var mixed
*/
private $viewData;
/**
* The submitted values that don't belong to any children
* @var array
*/
private $extraData = array();
/**
* Whether the data in model, normalized and view format is
* synchronized. Data may not be synchronized if transformation errors
* occur.
* @var Boolean
*/
private $synchronized = true;
/**
* Whether the form's data has been initialized.
*
* When the data is initialized with its default value, that default value
* is passed through the transformer chain in order to synchronize the
* model, normalized and view format for the first time. This is done
* lazily in order to save performance when {@link setData()} is called
* manually, making the initialization with the configured default value
* superfluous.
*
* @var Boolean
*/
private $defaultDataSet = false;
/**
* Whether setData() is currently being called.
* @var Boolean
*/
private $lockSetData = false;
/**
* Creates a new form based on the given configuration.
*
* @param FormConfigInterface $config The form configuration.
*
* @throws LogicException if a data mapper is not provided for a compound form
*/
public function __construct(FormConfigInterface $config)
{
// Compound forms always need a data mapper, otherwise calls to
// `setData` and `add` will not lead to the correct population of
// the child forms.
if ($config->getCompound() && !$config->getDataMapper()) {
throw new LogicException('Compound forms need a data mapper');
}
// If the form inherits the data from its parent, it is not necessary
// to call setData() with the default data.
if ($config->getInheritData()) {
$this->defaultDataSet = true;
}
$this->config = $config;
$this->children = new OrderedHashMap();
}
public function __clone()
{
$this->children = clone $this->children;
foreach ($this->children as $key => $child) {
$this->children[$key] = clone $child;
}
}
/**
* {@inheritdoc}
*/
public function getConfig()
{
return $this->config;
}
/**
* {@inheritdoc}
*/
public function getName()
{
return $this->config->getName();
}
/**
* {@inheritdoc}
*/
public function getPropertyPath()
{
if (null !== $this->config->getPropertyPath()) {
return $this->config->getPropertyPath();
}
if (null === $this->getName() || '' === $this->getName()) {
return null;
}
$parent = $this->parent;
while ($parent && $parent->getConfig()->getInheritData()) {
$parent = $parent->getParent();
}
if ($parent && null === $parent->getConfig()->getDataClass()) {
return new PropertyPath('['.$this->getName().']');
}
return new PropertyPath($this->getName());
}
/**
* {@inheritdoc}
*/
public function isRequired()
{
if (null === $this->parent || $this->parent->isRequired()) {
return $this->config->getRequired();
}
return false;
}
/**
* {@inheritDoc}
*/
public function isDisabled()
{
if (null === $this->parent || !$this->parent->isDisabled()) {
return $this->config->getDisabled();
}
return true;
}
/**
* {@inheritdoc}
*/
public function setParent(FormInterface $parent = null)
{
if ($this->submitted) {
throw new AlreadySubmittedException('You cannot set the parent of a submitted form');
}
if (null !== $parent && '' === $this->config->getName()) {
throw new LogicException('A form with an empty name cannot have a parent form.');
}
$this->parent = $parent;
return $this;
}
/**
* {@inheritdoc}
*/
public function getParent()
{
return $this->parent;
}
/**
* {@inheritdoc}
*/
public function getRoot()
{
return $this->parent ? $this->parent->getRoot() : $this;
}
/**
* {@inheritdoc}
*/
public function isRoot()
{
return null === $this->parent;
}
/**
* {@inheritdoc}
*/
public function setData($modelData)
{
// If the form is submitted while disabled, it is set to submitted, but the data is not
// changed. In such cases (i.e. when the form is not initialized yet) don't
// abort this method.
if ($this->submitted && $this->defaultDataSet) {
throw new AlreadySubmittedException('You cannot change the data of a submitted form.');
}
// If the form inherits its parent's data, disallow data setting to
// prevent merge conflicts
if ($this->config->getInheritData()) {
throw new RuntimeException('You cannot change the data of a form inheriting its parent data.');
}
// Don't allow modifications of the configured data if the data is locked
if ($this->config->getDataLocked() && $modelData !== $this->config->getData()) {
return $this;
}
if (is_object($modelData) && !$this->config->getByReference()) {
$modelData = clone $modelData;
}
if ($this->lockSetData) {
throw new RuntimeException('A cycle was detected. Listeners to the PRE_SET_DATA event must not call setData(). You should call setData() on the FormEvent object instead.');
}
$this->lockSetData = true;
$dispatcher = $this->config->getEventDispatcher();
// Hook to change content of the data
if ($dispatcher->hasListeners(FormEvents::PRE_SET_DATA)) {
$event = new FormEvent($this, $modelData);
$dispatcher->dispatch(FormEvents::PRE_SET_DATA, $event);
$modelData = $event->getData();
}
// Treat data as strings unless a value transformer exists
if (!$this->config->getViewTransformers() && !$this->config->getModelTransformers() && is_scalar($modelData)) {
$modelData = (string) $modelData;
}
// Synchronize representations - must not change the content!
$normData = $this->modelToNorm($modelData);
$viewData = $this->normToView($normData);
// Validate if view data matches data class (unless empty)
if (!FormUtil::isEmpty($viewData)) {
$dataClass = $this->config->getDataClass();
$actualType = is_object($viewData) ? 'an instance of class '.get_class($viewData) : ' a(n) '.gettype($viewData);
if (null === $dataClass && is_object($viewData) && !$viewData instanceof \ArrayAccess) {
$expectedType = 'scalar, array or an instance of \ArrayAccess';
throw new LogicException(
'The form\'s view data is expected to be of type '.$expectedType.', ' .
'but is '.$actualType.'. You ' .
'can avoid this error by setting the "data_class" option to ' .
'"'.get_class($viewData).'" or by adding a view transformer ' .
'that transforms '.$actualType.' to '.$expectedType.'.'
);
}
if (null !== $dataClass && !$viewData instanceof $dataClass) {
throw new LogicException(
'The form\'s view data is expected to be an instance of class ' .
$dataClass.', but is '. $actualType.'. You can avoid this error ' .
'by setting the "data_class" option to null or by adding a view ' .
'transformer that transforms '.$actualType.' to an instance of ' .
$dataClass.'.'
);
}
}
$this->modelData = $modelData;
$this->normData = $normData;
$this->viewData = $viewData;
$this->defaultDataSet = true;
$this->lockSetData = false;
// It is not necessary to invoke this method if the form doesn't have children,
// even if the form is compound.
if (count($this->children) > 0) {
// Update child forms from the data
$iterator = new InheritDataAwareIterator($this->children);
$iterator = new \RecursiveIteratorIterator($iterator);
$this->config->getDataMapper()->mapDataToForms($viewData, $iterator);
}
if ($dispatcher->hasListeners(FormEvents::POST_SET_DATA)) {
$event = new FormEvent($this, $modelData);
$dispatcher->dispatch(FormEvents::POST_SET_DATA, $event);
}
return $this;
}
/**
* {@inheritdoc}
*/
public function getData()
{
if ($this->config->getInheritData()) {
if (!$this->parent) {
throw new RuntimeException('The form is configured to inherit its parent\'s data, but does not have a parent.');
}
return $this->parent->getData();
}
if (!$this->defaultDataSet) {
$this->setData($this->config->getData());
}
return $this->modelData;
}
/**
* {@inheritdoc}
*/
public function getNormData()
{
if ($this->config->getInheritData()) {
if (!$this->parent) {
throw new RuntimeException('The form is configured to inherit its parent\'s data, but does not have a parent.');
}
return $this->parent->getNormData();
}
if (!$this->defaultDataSet) {
$this->setData($this->config->getData());
}
return $this->normData;
}
/**
* {@inheritdoc}
*/
public function getViewData()
{
if ($this->config->getInheritData()) {
if (!$this->parent) {
throw new RuntimeException('The form is configured to inherit its parent\'s data, but does not have a parent.');
}
return $this->parent->getViewData();
}
if (!$this->defaultDataSet) {
$this->setData($this->config->getData());
}
return $this->viewData;
}
/**
* {@inheritdoc}
*/
public function getExtraData()
{
return $this->extraData;
}
/**
* {@inheritdoc}
*/
public function initialize()
{
if (null !== $this->parent) {
throw new RuntimeException('Only root forms should be initialized.');
}
// Guarantee that the *_SET_DATA events have been triggered once the
// form is initialized. This makes sure that dynamically added or
// removed fields are already visible after initialization.
if (!$this->defaultDataSet) {
$this->setData($this->config->getData());
}
return $this;
}
/**
* {@inheritdoc}
*/
public function handleRequest($request = null)
{
$this->config->getRequestHandler()->handleRequest($this, $request);
return $this;
}
/**
* {@inheritdoc}
*/
public function submit($submittedData, $clearMissing = true)
{
if ($this->submitted) {
throw new AlreadySubmittedException('A form can only be submitted once');
}
// Initialize errors in the very beginning so that we don't lose any
// errors added during listeners
$this->errors = array();
// Obviously, a disabled form should not change its data upon submission.
if ($this->isDisabled()) {
$this->submitted = true;
return $this;
}
// The data must be initialized if it was not initialized yet.
// This is necessary to guarantee that the *_SET_DATA listeners
// are always invoked before submit() takes place.
if (!$this->defaultDataSet) {
$this->setData($this->config->getData());
}
// Treat false as NULL to support binding false to checkboxes.
// Don't convert NULL to a string here in order to determine later
// whether an empty value has been submitted or whether no value has
// been submitted at all. This is important for processing checkboxes
// and radio buttons with empty values.
if (false === $submittedData) {
$submittedData = null;
} elseif (is_scalar($submittedData)) {
$submittedData = (string) $submittedData;
}
$dispatcher = $this->config->getEventDispatcher();
$modelData = null;
$normData = null;
$viewData = null;
try {
// Hook to change content of the data submitted by the browser
if ($dispatcher->hasListeners(FormEvents::PRE_SUBMIT)) {
$event = new FormEvent($this, $submittedData);
$dispatcher->dispatch(FormEvents::PRE_SUBMIT, $event);
$submittedData = $event->getData();
}
// Check whether the form is compound.
// This check is preferable over checking the number of children,
// since forms without children may also be compound.
// (think of empty collection forms)
if ($this->config->getCompound()) {
if (null === $submittedData) {
$submittedData = array();
}
if (!is_array($submittedData)) {
throw new TransformationFailedException('Compound forms expect an array or NULL on submission.');
}
foreach ($this->children as $name => $child) {
if (array_key_exists($name, $submittedData) || $clearMissing) {
$child->submit(isset($submittedData[$name]) ? $submittedData[$name] : null, $clearMissing);
unset($submittedData[$name]);
if (null !== $this->clickedButton) {
continue;
}
if ($child instanceof ClickableInterface && $child->isClicked()) {
$this->clickedButton = $child;
continue;
}
if (method_exists($child, 'getClickedButton') && null !== $child->getClickedButton()) {
$this->clickedButton = $child->getClickedButton();
}
}
}
$this->extraData = $submittedData;
}
// Forms that inherit their parents' data also are not processed,
// because then it would be too difficult to merge the changes in
// the child and the parent form. Instead, the parent form also takes
// changes in the grandchildren (i.e. children of the form that inherits
// its parent's data) into account.
// (see InheritDataAwareIterator below)
if (!$this->config->getInheritData()) {
// If the form is compound, the default data in view format
// is reused. The data of the children is merged into this
// default data using the data mapper.
// If the form is not compound, the submitted data is also the data in view format.
$viewData = $this->config->getCompound() ? $this->viewData : $submittedData;
if (FormUtil::isEmpty($viewData)) {
$emptyData = $this->config->getEmptyData();
if ($emptyData instanceof \Closure) {
/* @var \Closure $emptyData */
$emptyData = $emptyData($this, $viewData);
}
$viewData = $emptyData;
}
// Merge form data from children into existing view data
// It is not necessary to invoke this method if the form has no children,
// even if it is compound.
if (count($this->children) > 0) {
// Use InheritDataAwareIterator to process children of
// descendants that inherit this form's data.
// These descendants will not be submitted normally (see the check
// for $this->config->getInheritData() above)
$childrenIterator = new InheritDataAwareIterator($this->children);
$childrenIterator = new \RecursiveIteratorIterator($childrenIterator);
$this->config->getDataMapper()->mapFormsToData($childrenIterator, $viewData);
}
// Normalize data to unified representation
$normData = $this->viewToNorm($viewData);
// Hook to change content of the data in the normalized
// representation
if ($dispatcher->hasListeners(FormEvents::SUBMIT)) {
$event = new FormEvent($this, $normData);
$dispatcher->dispatch(FormEvents::SUBMIT, $event);
$normData = $event->getData();
}
// Synchronize representations - must not change the content!
$modelData = $this->normToModel($normData);
$viewData = $this->normToView($normData);
}
} catch (TransformationFailedException $e) {
$this->synchronized = false;
// If $viewData was not yet set, set it to $submittedData so that
// the erroneous data is accessible on the form.
// Forms that inherit data never set any data, because the getters
// forward to the parent form's getters anyway.
if (null === $viewData && !$this->config->getInheritData()) {
$viewData = $submittedData;
}
}
$this->submitted = true;
$this->modelData = $modelData;
$this->normData = $normData;
$this->viewData = $viewData;
if ($dispatcher->hasListeners(FormEvents::POST_SUBMIT)) {
$event = new FormEvent($this, $viewData);
$dispatcher->dispatch(FormEvents::POST_SUBMIT, $event);
}
return $this;
}
/**
* Alias of {@link submit()}.
*
* @deprecated Deprecated since version 2.3, to be removed in 3.0. Use
* {@link submit()} instead.
*/
public function bind($submittedData)
{
return $this->submit($submittedData);
}
/**
* {@inheritdoc}
*/
public function addError(FormError $error)
{
if ($this->parent && $this->config->getErrorBubbling()) {
$this->parent->addError($error);
} else {
$this->errors[] = $error;
}
return $this;
}
/**
* {@inheritdoc}
*/
public function isSubmitted()
{
return $this->submitted;
}
/**
* Alias of {@link isSubmitted()}.
*
* @deprecated Deprecated since version 2.3, to be removed in 3.0. Use
* {@link isSubmitted()} instead.
*/
public function isBound()
{
return $this->submitted;
}
/**
* {@inheritdoc}
*/
public function isSynchronized()
{
return $this->synchronized;
}
/**
* {@inheritdoc}
*/
public function isEmpty()
{
foreach ($this->children as $child) {
if (!$child->isEmpty()) {
return false;
}
}
return FormUtil::isEmpty($this->modelData) ||
// arrays, countables
0 === count($this->modelData) ||
// traversables that are not countable
($this->modelData instanceof \Traversable && 0 === iterator_count($this->modelData));
}
/**
* {@inheritdoc}
*/
public function isValid()
{
if (!$this->submitted) {
return false;
}
if (count($this->errors) > 0) {
return false;
}
if ($this->isDisabled()) {
return true;
}
foreach ($this->children as $child) {
if ($child->isSubmitted() && !$child->isValid()) {
return false;
}
}
return true;
}
/**
* Returns the button that was used to submit the form.
*
* @return Button|null The clicked button or NULL if the form was not
* submitted
*/
public function getClickedButton()
{
if ($this->clickedButton) {
return $this->clickedButton;
}
if ($this->parent && method_exists($this->parent, 'getClickedButton')) {
return $this->parent->getClickedButton();
}
return null;
}
/**
* {@inheritdoc}
*/
public function getErrors()
{
return $this->errors;
}
/**
* Returns a string representation of all form errors (including children errors).
*
* This method should only be used to help debug a form.
*
* @param integer $level The indentation level (used internally)
*
* @return string A string representation of all errors
*/
public function getErrorsAsString($level = 0)
{
$errors = '';
foreach ($this->errors as $error) {
$errors .= str_repeat(' ', $level).'ERROR: '.$error->getMessage()."\n";
}
foreach ($this->children as $key => $child) {
$errors .= str_repeat(' ', $level).$key.":\n";
if ($child instanceof self && $err = $child->getErrorsAsString($level + 4)) {
$errors .= $err;
} else {
$errors .= str_repeat(' ', $level + 4)."No errors\n";
}
}
return $errors;
}
/**
* {@inheritdoc}
*/
public function all()
{
return iterator_to_array($this->children);
}
/**
* {@inheritdoc}
*/
public function add($child, $type = null, array $options = array())
{
if ($this->submitted) {
throw new AlreadySubmittedException('You cannot add children to a submitted form');
}
if (!$this->config->getCompound()) {
throw new LogicException('You cannot add children to a simple form. Maybe you should set the option "compound" to true?');
}
// Obtain the view data
$viewData = null;
// If setData() is currently being called, there is no need to call
// mapDataToForms() here, as mapDataToForms() is called at the end
// of setData() anyway. Not doing this check leads to an endless
// recursion when initializing the form lazily and an event listener
// (such as ResizeFormListener) adds fields depending on the data:
//
// * setData() is called, the form is not initialized yet
// * add() is called by the listener (setData() is not complete, so
// the form is still not initialized)
// * getViewData() is called
// * setData() is called since the form is not initialized yet
// * ... endless recursion ...
//
// Also skip data mapping if setData() has not been called yet.
// setData() will be called upon form initialization and data mapping
// will take place by then.
if (!$this->lockSetData && $this->defaultDataSet && !$this->config->getInheritData()) {
$viewData = $this->getViewData();
}
if (!$child instanceof FormInterface) {
if (!is_string($child) && !is_int($child)) {
throw new UnexpectedTypeException($child, 'string, integer or Symfony\Component\Form\FormInterface');
}
if (null !== $type && !is_string($type) && !$type instanceof FormTypeInterface) {
throw new UnexpectedTypeException($type, 'string or Symfony\Component\Form\FormTypeInterface');
}
// Never initialize child forms automatically
$options['auto_initialize'] = false;
if (null === $type) {
$child = $this->config->getFormFactory()->createForProperty($this->config->getDataClass(), $child, null, $options);
} else {
$child = $this->config->getFormFactory()->createNamed($child, $type, null, $options);
}
} elseif ($child->getConfig()->getAutoInitialize()) {
throw new RuntimeException(sprintf(
'Automatic initialization is only supported on root forms. You '.
'should set the "auto_initialize" option to false on the field "%s".',
$child->getName()
));
}
$this->children[$child->getName()] = $child;
$child->setParent($this);
if (!$this->lockSetData && $this->defaultDataSet && !$this->config->getInheritData()) {
$iterator = new InheritDataAwareIterator(new \ArrayIterator(array($child)));
$iterator = new \RecursiveIteratorIterator($iterator);
$this->config->getDataMapper()->mapDataToForms($viewData, $iterator);
}
return $this;
}
/**
* {@inheritdoc}
*/
public function remove($name)
{
if ($this->submitted) {
throw new AlreadySubmittedException('You cannot remove children from a submitted form');
}
if (isset($this->children[$name])) {
$this->children[$name]->setParent(null);
unset($this->children[$name]);
}
return $this;
}
/**
* {@inheritdoc}
*/
public function has($name)
{
return isset($this->children[$name]);
}
/**
* {@inheritdoc}
*/
public function get($name)
{
if (isset($this->children[$name])) {
return $this->children[$name];
}
throw new OutOfBoundsException(sprintf('Child "%s" does not exist.', $name));
}
/**
* Returns whether a child with the given name exists (implements the \ArrayAccess interface).
*
* @param string $name The name of the child
*
* @return Boolean
*/
public function offsetExists($name)
{
return $this->has($name);
}
/**
* Returns the child with the given name (implements the \ArrayAccess interface).
*
* @param string $name The name of the child
*
* @return FormInterface The child form
*
* @throws \OutOfBoundsException If the named child does not exist.
*/
public function offsetGet($name)
{
return $this->get($name);
}
/**
* Adds a child to the form (implements the \ArrayAccess interface).
*
* @param string $name Ignored. The name of the child is used.
* @param FormInterface $child The child to be added.
*
* @throws AlreadySubmittedException If the form has already been submitted.
* @throws LogicException When trying to add a child to a non-compound form.
*
* @see self::add()
*/
public function offsetSet($name, $child)
{
$this->add($child);
}
/**
* Removes the child with the given name from the form (implements the \ArrayAccess interface).
*
* @param string $name The name of the child to remove
*
* @throws AlreadySubmittedException If the form has already been submitted.
*/
public function offsetUnset($name)
{
$this->remove($name);
}
/**
* Returns the iterator for this group.
*
* @return \Traversable
*/
public function getIterator()
{
return $this->children;
}
/**
* Returns the number of form children (implements the \Countable interface).
*
* @return integer The number of embedded form children
*/
public function count()
{
return count($this->children);
}
/**
* {@inheritdoc}
*/
public function createView(FormView $parent = null)
{
if (null === $parent && $this->parent) {
$parent = $this->parent->createView();
}
$type = $this->config->getType();
$options = $this->config->getOptions();
// The methods createView(), buildView() and finishView() are called
// explicitly here in order to be able to override either of them
// in a custom resolved form type.
$view = $type->createView($this, $parent);
$type->buildView($view, $this, $options);
foreach ($this->children as $name => $child) {
$view->children[$name] = $child->createView($view);
}
$type->finishView($view, $this, $options);
return $view;
}
/**
* Normalizes the value if a normalization transformer is set.
*
* @param mixed $value The value to transform
*
* @return mixed
*/
private function modelToNorm($value)
{
foreach ($this->config->getModelTransformers() as $transformer) {
$value = $transformer->transform($value);
}
return $value;
}
/**
* Reverse transforms a value if a normalization transformer is set.
*
* @param string $value The value to reverse transform
*
* @return mixed
*/
private function normToModel($value)
{
$transformers = $this->config->getModelTransformers();
for ($i = count($transformers) - 1; $i >= 0; --$i) {
$value = $transformers[$i]->reverseTransform($value);
}
return $value;
}
/**
* Transforms the value if a value transformer is set.
*
* @param mixed $value The value to transform
*
* @return mixed
*/
private function normToView($value)
{
// Scalar values should be converted to strings to
// facilitate differentiation between empty ("") and zero (0).
// Only do this for simple forms, as the resulting value in
// compound forms is passed to the data mapper and thus should
// not be converted to a string before.
if (!$this->config->getViewTransformers() && !$this->config->getCompound()) {
return null === $value || is_scalar($value) ? (string) $value : $value;
}
foreach ($this->config->getViewTransformers() as $transformer) {
$value = $transformer->transform($value);
}
return $value;
}
/**
* Reverse transforms a value if a value transformer is set.
*
* @param string $value The value to reverse transform
*
* @return mixed
*/
private function viewToNorm($value)
{
$transformers = $this->config->getViewTransformers();
if (!$transformers) {
return '' === $value ? null : $value;
}
for ($i = count($transformers) - 1; $i >= 0; --$i) {
$value = $transformers[$i]->reverseTransform($value);
}
return $value;
}
}
PK ! di $ Exception/BadMethodCallException.phpnu [
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Form\Exception;
/**
* Base BadMethodCallException for the Form component.
*
* @author Bernhard Schussek
*/
class BadMethodCallException extends \BadMethodCallException implements ExceptionInterface
{
}
PK ! W
# Exception/AlreadyBoundException.phpnu [
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Form\Exception;
/**
* Alias of {@link AlreadySubmittedException}.
*
* @deprecated Deprecated since version 2.3, to be removed in 3.0. Use
* {@link AlreadySubmittedException} instead.
*/
class AlreadyBoundException extends LogicException
{
}
PK ! (d d + Exception/InvalidConfigurationException.phpnu [
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Form\Exception;
class InvalidConfigurationException extends InvalidArgumentException
{
}
PK ! _c= = % Exception/UnexpectedTypeException.phpnu [
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Form\Exception;
class UnexpectedTypeException extends InvalidArgumentException
{
public function __construct($value, $expectedType)
{
parent::__construct(sprintf('Expected argument of type "%s", "%s" given', $expectedType, is_object($value) ? get_class($value) : gettype($value)));
}
}
PK ! SD + Exception/TransformationFailedException.phpnu [
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Form\Exception;
/**
* Indicates a value transformation error.
*
* @author Bernhard Schussek
*/
class TransformationFailedException extends RuntimeException
{
}
PK ! é " Exception/OutOfBoundsException.phpnu [
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Form\Exception;
/**
* Base OutOfBoundsException for Form component.
*
* @author Alexander Kotynia
*/
class OutOfBoundsException extends \OutOfBoundsException implements ExceptionInterface
{
}
PK ! yu Exception/ExceptionInterface.phpnu [
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Form\Exception;
/**
* Base ExceptionInterface for the Form component.
*
* @author Bernhard Schussek
*/
interface ExceptionInterface
{
}
PK ! N Exception/RuntimeException.phpnu [
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Form\Exception;
/**
* Base RuntimeException for the Form component.
*
* @author Bernhard Schussek
*/
class RuntimeException extends \RuntimeException implements ExceptionInterface
{
}
PK ! K9 ' Exception/AlreadySubmittedException.phpnu [
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Form\Exception;
/**
* Thrown when an operation is called that is not acceptable after submitting
* a form.
*
* @author Bernhard Schussek
*/
class AlreadySubmittedException extends AlreadyBoundException
{
}
PK ! 1;T T # Exception/ErrorMappingException.phpnu [
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Form\Exception;
class ErrorMappingException extends RuntimeException
{
}
PK ! +R R ! Exception/StringCastException.phpnu [
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Form\Exception;
class StringCastException extends RuntimeException
{
}
PK ! X Exception/LogicException.phpnu [
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Form\Exception;
/**
* Base LogicException for Form component.
*
* @author Alexander Kotynia
*/
class LogicException extends \LogicException implements ExceptionInterface
{
}
PK ! gBz &