Merge remote branch 'origin/master' into annotations
Conflicts: UPDATE.md src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Configuration.php src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php
This commit is contained in:
commit
6c0b0449a6
28
UPDATE.md
28
UPDATE.md
@ -87,6 +87,31 @@ beta1 to beta2
|
||||
*/
|
||||
private $foo;
|
||||
|
||||
* Forms must now be explicitly enabled (automatically done in Symfony SE):
|
||||
|
||||
form: ~
|
||||
|
||||
# equivalent to
|
||||
form:
|
||||
enabled: true
|
||||
|
||||
* The Routing Exceptions have been moved:
|
||||
|
||||
Before:
|
||||
|
||||
Symfony\Component\Routing\Matcher\Exception\Exception
|
||||
Symfony\Component\Routing\Matcher\Exception\NotFoundException
|
||||
Symfony\Component\Routing\Matcher\Exception\MethodNotAllowedException
|
||||
|
||||
After:
|
||||
|
||||
Symfony\Component\Routing\Exception\Exception
|
||||
Symfony\Component\Routing\Exception\NotFoundException
|
||||
Symfony\Component\Routing\Exception\MethodNotAllowedException
|
||||
|
||||
* The form component's ``csrf_page_id`` option has been renamed to
|
||||
``intention``.
|
||||
|
||||
* The ``error_handler`` setting has been removed. The ``ErrorHandler`` class
|
||||
is now managed directly by Symfony SE in ``AppKernel``.
|
||||
|
||||
@ -220,6 +245,9 @@ beta1 to beta2
|
||||
* Form: Renamed option value "text" of "widget" option of the "date" type was
|
||||
renamed to "single-text". "text" indicates to use separate text boxes now
|
||||
(like for the "time" type).
|
||||
|
||||
* Form: Renamed view variable "name" to "full_name". The variable "name" now
|
||||
contains the local, short name (equivalent to $form->getName()).
|
||||
|
||||
PR12 to beta1
|
||||
-------------
|
||||
|
@ -180,4 +180,12 @@ class DoctrineOrmTypeGuesser implements FormTypeGuesserInterface
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
public function guessMinLength($class, $property)
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
@ -32,8 +32,10 @@ class EntityType extends AbstractType
|
||||
public function buildForm(FormBuilder $builder, array $options)
|
||||
{
|
||||
if ($options['multiple']) {
|
||||
$builder->addEventSubscriber(new MergeCollectionListener())
|
||||
->prependClientTransformer(new EntitiesToArrayTransformer($options['choice_list']));
|
||||
$builder
|
||||
->addEventSubscriber(new MergeCollectionListener())
|
||||
->prependClientTransformer(new EntitiesToArrayTransformer($options['choice_list']))
|
||||
;
|
||||
} else {
|
||||
$builder->prependClientTransformer(new EntityToIdTransformer($options['choice_list']));
|
||||
}
|
||||
@ -42,16 +44,16 @@ class EntityType extends AbstractType
|
||||
public function getDefaultOptions(array $options)
|
||||
{
|
||||
$defaultOptions = array(
|
||||
'multiple' => false,
|
||||
'expanded' => false,
|
||||
'em' => $this->em,
|
||||
'class' => null,
|
||||
'property' => null,
|
||||
'query_builder' => null,
|
||||
'choices' => array(),
|
||||
'multiple' => false,
|
||||
'expanded' => false,
|
||||
'em' => $this->em,
|
||||
'class' => null,
|
||||
'property' => null,
|
||||
'query_builder' => null,
|
||||
'choices' => array(),
|
||||
'preferred_choices' => array(),
|
||||
'multiple' => false,
|
||||
'expanded' => false,
|
||||
'multiple' => false,
|
||||
'expanded' => false,
|
||||
);
|
||||
|
||||
$options = array_replace($defaultOptions, $options);
|
||||
|
@ -0,0 +1,56 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Bridge\Doctrine\Validator\Constraints;
|
||||
|
||||
use Symfony\Component\Validator\Constraint;
|
||||
use Symfony\Component\Validator\ConstraintValidator;
|
||||
use Symfony\Component\Validator\Exception\UnexpectedTypeException;
|
||||
|
||||
/**
|
||||
* Constraint for the Unique Entity validator
|
||||
*
|
||||
* @author Benjamin Eberlei <kontakt@beberlei.de>
|
||||
*/
|
||||
class UniqueEntity extends Constraint
|
||||
{
|
||||
public $message = 'This value is already used.';
|
||||
public $em = null;
|
||||
public $fields = array();
|
||||
|
||||
public function getRequiredOptions()
|
||||
{
|
||||
return array('fields');
|
||||
}
|
||||
|
||||
/**
|
||||
* The validator must be defined as a service with this name.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function validatedBy()
|
||||
{
|
||||
return 'doctrine.orm.validator.unique';
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function getTargets()
|
||||
{
|
||||
return self::CLASS_CONSTRAINT;
|
||||
}
|
||||
|
||||
public function getDefaultOption()
|
||||
{
|
||||
return 'fields';
|
||||
}
|
||||
}
|
@ -0,0 +1,81 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Bridge\Doctrine\Validator\Constraints;
|
||||
|
||||
use Symfony\Bundle\DoctrineBundle\Registry;
|
||||
use Symfony\Component\Validator\Constraint;
|
||||
use Symfony\Component\Validator\Exception\UnexpectedTypeException;
|
||||
use Symfony\Component\Validator\Exception\ConstraintDefinitionException;
|
||||
use Symfony\Component\Validator\ConstraintValidator;
|
||||
|
||||
/**
|
||||
* Unique Entity Validator checks if one or a set of fields contain unique values.
|
||||
*
|
||||
* @author Benjamin Eberlei <kontakt@beberlei.de>
|
||||
*/
|
||||
class UniqueEntityValidator extends ConstraintValidator
|
||||
{
|
||||
/**
|
||||
* @var Registry
|
||||
*/
|
||||
private $registry;
|
||||
|
||||
/**
|
||||
* @param Registry $registry
|
||||
*/
|
||||
public function __construct(Registry $registry)
|
||||
{
|
||||
$this->registry = $registry;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param object $entity
|
||||
* @param Constraint $constraint
|
||||
* @return bool
|
||||
*/
|
||||
public function isValid($entity, Constraint $constraint)
|
||||
{
|
||||
if (!is_array($constraint->fields) && !is_string($constraint->fields)) {
|
||||
throw new UnexpectedTypeException($constraint->fields, 'array');
|
||||
}
|
||||
$fields = (array)$constraint->fields;
|
||||
if (count($constraint->fields) == 0) {
|
||||
throw new ConstraintDefinitionException("At least one field has to specified.");
|
||||
}
|
||||
|
||||
$em = $this->registry->getEntityManager($constraint->em);
|
||||
|
||||
$className = $this->context->getCurrentClass();
|
||||
$class = $em->getClassMetadata($className);
|
||||
|
||||
$criteria = array();
|
||||
foreach ($fields as $fieldName) {
|
||||
if (!isset($class->reflFields[$fieldName])) {
|
||||
throw new ConstraintDefinitionException("Only field names mapped by Doctrine can be validated for uniqueness.");
|
||||
}
|
||||
|
||||
$criteria[$fieldName] = $class->reflFields[$fieldName]->getValue($entity);
|
||||
}
|
||||
|
||||
$repository = $em->getRepository($className);
|
||||
$result = $repository->findBy($criteria);
|
||||
|
||||
if (count($result) > 0 && $result[0] !== $entity) {
|
||||
$oldPath = $this->context->getPropertyPath();
|
||||
$this->context->setPropertyPath( empty($oldPath) ? $fields[0] : $oldPath . "." . $fields[0]);
|
||||
$this->context->addViolation($constraint->message, array(), $criteria[$constraint->fields[0]]);
|
||||
$this->context->setPropertyPath($oldPath);
|
||||
}
|
||||
|
||||
return true; // all true, we added the violation already!
|
||||
}
|
||||
}
|
@ -34,16 +34,9 @@ class TransChoiceTokenParser extends TransTokenParser
|
||||
|
||||
$vars = new \Twig_Node_Expression_Array(array(), $lineno);
|
||||
|
||||
$body = null;
|
||||
$count = $this->parser->getExpressionParser()->parseExpression();
|
||||
$domain = new \Twig_Node_Expression_Constant('messages', $lineno);
|
||||
|
||||
if (!$stream->test(\Twig_Token::BLOCK_END_TYPE) && $stream->test('for')) {
|
||||
// {% transchoice count for "message" %}
|
||||
// {% transchoice count for message %}
|
||||
$stream->next();
|
||||
$body = $this->parser->getExpressionParser()->parseExpression();
|
||||
}
|
||||
$domain = new \Twig_Node_Expression_Constant('messages', $lineno);
|
||||
|
||||
if ($stream->test('with')) {
|
||||
// {% transchoice count with vars %}
|
||||
@ -57,11 +50,9 @@ class TransChoiceTokenParser extends TransTokenParser
|
||||
$domain = $this->parser->getExpressionParser()->parseExpression();
|
||||
}
|
||||
|
||||
if (null === $body) {
|
||||
// {% transchoice count %}message{% endtranschoice %}
|
||||
$stream->expect(\Twig_Token::BLOCK_END_TYPE);
|
||||
$body = $this->parser->subparse(array($this, 'decideTransChoiceFork'), true);
|
||||
}
|
||||
$stream->expect(\Twig_Token::BLOCK_END_TYPE);
|
||||
|
||||
$body = $this->parser->subparse(array($this, 'decideTransChoiceFork'), true);
|
||||
|
||||
if (!$body instanceof \Twig_Node_Text && !$body instanceof \Twig_Node_Expression) {
|
||||
throw new \Twig_Error_Syntax('A message must be a simple text.');
|
||||
|
@ -36,6 +36,8 @@ class DumpCommand extends Command
|
||||
->setDescription('Dumps all assets to the filesystem')
|
||||
->addArgument('write_to', InputArgument::OPTIONAL, 'Override the configured asset root')
|
||||
->addOption('watch', null, InputOption::VALUE_NONE, 'Check for changes every second, debug mode only')
|
||||
->addOption('force', null, InputOption::VALUE_NONE, 'Force an initial generation of all assets (used with --watch)')
|
||||
->addOption('period', null, InputOption::VALUE_REQUIRED, 'Set the polling period in seconds (used with --watch)', 1)
|
||||
;
|
||||
}
|
||||
|
||||
@ -49,6 +51,10 @@ class DumpCommand extends Command
|
||||
|
||||
protected function execute(InputInterface $input, OutputInterface $output)
|
||||
{
|
||||
$output->writeln(sprintf('Dumping all <comment>%s</comment> assets.', $input->getOption('env')));
|
||||
$output->writeln(sprintf('Debug mode is <comment>%s</comment>.', $input->getOption('no-debug') ? 'off' : 'on'));
|
||||
$output->writeln('');
|
||||
|
||||
if (!$input->getOption('watch')) {
|
||||
foreach ($this->am->getNames() as $name) {
|
||||
$this->dumpAsset($name, $output);
|
||||
@ -61,7 +67,7 @@ class DumpCommand extends Command
|
||||
throw new \RuntimeException('The --watch option is only available in debug mode.');
|
||||
}
|
||||
|
||||
$this->watch($output);
|
||||
$this->watch($input, $output);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -72,25 +78,25 @@ class DumpCommand extends Command
|
||||
*
|
||||
* @param OutputInterface $output The command output
|
||||
*/
|
||||
private function watch(OutputInterface $output)
|
||||
private function watch(InputInterface $input, OutputInterface $output)
|
||||
{
|
||||
$refl = new \ReflectionClass('Assetic\\AssetManager');
|
||||
$prop = $refl->getProperty('assets');
|
||||
$prop->setAccessible(true);
|
||||
|
||||
$cache = sys_get_temp_dir().'/assetic_watch_'.substr(sha1($this->basePath), 0, 7);
|
||||
if (file_exists($cache)) {
|
||||
$previously = unserialize(file_get_contents($cache));
|
||||
} else {
|
||||
if ($input->getOption('force') || !file_exists($cache)) {
|
||||
$previously = array();
|
||||
} else {
|
||||
$previously = unserialize(file_get_contents($cache));
|
||||
}
|
||||
|
||||
$error = '';
|
||||
while (true) {
|
||||
try {
|
||||
foreach ($this->am->getNames() as $name) {
|
||||
if ($asset = $this->checkAsset($name, $previously)) {
|
||||
$this->dumpAsset($asset, $output);
|
||||
if ($this->checkAsset($name, $previously)) {
|
||||
$this->dumpAsset($name, $output);
|
||||
}
|
||||
}
|
||||
|
||||
@ -101,7 +107,7 @@ class DumpCommand extends Command
|
||||
file_put_contents($cache, serialize($previously));
|
||||
$error = '';
|
||||
|
||||
sleep(1);
|
||||
sleep($input->getOption('period'));
|
||||
} catch (\Exception $e) {
|
||||
if ($error != $msg = $e->getMessage()) {
|
||||
$output->writeln('<error>[error]</error> '.$msg);
|
||||
@ -117,7 +123,7 @@ class DumpCommand extends Command
|
||||
* @param string $name The asset name
|
||||
* @param array &$previously An array of previous visits
|
||||
*
|
||||
* @return AssetInterface|Boolean The asset if it should be dumped
|
||||
* @return Boolean Whether the asset should be dumped
|
||||
*/
|
||||
private function checkAsset($name, array &$previously)
|
||||
{
|
||||
@ -133,7 +139,7 @@ class DumpCommand extends Command
|
||||
|
||||
$previously[$name] = array('mtime' => $mtime, 'formula' => $formula);
|
||||
|
||||
return $changed ? $asset : false;
|
||||
return $changed;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -0,0 +1,16 @@
|
||||
<?xml version="1.0" ?>
|
||||
|
||||
<container xmlns="http://symfony.com/schema/dic/services"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://symfony.com/schema/dic/services http://symfony.com/schema/dic/services/services-1.0.xsd">
|
||||
|
||||
<parameters>
|
||||
<parameter key="assetic.filter.cssimport.class">Assetic\Filter\CssImportFilter</parameter>
|
||||
</parameters>
|
||||
|
||||
<services>
|
||||
<service id="assetic.filter.cssimport" class="%assetic.filter.cssimport.class%">
|
||||
<tag name="assetic.filter" alias="cssimport" />
|
||||
</service>
|
||||
</services>
|
||||
</container>
|
@ -0,0 +1,18 @@
|
||||
<?xml version="1.0" ?>
|
||||
|
||||
<container xmlns="http://symfony.com/schema/dic/services"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://symfony.com/schema/dic/services http://symfony.com/schema/dic/services/services-1.0.xsd">
|
||||
|
||||
<parameters>
|
||||
<parameter key="assetic.filter.packager.class">Assetic\Filter\PackagerFilter</parameter>
|
||||
<parameter key="assetic.filter.packager.packages" type="collection" />
|
||||
</parameters>
|
||||
|
||||
<services>
|
||||
<service id="assetic.filter.packager" class="%assetic.filter.packager.class%">
|
||||
<tag name="assetic.filter" alias="packager" />
|
||||
<argument>%assetic.filter.packager.packages%</argument>
|
||||
</service>
|
||||
</services>
|
||||
</container>
|
@ -15,14 +15,12 @@
|
||||
<tag name="assetic.templating.php" />
|
||||
<argument type="service" id="templating.helper.router" />
|
||||
<argument type="service" id="assetic.asset_factory" />
|
||||
<argument>%assetic.debug%</argument>
|
||||
</service>
|
||||
|
||||
<service id="assetic.helper.static" class="%assetic.helper.static.class%">
|
||||
<tag name="assetic.templating.php" />
|
||||
<argument type="service" id="templating.helper.assets" />
|
||||
<argument type="service" id="assetic.asset_factory" />
|
||||
<argument>%assetic.debug%</argument>
|
||||
</service>
|
||||
|
||||
<service id="assetic.php_formula_loader" class="%assetic.cached_formula_loader.class%" public="false">
|
||||
|
@ -67,8 +67,11 @@ class AsseticLoader extends Loader
|
||||
|
||||
$this->loadRouteForAsset($routes, $asset, $name);
|
||||
|
||||
$debug = isset($formula[2]['debug']) ? $formula[2]['debug'] : $this->am->isDebug();
|
||||
$combine = isset($formula[2]['combine']) ? $formula[2]['combine'] : !$debug;
|
||||
|
||||
// add a route for each "leaf" in debug mode
|
||||
if (isset($formula[2]['debug']) ? $formula[2]['debug'] : $this->am->isDebug()) {
|
||||
if (!$combine) {
|
||||
$i = 0;
|
||||
foreach ($asset as $leaf) {
|
||||
$this->loadRouteForAsset($routes, $leaf, $name, $i++);
|
||||
|
@ -13,6 +13,7 @@ namespace Symfony\Bundle\AsseticBundle\Templating;
|
||||
|
||||
use Assetic\Asset\AssetInterface;
|
||||
use Assetic\Factory\AssetFactory;
|
||||
use Assetic\Util\TraversableString;
|
||||
use Symfony\Component\Templating\Helper\Helper;
|
||||
|
||||
/**
|
||||
@ -23,18 +24,15 @@ use Symfony\Component\Templating\Helper\Helper;
|
||||
abstract class AsseticHelper extends Helper
|
||||
{
|
||||
protected $factory;
|
||||
protected $debug;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param AssetFactory $factory The asset factory
|
||||
* @param Boolean $debug The debug mode
|
||||
*/
|
||||
public function __construct(AssetFactory $factory, $debug = false)
|
||||
public function __construct(AssetFactory $factory)
|
||||
{
|
||||
$this->factory = $factory;
|
||||
$this->debug = $debug;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -43,7 +41,7 @@ abstract class AsseticHelper extends Helper
|
||||
public function javascripts($inputs = array(), $filters = array(), array $options = array())
|
||||
{
|
||||
if (!isset($options['output'])) {
|
||||
$options['output'] = 'js/*';
|
||||
$options['output'] = 'js/*.js';
|
||||
}
|
||||
|
||||
return $this->getAssetUrls($inputs, $filters, $options);
|
||||
@ -55,7 +53,7 @@ abstract class AsseticHelper extends Helper
|
||||
public function stylesheets($inputs = array(), $filters = array(), array $options = array())
|
||||
{
|
||||
if (!isset($options['output'])) {
|
||||
$options['output'] = 'css/*';
|
||||
$options['output'] = 'css/*.css';
|
||||
}
|
||||
|
||||
return $this->getAssetUrls($inputs, $filters, $options);
|
||||
@ -109,7 +107,11 @@ abstract class AsseticHelper extends Helper
|
||||
}
|
||||
|
||||
if (!isset($options['debug'])) {
|
||||
$options['debug'] = $this->debug;
|
||||
$options['debug'] = $this->factory->isDebug();
|
||||
}
|
||||
|
||||
if (!isset($options['combine'])) {
|
||||
$options['combine'] = !$options['debug'];
|
||||
}
|
||||
|
||||
if (isset($options['single']) && $options['single'] && 1 < count($inputs)) {
|
||||
@ -117,23 +119,25 @@ abstract class AsseticHelper extends Helper
|
||||
}
|
||||
|
||||
if (!isset($options['name'])) {
|
||||
$options['name'] = $this->factory->generateAssetName($inputs, $filters);
|
||||
$options['name'] = $this->factory->generateAssetName($inputs, $filters, $options);
|
||||
}
|
||||
|
||||
$coll = $this->factory->createAsset($inputs, $filters, $options);
|
||||
$asset = $this->factory->createAsset($inputs, $filters, $options);
|
||||
|
||||
if (!$options['debug']) {
|
||||
return array($this->getAssetUrl($coll, $options));
|
||||
$one = $this->getAssetUrl($asset, $options);
|
||||
$many = array();
|
||||
if ($options['combine']) {
|
||||
$many[] = $one;
|
||||
} else {
|
||||
$i = 0;
|
||||
foreach ($asset as $leaf) {
|
||||
$many[] = $this->getAssetUrl($leaf, array_replace($options, array(
|
||||
'name' => $options['name'].'_'.$i++,
|
||||
)));
|
||||
}
|
||||
}
|
||||
|
||||
$urls = array();
|
||||
foreach ($coll as $leaf) {
|
||||
$urls[] = $this->getAssetUrl($leaf, array_replace($options, array(
|
||||
'name' => $options['name'].'_'.count($urls),
|
||||
)));
|
||||
}
|
||||
|
||||
return $urls;
|
||||
return new TraversableString($one, $many);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -29,13 +29,12 @@ class DynamicAsseticHelper extends AsseticHelper
|
||||
*
|
||||
* @param RouterHelper $routerHelper The router helper
|
||||
* @param AssetFactory $factory The asset factory
|
||||
* @param Boolean $debug The debug mode
|
||||
*/
|
||||
public function __construct(RouterHelper $routerHelper, AssetFactory $factory, $debug = false)
|
||||
public function __construct(RouterHelper $routerHelper, AssetFactory $factory)
|
||||
{
|
||||
$this->routerHelper = $routerHelper;
|
||||
|
||||
parent::__construct($factory, $debug);
|
||||
parent::__construct($factory);
|
||||
}
|
||||
|
||||
protected function getAssetUrl(AssetInterface $asset, $options = array())
|
||||
|
@ -29,13 +29,12 @@ class StaticAsseticHelper extends AsseticHelper
|
||||
*
|
||||
* @param AssetsHelper $assetsHelper The assets helper
|
||||
* @param AssetFactory $factory The asset factory
|
||||
* @param Boolean $debug The debug mode
|
||||
*/
|
||||
public function __construct(AssetsHelper $assetsHelper, AssetFactory $factory, $debug = false)
|
||||
public function __construct(AssetsHelper $assetsHelper, AssetFactory $factory)
|
||||
{
|
||||
$this->assetsHelper = $assetsHelper;
|
||||
|
||||
parent::__construct($factory, $debug);
|
||||
parent::__construct($factory);
|
||||
}
|
||||
|
||||
protected function getAssetUrl(AssetInterface $asset, $options = array())
|
||||
|
@ -13,6 +13,7 @@ namespace Symfony\Bundle\AsseticBundle\Tests\Command;
|
||||
|
||||
use Symfony\Bundle\AsseticBundle\Command\DumpCommand;
|
||||
use Symfony\Component\Console\Input\ArrayInput;
|
||||
use Symfony\Component\Console\Input\InputOption;
|
||||
use Symfony\Component\Console\Output\NullOutput;
|
||||
|
||||
class DumpCommandTest extends \PHPUnit_Framework_TestCase
|
||||
@ -52,7 +53,10 @@ class DumpCommandTest extends \PHPUnit_Framework_TestCase
|
||||
->will($this->returnValue(array()));
|
||||
$this->definition->expects($this->any())
|
||||
->method('getOptions')
|
||||
->will($this->returnValue(array()));
|
||||
->will($this->returnValue(array(
|
||||
new InputOption('--env', '-e', InputOption::VALUE_REQUIRED, 'The Environment name.', 'dev'),
|
||||
new InputOption('--no-debug', null, InputOption::VALUE_NONE, 'Switches off debug mode.'),
|
||||
)));
|
||||
$this->application->expects($this->any())
|
||||
->method('getKernel')
|
||||
->will($this->returnValue($this->kernel));
|
||||
|
@ -102,12 +102,16 @@ class AsseticExtensionTest extends \PHPUnit_Framework_TestCase
|
||||
return array(
|
||||
array('closure', array('jar' => '/path/to/closure.jar')),
|
||||
array('coffee'),
|
||||
array('compass'),
|
||||
array('cssembed', array('jar' => '/path/to/cssembed.jar')),
|
||||
array('cssimport'),
|
||||
array('cssrewrite'),
|
||||
array('jpegtran'),
|
||||
array('jpegoptim'),
|
||||
array('jpegtran'),
|
||||
array('less'),
|
||||
array('lessphp'),
|
||||
array('optipng'),
|
||||
array('packager'),
|
||||
array('pngout'),
|
||||
array('sass'),
|
||||
array('scss'),
|
||||
|
@ -43,41 +43,6 @@ class FunctionalTest extends \PHPUnit_Framework_TestCase
|
||||
$filesystem->remove($this->cacheDir);
|
||||
}
|
||||
|
||||
public function testRoutes()
|
||||
{
|
||||
$countRoutes = function($router)
|
||||
{
|
||||
$count = 0;
|
||||
foreach ($router->getRouteCollection()->all() as $name => $route) {
|
||||
if (0 === strpos($name, '_assetic_')) {
|
||||
++$count;
|
||||
}
|
||||
}
|
||||
|
||||
return $count;
|
||||
};
|
||||
|
||||
$kernel = new TestKernel('test', false);
|
||||
$kernel->boot();
|
||||
|
||||
$am = $kernel->getContainer()->get('assetic.asset_manager');
|
||||
$names = $am->getNames();
|
||||
$baseline = $expected = count($names);
|
||||
|
||||
foreach ($names as $name) {
|
||||
$asset = $am->get($name);
|
||||
foreach ($asset as $leaf) {
|
||||
++$expected;
|
||||
}
|
||||
}
|
||||
|
||||
$this->assertEquals($baseline, $countRoutes($kernel->getContainer()->get('router')));
|
||||
|
||||
$kernel = new TestKernel('test', true);
|
||||
$kernel->boot();
|
||||
$this->assertEquals($expected, $countRoutes($kernel->getContainer()->get('router')));
|
||||
}
|
||||
|
||||
public function testTwigRenderDebug()
|
||||
{
|
||||
$kernel = new TestKernel('test', true);
|
||||
|
@ -34,7 +34,7 @@ class AsseticHelperTest extends \PHPUnit_Framework_TestCase
|
||||
$helper = new AsseticHelperForTest(new AssetFactory('/foo', $debug), $debug);
|
||||
$urls = $helper->javascripts(array('js/jquery.js', 'js/jquery.plugin.js'));
|
||||
|
||||
$this->assertInternalType('array', $urls, '->javascripts() returns an array');
|
||||
$this->assertInstanceOf('Traversable', $urls, '->javascripts() returns an array');
|
||||
$this->assertEquals($count, count($urls), $message);
|
||||
}
|
||||
|
||||
|
@ -0,0 +1,31 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Bundle\DoctrineBundle\DependencyInjection\Compiler;
|
||||
|
||||
use Symfony\Component\DependencyInjection\ContainerBuilder;
|
||||
use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
|
||||
|
||||
class AddValidatorNamespaceAliasPass implements CompilerPassInterface
|
||||
{
|
||||
public function process(ContainerBuilder $container)
|
||||
{
|
||||
if (!$container->hasDefinition('validator.mapping.loader.annotation_loader')) {
|
||||
return;
|
||||
}
|
||||
|
||||
$loader = $container->getDefinition('validator.mapping.loader.annotation_loader');
|
||||
$args = $container->getParameterBag()->resolveValue($loader->getArguments());
|
||||
|
||||
$args[0]['assertORM'] = 'Symfony\\Bridge\\Doctrine\\Validator\\Constraints\\';
|
||||
$loader->replaceArgument(0, $args[0]);
|
||||
}
|
||||
}
|
@ -13,6 +13,7 @@ namespace Symfony\Bundle\DoctrineBundle;
|
||||
|
||||
use Symfony\Component\DependencyInjection\Compiler\PassConfig;
|
||||
use Symfony\Bundle\DoctrineBundle\DependencyInjection\Compiler\RegisterEventListenersAndSubscribersPass;
|
||||
use Symfony\Bundle\DoctrineBundle\DependencyInjection\Compiler\AddValidatorNamespaceAliasPass;
|
||||
use Symfony\Component\DependencyInjection\ContainerBuilder;
|
||||
use Symfony\Component\HttpKernel\Bundle\Bundle;
|
||||
|
||||
@ -29,5 +30,6 @@ class DoctrineBundle extends Bundle
|
||||
parent::build($container);
|
||||
|
||||
$container->addCompilerPass(new RegisterEventListenersAndSubscribersPass(), PassConfig::TYPE_BEFORE_OPTIMIZATION);
|
||||
$container->addCompilerPass(new AddValidatorNamespaceAliasPass(), PassConfig::TYPE_BEFORE_OPTIMIZATION);
|
||||
}
|
||||
}
|
||||
|
@ -31,6 +31,9 @@
|
||||
|
||||
<!-- form field factory guesser -->
|
||||
<parameter key="form.type_guesser.doctrine.class">Symfony\Bridge\Doctrine\Form\DoctrineOrmTypeGuesser</parameter>
|
||||
|
||||
<!-- validator -->
|
||||
<parameter key="doctrine.orm.validator.unique.class">Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntityValidator</parameter>
|
||||
</parameters>
|
||||
|
||||
<services>
|
||||
@ -57,5 +60,11 @@
|
||||
<service id="doctrine.orm.configuration" class="%doctrine.orm.configuration.class%" abstract="true" public="false" />
|
||||
|
||||
<service id="doctrine.orm.entity_manager.abstract" class="%doctrine.orm.entity_manager.class%" factory-class="%doctrine.orm.entity_manager.class%" factory-method="create" abstract="true" />
|
||||
|
||||
<!-- validator -->
|
||||
<service id="doctrine.orm.validator.unique" class="%doctrine.orm.validator.unique.class%">
|
||||
<tag name="validator.constraint_validator" alias="doctrine.orm.validator.unique" />
|
||||
<argument type="service" id="doctrine" />
|
||||
</service>
|
||||
</services>
|
||||
</container>
|
||||
|
@ -37,6 +37,8 @@ class ContainerTest extends TestCase
|
||||
$this->assertInstanceOf('Doctrine\Common\EventManager', $container->get('doctrine.dbal.event_manager'));
|
||||
$this->assertInstanceOf('Doctrine\DBAL\Event\Listeners\MysqlSessionInit', $container->get('doctrine.dbal.default_connection.events.mysqlsessioninit'));
|
||||
$this->assertInstanceOf('Symfony\Bundle\DoctrineBundle\CacheWarmer\ProxyCacheWarmer', $container->get('doctrine.orm.proxy_cache_warmer'));
|
||||
$this->assertInstanceOf('Symfony\Bundle\DoctrineBundle\Registry', $container->get('doctrine'));
|
||||
$this->assertInstanceOf('Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntityValidator', $container->get('doctrine.orm.validator.unique'));
|
||||
|
||||
$this->assertSame($container->get('my.platform'), $container->get('doctrine.dbal.default_connection')->getDatabasePlatform());
|
||||
|
||||
|
@ -46,7 +46,7 @@ class Configuration implements ConfigurationInterface
|
||||
->end()
|
||||
;
|
||||
|
||||
$this->addCsrfProtectionSection($rootNode);
|
||||
$this->addFormSection($rootNode);
|
||||
$this->addEsiSection($rootNode);
|
||||
$this->addProfilerSection($rootNode);
|
||||
$this->addRouterSection($rootNode);
|
||||
@ -59,10 +59,18 @@ class Configuration implements ConfigurationInterface
|
||||
return $treeBuilder;
|
||||
}
|
||||
|
||||
private function addCsrfProtectionSection(ArrayNodeDefinition $rootNode)
|
||||
private function addFormSection(ArrayNodeDefinition $rootNode)
|
||||
{
|
||||
$rootNode
|
||||
->children()
|
||||
->arrayNode('form')
|
||||
->canBeUnset()
|
||||
->treatNullLike(array('enabled' => true))
|
||||
->treatTrueLike(array('enabled' => true))
|
||||
->children()
|
||||
->booleanNode('enabled')->defaultTrue()->end()
|
||||
->end()
|
||||
->end()
|
||||
->arrayNode('csrf_protection')
|
||||
->canBeUnset()
|
||||
->treatNullLike(array('enabled' => true))
|
||||
@ -85,7 +93,7 @@ class Configuration implements ConfigurationInterface
|
||||
->treatNullLike(array('enabled' => true))
|
||||
->treatTrueLike(array('enabled' => true))
|
||||
->children()
|
||||
->booleanNode('enabled')->end()
|
||||
->booleanNode('enabled')->defaultTrue()->end()
|
||||
->end()
|
||||
->end()
|
||||
->end()
|
||||
@ -229,6 +237,8 @@ class Configuration implements ConfigurationInterface
|
||||
->children()
|
||||
->arrayNode('translator')
|
||||
->canBeUnset()
|
||||
->treatNullLike(array('enabled' => true))
|
||||
->treatTrueLike(array('enabled' => true))
|
||||
->children()
|
||||
->booleanNode('enabled')->defaultTrue()->end()
|
||||
->scalarNode('fallback')->defaultValue('en')->end()
|
||||
@ -244,8 +254,10 @@ class Configuration implements ConfigurationInterface
|
||||
->children()
|
||||
->arrayNode('validation')
|
||||
->canBeUnset()
|
||||
->treatNullLike(array('enabled' => true))
|
||||
->treatTrueLike(array('enabled' => true))
|
||||
->children()
|
||||
->booleanNode('enabled')->end()
|
||||
->booleanNode('enabled')->defaultTrue()->end()
|
||||
->scalarNode('cache')->end()
|
||||
->booleanNode('enable_annotations')->defaultFalse()->end()
|
||||
->end()
|
||||
|
@ -12,7 +12,6 @@
|
||||
namespace Symfony\Bundle\FrameworkBundle\DependencyInjection;
|
||||
|
||||
use Symfony\Component\Config\Loader\LoaderInterface;
|
||||
|
||||
use Symfony\Component\DependencyInjection\ContainerBuilder;
|
||||
use Symfony\Component\DependencyInjection\Definition;
|
||||
use Symfony\Component\DependencyInjection\Parameter;
|
||||
@ -43,7 +42,6 @@ class FrameworkExtension extends Extension
|
||||
$loader = new XmlFileLoader($container, new FileLocator(__DIR__.'/../Resources/config'));
|
||||
|
||||
$loader->load('web.xml');
|
||||
$loader->load('form.xml');
|
||||
$loader->load('services.xml');
|
||||
|
||||
// A translator must always be registered (as support is included by
|
||||
@ -72,8 +70,17 @@ class FrameworkExtension extends Extension
|
||||
$loader->load('test.xml');
|
||||
}
|
||||
|
||||
if (isset($config['csrf_protection'])) {
|
||||
$this->registerCsrfProtectionConfiguration($config['csrf_protection'], $container);
|
||||
if (isset($config['session'])) {
|
||||
$this->registerSessionConfiguration($config['session'], $container, $loader);
|
||||
}
|
||||
|
||||
if ($hasForm = isset($config['form']) && !empty($config['form']['enabled'])) {
|
||||
$this->registerFormConfiguration($config, $container, $loader);
|
||||
$config['validation']['enabled'] = true;
|
||||
}
|
||||
|
||||
if (!empty($config['validation']['enabled'])) {
|
||||
$this->registerValidationConfiguration($config['validation'], $container, $loader);
|
||||
}
|
||||
|
||||
if (isset($config['esi'])) {
|
||||
@ -88,10 +95,6 @@ class FrameworkExtension extends Extension
|
||||
$this->registerRouterConfiguration($config['router'], $container, $loader);
|
||||
}
|
||||
|
||||
if (isset($config['session'])) {
|
||||
$this->registerSessionConfiguration($config['session'], $container, $loader);
|
||||
}
|
||||
|
||||
if (isset($config['templating'])) {
|
||||
$this->registerTemplatingConfiguration($config['templating'], $config['ide'], $container, $loader);
|
||||
}
|
||||
@ -100,10 +103,6 @@ class FrameworkExtension extends Extension
|
||||
$this->registerTranslatorConfiguration($config['translator'], $container);
|
||||
}
|
||||
|
||||
if (isset($config['validation'])) {
|
||||
$this->registerValidationConfiguration($config['validation'], $container, $loader);
|
||||
}
|
||||
|
||||
$this->registerAnnotationsConfiguration($config['annotations'], $container, $loader);
|
||||
|
||||
$this->addClassesToCompile(array(
|
||||
@ -139,15 +138,32 @@ class FrameworkExtension extends Extension
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads the CSRF protection configuration.
|
||||
* Loads Form configuration.
|
||||
*
|
||||
* @param array $config A CSRF protection configuration array
|
||||
* @param array $config A configuration array
|
||||
* @param ContainerBuilder $container A ContainerBuilder instance
|
||||
* @param XmlFileLoader $loader An XmlFileLoader instance
|
||||
*/
|
||||
private function registerCsrfProtectionConfiguration(array $config, ContainerBuilder $container)
|
||||
private function registerFormConfiguration($config, ContainerBuilder $container, XmlFileLoader $loader)
|
||||
{
|
||||
$container->setParameter('form.type_extension.csrf.enabled', $config['enabled']);
|
||||
$container->setParameter('form.type_extension.csrf.field_name', $config['field_name']);
|
||||
$loader->load('form.xml');
|
||||
if (isset($config['csrf_protection'])) {
|
||||
if (!isset($config['session'])) {
|
||||
throw new \LogicException('CSRF protection needs that sessions are enabled.');
|
||||
}
|
||||
$loader->load('form_csrf.xml');
|
||||
|
||||
$container->setParameter('form.type_extension.csrf.enabled', $config['csrf_protection']['enabled']);
|
||||
$container->setParameter('form.type_extension.csrf.field_name', $config['csrf_protection']['field_name']);
|
||||
}
|
||||
|
||||
if ($container->hasDefinition('session')) {
|
||||
$container->removeDefinition('file.temporary_storage');
|
||||
$container->setDefinition('file.temporary_storage', $container->getDefinition('file.temporary_storage.session'));
|
||||
$container->removeDefinition('file.temporary_storage.session');
|
||||
} else {
|
||||
$container->removeDefinition('file.temporary_storage.session');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@ -325,7 +341,7 @@ class FrameworkExtension extends Extension
|
||||
|
||||
$container->setParameter('templating.helper.assets.assets_base_urls', isset($config['assets_base_urls']) ? $config['assets_base_urls'] : array());
|
||||
$container->setParameter('templating.helper.assets.assets_version', $config['assets_version']);
|
||||
$container->setParameter('templating.helper.assets.packages', $packages);
|
||||
$container->getDefinition('templating.helper.assets')->replaceArgument(3, $packages);
|
||||
|
||||
if (!empty($config['loaders'])) {
|
||||
$loaders = array_map(function($loader) { return new Reference($loader); }, $config['loaders']);
|
||||
@ -443,10 +459,6 @@ class FrameworkExtension extends Extension
|
||||
*/
|
||||
private function registerValidationConfiguration(array $config, ContainerBuilder $container, XmlFileLoader $loader)
|
||||
{
|
||||
if (empty($config['enabled'])) {
|
||||
return;
|
||||
}
|
||||
|
||||
$loader->load('validator.xml');
|
||||
|
||||
$container->setParameter('validator.mapping.loader.xml_files_loader.mapping_files', $this->getValidatorXmlMappingFiles($container));
|
||||
|
@ -18,8 +18,8 @@ use Symfony\Component\HttpKernel\Exception\MethodNotAllowedHttpException;
|
||||
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
use Symfony\Component\DependencyInjection\ContainerInterface;
|
||||
use Symfony\Component\Routing\Matcher\Exception\MethodNotAllowedException;
|
||||
use Symfony\Component\Routing\Matcher\Exception\NotFoundException;
|
||||
use Symfony\Component\Routing\Exception\MethodNotAllowedException;
|
||||
use Symfony\Component\Routing\Exception\ResourceNotFoundException;
|
||||
use Symfony\Component\Routing\RouterInterface;
|
||||
use Symfony\Component\Routing\RequestContext;
|
||||
|
||||
@ -107,7 +107,7 @@ class RequestListener
|
||||
}
|
||||
|
||||
$request->attributes->add($parameters);
|
||||
} catch (NotFoundException $e) {
|
||||
} catch (ResourceNotFoundException $e) {
|
||||
$message = sprintf('No route found for "%s %s"', $request->getMethod(), $request->getPathInfo());
|
||||
if (null !== $this->logger) {
|
||||
$this->logger->err($message);
|
||||
|
@ -8,8 +8,8 @@
|
||||
<parameter key="form.extension.class">Symfony\Component\Form\Extension\DependencyInjection\DependencyInjectionExtension</parameter>
|
||||
<parameter key="form.factory.class">Symfony\Component\Form\FormFactory</parameter>
|
||||
<parameter key="form.type_guesser.validator.class">Symfony\Component\Form\Extension\Validator\ValidatorTypeGuesser</parameter>
|
||||
<parameter key="form.csrf_provider.class">Symfony\Component\Form\Extension\Csrf\CsrfProvider\SessionCsrfProvider</parameter>
|
||||
<parameter key="file.temporary_storage.class">Symfony\Component\HttpFoundation\File\SessionBasedTemporaryStorage</parameter>
|
||||
<parameter key="file.temporary_storage.class">Symfony\Component\HttpFoundation\File\TemporaryStorage</parameter>
|
||||
<parameter key="file.temporary_storage.session.class">Symfony\Component\HttpFoundation\File\SessionBasedTemporaryStorage</parameter>
|
||||
</parameters>
|
||||
|
||||
<services>
|
||||
@ -51,15 +51,14 @@
|
||||
<argument type="service" id="validator.mapping.class_metadata_factory" />
|
||||
</service>
|
||||
|
||||
<!-- CsrfProvider -->
|
||||
<service id="form.csrf_provider" class="%form.csrf_provider.class%">
|
||||
<!-- TemporaryStorage - where should we put this? -->
|
||||
<service id="file.temporary_storage.session" class="%file.temporary_storage.session.class%">
|
||||
<argument type="service" id="session" />
|
||||
<argument>%kernel.secret%</argument>
|
||||
<argument>%kernel.cache_dir%/upload</argument>
|
||||
</service>
|
||||
|
||||
<!-- TemporaryStorage - where should we put this? -->
|
||||
<service id="file.temporary_storage" class="%file.temporary_storage.class%">
|
||||
<argument type="service" id="session" />
|
||||
<argument>%kernel.secret%</argument>
|
||||
<argument>%kernel.cache_dir%/upload</argument>
|
||||
</service>
|
||||
@ -130,6 +129,9 @@
|
||||
<service id="form.type.repeated" class="Symfony\Component\Form\Extension\Core\Type\RepeatedType">
|
||||
<tag name="form.type" alias="repeated" />
|
||||
</service>
|
||||
<service id="form.type.search" class="Symfony\Component\Form\Extension\Core\Type\SearchType">
|
||||
<tag name="form.type" alias="search" />
|
||||
</service>
|
||||
<service id="form.type.textarea" class="Symfony\Component\Form\Extension\Core\Type\TextareaType">
|
||||
<tag name="form.type" alias="textarea" />
|
||||
</service>
|
||||
@ -151,16 +153,5 @@
|
||||
<tag name="form.type_extension" alias="field" />
|
||||
<argument type="service" id="validator" />
|
||||
</service>
|
||||
|
||||
<!-- CsrfExtension -->
|
||||
<service id="form.type.csrf" class="Symfony\Component\Form\Extension\Csrf\Type\CsrfType">
|
||||
<tag name="form.type" alias="csrf" />
|
||||
<argument type="service" id="form.csrf_provider" />
|
||||
</service>
|
||||
<service id="form.type_extension.csrf" class="Symfony\Component\Form\Extension\Csrf\Type\FormTypeCsrfExtension">
|
||||
<tag name="form.type_extension" alias="form" />
|
||||
<argument>%form.type_extension.csrf.enabled%</argument>
|
||||
<argument>%form.type_extension.csrf.field_name%</argument>
|
||||
</service>
|
||||
</services>
|
||||
</container>
|
||||
|
@ -0,0 +1,27 @@
|
||||
<?xml version="1.0" ?>
|
||||
|
||||
<container xmlns="http://symfony.com/schema/dic/services"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://symfony.com/schema/dic/services http://symfony.com/schema/dic/services/services-1.0.xsd">
|
||||
|
||||
<parameters>
|
||||
<parameter key="form.csrf_provider.class">Symfony\Component\Form\Extension\Csrf\CsrfProvider\SessionCsrfProvider</parameter>
|
||||
</parameters>
|
||||
|
||||
<services>
|
||||
<service id="form.csrf_provider" class="%form.csrf_provider.class%">
|
||||
<argument type="service" id="session" />
|
||||
<argument>%kernel.secret%</argument>
|
||||
</service>
|
||||
|
||||
<service id="form.type.csrf" class="Symfony\Component\Form\Extension\Csrf\Type\CsrfType">
|
||||
<tag name="form.type" alias="csrf" />
|
||||
<argument type="service" id="form.csrf_provider" />
|
||||
</service>
|
||||
<service id="form.type_extension.csrf" class="Symfony\Component\Form\Extension\Csrf\Type\FormTypeCsrfExtension">
|
||||
<tag name="form.type_extension" alias="form" />
|
||||
<argument>%form.type_extension.csrf.enabled%</argument>
|
||||
<argument>%form.type_extension.csrf.field_name%</argument>
|
||||
</service>
|
||||
</services>
|
||||
</container>
|
@ -9,6 +9,7 @@
|
||||
|
||||
<xsd:complexType name="config">
|
||||
<xsd:all>
|
||||
<xsd:element name="form" type="form" minOccurs="0" maxOccurs="1" />
|
||||
<xsd:element name="csrf-protection" type="csrf_protection" minOccurs="0" maxOccurs="1" />
|
||||
<xsd:element name="esi" type="esi" minOccurs="0" maxOccurs="1" />
|
||||
<xsd:element name="profiler" type="profiler" minOccurs="0" maxOccurs="1" />
|
||||
@ -36,6 +37,10 @@
|
||||
</xsd:restriction>
|
||||
</xsd:simpleType>
|
||||
|
||||
<xsd:complexType name="form">
|
||||
<xsd:attribute name="enabled" type="xsd:boolean" />
|
||||
</xsd:complexType>
|
||||
|
||||
<xsd:complexType name="csrf_protection">
|
||||
<xsd:attribute name="enabled" type="xsd:boolean" />
|
||||
<xsd:attribute name="field-name" type="xsd:string" />
|
||||
|
@ -37,7 +37,7 @@
|
||||
<argument type="service" id="request" strict="false" />
|
||||
<argument>%templating.helper.assets.assets_base_urls%</argument>
|
||||
<argument>%templating.helper.assets.assets_version%</argument>
|
||||
<argument>%templating.helper.assets.packages%</argument>
|
||||
<argument type="collection" /> <!-- packages -->
|
||||
</service>
|
||||
|
||||
<service id="templating.helper.request" class="%templating.helper.request.class%">
|
||||
|
@ -1,6 +1,6 @@
|
||||
<input type="checkbox"
|
||||
<?php echo $view['form']->attributes() ?>
|
||||
name="<?php echo $view->escape($name) ?>"
|
||||
name="<?php echo $view->escape($full_name) ?>"
|
||||
<?php if ($value): ?>value="<?php echo $view->escape($value) ?>"<?php endif ?>
|
||||
<?php if ($read_only): ?>disabled="disabled"<?php endif ?>
|
||||
<?php if ($required): ?>required="required"<?php endif ?>
|
||||
|
@ -8,7 +8,7 @@
|
||||
<?php else: ?>
|
||||
<select
|
||||
<?php echo $view['form']->attributes() ?>
|
||||
name="<?php echo $view->escape($name) ?>"
|
||||
name="<?php echo $view->escape($full_name) ?>"
|
||||
<?php if ($read_only): ?> disabled="disabled"<?php endif ?>
|
||||
<?php if ($multiple): ?> multiple="multiple"<?php endif ?>
|
||||
>
|
||||
|
@ -1,7 +1,7 @@
|
||||
<?php if ($widget == 'single-text'): ?>
|
||||
<input type="text"
|
||||
<?php echo $view['form']->attributes() ?>
|
||||
name="<?php echo $view->escape($name) ?>"
|
||||
name="<?php echo $view->escape($full_name) ?>"
|
||||
value="<?php echo $view->escape($value) ?>"
|
||||
<?php if ($read_only): ?>disabled="disabled"<?php endif ?>
|
||||
<?php if ($required): ?>required="required"<?php endif ?>
|
||||
|
@ -1,6 +1,6 @@
|
||||
<input type="email"
|
||||
<?php echo $view['form']->attributes() ?>
|
||||
name="<?php echo $view->escape($name) ?>"
|
||||
name="<?php echo $view->escape($full_name) ?>"
|
||||
value="<?php echo $view->escape($value) ?>"
|
||||
<?php if ($max_length): ?>maxlength="<?php echo $view->escape($max_length) ?>"<?php endif ?>
|
||||
<?php if ($read_only): ?>disabled="disabled"<?php endif ?>
|
||||
|
@ -1,6 +1,6 @@
|
||||
<input
|
||||
<?php echo $view['form']->attributes() ?>
|
||||
name="<?php echo $view->escape($name) ?>"
|
||||
name="<?php echo $view->escape($full_name) ?>"
|
||||
value="<?php echo $view->escape($value) ?>"
|
||||
<?php if ($read_only): ?>disabled="disabled"<?php endif ?>
|
||||
<?php if ($required): ?>required="required"<?php endif ?>
|
||||
|
@ -1,6 +1,6 @@
|
||||
<input type="hidden"
|
||||
<?php echo $view['form']->attributes() ?>
|
||||
name="<?php echo $view->escape($name) ?>"
|
||||
name="<?php echo $view->escape($full_name) ?>"
|
||||
value="<?php echo $view->escape($value) ?>"
|
||||
<?php if ($read_only): ?>disabled="disabled"<?php endif ?>
|
||||
/>
|
@ -1,6 +1,6 @@
|
||||
<input type="number"
|
||||
<?php echo $view['form']->attributes() ?>
|
||||
name="<?php echo $view->escape($name) ?>"
|
||||
name="<?php echo $view->escape($full_name) ?>"
|
||||
value="<?php echo $view->escape($value) ?>"
|
||||
<?php if ($read_only): ?>disabled="disabled"<?php endif ?>
|
||||
<?php if ($required): ?>required="required"<?php endif ?>
|
||||
|
@ -1,8 +1,9 @@
|
||||
<input type="text"
|
||||
<?php echo $view['form']->attributes() ?>
|
||||
name="<?php echo $view->escape($name) ?>"
|
||||
name="<?php echo $view->escape($full_name) ?>"
|
||||
value="<?php echo $view->escape($value) ?>"
|
||||
<?php if ($read_only): ?>disabled="disabled"<?php endif ?>
|
||||
<?php if ($required): ?>required="required"<?php endif ?>
|
||||
<?php if ($max_length): ?>maxlength="<?php echo $max_length ?>"<?php endif ?>
|
||||
<?php if ($pattern): ?>pattern="<?php echo $pattern ?>"<?php endif ?>
|
||||
/>
|
@ -1,8 +1,9 @@
|
||||
<input type="password"
|
||||
<?php echo $view['form']->attributes() ?>
|
||||
name="<?php echo $view->escape($name) ?>"
|
||||
name="<?php echo $view->escape($full_name) ?>"
|
||||
value="<?php echo $view->escape($value) ?>"
|
||||
<?php if ($read_only): ?>disabled="disabled"<?php endif ?>
|
||||
<?php if ($required): ?>required="required"<?php endif ?>
|
||||
<?php if ($max_length): ?>maxlength="<?php echo $max_length ?>"<?php endif ?>
|
||||
<?php if ($pattern): ?>pattern="<?php echo $pattern ?>"<?php endif ?>
|
||||
/>
|
@ -1,6 +1,6 @@
|
||||
<input type="radio"
|
||||
<?php echo $view['form']->attributes() ?>
|
||||
name="<?php echo $view->escape($name) ?>"
|
||||
name="<?php echo $view->escape($full_name) ?>"
|
||||
value="<?php echo $view->escape($value) ?>"
|
||||
<?php if ($read_only): ?>disabled="disabled"<?php endif ?>
|
||||
<?php if ($required): ?>required="required"<?php endif ?>
|
||||
|
@ -0,0 +1,8 @@
|
||||
<input type="search"
|
||||
<?php echo $view['form']->attributes() ?>
|
||||
name="<?php echo $view->escape($name) ?>"
|
||||
value="<?php echo $view->escape($value) ?>"
|
||||
<?php if ($read_only): ?>disabled="disabled"<?php endif ?>
|
||||
<?php if ($required): ?>required="required"<?php endif ?>
|
||||
<?php if ($max_length): ?>maxlength="<?php echo $max_length ?>"<?php endif ?>
|
||||
/>
|
@ -1,8 +1,9 @@
|
||||
<input type="text"
|
||||
<?php echo $view['form']->attributes() ?>
|
||||
name="<?php echo $view->escape($name) ?>"
|
||||
name="<?php echo $view->escape($full_name) ?>"
|
||||
value="<?php echo $view->escape($value) ?>"
|
||||
<?php if ($read_only): ?>disabled="disabled"<?php endif ?>
|
||||
<?php if ($required): ?>required="required"<?php endif ?>
|
||||
<?php if ($max_length): ?>maxlength="<?php echo $max_length ?>"<?php endif ?>
|
||||
<?php if ($pattern): ?>pattern="<?php echo $pattern ?>"<?php endif ?>
|
||||
/>
|
@ -1,6 +1,6 @@
|
||||
<textarea
|
||||
<?php echo $view['form']->attributes() ?>
|
||||
name="<?php echo $view->escape($name) ?>"
|
||||
name="<?php echo $view->escape($full_name) ?>"
|
||||
<?php if ($read_only): ?>disabled="disabled"<?php endif ?>
|
||||
<?php if ($required): ?>required="required"<?php endif ?>
|
||||
><?php echo $view->escape($value) ?></textarea>
|
||||
|
@ -1,6 +1,6 @@
|
||||
<input type="url"
|
||||
<?php echo $view['form']->attributes() ?>
|
||||
name="<?php echo $view->escape($name) ?>"
|
||||
name="<?php echo $view->escape($full_name) ?>"
|
||||
value="<?php echo $view->escape($value) ?>"
|
||||
<?php if ($read_only): ?>disabled="disabled"<?php endif ?>
|
||||
<?php if ($required): ?>required="required"<?php endif ?>
|
||||
|
@ -135,7 +135,7 @@ class FormHelper extends Helper
|
||||
$variables
|
||||
);
|
||||
|
||||
array_push($this->viewStack, $view);
|
||||
$this->viewStack[] = $view;
|
||||
|
||||
$html = $this->engine->render($template, $this->varStack[$view]);
|
||||
|
||||
|
@ -2,6 +2,7 @@
|
||||
|
||||
$container->loadFromExtension('framework', array(
|
||||
'secret' => 's3cr3t',
|
||||
'form' => null,
|
||||
'csrf_protection' => array(
|
||||
'enabled' => true,
|
||||
'field_name' => '_csrf',
|
||||
|
@ -8,6 +8,7 @@
|
||||
|
||||
<framework:config secret="s3cr3t">
|
||||
<framework:csrf-protection enabled="true" field-name="_csrf" />
|
||||
<framework:form />
|
||||
<framework:esi enabled="true" />
|
||||
<framework:profiler only-exceptions="true" />
|
||||
<framework:router cache-warmer="true" resource="%kernel.root_dir%/config/routing.xml" type="xml" />
|
||||
|
@ -1,5 +1,6 @@
|
||||
framework:
|
||||
secret: s3cr3t
|
||||
form: ~
|
||||
csrf_protection:
|
||||
enabled: true
|
||||
field_name: _csrf
|
||||
|
@ -53,7 +53,7 @@ class LoggerChannelPass implements CompilerPassInterface
|
||||
$logger = new DefinitionDecorator('monolog.logger_prototype');
|
||||
$logger->replaceArgument(0, $channel);
|
||||
$container->setDefinition($loggerId, $logger);
|
||||
array_push($this->channels, $channel);
|
||||
$this->channels[] = $channel;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -140,7 +140,7 @@ class MonologExtension extends Extension
|
||||
case 'fingers_crossed':
|
||||
$handler['action_level'] = is_int($handler['action_level']) ? $handler['action_level'] : constant('Monolog\Logger::'.strtoupper($handler['action_level']));
|
||||
$nestedHandlerId = $this->getHandlerId($handler['handler']);
|
||||
array_push($this->nestedHandlers, $nestedHandlerId);
|
||||
$this->nestedHandlers[] = $nestedHandlerId;
|
||||
|
||||
$definition->setArguments(array(
|
||||
new Reference($nestedHandlerId),
|
||||
@ -153,7 +153,7 @@ class MonologExtension extends Extension
|
||||
|
||||
case 'buffer':
|
||||
$nestedHandlerId = $this->getHandlerId($handler['handler']);
|
||||
array_push($this->nestedHandlers, $nestedHandlerId);
|
||||
$this->nestedHandlers[] = $nestedHandlerId;
|
||||
|
||||
$definition->setArguments(array(
|
||||
new Reference($nestedHandlerId),
|
||||
@ -167,7 +167,7 @@ class MonologExtension extends Extension
|
||||
$references = array();
|
||||
foreach ($handler['members'] as $nestedHandler) {
|
||||
$nestedHandlerId = $this->getHandlerId($nestedHandler);
|
||||
array_push($this->nestedHandlers, $nestedHandlerId);
|
||||
$this->nestedHandlers[] = $nestedHandlerId;
|
||||
$references[] = new Reference($nestedHandlerId);
|
||||
}
|
||||
|
||||
|
@ -30,7 +30,7 @@ class FormLoginFactory extends AbstractFactory
|
||||
$this->addOption('username_parameter', '_username');
|
||||
$this->addOption('password_parameter', '_password');
|
||||
$this->addOption('csrf_parameter', '_csrf_token');
|
||||
$this->addOption('csrf_page_id', 'form_login');
|
||||
$this->addOption('intention', 'authenticate');
|
||||
$this->addOption('post_only', true);
|
||||
}
|
||||
|
||||
|
@ -53,12 +53,34 @@ class TemplatingExtension extends \Twig_Extension
|
||||
{
|
||||
return array(
|
||||
'asset' => new \Twig_Function_Method($this, 'getAssetUrl'),
|
||||
'assets_version' => new \Twig_Function_Method($this, 'getAssetsVersion'),
|
||||
);
|
||||
}
|
||||
|
||||
public function getAssetUrl($location, $packageName = null)
|
||||
/**
|
||||
* Returns the public path of an asset
|
||||
*
|
||||
* Absolute paths (i.e. http://...) are returned unmodified.
|
||||
*
|
||||
* @param string $path A public path
|
||||
* @param string $packageName The name of the asset package to use
|
||||
*
|
||||
* @return string A public path which takes into account the base path and URL path
|
||||
*/
|
||||
public function getAssetUrl($path, $packageName = null)
|
||||
{
|
||||
return $this->container->get('templating.helper.assets')->getUrl($location, $packageName);
|
||||
return $this->container->get('templating.helper.assets')->getUrl($path, $packageName);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the version of the assets in a package
|
||||
*
|
||||
* @param string $packageName
|
||||
* @return int
|
||||
*/
|
||||
public function getAssetsVersion($packageName = null)
|
||||
{
|
||||
return $this->container->get('templating.helper.assets')->getVersion($packageName);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -43,11 +43,18 @@
|
||||
|
||||
{% block attributes %}
|
||||
{% spaceless %}
|
||||
id="{{ id }}" name="{{ name }}"{% if read_only %} disabled="disabled"{% endif %}{% if required %} required="required"{% endif %}{% if max_length %} maxlength="{{ max_length }}"{% endif %}
|
||||
id="{{ id }}" name="{{ full_name }}"{% if read_only %} disabled="disabled"{% endif %}{% if required %} required="required"{% endif %}{% if max_length %} maxlength="{{ max_length }}"{% endif %}{% if pattern %} pattern="{{ pattern }}"{% endif %}
|
||||
{% for attrname,attrvalue in attr %}{{attrname}}="{{attrvalue}}" {% endfor %}
|
||||
{% endspaceless %}
|
||||
{% endblock attributes %}
|
||||
|
||||
{% block container_attributes %}
|
||||
{% spaceless %}
|
||||
id="{{ id }}"
|
||||
{% for attrname,attrvalue in attr %}{{attrname}}="{{attrvalue}}" {% endfor %}
|
||||
{% endspaceless %}
|
||||
{% endblock container_attributes %}
|
||||
|
||||
{% block field_widget %}
|
||||
{% spaceless %}
|
||||
{% set type = type|default('text') %}
|
||||
@ -103,7 +110,7 @@
|
||||
{% block choice_widget %}
|
||||
{% spaceless %}
|
||||
{% if expanded %}
|
||||
<div {{ block('attributes') }}>
|
||||
<div {{ block('container_attributes') }}>
|
||||
{% for choice, child in form %}
|
||||
{{ form_widget(child) }}
|
||||
{{ form_label(child) }}
|
||||
@ -140,7 +147,7 @@
|
||||
|
||||
{% block datetime_widget %}
|
||||
{% spaceless %}
|
||||
<div {{ block('attributes') }}>
|
||||
<div {{ block('container_attributes') }}>
|
||||
{{ form_errors(form.date) }}
|
||||
{{ form_errors(form.time) }}
|
||||
{{ form_widget(form.date) }}
|
||||
@ -154,7 +161,7 @@
|
||||
{% if widget == 'single-text' %}
|
||||
{{ block('text_widget') }}
|
||||
{% else %}
|
||||
<div {{ block('attributes') }}>
|
||||
<div {{ block('container_attributes') }}>
|
||||
{{ date_pattern|replace({
|
||||
'{{ year }}': form_widget(form.year),
|
||||
'{{ month }}': form_widget(form.month),
|
||||
@ -167,7 +174,7 @@
|
||||
|
||||
{% block time_widget %}
|
||||
{% spaceless %}
|
||||
<div {{ block('attributes') }}>
|
||||
<div {{ block('container_attributes') }}>
|
||||
{{ form_widget(form.hour, { 'attr': { 'size': '1' } }) }}:{{ form_widget(form.minute, { 'attr': { 'size': '1' } }) }}{% if with_seconds %}:{{ form_widget(form.second, { 'attr': { 'size': '1' } }) }}{% endif %}
|
||||
</div>
|
||||
{% endspaceless %}
|
||||
@ -201,6 +208,13 @@
|
||||
{% endspaceless %}
|
||||
{% endblock url_widget %}
|
||||
|
||||
{% block search_widget %}
|
||||
{% spaceless %}
|
||||
{% set type = type|default('search') %}
|
||||
{{ block('field_widget') }}
|
||||
{% endspaceless %}
|
||||
{% endblock search_widget %}
|
||||
|
||||
{% block percent_widget %}
|
||||
{% spaceless %}
|
||||
{% set type = type|default('text') %}
|
||||
@ -210,7 +224,7 @@
|
||||
|
||||
{% block file_widget %}
|
||||
{% spaceless %}
|
||||
<div {{ block('attributes') }}>
|
||||
<div {{ block('container_attributes') }}>
|
||||
{{ form_widget(form.file) }}
|
||||
{{ form_widget(form.token) }}
|
||||
{{ form_widget(form.name) }}
|
||||
@ -244,7 +258,7 @@
|
||||
|
||||
{% block form_widget %}
|
||||
{% spaceless %}
|
||||
<div {{ block('attributes') }}>
|
||||
<div {{ block('container_attributes') }}>
|
||||
{{ block('field_rows') }}
|
||||
{{ form_rest(form) }}
|
||||
</div>
|
||||
|
@ -44,7 +44,7 @@
|
||||
|
||||
{% block form_widget %}
|
||||
{% spaceless %}
|
||||
<table {{ block('attributes') }}>
|
||||
<table {{ block('container_attributes') }}>
|
||||
{{ block('field_rows') }}
|
||||
{{ form_rest(form) }}
|
||||
</table>
|
||||
|
@ -49,7 +49,8 @@ class ConfigCache
|
||||
/**
|
||||
* Checks if the cache is still fresh.
|
||||
*
|
||||
* This method always returns true is debug is on and the cache file exists.
|
||||
* This method always returns true when debug is off and the
|
||||
* cache file exists.
|
||||
*
|
||||
* @return Boolean true if the cache is fresh, false otherwise
|
||||
*/
|
||||
|
@ -70,16 +70,20 @@ class DialogHelper extends Helper
|
||||
/**
|
||||
* Asks for a value and validates the response.
|
||||
*
|
||||
* The validator receives the data to validate. It must return the
|
||||
* validated data when the data is valid and throw an exception
|
||||
* otherwise.
|
||||
*
|
||||
* @param OutputInterface $output
|
||||
* @param string|array $question
|
||||
* @param Closure $validator
|
||||
* @param callback $validator A PHP callback
|
||||
* @param integer $attempts Max number of times to ask before giving up (false by default, which means infinite)
|
||||
*
|
||||
* @return mixed
|
||||
*
|
||||
* @throws \Exception When any of the validator returns an error
|
||||
*/
|
||||
public function askAndValidate(OutputInterface $output, $question, \Closure $validator, $attempts = false)
|
||||
public function askAndValidate(OutputInterface $output, $question, $validator, $attempts = false)
|
||||
{
|
||||
// @codeCoverageIgnoreStart
|
||||
$error = null;
|
||||
@ -91,7 +95,7 @@ class DialogHelper extends Helper
|
||||
$value = $this->ask($output, $question, null);
|
||||
|
||||
try {
|
||||
return $validator($value);
|
||||
return call_user_func($validator, $value);
|
||||
} catch (\Exception $error) {
|
||||
}
|
||||
}
|
||||
|
@ -4,7 +4,7 @@ namespace Symfony\Component\DependencyInjection\Compiler;
|
||||
|
||||
use Symfony\Component\DependencyInjection\Definition;
|
||||
|
||||
use Symfony\Component\DependencyInjection\Exception\NonExistentServiceException;
|
||||
use Symfony\Component\DependencyInjection\Exception\ServiceNotFoundException;
|
||||
use Symfony\Component\DependencyInjection\ContainerInterface;
|
||||
use Symfony\Component\DependencyInjection\Reference;
|
||||
use Symfony\Component\DependencyInjection\ContainerBuilder;
|
||||
@ -47,7 +47,7 @@ class CheckExceptionOnInvalidReferenceBehaviorPass implements CompilerPassInterf
|
||||
$destId = (string) $argument;
|
||||
|
||||
if (!$this->container->has($destId)) {
|
||||
throw new NonExistentServiceException($destId, $this->sourceId);
|
||||
throw new ServiceNotFoundException($destId, $this->sourceId);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -12,7 +12,7 @@
|
||||
namespace Symfony\Component\DependencyInjection\Compiler;
|
||||
|
||||
use Symfony\Component\DependencyInjection\ContainerBuilder;
|
||||
use Symfony\Component\DependencyInjection\Exception\NonExistentParameterException;
|
||||
use Symfony\Component\DependencyInjection\Exception\ParameterNotFoundException;
|
||||
|
||||
/**
|
||||
* Resolves all parameter placeholders "%somevalue%" to their real values.
|
||||
@ -45,7 +45,7 @@ class ResolveParameterPlaceHoldersPass implements CompilerPassInterface
|
||||
$definition->setMethodCalls($calls);
|
||||
|
||||
$definition->setProperties($this->resolveValue($definition->getProperties()));
|
||||
} catch (NonExistentParameterException $e) {
|
||||
} catch (ParameterNotFoundException $e) {
|
||||
$e->setSourceId($id);
|
||||
|
||||
throw $e;
|
||||
@ -62,7 +62,7 @@ class ResolveParameterPlaceHoldersPass implements CompilerPassInterface
|
||||
foreach ($parameterBag->all() as $key => $value) {
|
||||
try {
|
||||
$parameterBag->set($key, $this->resolveValue($value));
|
||||
} catch (NonExistentParameterException $e) {
|
||||
} catch (ParameterNotFoundException $e) {
|
||||
$e->setSourceKey($key);
|
||||
|
||||
throw $e;
|
||||
|
@ -11,7 +11,7 @@
|
||||
|
||||
namespace Symfony\Component\DependencyInjection;
|
||||
|
||||
use Symfony\Component\DependencyInjection\Exception\NonExistentServiceException;
|
||||
use Symfony\Component\DependencyInjection\Exception\ServiceNotFoundException;
|
||||
use Symfony\Component\DependencyInjection\Exception\CircularReferenceException;
|
||||
use Symfony\Component\DependencyInjection\ParameterBag\ParameterBagInterface;
|
||||
use Symfony\Component\DependencyInjection\ParameterBag\ParameterBag;
|
||||
@ -238,7 +238,7 @@ class Container implements ContainerInterface
|
||||
}
|
||||
|
||||
if (self::EXCEPTION_ON_INVALID_REFERENCE === $invalidBehavior) {
|
||||
throw new NonExistentServiceException($id);
|
||||
throw new ServiceNotFoundException($id);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -12,11 +12,11 @@
|
||||
namespace Symfony\Component\DependencyInjection\Exception;
|
||||
|
||||
/**
|
||||
* Exception
|
||||
* ExceptionInterface
|
||||
*
|
||||
* @author Fabien Potencier <fabien@symfony.com>
|
||||
* @author Bulat Shakirzyanov <bulat@theopenskyproject.com>
|
||||
*/
|
||||
interface Exception
|
||||
interface ExceptionInterface
|
||||
{
|
||||
}
|
@ -18,6 +18,6 @@ use \InvalidArgumentException as BaseInvalidArgumentException;
|
||||
*
|
||||
* @author Bulat Shakirzyanov <bulat@theopenskyproject.com>
|
||||
*/
|
||||
class InvalidArgumentException extends BaseInvalidArgumentException implements Exception
|
||||
class InvalidArgumentException extends BaseInvalidArgumentException implements ExceptionInterface
|
||||
{
|
||||
}
|
||||
|
@ -16,7 +16,7 @@ namespace Symfony\Component\DependencyInjection\Exception;
|
||||
*
|
||||
* @author Fabien Potencier <fabien@symfony.com>
|
||||
*/
|
||||
class NonExistentParameterException extends InvalidArgumentException
|
||||
class ParameterNotFoundException extends InvalidArgumentException
|
||||
{
|
||||
private $key;
|
||||
private $sourceId;
|
@ -7,6 +7,6 @@ namespace Symfony\Component\DependencyInjection\Exception;
|
||||
*
|
||||
* @author Johannes M. Schmitt <schmittjoh@gmail.com>
|
||||
*/
|
||||
class RuntimeException extends \RuntimeException implements Exception
|
||||
class RuntimeException extends \RuntimeException implements ExceptionInterface
|
||||
{
|
||||
}
|
@ -7,7 +7,7 @@ namespace Symfony\Component\DependencyInjection\Exception;
|
||||
*
|
||||
* @author Johannes M. Schmitt <schmittjoh@gmail.com>
|
||||
*/
|
||||
class NonExistentServiceException extends InvalidArgumentException
|
||||
class ServiceNotFoundException extends InvalidArgumentException
|
||||
{
|
||||
private $id;
|
||||
private $sourceId;
|
@ -11,7 +11,7 @@
|
||||
|
||||
namespace Symfony\Component\DependencyInjection\ParameterBag;
|
||||
|
||||
use Symfony\Component\DependencyInjection\Exception\NonExistentParameterException;
|
||||
use Symfony\Component\DependencyInjection\Exception\ParameterNotFoundException;
|
||||
|
||||
/**
|
||||
*
|
||||
@ -69,14 +69,14 @@ class ParameterBag implements ParameterBagInterface
|
||||
*
|
||||
* @return mixed The parameter value
|
||||
*
|
||||
* @throws \InvalidArgumentException if the parameter is not defined
|
||||
* @throws ParameterNotFoundException if the parameter is not defined
|
||||
*/
|
||||
public function get($name)
|
||||
{
|
||||
$name = strtolower($name);
|
||||
|
||||
if (!array_key_exists($name, $this->parameters)) {
|
||||
throw new NonExistentParameterException($name);
|
||||
throw new ParameterNotFoundException($name);
|
||||
}
|
||||
|
||||
return $this->parameters[$name];
|
||||
@ -113,7 +113,7 @@ class ParameterBag implements ParameterBagInterface
|
||||
foreach ($this->parameters as $key => $value) {
|
||||
try {
|
||||
$this->parameters[$key] = $this->resolveValue($value);
|
||||
} catch (NonExistentParameterException $e) {
|
||||
} catch (ParameterNotFoundException $e) {
|
||||
$e->setSourceKey($key);
|
||||
|
||||
throw $e;
|
||||
@ -126,7 +126,7 @@ class ParameterBag implements ParameterBagInterface
|
||||
*
|
||||
* @param mixed $value A value
|
||||
*
|
||||
* @throws \InvalidArgumentException if a placeholder references a parameter that does not exist
|
||||
* @throws ParameterNotFoundException if a placeholder references a parameter that does not exist
|
||||
*/
|
||||
public function resolveValue($value)
|
||||
{
|
||||
|
@ -11,7 +11,7 @@
|
||||
|
||||
namespace Symfony\Component\DependencyInjection\ParameterBag;
|
||||
|
||||
use Symfony\Component\DependencyInjection\Exception\NonExistentParameterException;
|
||||
use Symfony\Component\DependencyInjection\Exception\ParameterNotFoundException;
|
||||
|
||||
/**
|
||||
* ParameterBagInterface.
|
||||
@ -46,7 +46,7 @@ interface ParameterBagInterface
|
||||
*
|
||||
* @return mixed The parameter value
|
||||
*
|
||||
* @throws NonExistentParameterException if the parameter is not defined
|
||||
* @throws ParameterNotFoundException if the parameter is not defined
|
||||
*/
|
||||
function get($name);
|
||||
|
||||
@ -66,4 +66,18 @@ interface ParameterBagInterface
|
||||
* @return Boolean true if the parameter name is defined, false otherwise
|
||||
*/
|
||||
function has($name);
|
||||
|
||||
/**
|
||||
* Replaces parameter placeholders (%name%) by their values for all parameters.
|
||||
*/
|
||||
function resolve();
|
||||
|
||||
/**
|
||||
* Replaces parameter placeholders (%name%) by their values.
|
||||
*
|
||||
* @param mixed $value A value
|
||||
*
|
||||
* @throws ParameterNotFoundException if a placeholder references a parameter that does not exist
|
||||
*/
|
||||
function resolveValue($value);
|
||||
}
|
||||
|
@ -52,6 +52,7 @@ class CoreExtension extends AbstractExtension
|
||||
new Type\PercentType(),
|
||||
new Type\RadioType(),
|
||||
new Type\RepeatedType(),
|
||||
new Type\SearchType(),
|
||||
new Type\TextareaType(),
|
||||
new Type\TextType(),
|
||||
new Type\TimeType(),
|
||||
|
@ -35,6 +35,11 @@ class ResizeFormListener implements EventSubscriberInterface
|
||||
*/
|
||||
private $type;
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
private $options;
|
||||
|
||||
/**
|
||||
* Whether children could be added to the group
|
||||
* @var Boolean
|
||||
@ -47,12 +52,13 @@ class ResizeFormListener implements EventSubscriberInterface
|
||||
*/
|
||||
private $allowDelete;
|
||||
|
||||
public function __construct(FormFactoryInterface $factory, $type, $allowAdd = false, $allowDelete = false)
|
||||
public function __construct(FormFactoryInterface $factory, $type, array $options = array(), $allowAdd = false, $allowDelete = false)
|
||||
{
|
||||
$this->factory = $factory;
|
||||
$this->type = $type;
|
||||
$this->allowAdd = $allowAdd;
|
||||
$this->allowDelete = $allowDelete;
|
||||
$this->options = $options;
|
||||
}
|
||||
|
||||
public static function getSubscribedEvents()
|
||||
@ -86,9 +92,9 @@ class ResizeFormListener implements EventSubscriberInterface
|
||||
|
||||
// Then add all rows again in the correct order
|
||||
foreach ($data as $name => $value) {
|
||||
$form->add($this->factory->createNamed($this->type, $name, null, array(
|
||||
$form->add($this->factory->createNamed($this->type, $name, null, array_replace(array(
|
||||
'property_path' => '['.$name.']',
|
||||
)));
|
||||
), $this->options)));
|
||||
}
|
||||
}
|
||||
|
||||
@ -118,9 +124,9 @@ class ResizeFormListener implements EventSubscriberInterface
|
||||
if ($this->allowAdd) {
|
||||
foreach ($data as $name => $value) {
|
||||
if (!$form->has($name)) {
|
||||
$form->add($this->factory->createNamed($this->type, $name, null, array(
|
||||
$form->add($this->factory->createNamed($this->type, $name, null, array_replace(array(
|
||||
'property_path' => '['.$name.']',
|
||||
)));
|
||||
), $this->options)));
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -149,4 +155,4 @@ class ResizeFormListener implements EventSubscriberInterface
|
||||
|
||||
$event->setData($data);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -21,14 +21,18 @@ class CheckboxType extends AbstractType
|
||||
{
|
||||
public function buildForm(FormBuilder $builder, array $options)
|
||||
{
|
||||
$builder->appendClientTransformer(new BooleanToStringTransformer())
|
||||
->setAttribute('value', $options['value']);
|
||||
$builder
|
||||
->appendClientTransformer(new BooleanToStringTransformer())
|
||||
->setAttribute('value', $options['value'])
|
||||
;
|
||||
}
|
||||
|
||||
public function buildView(FormView $view, FormInterface $form)
|
||||
{
|
||||
$view->set('value', $form->getAttribute('value'));
|
||||
$view->set('checked', (Boolean) $form->getData());
|
||||
$view
|
||||
->set('value', $form->getAttribute('value'))
|
||||
->set('checked', (Boolean) $form->getData())
|
||||
;
|
||||
}
|
||||
|
||||
public function getDefaultOptions(array $options)
|
||||
|
@ -46,15 +46,15 @@ class ChoiceType extends AbstractType
|
||||
|
||||
foreach ($options['choices'] as $choice => $value) {
|
||||
if ($options['multiple']) {
|
||||
$builder->add((string)$choice, 'checkbox', array(
|
||||
'value' => $choice,
|
||||
'label' => $value,
|
||||
$builder->add((string) $choice, 'checkbox', array(
|
||||
'value' => $choice,
|
||||
'label' => $value,
|
||||
// The user can check 0 or more checkboxes. If required
|
||||
// is true, he is required to check all of them.
|
||||
'required' => false,
|
||||
'required' => false,
|
||||
));
|
||||
} else {
|
||||
$builder->add((string)$choice, 'radio', array(
|
||||
$builder->add((string) $choice, 'radio', array(
|
||||
'value' => $choice,
|
||||
'label' => $value,
|
||||
));
|
||||
@ -62,17 +62,21 @@ class ChoiceType extends AbstractType
|
||||
}
|
||||
}
|
||||
|
||||
$builder->setAttribute('choice_list', $options['choice_list'])
|
||||
$builder
|
||||
->setAttribute('choice_list', $options['choice_list'])
|
||||
->setAttribute('preferred_choices', $options['preferred_choices'])
|
||||
->setAttribute('multiple', $options['multiple'])
|
||||
->setAttribute('expanded', $options['expanded']);
|
||||
->setAttribute('expanded', $options['expanded'])
|
||||
;
|
||||
|
||||
if ($options['expanded']) {
|
||||
if ($options['multiple']) {
|
||||
$builder->appendClientTransformer(new ArrayToBooleanChoicesTransformer($options['choice_list']));
|
||||
} else {
|
||||
$builder->appendClientTransformer(new ScalarToBooleanChoicesTransformer($options['choice_list']));
|
||||
$builder->addEventSubscriber(new FixRadioInputListener(), 10);
|
||||
$builder
|
||||
->appendClientTransformer(new ScalarToBooleanChoicesTransformer($options['choice_list']))
|
||||
->addEventSubscriber(new FixRadioInputListener(), 10)
|
||||
;
|
||||
}
|
||||
} else {
|
||||
if ($options['multiple']) {
|
||||
@ -89,18 +93,20 @@ class ChoiceType extends AbstractType
|
||||
$choices = $form->getAttribute('choice_list')->getChoices();
|
||||
$preferred = array_flip($form->getAttribute('preferred_choices'));
|
||||
|
||||
$view->set('multiple', $form->getAttribute('multiple'));
|
||||
$view->set('expanded', $form->getAttribute('expanded'));
|
||||
$view->set('preferred_choices', array_intersect_key($choices, $preferred));
|
||||
$view->set('choices', array_diff_key($choices, $preferred));
|
||||
$view->set('separator', '-------------------');
|
||||
$view->set('empty_value', '');
|
||||
$view
|
||||
->set('multiple', $form->getAttribute('multiple'))
|
||||
->set('expanded', $form->getAttribute('expanded'))
|
||||
->set('preferred_choices', array_intersect_key($choices, $preferred))
|
||||
->set('choices', array_diff_key($choices, $preferred))
|
||||
->set('separator', '-------------------')
|
||||
->set('empty_value', '')
|
||||
;
|
||||
|
||||
if ($view->get('multiple') && !$view->get('expanded')) {
|
||||
// Add "[]" to the name in case a select tag with multiple options is
|
||||
// displayed. Otherwise only one of the selected options is sent in the
|
||||
// POST request.
|
||||
$view->set('name', $view->get('name').'[]');
|
||||
$view->set('full_name', $view->get('full_name').'[]');
|
||||
}
|
||||
}
|
||||
|
||||
@ -110,14 +116,13 @@ class ChoiceType extends AbstractType
|
||||
$expanded = isset($options['expanded']) && $options['expanded'];
|
||||
|
||||
return array(
|
||||
'multiple' => false,
|
||||
'expanded' => false,
|
||||
'choice_list' => null,
|
||||
'choices' => array(),
|
||||
'multiple' => false,
|
||||
'expanded' => false,
|
||||
'choice_list' => null,
|
||||
'choices' => array(),
|
||||
'preferred_choices' => array(),
|
||||
'csrf_protection' => false,
|
||||
'empty_data' => $multiple || $expanded ? array() : '',
|
||||
'error_bubbling' => false,
|
||||
'empty_data' => $multiple || $expanded ? array() : '',
|
||||
'error_bubbling' => false,
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -22,33 +22,43 @@ class CollectionType extends AbstractType
|
||||
public function buildForm(FormBuilder $builder, array $options)
|
||||
{
|
||||
if ($options['allow_add'] && $options['prototype']) {
|
||||
$builder->add('$$name$$', $options['type'], array(
|
||||
$builder->add('$$name$$', $options['type'], array_replace(array(
|
||||
'property_path' => false,
|
||||
'required' => false,
|
||||
));
|
||||
), $options['options']));
|
||||
}
|
||||
|
||||
$listener = new ResizeFormListener($builder->getFormFactory(),
|
||||
$options['type'], $options['allow_add'], $options['allow_delete']);
|
||||
$listener = new ResizeFormListener(
|
||||
$builder->getFormFactory(),
|
||||
$options['type'],
|
||||
$options['options'],
|
||||
$options['allow_add'],
|
||||
$options['allow_delete']
|
||||
);
|
||||
|
||||
$builder->addEventSubscriber($listener)
|
||||
$builder
|
||||
->addEventSubscriber($listener)
|
||||
->setAttribute('allow_add', $options['allow_add'])
|
||||
->setAttribute('allow_delete', $options['allow_delete']);
|
||||
->setAttribute('allow_delete', $options['allow_delete'])
|
||||
;
|
||||
}
|
||||
|
||||
public function buildView(FormView $view, FormInterface $form)
|
||||
{
|
||||
$view->set('allow_add', $form->getAttribute('allow_add'));
|
||||
$view->set('allow_delete', $form->getAttribute('allow_delete'));
|
||||
$view
|
||||
->set('allow_add', $form->getAttribute('allow_add'))
|
||||
->set('allow_delete', $form->getAttribute('allow_delete'))
|
||||
;
|
||||
}
|
||||
|
||||
public function getDefaultOptions(array $options)
|
||||
{
|
||||
return array(
|
||||
'allow_add' => false,
|
||||
'allow_delete' => false,
|
||||
'prototype' => true,
|
||||
'type' => 'text',
|
||||
'allow_add' => false,
|
||||
'allow_delete' => false,
|
||||
'prototype' => true,
|
||||
'type' => 'text',
|
||||
'options' => array(),
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -37,9 +37,6 @@ class DateTimeType extends AbstractType
|
||||
'with_seconds',
|
||||
)));
|
||||
|
||||
if (isset($options['date_pattern'])) {
|
||||
$dateOptions['pattern'] = $options['date_pattern'];
|
||||
}
|
||||
if (isset($options['date_widget'])) {
|
||||
$dateOptions['widget'] = $options['date_widget'];
|
||||
}
|
||||
@ -49,9 +46,6 @@ class DateTimeType extends AbstractType
|
||||
|
||||
$dateOptions['input'] = 'array';
|
||||
|
||||
if (isset($options['time_pattern'])) {
|
||||
$timeOptions['pattern'] = $options['time_pattern'];
|
||||
}
|
||||
if (isset($options['time_widget'])) {
|
||||
$timeOptions['widget'] = $options['time_widget'];
|
||||
}
|
||||
@ -66,7 +60,8 @@ class DateTimeType extends AbstractType
|
||||
$timeParts[] = 'second';
|
||||
}
|
||||
|
||||
$builder->appendClientTransformer(new DataTransformerChain(array(
|
||||
$builder
|
||||
->appendClientTransformer(new DataTransformerChain(array(
|
||||
new DateTimeToArrayTransformer($options['data_timezone'], $options['user_timezone'], $parts),
|
||||
new ArrayToPartsTransformer(array(
|
||||
'date' => array('year', 'month', 'day'),
|
||||
@ -74,7 +69,8 @@ class DateTimeType extends AbstractType
|
||||
)),
|
||||
)))
|
||||
->add('date', 'date', $dateOptions)
|
||||
->add('time', 'time', $timeOptions);
|
||||
->add('time', 'time', $timeOptions)
|
||||
;
|
||||
|
||||
if ($options['input'] === 'string') {
|
||||
$builder->appendNormTransformer(new ReversedTransformer(
|
||||
@ -94,52 +90,50 @@ class DateTimeType extends AbstractType
|
||||
public function getDefaultOptions(array $options)
|
||||
{
|
||||
return array(
|
||||
'input' => 'datetime',
|
||||
'with_seconds' => false,
|
||||
'input' => 'datetime',
|
||||
'with_seconds' => false,
|
||||
'data_timezone' => null,
|
||||
'user_timezone' => null,
|
||||
// Don't modify \DateTime classes by reference, we treat
|
||||
// them like immutable value objects
|
||||
'by_reference' => false,
|
||||
'date_pattern' => null,
|
||||
'date_widget' => null,
|
||||
'date_format' => null,
|
||||
'time_pattern' => null,
|
||||
'time_widget' => null,
|
||||
'by_reference' => false,
|
||||
'date_widget' => null,
|
||||
'date_format' => null,
|
||||
'time_widget' => null,
|
||||
/* Defaults for date field */
|
||||
'years' => range(date('Y') - 5, date('Y') + 5),
|
||||
'months' => range(1, 12),
|
||||
'days' => range(1, 31),
|
||||
'years' => range(date('Y') - 5, date('Y') + 5),
|
||||
'months' => range(1, 12),
|
||||
'days' => range(1, 31),
|
||||
/* Defaults for time field */
|
||||
'hours' => range(0, 23),
|
||||
'minutes' => range(0, 59),
|
||||
'seconds' => range(0, 59),
|
||||
'with_seconds' => false,
|
||||
'hours' => range(0, 23),
|
||||
'minutes' => range(0, 59),
|
||||
'seconds' => range(0, 59),
|
||||
'with_seconds' => false,
|
||||
);
|
||||
}
|
||||
|
||||
public function getAllowedOptionValues(array $options)
|
||||
{
|
||||
return array(
|
||||
'input' => array(
|
||||
'input' => array(
|
||||
'datetime',
|
||||
'string',
|
||||
'timestamp',
|
||||
'array',
|
||||
),
|
||||
'date_widget' => array(
|
||||
'date_widget' => array(
|
||||
null, // inherit default from DateType
|
||||
'text',
|
||||
'choice',
|
||||
),
|
||||
'date_format' => array(
|
||||
'date_format' => array(
|
||||
null, // inherit default from DateType
|
||||
\IntlDateFormatter::FULL,
|
||||
\IntlDateFormatter::LONG,
|
||||
\IntlDateFormatter::MEDIUM,
|
||||
\IntlDateFormatter::SHORT,
|
||||
),
|
||||
'time_widget' => array(
|
||||
'time_widget' => array(
|
||||
null, // inherit default from TimeType
|
||||
'text',
|
||||
'choice',
|
||||
|
@ -60,10 +60,12 @@ class DateType extends AbstractType
|
||||
);
|
||||
}
|
||||
|
||||
$builder->add('year', $widget, $yearOptions)
|
||||
$builder
|
||||
->add('year', $widget, $yearOptions)
|
||||
->add('month', $widget, $monthOptions)
|
||||
->add('day', $widget, $dayOptions)
|
||||
->appendClientTransformer(new DateTimeToArrayTransformer($options['data_timezone'], $options['user_timezone'], array('year', 'month', 'day')));
|
||||
->appendClientTransformer(new DateTimeToArrayTransformer($options['data_timezone'], $options['user_timezone'], array('year', 'month', 'day')))
|
||||
;
|
||||
}
|
||||
|
||||
if ($options['input'] === 'string') {
|
||||
@ -84,7 +86,8 @@ class DateType extends AbstractType
|
||||
|
||||
$builder
|
||||
->setAttribute('formatter', $formatter)
|
||||
->setAttribute('widget', $options['widget']);
|
||||
->setAttribute('widget', $options['widget'])
|
||||
;
|
||||
}
|
||||
|
||||
public function buildViewBottomUp(FormView $view, FormInterface $form)
|
||||
@ -111,37 +114,35 @@ class DateType extends AbstractType
|
||||
public function getDefaultOptions(array $options)
|
||||
{
|
||||
return array(
|
||||
'years' => range(date('Y') - 5, date('Y') + 5),
|
||||
'months' => range(1, 12),
|
||||
'days' => range(1, 31),
|
||||
'widget' => 'choice',
|
||||
'input' => 'datetime',
|
||||
'pattern' => null,
|
||||
'format' => \IntlDateFormatter::MEDIUM,
|
||||
'data_timezone' => null,
|
||||
'user_timezone' => null,
|
||||
'csrf_protection' => false,
|
||||
'years' => range(date('Y') - 5, date('Y') + 5),
|
||||
'months' => range(1, 12),
|
||||
'days' => range(1, 31),
|
||||
'widget' => 'choice',
|
||||
'input' => 'datetime',
|
||||
'format' => \IntlDateFormatter::MEDIUM,
|
||||
'data_timezone' => null,
|
||||
'user_timezone' => null,
|
||||
// Don't modify \DateTime classes by reference, we treat
|
||||
// them like immutable value objects
|
||||
'by_reference' => false,
|
||||
'by_reference' => false,
|
||||
);
|
||||
}
|
||||
|
||||
public function getAllowedOptionValues(array $options)
|
||||
{
|
||||
return array(
|
||||
'input' => array(
|
||||
'input' => array(
|
||||
'datetime',
|
||||
'string',
|
||||
'timestamp',
|
||||
'array',
|
||||
),
|
||||
'widget' => array(
|
||||
'widget' => array(
|
||||
'single-text',
|
||||
'text',
|
||||
'choice',
|
||||
),
|
||||
'format' => array(
|
||||
'format' => array(
|
||||
\IntlDateFormatter::FULL,
|
||||
\IntlDateFormatter::LONG,
|
||||
\IntlDateFormatter::MEDIUM,
|
||||
|
@ -35,7 +35,8 @@ class FieldType extends AbstractType
|
||||
$options['property_path'] = new PropertyPath($options['property_path']);
|
||||
}
|
||||
|
||||
$builder->setRequired($options['required'])
|
||||
$builder
|
||||
->setRequired($options['required'])
|
||||
->setReadOnly($options['read_only'])
|
||||
->setErrorBubbling($options['error_bubbling'])
|
||||
->setEmptyData($options['empty_data'])
|
||||
@ -43,9 +44,11 @@ class FieldType extends AbstractType
|
||||
->setAttribute('property_path', $options['property_path'])
|
||||
->setAttribute('error_mapping', $options['error_mapping'])
|
||||
->setAttribute('max_length', $options['max_length'])
|
||||
->setAttribute('pattern', $options['pattern'])
|
||||
->setAttribute('label', $options['label'] ?: $this->humanize($builder->getName()))
|
||||
->setData($options['data'])
|
||||
->addValidator(new DefaultValidator());
|
||||
->addValidator(new DefaultValidator())
|
||||
;
|
||||
|
||||
if ($options['trim']) {
|
||||
$builder->addEventSubscriber(new TrimListener());
|
||||
@ -56,7 +59,7 @@ class FieldType extends AbstractType
|
||||
{
|
||||
if ($view->hasParent()) {
|
||||
$parentId = $view->getParent()->get('id');
|
||||
$parentName = $view->getParent()->get('name');
|
||||
$parentName = $view->getParent()->get('full_name');
|
||||
$id = sprintf('%s_%s', $parentId, $form->getName());
|
||||
$name = sprintf('%s[%s]', $parentName, $form->getName());
|
||||
} else {
|
||||
@ -64,18 +67,22 @@ class FieldType extends AbstractType
|
||||
$name = $form->getName();
|
||||
}
|
||||
|
||||
$view->set('form', $view);
|
||||
$view->set('id', $id);
|
||||
$view->set('name', $name);
|
||||
$view->set('errors', $form->getErrors());
|
||||
$view->set('value', $form->getClientData());
|
||||
$view->set('read_only', $form->isReadOnly());
|
||||
$view->set('required', $form->isRequired());
|
||||
$view->set('max_length', $form->getAttribute('max_length'));
|
||||
$view->set('size', null);
|
||||
$view->set('label', $form->getAttribute('label'));
|
||||
$view->set('multipart', false);
|
||||
$view->set('attr', array());
|
||||
$view
|
||||
->set('form', $view)
|
||||
->set('id', $id)
|
||||
->set('name', $form->getName())
|
||||
->set('full_name', $name)
|
||||
->set('errors', $form->getErrors())
|
||||
->set('value', $form->getClientData())
|
||||
->set('read_only', $form->isReadOnly())
|
||||
->set('required', $form->isRequired())
|
||||
->set('max_length', $form->getAttribute('max_length'))
|
||||
->set('pattern', $form->getAttribute('pattern'))
|
||||
->set('size', null)
|
||||
->set('label', $form->getAttribute('label'))
|
||||
->set('multipart', false)
|
||||
->set('attr', array())
|
||||
;
|
||||
|
||||
$types = array();
|
||||
foreach (array_reverse((array) $form->getTypes()) as $type) {
|
||||
@ -87,17 +94,18 @@ class FieldType extends AbstractType
|
||||
public function getDefaultOptions(array $options)
|
||||
{
|
||||
$defaultOptions = array(
|
||||
'data' => null,
|
||||
'data_class' => null,
|
||||
'trim' => true,
|
||||
'required' => true,
|
||||
'read_only' => false,
|
||||
'max_length' => null,
|
||||
'property_path' => null,
|
||||
'by_reference' => true,
|
||||
'error_bubbling' => false,
|
||||
'error_mapping' => array(),
|
||||
'label' => null,
|
||||
'data' => null,
|
||||
'data_class' => null,
|
||||
'trim' => true,
|
||||
'required' => true,
|
||||
'read_only' => false,
|
||||
'max_length' => null,
|
||||
'pattern' => null,
|
||||
'property_path' => null,
|
||||
'by_reference' => true,
|
||||
'error_bubbling' => false,
|
||||
'error_mapping' => array(),
|
||||
'label' => null,
|
||||
);
|
||||
|
||||
$class = isset($options['data_class']) ? $options['data_class'] : null;
|
||||
|
@ -44,20 +44,21 @@ class FileType extends AbstractType
|
||||
->add('file', 'field')
|
||||
->add('token', 'hidden')
|
||||
->add('name', 'hidden')
|
||||
->add('originalName', 'hidden');
|
||||
->add('originalName', 'hidden')
|
||||
;
|
||||
}
|
||||
|
||||
public function buildViewBottomUp(FormView $view, FormInterface $form)
|
||||
{
|
||||
$view->set('multipart', true);
|
||||
$view['file']->set('type', 'file');
|
||||
$view['file']->set('value', '');
|
||||
}
|
||||
|
||||
public function getDefaultOptions(array $options)
|
||||
{
|
||||
return array(
|
||||
'type' => 'string',
|
||||
'csrf_protection' => false,
|
||||
'type' => 'string',
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -42,10 +42,10 @@ class FormType extends AbstractType
|
||||
public function getDefaultOptions(array $options)
|
||||
{
|
||||
$defaultOptions = array(
|
||||
'virtual' => false,
|
||||
'virtual' => false,
|
||||
// Errors in forms bubble by default, so that form errors will
|
||||
// end up as global errors in the root form
|
||||
'error_bubbling' => true,
|
||||
'error_bubbling' => true,
|
||||
);
|
||||
|
||||
if (empty($options['data_class'])) {
|
||||
|
@ -19,15 +19,20 @@ class IntegerType extends AbstractType
|
||||
{
|
||||
public function buildForm(FormBuilder $builder, array $options)
|
||||
{
|
||||
$builder->appendClientTransformer(new IntegerToLocalizedStringTransformer($options['precision'], $options['grouping'], $options['rounding_mode']));
|
||||
$builder->appendClientTransformer(
|
||||
new IntegerToLocalizedStringTransformer(
|
||||
$options['precision'],
|
||||
$options['grouping'],
|
||||
$options['rounding_mode']
|
||||
));
|
||||
}
|
||||
|
||||
public function getDefaultOptions(array $options)
|
||||
{
|
||||
return array(
|
||||
// default precision is locale specific (usually around 3)
|
||||
'precision' => null,
|
||||
'grouping' => false,
|
||||
'precision' => null,
|
||||
'grouping' => false,
|
||||
// Integer cast rounds towards 0, so do the same when displaying fractions
|
||||
'rounding_mode' => \NumberFormatter::ROUND_DOWN,
|
||||
);
|
||||
|
@ -23,8 +23,15 @@ class MoneyType extends AbstractType
|
||||
|
||||
public function buildForm(FormBuilder $builder, array $options)
|
||||
{
|
||||
$builder->appendClientTransformer(new MoneyToLocalizedStringTransformer($options['precision'], $options['grouping'], null, $options['divisor']))
|
||||
->setAttribute('currency', $options['currency']);
|
||||
$builder
|
||||
->appendClientTransformer(new MoneyToLocalizedStringTransformer(
|
||||
$options['precision'],
|
||||
$options['grouping'],
|
||||
null,
|
||||
$options['divisor']
|
||||
))
|
||||
->setAttribute('currency', $options['currency'])
|
||||
;
|
||||
}
|
||||
|
||||
public function buildView(FormView $view, FormInterface $form)
|
||||
@ -36,9 +43,9 @@ class MoneyType extends AbstractType
|
||||
{
|
||||
return array(
|
||||
'precision' => 2,
|
||||
'grouping' => false,
|
||||
'divisor' => 1,
|
||||
'currency' => 'EUR',
|
||||
'grouping' => false,
|
||||
'divisor' => 1,
|
||||
'currency' => 'EUR',
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -19,15 +19,19 @@ class NumberType extends AbstractType
|
||||
{
|
||||
public function buildForm(FormBuilder $builder, array $options)
|
||||
{
|
||||
$builder->appendClientTransformer(new NumberToLocalizedStringTransformer($options['precision'], $options['grouping'], $options['rounding_mode']));
|
||||
$builder->appendClientTransformer(new NumberToLocalizedStringTransformer(
|
||||
$options['precision'],
|
||||
$options['grouping'],
|
||||
$options['rounding_mode']
|
||||
));
|
||||
}
|
||||
|
||||
public function getDefaultOptions(array $options)
|
||||
{
|
||||
return array(
|
||||
// default precision is locale specific (usually around 3)
|
||||
'precision' => null,
|
||||
'grouping' => false,
|
||||
'precision' => null,
|
||||
'grouping' => false,
|
||||
'rounding_mode' => \NumberFormatter::ROUND_HALFUP,
|
||||
);
|
||||
}
|
||||
|
@ -26,7 +26,7 @@ class PercentType extends AbstractType
|
||||
{
|
||||
return array(
|
||||
'precision' => 0,
|
||||
'type' => 'fractional',
|
||||
'type' => 'fractional',
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -21,17 +21,21 @@ class RadioType extends AbstractType
|
||||
{
|
||||
public function buildForm(FormBuilder $builder, array $options)
|
||||
{
|
||||
$builder->appendClientTransformer(new BooleanToStringTransformer())
|
||||
->setAttribute('value', $options['value']);
|
||||
$builder
|
||||
->appendClientTransformer(new BooleanToStringTransformer())
|
||||
->setAttribute('value', $options['value'])
|
||||
;
|
||||
}
|
||||
|
||||
public function buildView(FormView $view, FormInterface $form)
|
||||
{
|
||||
$view->set('value', $form->getAttribute('value'));
|
||||
$view->set('checked', (Boolean) $form->getData());
|
||||
$view
|
||||
->set('value', $form->getAttribute('value'))
|
||||
->set('checked', (Boolean) $form->getData())
|
||||
;
|
||||
|
||||
if ($view->hasParent()) {
|
||||
$view->set('name', $view->getParent()->get('name'));
|
||||
$view->set('full_name', $view->getParent()->get('full_name'));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -19,23 +19,24 @@ class RepeatedType extends AbstractType
|
||||
{
|
||||
public function buildForm(FormBuilder $builder, array $options)
|
||||
{
|
||||
$builder->appendClientTransformer(new ValueToDuplicatesTransformer(array(
|
||||
$builder
|
||||
->appendClientTransformer(new ValueToDuplicatesTransformer(array(
|
||||
$options['first_name'],
|
||||
$options['second_name'],
|
||||
)))
|
||||
->add($options['first_name'], $options['type'], $options['options'])
|
||||
->add($options['second_name'], $options['type'], $options['options']);
|
||||
->add($options['second_name'], $options['type'], $options['options'])
|
||||
;
|
||||
}
|
||||
|
||||
public function getDefaultOptions(array $options)
|
||||
{
|
||||
return array(
|
||||
'type' => 'text',
|
||||
'options' => array(),
|
||||
'first_name' => 'first',
|
||||
'second_name' => 'second',
|
||||
'csrf_protection' => false,
|
||||
'error_bubbling' => false,
|
||||
'type' => 'text',
|
||||
'options' => array(),
|
||||
'first_name' => 'first',
|
||||
'second_name' => 'second',
|
||||
'error_bubbling' => false,
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -0,0 +1,27 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\Form\Extension\Core\Type;
|
||||
|
||||
use Symfony\Component\Form\AbstractType;
|
||||
|
||||
class SearchType extends AbstractType
|
||||
{
|
||||
public function getParent(array $options)
|
||||
{
|
||||
return 'text';
|
||||
}
|
||||
|
||||
public function getName()
|
||||
{
|
||||
return 'search';
|
||||
}
|
||||
}
|
@ -66,33 +66,39 @@ class TimeType extends AbstractType
|
||||
}
|
||||
|
||||
$builder
|
||||
->appendClientTransformer(new DateTimeToArrayTransformer($options['data_timezone'], $options['user_timezone'], $parts, $options['widget'] === 'text'))
|
||||
->appendClientTransformer(new DateTimeToArrayTransformer(
|
||||
$options['data_timezone'],
|
||||
$options['user_timezone'],
|
||||
$parts,
|
||||
$options['widget'] === 'text'
|
||||
))
|
||||
->setAttribute('widget', $options['widget'])
|
||||
->setAttribute('with_seconds', $options['with_seconds']);
|
||||
->setAttribute('with_seconds', $options['with_seconds'])
|
||||
;
|
||||
}
|
||||
|
||||
public function buildView(FormView $view, FormInterface $form)
|
||||
{
|
||||
$view->set('widget', $form->getAttribute('widget'));
|
||||
$view->set('with_seconds', $form->getAttribute('with_seconds'));
|
||||
$view
|
||||
->set('widget', $form->getAttribute('widget'))
|
||||
->set('with_seconds', $form->getAttribute('with_seconds'))
|
||||
;
|
||||
}
|
||||
|
||||
public function getDefaultOptions(array $options)
|
||||
{
|
||||
return array(
|
||||
'hours' => range(0, 23),
|
||||
'minutes' => range(0, 59),
|
||||
'seconds' => range(0, 59),
|
||||
'widget' => 'choice',
|
||||
'input' => 'datetime',
|
||||
'with_seconds' => false,
|
||||
'pattern' => null,
|
||||
'data_timezone' => null,
|
||||
'user_timezone' => null,
|
||||
'csrf_protection' => false,
|
||||
'hours' => range(0, 23),
|
||||
'minutes' => range(0, 59),
|
||||
'seconds' => range(0, 59),
|
||||
'widget' => 'choice',
|
||||
'input' => 'datetime',
|
||||
'with_seconds' => false,
|
||||
'data_timezone' => null,
|
||||
'user_timezone' => null,
|
||||
// Don't modify \DateTime classes by reference, we treat
|
||||
// them like immutable value objects
|
||||
'by_reference' => false,
|
||||
'by_reference' => false,
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -15,15 +15,26 @@ use Symfony\Component\Form\Extension\Csrf\Type;
|
||||
use Symfony\Component\Form\Extension\Csrf\CsrfProvider\CsrfProviderInterface;
|
||||
use Symfony\Component\Form\AbstractExtension;
|
||||
|
||||
/**
|
||||
* This extension protects forms by using a CSRF token
|
||||
*/
|
||||
class CsrfExtension extends AbstractExtension
|
||||
{
|
||||
private $csrfProvider;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param CsrfProviderInterface $csrfProvider The CSRF provider
|
||||
*/
|
||||
public function __construct(CsrfProviderInterface $csrfProvider)
|
||||
{
|
||||
$this->csrfProvider = $csrfProvider;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
protected function loadTypes()
|
||||
{
|
||||
return array(
|
||||
@ -31,10 +42,18 @@ class CsrfExtension extends AbstractExtension
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
protected function loadTypeExtensions()
|
||||
{
|
||||
return array(
|
||||
new Type\ChoiceTypeCsrfExtension(),
|
||||
new Type\DateTypeCsrfExtension(),
|
||||
new Type\FileTypeCsrfExtension(),
|
||||
new Type\FormTypeCsrfExtension(),
|
||||
new Type\RepeatedTypeCsrfExtension(),
|
||||
new Type\TimeTypeCsrfExtension(),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -21,31 +21,29 @@ namespace Symfony\Component\Form\Extension\Csrf\CsrfProvider;
|
||||
* secret information.
|
||||
*
|
||||
* If you want to secure a form submission against CSRF attacks, you could
|
||||
* use the class name of the form as page ID. This way you make sure that the
|
||||
* form can only be bound to pages that are designed to handle the form,
|
||||
* that is, that use the same class name to validate the CSRF token with
|
||||
* isCsrfTokenValid().
|
||||
* supply an "intention" string. This way you make sure that the form can only
|
||||
* be bound to pages that are designed to handle the form, that is, that use
|
||||
* the same intention string to validate the CSRF token with isCsrfTokenValid().
|
||||
*
|
||||
* @author Bernhard Schussek <bernhard.schussek@symfony.com>
|
||||
*/
|
||||
interface CsrfProviderInterface
|
||||
{
|
||||
/**
|
||||
* Generates a CSRF token for a page of your application
|
||||
* Generates a CSRF token for a page of your application.
|
||||
*
|
||||
* @param string $pageId Some value that identifies the page (for example,
|
||||
* the class name of the form). Doesn't have to be
|
||||
* a secret value.
|
||||
* @param string $intention Some value that identifies the action intention
|
||||
* (i.e. "authenticate"). Doesn't have to be a secret value.
|
||||
*/
|
||||
public function generateCsrfToken($pageId);
|
||||
public function generateCsrfToken($intention);
|
||||
|
||||
/**
|
||||
* Validates a CSRF token
|
||||
* Validates a CSRF token.
|
||||
*
|
||||
* @param string $pageId The page ID used when generating the CSRF token
|
||||
* @param string $token The token supplied by the browser
|
||||
* @return Boolean Whether the token supplied by the browser is
|
||||
* correct
|
||||
* @param string $intention The intention used when generating the CSRF token
|
||||
* @param string $token The token supplied by the browser
|
||||
*
|
||||
* @return Boolean Whether the token supplied by the browser is correct
|
||||
*/
|
||||
public function isCsrfTokenValid($pageId, $token);
|
||||
public function isCsrfTokenValid($intention, $token);
|
||||
}
|
@ -43,17 +43,17 @@ class DefaultCsrfProvider implements CsrfProviderInterface
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function generateCsrfToken($pageId)
|
||||
public function generateCsrfToken($intention)
|
||||
{
|
||||
return sha1($this->secret.$pageId.$this->getSessionId());
|
||||
return sha1($this->secret.$intention.$this->getSessionId());
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function isCsrfTokenValid($pageId, $token)
|
||||
public function isCsrfTokenValid($intention, $token)
|
||||
{
|
||||
return $token === $this->generateCsrfToken($pageId);
|
||||
return $token === $this->generateCsrfToken($intention);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -0,0 +1,27 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\Form\Extension\Csrf\Type;
|
||||
|
||||
use Symfony\Component\Form\AbstractTypeExtension;
|
||||
|
||||
class ChoiceTypeCsrfExtension extends AbstractTypeExtension
|
||||
{
|
||||
public function getDefaultOptions(array $options)
|
||||
{
|
||||
return array('csrf_protection' => false);
|
||||
}
|
||||
|
||||
public function getExtendedType()
|
||||
{
|
||||
return 'choice';
|
||||
}
|
||||
}
|
@ -22,43 +22,70 @@ class CsrfType extends AbstractType
|
||||
{
|
||||
private $csrfProvider;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param CsrfProviderInterface $csrfProvider The provider to use to generate the token
|
||||
*/
|
||||
public function __construct(CsrfProviderInterface $csrfProvider)
|
||||
{
|
||||
$this->csrfProvider = $csrfProvider;
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds the CSRF field.
|
||||
*
|
||||
* A validator is added to check the token value when the CSRF field is added to
|
||||
* a root form
|
||||
*
|
||||
* @param FormBuilder $builder The form builder
|
||||
* @param array $options The options
|
||||
*/
|
||||
public function buildForm(FormBuilder $builder, array $options)
|
||||
{
|
||||
$csrfProvider = $options['csrf_provider'];
|
||||
$pageId = $options['page_id'];
|
||||
$intention = $options['intention'];
|
||||
|
||||
$validator = function (FormInterface $form) use ($csrfProvider, $intention)
|
||||
{
|
||||
if ((!$form->hasParent() || $form->getParent()->isRoot())
|
||||
&& !$csrfProvider->isCsrfTokenValid($intention, $form->getData())) {
|
||||
$form->addError(new FormError('The CSRF token is invalid. Please try to resubmit the form'));
|
||||
$form->setData($csrfProvider->generateCsrfToken($intention));
|
||||
}
|
||||
};
|
||||
|
||||
$builder
|
||||
->setData($csrfProvider->generateCsrfToken($pageId))
|
||||
->addValidator(new CallbackValidator(
|
||||
function (FormInterface $form) use ($csrfProvider, $pageId) {
|
||||
if ((!$form->hasParent() || $form->getParent()->isRoot())
|
||||
&& !$csrfProvider->isCsrfTokenValid($pageId, $form->getData())) {
|
||||
$form->addError(new FormError('The CSRF token is invalid. Please try to resubmit the form'));
|
||||
$form->setData($csrfProvider->generateCsrfToken($pageId));
|
||||
}
|
||||
}
|
||||
));
|
||||
->setData($csrfProvider->generateCsrfToken($intention))
|
||||
->addValidator(new CallbackValidator($validator))
|
||||
;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function getDefaultOptions(array $options)
|
||||
{
|
||||
return array(
|
||||
'csrf_provider' => $this->csrfProvider,
|
||||
'page_id' => null,
|
||||
'intention' => null,
|
||||
'property_path' => false,
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function getParent(array $options)
|
||||
{
|
||||
return 'hidden';
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the name of this form.
|
||||
*
|
||||
* @return string 'csrf'
|
||||
*/
|
||||
public function getName()
|
||||
{
|
||||
return 'csrf';
|
||||
|
@ -0,0 +1,27 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\Form\Extension\Csrf\Type;
|
||||
|
||||
use Symfony\Component\Form\AbstractTypeExtension;
|
||||
|
||||
class DateTypeCsrfExtension extends AbstractTypeExtension
|
||||
{
|
||||
public function getDefaultOptions(array $options)
|
||||
{
|
||||
return array('csrf_protection' => false);
|
||||
}
|
||||
|
||||
public function getExtendedType()
|
||||
{
|
||||
return 'date';
|
||||
}
|
||||
}
|
@ -0,0 +1,27 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\Form\Extension\Csrf\Type;
|
||||
|
||||
use Symfony\Component\Form\AbstractTypeExtension;
|
||||
|
||||
class FileTypeCsrfExtension extends AbstractTypeExtension
|
||||
{
|
||||
public function getDefaultOptions(array $options)
|
||||
{
|
||||
return array('csrf_protection' => false);
|
||||
}
|
||||
|
||||
public function getExtendedType()
|
||||
{
|
||||
return 'file';
|
||||
}
|
||||
}
|
@ -27,20 +27,34 @@ class FormTypeCsrfExtension extends AbstractTypeExtension
|
||||
$this->fieldName = $fieldName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a CSRF field to the form when the CSRF protection is enabled.
|
||||
*
|
||||
* @param FormBuilder $builder The form builder
|
||||
* @param array $options The options
|
||||
*/
|
||||
public function buildForm(FormBuilder $builder, array $options)
|
||||
{
|
||||
if ($options['csrf_protection']) {
|
||||
$csrfOptions = array('page_id' => $options['csrf_page_id']);
|
||||
$csrfOptions = array('intention' => $options['intention']);
|
||||
|
||||
if ($options['csrf_provider']) {
|
||||
$csrfOptions['csrf_provider'] = $options['csrf_provider'];
|
||||
}
|
||||
|
||||
$builder->add($options['csrf_field_name'], 'csrf', $csrfOptions)
|
||||
->setAttribute('csrf_field_name', $options['csrf_field_name']);
|
||||
$builder
|
||||
->add($options['csrf_field_name'], 'csrf', $csrfOptions)
|
||||
->setAttribute('csrf_field_name', $options['csrf_field_name'])
|
||||
;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes CSRF fields from all the form views except the root one.
|
||||
*
|
||||
* @param FormView $view The form view
|
||||
* @param FormInterface $form The form
|
||||
*/
|
||||
public function buildViewBottomUp(FormView $view, FormInterface $form)
|
||||
{
|
||||
if ($view->hasParent() && $form->hasAttribute('csrf_field_name')) {
|
||||
@ -52,16 +66,22 @@ class FormTypeCsrfExtension extends AbstractTypeExtension
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function getDefaultOptions(array $options)
|
||||
{
|
||||
return array(
|
||||
'csrf_protection' => $this->enabled,
|
||||
'csrf_field_name' => $this->fieldName,
|
||||
'csrf_provider' => null,
|
||||
'csrf_page_id' => get_class($this),
|
||||
'csrf_protection' => $this->enabled,
|
||||
'csrf_field_name' => $this->fieldName,
|
||||
'csrf_provider' => null,
|
||||
'intention' => 'unknown',
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function getExtendedType()
|
||||
{
|
||||
return 'form';
|
||||
|
@ -0,0 +1,27 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\Form\Extension\Csrf\Type;
|
||||
|
||||
use Symfony\Component\Form\AbstractTypeExtension;
|
||||
|
||||
class RepeatedTypeCsrfExtension extends AbstractTypeExtension
|
||||
{
|
||||
public function getDefaultOptions(array $options)
|
||||
{
|
||||
return array('csrf_protection' => false);
|
||||
}
|
||||
|
||||
public function getExtendedType()
|
||||
{
|
||||
return 'repeated';
|
||||
}
|
||||
}
|
@ -0,0 +1,27 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\Form\Extension\Csrf\Type;
|
||||
|
||||
use Symfony\Component\Form\AbstractTypeExtension;
|
||||
|
||||
class TimeTypeCsrfExtension extends AbstractTypeExtension
|
||||
{
|
||||
public function getDefaultOptions(array $options)
|
||||
{
|
||||
return array('csrf_protection' => false);
|
||||
}
|
||||
|
||||
public function getExtendedType()
|
||||
{
|
||||
return 'time';
|
||||
}
|
||||
}
|
@ -63,6 +63,18 @@ class ValidatorTypeGuesser implements FormTypeGuesserInterface
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
public function guessMinLength($class, $property)
|
||||
{
|
||||
$guesser = $this;
|
||||
|
||||
return $this->guess($class, $property, function (Constraint $constraint) use ($guesser) {
|
||||
return $guesser->guessMinLengthForConstraint($constraint);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Guesses a field class name for a given constraint
|
||||
*
|
||||
@ -266,6 +278,28 @@ class ValidatorTypeGuesser implements FormTypeGuesserInterface
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Guesses a field's minimum length based on the given constraint
|
||||
*
|
||||
* @param Constraint $constraint The constraint to guess for
|
||||
* @return Guess The guess for the minimum length
|
||||
*/
|
||||
public function guessMinLengthForConstraint(Constraint $constraint)
|
||||
{
|
||||
switch (get_class($constraint)) {
|
||||
case 'Symfony\Component\Validator\Constraints\MinLength':
|
||||
return new ValueGuess(
|
||||
$constraint->limit,
|
||||
Guess::HIGH_CONFIDENCE
|
||||
);
|
||||
case 'Symfony\Component\Validator\Constraints\Min':
|
||||
return new ValueGuess(
|
||||
strlen((string)$constraint->limit),
|
||||
Guess::HIGH_CONFIDENCE
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Iterates over the constraints of a property, executes a constraints on
|
||||
* them and returns the best guess
|
||||
|
@ -24,13 +24,6 @@ use Symfony\Component\EventDispatcher\EventDispatcherInterface;
|
||||
*
|
||||
* A form is composed of a validator schema and a widget form schema.
|
||||
*
|
||||
* Form also takes care of CSRF protection by default.
|
||||
*
|
||||
* A CSRF secret can be any random string. If set to false, it disables the
|
||||
* CSRF protection, and if set to null, it forces the form to use the global
|
||||
* CSRF secret. If the global CSRF secret is also null, then a random one
|
||||
* is generated on the fly.
|
||||
*
|
||||
* To implement your own form fields, you need to have a thorough understanding
|
||||
* of the data flow within a form field. A form field stores its data in three
|
||||
* different representations:
|
||||
@ -459,7 +452,9 @@ class Form implements \IteratorAggregate, FormInterface
|
||||
public function bind($clientData)
|
||||
{
|
||||
if ($this->readOnly) {
|
||||
return;
|
||||
$this->bound = true;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
if (is_scalar($clientData) || null === $clientData) {
|
||||
@ -558,6 +553,8 @@ class Form implements \IteratorAggregate, FormInterface
|
||||
foreach ($this->validators as $validator) {
|
||||
$validator->validate($this);
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -568,6 +565,8 @@ class Form implements \IteratorAggregate, FormInterface
|
||||
*
|
||||
* @param Request $request The request to bind to the form
|
||||
*
|
||||
* @return Form This form
|
||||
*
|
||||
* @throws FormException if the method of the request is not one of GET, POST or PUT
|
||||
*/
|
||||
public function bindRequest(Request $request)
|
||||
@ -588,7 +587,7 @@ class Form implements \IteratorAggregate, FormInterface
|
||||
throw new FormException(sprintf('The request method "%s" is not supported', $request->getMethod()));
|
||||
}
|
||||
|
||||
$this->bind($data);
|
||||
return $this->bind($data);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -604,9 +603,11 @@ class Form implements \IteratorAggregate, FormInterface
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds an error to the field.
|
||||
* Adds an error to this form.
|
||||
*
|
||||
* @see FormInterface
|
||||
* @param FormError $error
|
||||
*
|
||||
* @return Form The current form
|
||||
*/
|
||||
public function addError(FormError $error)
|
||||
{
|
||||
@ -615,6 +616,8 @@ class Form implements \IteratorAggregate, FormInterface
|
||||
} else {
|
||||
$this->errors[] = $error;
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -754,6 +757,8 @@ class Form implements \IteratorAggregate, FormInterface
|
||||
* Adds a child to the form.
|
||||
*
|
||||
* @param FormInterface $child The FormInterface to add as a child
|
||||
*
|
||||
* @return Form the current form
|
||||
*/
|
||||
public function add(FormInterface $child)
|
||||
{
|
||||
@ -764,12 +769,16 @@ class Form implements \IteratorAggregate, FormInterface
|
||||
if ($this->dataMapper) {
|
||||
$this->dataMapper->mapDataToForm($this->getClientData(), $child);
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes a child from the form.
|
||||
*
|
||||
* @param string $name The name of the child to remove
|
||||
*
|
||||
* @return Form the current form
|
||||
*/
|
||||
public function remove($name)
|
||||
{
|
||||
@ -778,6 +787,8 @@ class Form implements \IteratorAggregate, FormInterface
|
||||
|
||||
unset($this->children[$name]);
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -372,9 +372,16 @@ class FormBuilder
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Clears the client transformers.
|
||||
*
|
||||
* @return FormBuilder The current builder
|
||||
*/
|
||||
public function resetClientTransformers()
|
||||
{
|
||||
$this->clientTransformers = array();
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -610,12 +617,16 @@ class FormBuilder
|
||||
* Removes the field with the given name.
|
||||
*
|
||||
* @param string $name
|
||||
*
|
||||
* @return FormBuilder The current builder
|
||||
*/
|
||||
public function remove($name)
|
||||
{
|
||||
if (isset($this->children[$name])) {
|
||||
unset($this->children[$name]);
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -305,6 +305,7 @@ class FormFactory implements FormFactoryInterface
|
||||
|
||||
$typeGuess = $this->guesser->guessType($class, $property);
|
||||
$maxLengthGuess = $this->guesser->guessMaxLength($class, $property);
|
||||
$minLengthGuess = $this->guesser->guessMinLength($class, $property);
|
||||
$requiredGuess = $this->guesser->guessRequired($class, $property);
|
||||
|
||||
$type = $typeGuess ? $typeGuess->getType() : 'text';
|
||||
@ -313,6 +314,14 @@ class FormFactory implements FormFactoryInterface
|
||||
$options = array_merge(array('max_length' => $maxLengthGuess->getValue()), $options);
|
||||
}
|
||||
|
||||
if ($minLengthGuess) {
|
||||
if ($maxLengthGuess) {
|
||||
$options = array_merge(array('pattern' => '.{'.$minLengthGuess->getValue().','.$maxLengthGuess->getValue().'}'), $options);
|
||||
} else {
|
||||
$options = array_merge(array('pattern' => '.{'.$minLengthGuess->getValue().',}'), $options);
|
||||
}
|
||||
}
|
||||
|
||||
if ($requiredGuess) {
|
||||
$options = array_merge(array('required' => $requiredGuess->getValue()), $options);
|
||||
}
|
||||
|
@ -61,6 +61,13 @@ class FormTypeGuesserChain implements FormTypeGuesserInterface
|
||||
});
|
||||
}
|
||||
|
||||
public function guessMinLength($class, $property)
|
||||
{
|
||||
return $this->guess(function ($guesser) use ($class, $property) {
|
||||
return $guesser->guessMinLength($class, $property);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Executes a closure for each guesser and returns the best guess from the
|
||||
* return values
|
||||
|
@ -42,4 +42,14 @@ interface FormTypeGuesserInterface
|
||||
* @return Guess A guess for the field's maximum length
|
||||
*/
|
||||
function guessMaxLength($class, $property);
|
||||
|
||||
/**
|
||||
* Returns a guess about the field's minimum length
|
||||
*
|
||||
* @param string $class The fully qualified class name
|
||||
* @param string $property The name of the property to guess for
|
||||
* @return Guess A guess for the field's minimum length
|
||||
*/
|
||||
function guessMinLength($class, $property);
|
||||
|
||||
}
|
@ -38,10 +38,14 @@ class FormView implements \ArrayAccess, \IteratorAggregate, \Countable
|
||||
/**
|
||||
* @param string $name
|
||||
* @param mixed $value
|
||||
*
|
||||
* @return FormView The current view
|
||||
*/
|
||||
public function set($name, $value)
|
||||
{
|
||||
$this->vars[$name] = $value;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -91,10 +95,14 @@ class FormView implements \ArrayAccess, \IteratorAggregate, \Countable
|
||||
*
|
||||
* @param string $name The name of the attribute
|
||||
* @param string $value The value
|
||||
*
|
||||
* @return FormView The current view
|
||||
*/
|
||||
public function setAttribute($name, $value)
|
||||
{
|
||||
$this->vars['attr'][$name] = $value;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -109,20 +117,28 @@ class FormView implements \ArrayAccess, \IteratorAggregate, \Countable
|
||||
|
||||
/**
|
||||
* Marks the attached form as rendered
|
||||
*
|
||||
* @return FormView The current view
|
||||
*/
|
||||
public function setRendered()
|
||||
{
|
||||
$this->rendered = true;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the parent view.
|
||||
*
|
||||
* @param FormView $parent The parent view
|
||||
*
|
||||
* @return FormView The current view
|
||||
*/
|
||||
public function setParent(FormView $parent = null)
|
||||
{
|
||||
$this->parent = $parent;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -149,10 +165,14 @@ class FormView implements \ArrayAccess, \IteratorAggregate, \Countable
|
||||
* Sets the children view.
|
||||
*
|
||||
* @param array $children The children as instances of FormView
|
||||
*
|
||||
* @return FormView The current view
|
||||
*/
|
||||
public function setChildren(array $children)
|
||||
{
|
||||
$this->children = $children;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user