2011-02-19 12:52:37 +00:00
|
|
|
<?php
|
|
|
|
|
|
|
|
/*
|
|
|
|
* This file is part of the Symfony package.
|
|
|
|
*
|
|
|
|
* (c) Fabien Potencier <fabien.potencier@symfony-project.com>
|
|
|
|
*
|
|
|
|
* For the full copyright and license information, please view the LICENSE
|
|
|
|
* file that was distributed with this source code.
|
|
|
|
*/
|
|
|
|
|
|
|
|
namespace Symfony\Component\Form;
|
|
|
|
|
2011-03-22 11:36:41 +00:00
|
|
|
use Symfony\Component\Form\Type\FormTypeInterface;
|
2011-03-18 15:20:00 +00:00
|
|
|
use Symfony\Component\Form\Type\Loader\TypeLoaderInterface;
|
2011-03-19 15:46:03 +00:00
|
|
|
use Symfony\Component\Form\Type\Guesser\TypeGuesserInterface;
|
|
|
|
use Symfony\Component\Form\Type\Guesser\Guess;
|
2011-03-25 14:30:33 +00:00
|
|
|
use Symfony\Component\Form\Exception\FormException;
|
2011-03-25 01:26:14 +00:00
|
|
|
use Symfony\Component\Form\Exception\UnexpectedTypeException;
|
2011-02-19 12:52:37 +00:00
|
|
|
|
2011-03-02 11:20:30 +00:00
|
|
|
class FormFactory implements FormFactoryInterface
|
2011-02-19 12:52:37 +00:00
|
|
|
{
|
2011-03-18 15:20:00 +00:00
|
|
|
private $typeLoader;
|
2011-03-02 13:58:19 +00:00
|
|
|
|
|
|
|
private $guessers = array();
|
|
|
|
|
2011-04-07 08:57:44 +01:00
|
|
|
public function __construct(TypeLoaderInterface $typeLoader, array $guessers = array())
|
2011-02-19 12:52:37 +00:00
|
|
|
{
|
2011-03-25 01:26:14 +00:00
|
|
|
foreach ($guessers as $guesser) {
|
|
|
|
if (!$guesser instanceof TypeGuesserInterface) {
|
|
|
|
throw new UnexpectedTypeException($guesser, 'Symfony\Component\Form\Type\Guesser\TypeGuesserInterface');
|
|
|
|
}
|
|
|
|
}
|
2011-03-18 15:20:00 +00:00
|
|
|
$this->typeLoader = $typeLoader;
|
2011-03-25 01:26:14 +00:00
|
|
|
$this->guessers = $guessers;
|
2011-02-19 12:52:37 +00:00
|
|
|
}
|
|
|
|
|
2011-03-18 15:20:00 +00:00
|
|
|
public function createBuilder($type, $name = null, array $options = array())
|
2011-02-19 14:26:07 +00:00
|
|
|
{
|
2011-03-18 15:20:00 +00:00
|
|
|
// TODO $type can be FQN of a type class
|
2011-03-04 15:01:50 +00:00
|
|
|
|
2011-03-18 11:50:26 +00:00
|
|
|
$builder = null;
|
2011-03-24 15:16:31 +00:00
|
|
|
$types = array();
|
2011-03-25 14:30:33 +00:00
|
|
|
$knownOptions = array();
|
|
|
|
$passedOptions = array_keys($options);
|
2011-02-21 22:40:12 +00:00
|
|
|
|
2011-03-02 15:00:31 +00:00
|
|
|
// TESTME
|
2011-03-26 17:48:55 +00:00
|
|
|
if (null === $name) {
|
2011-04-15 17:58:15 +01:00
|
|
|
$name = is_object($type) ? $type->getName() : $type;
|
2011-03-02 15:00:31 +00:00
|
|
|
}
|
|
|
|
|
2011-03-18 15:20:00 +00:00
|
|
|
while (null !== $type) {
|
|
|
|
// TODO check if type exists
|
2011-03-26 17:48:55 +00:00
|
|
|
if (!$type instanceof FormTypeInterface) {
|
|
|
|
$type = $this->typeLoader->getType($type);
|
|
|
|
}
|
|
|
|
|
2011-03-24 15:16:31 +00:00
|
|
|
array_unshift($types, $type);
|
2011-03-25 14:30:33 +00:00
|
|
|
$defaultOptions = $type->getDefaultOptions($options);
|
|
|
|
$options = array_merge($defaultOptions, $options);
|
|
|
|
$knownOptions = array_merge($knownOptions, array_keys($defaultOptions));
|
2011-03-18 15:20:00 +00:00
|
|
|
$type = $type->getParent($options);
|
2011-02-21 22:40:12 +00:00
|
|
|
}
|
2011-02-19 12:52:37 +00:00
|
|
|
|
2011-03-25 14:30:33 +00:00
|
|
|
$diff = array_diff($passedOptions, $knownOptions);
|
|
|
|
|
|
|
|
if (count($diff) > 0) {
|
|
|
|
throw new FormException(sprintf('The options "%s" do not exist', implode('", "', $diff)));
|
|
|
|
}
|
|
|
|
|
|
|
|
for ($i = 0, $l = count($types); $i < $l && !$builder; ++$i) {
|
2011-04-14 14:25:30 +01:00
|
|
|
$builder = $types[$i]->createBuilder($name, $this, $options);
|
2011-03-25 14:30:33 +00:00
|
|
|
}
|
|
|
|
|
2011-03-02 13:58:19 +00:00
|
|
|
// TODO check if instance exists
|
2011-02-19 16:30:19 +00:00
|
|
|
|
2011-03-24 15:16:31 +00:00
|
|
|
$builder->setTypes($types);
|
2011-03-18 11:50:26 +00:00
|
|
|
|
2011-03-24 15:16:31 +00:00
|
|
|
foreach ($types as $type) {
|
2011-03-26 17:52:24 +00:00
|
|
|
$type->buildForm($builder, $options);
|
2011-02-19 14:26:07 +00:00
|
|
|
}
|
|
|
|
|
2011-03-18 11:50:26 +00:00
|
|
|
return $builder;
|
2011-03-01 14:18:55 +00:00
|
|
|
}
|
2011-03-02 13:58:19 +00:00
|
|
|
|
2011-03-18 15:20:00 +00:00
|
|
|
public function create($type, $name = null, array $options = array())
|
2011-03-18 11:50:26 +00:00
|
|
|
{
|
2011-03-20 14:16:53 +00:00
|
|
|
return $this->createBuilder($type, $name, $options)->getForm();
|
2011-03-18 11:50:26 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
public function createBuilderForProperty($class, $property, array $options = array())
|
2011-03-02 13:58:19 +00:00
|
|
|
{
|
|
|
|
// guess field class and options
|
2011-03-18 15:20:00 +00:00
|
|
|
$typeGuess = $this->guess(function ($guesser) use ($class, $property) {
|
|
|
|
return $guesser->guessType($class, $property);
|
2011-03-02 13:58:19 +00:00
|
|
|
});
|
|
|
|
|
|
|
|
// guess maximum length
|
|
|
|
$maxLengthGuess = $this->guess(function ($guesser) use ($class, $property) {
|
|
|
|
return $guesser->guessMaxLength($class, $property);
|
|
|
|
});
|
|
|
|
|
|
|
|
// guess whether field is required
|
|
|
|
$requiredGuess = $this->guess(function ($guesser) use ($class, $property) {
|
|
|
|
return $guesser->guessRequired($class, $property);
|
|
|
|
});
|
|
|
|
|
|
|
|
// construct field
|
2011-03-18 15:20:00 +00:00
|
|
|
$type = $typeGuess ? $typeGuess->getType() : 'text';
|
2011-03-02 13:58:19 +00:00
|
|
|
|
2011-03-18 13:37:54 +00:00
|
|
|
if ($maxLengthGuess) {
|
|
|
|
$options = array_merge(array('max_length' => $maxLengthGuess->getValue()), $options);
|
2011-03-02 13:58:19 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if ($requiredGuess) {
|
|
|
|
$options = array_merge(array('required' => $requiredGuess->getValue()), $options);
|
|
|
|
}
|
|
|
|
|
|
|
|
// user options may override guessed options
|
2011-03-18 15:20:00 +00:00
|
|
|
if ($typeGuess) {
|
|
|
|
$options = array_merge($typeGuess->getOptions(), $options);
|
2011-03-18 13:37:54 +00:00
|
|
|
}
|
2011-03-02 13:58:19 +00:00
|
|
|
|
2011-03-18 15:20:00 +00:00
|
|
|
return $this->createBuilder($type, $property, $options);
|
2011-03-18 11:50:26 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @inheritDoc
|
|
|
|
*/
|
2011-03-18 13:37:54 +00:00
|
|
|
public function createForProperty($class, $property, array $options = array())
|
2011-03-18 11:50:26 +00:00
|
|
|
{
|
2011-03-20 14:16:53 +00:00
|
|
|
return $this->createBuilderForProperty($class, $property, $options)->getForm();
|
2011-03-02 13:58:19 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* 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 FieldFactoryGuess
|
|
|
|
* instance
|
|
|
|
* @return FieldFactoryGuess The guess with the highest confidence
|
|
|
|
*/
|
|
|
|
protected function guess(\Closure $closure)
|
|
|
|
{
|
|
|
|
$guesses = array();
|
|
|
|
|
|
|
|
foreach ($this->guessers as $guesser) {
|
|
|
|
if ($guess = $closure($guesser)) {
|
|
|
|
$guesses[] = $guess;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-03-19 15:46:03 +00:00
|
|
|
return Guess::getBestGuess($guesses);
|
2011-03-02 13:58:19 +00:00
|
|
|
}
|
2011-03-24 21:20:54 +00:00
|
|
|
}
|