Merge remote branch 'origin/master' into doctrine
This commit is contained in:
commit
51f1add9b3
81
UPDATE.md
81
UPDATE.md
@ -9,6 +9,84 @@ timeline closely anyway.
|
||||
beta1 to beta2
|
||||
--------------
|
||||
|
||||
* The annotation parsing process has been changed. All annotations which are used
|
||||
in a class must now be imported (just like you import PHP namespaces with the
|
||||
"use" statement):
|
||||
|
||||
Before:
|
||||
|
||||
/**
|
||||
* @orm:Entity
|
||||
*/
|
||||
class MyUser
|
||||
{
|
||||
/**
|
||||
* @orm:Id
|
||||
* @orm:GeneratedValue(strategy = "AUTO")
|
||||
* @orm:Column(type="integer")
|
||||
* @var integer
|
||||
*/
|
||||
private $id;
|
||||
|
||||
/**
|
||||
* @orm:Column(type="string", nullable=false)
|
||||
* @assert:NotBlank
|
||||
* @var string
|
||||
*/
|
||||
private $name;
|
||||
}
|
||||
|
||||
After:
|
||||
|
||||
use Doctrine\ORM\Mapping as ORM;
|
||||
use Symfony\Component\Validator\Constraints as Assert;
|
||||
|
||||
/**
|
||||
* @ORM\Entity
|
||||
*/
|
||||
class MyUser
|
||||
{
|
||||
/**
|
||||
* @ORM\Id
|
||||
* @ORM\GeneratedValue(strategy="AUTO")
|
||||
* @ORM\Column(type="integer")
|
||||
*
|
||||
* @var integer
|
||||
*/
|
||||
private $id;
|
||||
|
||||
/**
|
||||
* @ORM\Column(type="string", nullable=false)
|
||||
* @Assert\NotBlank
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
private $name;
|
||||
}
|
||||
|
||||
* The config under "framework.validation.annotations" has been removed and was
|
||||
replaced with a boolean flag "framework.validation.enable_annotations" which
|
||||
defaults to false.
|
||||
|
||||
* The Set constraint has been removed as it is not required anymore.
|
||||
|
||||
Before:
|
||||
|
||||
/**
|
||||
* @assert:Set({@assert:Callback(...), @assert:Callback(...)})
|
||||
*/
|
||||
private $foo;
|
||||
|
||||
After:
|
||||
|
||||
use Symfony\Component\Validator\Constraints\Callback;
|
||||
|
||||
/**
|
||||
* @Callback(...)
|
||||
* @Callback(...)
|
||||
*/
|
||||
private $foo;
|
||||
|
||||
* Forms must now be explicitly enabled (automatically done in Symfony SE):
|
||||
|
||||
form: ~
|
||||
@ -168,6 +246,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;
|
||||
}
|
||||
}
|
||||
|
@ -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!
|
||||
}
|
||||
}
|
@ -33,6 +33,8 @@ class FormExtension extends \Twig_Extension
|
||||
{
|
||||
$this->themes = new \SplObjectStorage();
|
||||
$this->varStack = new \SplObjectStorage();
|
||||
$this->templates = new \SplObjectStorage();
|
||||
|
||||
$this->resources = $resources;
|
||||
}
|
||||
|
||||
@ -53,6 +55,7 @@ class FormExtension extends \Twig_Extension
|
||||
public function setTheme(FormView $view, array $resources)
|
||||
{
|
||||
$this->themes->attach($view, $resources);
|
||||
$this->templates->detach($view);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -183,35 +186,48 @@ class FormExtension extends \Twig_Extension
|
||||
throw new FormException(sprintf('Unable to render form as none of the following blocks exist: "%s".', implode('", "', $blocks)));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the templates used by the view.
|
||||
*
|
||||
* templates are looked for in the following resources:
|
||||
* * resources from the themes (and its parents)
|
||||
* * default resources
|
||||
*
|
||||
* @param FormView $view The view
|
||||
*
|
||||
* @return array An array of Twig_TemplateInterface instances
|
||||
*/
|
||||
protected function getTemplates(FormView $view)
|
||||
{
|
||||
// templates are looked for in the following resources:
|
||||
// * resources from the themes (and its parents)
|
||||
// * default resources
|
||||
if (!$this->templates->contains($view)) {
|
||||
// defaults
|
||||
$all = $this->resources;
|
||||
|
||||
// defaults
|
||||
$all = $this->resources;
|
||||
// themes
|
||||
$parent = $view;
|
||||
do {
|
||||
if (isset($this->themes[$parent])) {
|
||||
$all = array_merge($all, $this->themes[$parent]);
|
||||
}
|
||||
} while ($parent = $parent->getParent());
|
||||
|
||||
// themes
|
||||
$parent = $view;
|
||||
do {
|
||||
if (isset($this->themes[$parent])) {
|
||||
$all = array_merge($all, $this->themes[$parent]);
|
||||
}
|
||||
} while ($parent = $parent->getParent());
|
||||
$templates = array();
|
||||
foreach ($all as $resource) {
|
||||
if (!$resource instanceof \Twig_Template) {
|
||||
$resource = $this->environment->loadTemplate($resource);
|
||||
}
|
||||
|
||||
$templates = array();
|
||||
foreach ($all as $resource) {
|
||||
if (!$resource instanceof \Twig_Template) {
|
||||
$resource = $this->environment->loadTemplate($resource);
|
||||
$blocks = array();
|
||||
foreach ($this->getBlockNames($resource) as $name) {
|
||||
$blocks[$name] = $resource;
|
||||
}
|
||||
|
||||
$templates = array_replace($templates, $blocks);
|
||||
}
|
||||
|
||||
$blocks = array();
|
||||
foreach ($this->getBlockNames($resource) as $name) {
|
||||
$blocks[$name] = $resource;
|
||||
}
|
||||
|
||||
$templates = array_replace($templates, $blocks);
|
||||
$this->templates->attach($view, $templates);
|
||||
} else {
|
||||
$templates = $this->templates[$view];
|
||||
}
|
||||
|
||||
return $templates;
|
||||
|
@ -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())
|
||||
|
@ -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);
|
||||
|
@ -4,7 +4,7 @@ framework:
|
||||
csrf_protection:
|
||||
enabled: true
|
||||
router: { resource: "%kernel.root_dir%/config/routing.yml" }
|
||||
validation: { enabled: true, annotations: true }
|
||||
validation: { enabled: true, enable_annotations: true }
|
||||
templating: { engines: ['twig', 'php'] }
|
||||
session:
|
||||
default_locale: en
|
||||
|
@ -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,67 @@
|
||||
<?php
|
||||
|
||||
namespace Symfony\Bundle\DoctrineBundle\Annotations;
|
||||
|
||||
use Doctrine\Common\Annotations\Reader;
|
||||
|
||||
/**
|
||||
* Allows the reader to be used in-place of Doctrine's reader.
|
||||
*
|
||||
* This can be removed once the BC layer is in place.
|
||||
*
|
||||
* @author Johannes M. Schmitt <schmittjoh@gmail.com>
|
||||
*/
|
||||
class IndexedReader implements Reader
|
||||
{
|
||||
private $delegate;
|
||||
|
||||
public function __construct(Reader $reader)
|
||||
{
|
||||
$this->delegate = $reader;
|
||||
}
|
||||
|
||||
public function getClassAnnotations(\ReflectionClass $class)
|
||||
{
|
||||
$annotations = array();
|
||||
foreach ($this->delegate->getClassAnnotations($class) as $annot) {
|
||||
$annotations[get_class($annot)] = $annot;
|
||||
}
|
||||
|
||||
return $annotations;
|
||||
}
|
||||
|
||||
public function getClassAnnotation(\ReflectionClass $class, $annotation)
|
||||
{
|
||||
return $this->delegate->getClassAnnotation($class, $annotation);
|
||||
}
|
||||
|
||||
public function getMethodAnnotations(\ReflectionMethod $method)
|
||||
{
|
||||
$annotations = array();
|
||||
foreach ($this->delegate->getMethodAnnotations($method) as $annot) {
|
||||
$annotations[get_class($annot)] = $annot;
|
||||
}
|
||||
|
||||
return $annotations;
|
||||
}
|
||||
|
||||
public function getMethodAnnotation(\ReflectionMethod $method, $annotation)
|
||||
{
|
||||
return $this->delegate->getMethodAnnotation($method, $annotation);
|
||||
}
|
||||
|
||||
public function getPropertyAnnotations(\ReflectionProperty $property)
|
||||
{
|
||||
$annotations = array();
|
||||
foreach ($this->delegate->getPropertyAnnotations($property) as $annot) {
|
||||
$annotations[get_class($annot)] = $annot;
|
||||
}
|
||||
|
||||
return $annotations;
|
||||
}
|
||||
|
||||
public function getPropertyAnnotation(\ReflectionProperty $property, $annotation)
|
||||
{
|
||||
return $this->delegate->getPropertyAnnotation($property, $annotation);
|
||||
}
|
||||
}
|
@ -20,7 +20,7 @@
|
||||
<!-- metadata -->
|
||||
<parameter key="doctrine.orm.metadata.driver_chain.class">Doctrine\ORM\Mapping\Driver\DriverChain</parameter>
|
||||
<parameter key="doctrine.orm.metadata.annotation.class">Doctrine\ORM\Mapping\Driver\AnnotationDriver</parameter>
|
||||
<parameter key="doctrine.orm.metadata.annotation_reader.class">Doctrine\Common\Annotations\AnnotationReader</parameter>
|
||||
<parameter key="doctrine.orm.metadata.annotation_reader.class">Symfony\Bundle\DoctrineBundle\Annotations\IndexedReader</parameter>
|
||||
<parameter key="doctrine.orm.metadata.xml.class">Symfony\Bundle\DoctrineBundle\Mapping\Driver\XmlDriver</parameter>
|
||||
<parameter key="doctrine.orm.metadata.yml.class">Symfony\Bundle\DoctrineBundle\Mapping\Driver\YamlDriver</parameter>
|
||||
<parameter key="doctrine.orm.metadata.php.class">Doctrine\ORM\Mapping\Driver\PHPDriver</parameter>
|
||||
@ -31,15 +31,15 @@
|
||||
|
||||
<!-- 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>
|
||||
<!--- Annotation Metadata Reader Service -->
|
||||
<service id="doctrine.orm.metadata.annotation_reader" class="%doctrine.orm.metadata.annotation_reader.class%" public="false">
|
||||
<call method="setAnnotationNamespaceAlias">
|
||||
<argument>Doctrine\ORM\Mapping\</argument>
|
||||
<argument>orm</argument>
|
||||
</call>
|
||||
<argument type="service" id="annotation_reader" />
|
||||
</service>
|
||||
|
||||
<service id="doctrine.orm.proxy_cache_warmer" class="%doctrine.orm.proxy_cache_warmer.class%" public="false">
|
||||
@ -60,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>
|
||||
|
@ -24,7 +24,7 @@ class ContainerTest extends TestCase
|
||||
$this->assertInstanceOf('Doctrine\DBAL\Configuration', $container->get('doctrine.dbal.default_connection.configuration'));
|
||||
$this->assertInstanceOf('Doctrine\Common\EventManager', $container->get('doctrine.dbal.default_connection.event_manager'));
|
||||
$this->assertInstanceOf('Doctrine\DBAL\Connection', $container->get('doctrine.dbal.default_connection'));
|
||||
$this->assertInstanceOf('Doctrine\Common\Annotations\AnnotationReader', $container->get('doctrine.orm.metadata.annotation_reader'));
|
||||
$this->assertInstanceOf('Doctrine\Common\Annotations\Reader', $container->get('doctrine.orm.metadata.annotation_reader'));
|
||||
$this->assertInstanceOf('Doctrine\ORM\Configuration', $container->get('doctrine.orm.default_configuration'));
|
||||
$this->assertInstanceOf('Doctrine\ORM\Mapping\Driver\DriverChain', $container->get('doctrine.orm.default_metadata_driver'));
|
||||
$this->assertInstanceOf('Doctrine\Common\Cache\ArrayCache', $container->get('doctrine.orm.default_metadata_cache'));
|
||||
@ -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());
|
||||
|
||||
|
@ -35,7 +35,7 @@ abstract class AbstractDoctrineExtensionTest extends TestCase
|
||||
// doctrine.dbal.default_connection
|
||||
$this->assertEquals('%doctrine.default_connection%', $container->getDefinition('doctrine')->getArgument(3), '->load() overrides existing configuration options');
|
||||
$this->assertEquals('foo', $container->getParameter('doctrine.default_connection'), '->load() overrides existing configuration options');
|
||||
|
||||
|
||||
}
|
||||
|
||||
public function testDbalLoad()
|
||||
@ -121,7 +121,6 @@ abstract class AbstractDoctrineExtensionTest extends TestCase
|
||||
$this->assertEquals('Doctrine\Common\Cache\XcacheCache', $container->getParameter('doctrine.orm.cache.xcache.class'));
|
||||
$this->assertEquals('Doctrine\ORM\Mapping\Driver\DriverChain', $container->getParameter('doctrine.orm.metadata.driver_chain.class'));
|
||||
$this->assertEquals('Doctrine\ORM\Mapping\Driver\AnnotationDriver', $container->getParameter('doctrine.orm.metadata.annotation.class'));
|
||||
$this->assertEquals('Doctrine\Common\Annotations\AnnotationReader', $container->getParameter('doctrine.orm.metadata.annotation_reader.class'));
|
||||
$this->assertEquals('Symfony\Bundle\DoctrineBundle\Mapping\Driver\XmlDriver', $container->getParameter('doctrine.orm.metadata.xml.class'));
|
||||
$this->assertEquals('Symfony\Bundle\DoctrineBundle\Mapping\Driver\YamlDriver', $container->getParameter('doctrine.orm.metadata.yml.class'));
|
||||
|
||||
|
@ -11,6 +11,10 @@
|
||||
|
||||
namespace Symfony\Bundle\DoctrineBundle\Tests;
|
||||
|
||||
use Symfony\Bundle\DoctrineBundle\Annotations\IndexedReader;
|
||||
|
||||
use Doctrine\Common\Annotations\AnnotationReader;
|
||||
use Doctrine\ORM\Mapping\Driver\AnnotationDriver;
|
||||
use Doctrine\ORM\EntityManager;
|
||||
use Symfony\Component\DependencyInjection\ContainerBuilder;
|
||||
use Symfony\Component\DependencyInjection\ParameterBag\ParameterBag;
|
||||
@ -36,7 +40,7 @@ class TestCase extends \PHPUnit_Framework_TestCase
|
||||
$config->setAutoGenerateProxyClasses(true);
|
||||
$config->setProxyDir(\sys_get_temp_dir());
|
||||
$config->setProxyNamespace('SymfonyTests\Doctrine');
|
||||
$config->setMetadataDriverImpl($config->newDefaultAnnotationDriver($paths));
|
||||
$config->setMetadataDriverImpl(new AnnotationDriver(new IndexedReader(new AnnotationReader()), $paths));
|
||||
$config->setQueryCacheImpl(new \Doctrine\Common\Cache\ArrayCache());
|
||||
$config->setMetadataCacheImpl(new \Doctrine\Common\Cache\ArrayCache());
|
||||
|
||||
@ -56,6 +60,7 @@ class TestCase extends \PHPUnit_Framework_TestCase
|
||||
'kernel.cache_dir' => sys_get_temp_dir(),
|
||||
'kernel.root_dir' => __DIR__ . "/../../../../" // src dir
|
||||
)));
|
||||
$container->set('annotation_reader', new AnnotationReader());
|
||||
$loader = new DoctrineExtension();
|
||||
$container->registerExtension($loader);
|
||||
$loader->load(array(array(
|
||||
|
@ -16,7 +16,7 @@ use Symfony\Component\Console\Input\InputOption;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
use Symfony\Component\Console\Output\Output;
|
||||
use Symfony\Bundle\FrameworkBundle\Util\Mustache;
|
||||
use Symfony\Bundle\FrameworkBundle\Generator\Generator;
|
||||
|
||||
/**
|
||||
* Initializes a new bundle.
|
||||
@ -105,7 +105,7 @@ EOT
|
||||
$filesystem->mirror(__DIR__.'/../Resources/skeleton/bundle/generic', $targetDir);
|
||||
$filesystem->mirror(__DIR__.'/../Resources/skeleton/bundle/'.$input->getOption('format'), $targetDir);
|
||||
|
||||
Mustache::renderDir($targetDir, array(
|
||||
Generator::renderDir($targetDir, array(
|
||||
'namespace' => $namespace,
|
||||
'bundle' => $bundle,
|
||||
));
|
||||
|
@ -54,6 +54,7 @@ class Configuration implements ConfigurationInterface
|
||||
$this->addTemplatingSection($rootNode);
|
||||
$this->addTranslatorSection($rootNode);
|
||||
$this->addValidationSection($rootNode);
|
||||
$this->addAnnotationsSection($rootNode);
|
||||
|
||||
return $treeBuilder;
|
||||
}
|
||||
@ -255,28 +256,29 @@ class Configuration implements ConfigurationInterface
|
||||
->canBeUnset()
|
||||
->treatNullLike(array('enabled' => true))
|
||||
->treatTrueLike(array('enabled' => true))
|
||||
// For XML, namespace is a child of validation, so it must be moved under annotations
|
||||
->beforeNormalization()
|
||||
->ifTrue(function($v) { return is_array($v) && !empty($v['annotations']) && !empty($v['namespace']); })
|
||||
->then(function($v){
|
||||
$v['annotations'] = array('namespace' => $v['namespace']);
|
||||
unset($v['namespace']);
|
||||
return $v;
|
||||
})
|
||||
->end()
|
||||
->children()
|
||||
->booleanNode('enabled')->defaultTrue()->end()
|
||||
->booleanNode('enabled')->defaultTrue()->end()
|
||||
->scalarNode('cache')->end()
|
||||
->arrayNode('annotations')
|
||||
->canBeUnset()
|
||||
->treatNullLike(array())
|
||||
->treatTrueLike(array())
|
||||
->fixXmlConfig('namespace')
|
||||
->booleanNode('enable_annotations')->defaultFalse()->end()
|
||||
->end()
|
||||
->end()
|
||||
->end()
|
||||
;
|
||||
}
|
||||
|
||||
private function addAnnotationsSection(ArrayNodeDefinition $rootNode)
|
||||
{
|
||||
$rootNode
|
||||
->children()
|
||||
->arrayNode('annotations')
|
||||
->addDefaultsIfNotSet()
|
||||
->children()
|
||||
->scalarNode('cache')->defaultValue('file')->end()
|
||||
->arrayNode('file_cache')
|
||||
->addDefaultsIfNotSet()
|
||||
->children()
|
||||
->arrayNode('namespaces')
|
||||
->useAttributeAsKey('prefix')
|
||||
->prototype('scalar')->end()
|
||||
->end()
|
||||
->scalarNode('dir')->defaultValue('%kernel.cache_dir%/annotations')->end()
|
||||
->booleanNode('debug')->defaultValue($this->debug)->end()
|
||||
->end()
|
||||
->end()
|
||||
->end()
|
||||
|
@ -11,6 +11,7 @@
|
||||
|
||||
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;
|
||||
@ -102,6 +103,8 @@ class FrameworkExtension extends Extension
|
||||
$this->registerTranslatorConfiguration($config['translator'], $container);
|
||||
}
|
||||
|
||||
$this->registerAnnotationsConfiguration($config['annotations'], $container, $loader);
|
||||
|
||||
$this->addClassesToCompile(array(
|
||||
'Symfony\\Component\\HttpFoundation\\ParameterBag',
|
||||
'Symfony\\Component\\HttpFoundation\\HeaderBag',
|
||||
@ -461,22 +464,11 @@ class FrameworkExtension extends Extension
|
||||
$container->setParameter('validator.mapping.loader.xml_files_loader.mapping_files', $this->getValidatorXmlMappingFiles($container));
|
||||
$container->setParameter('validator.mapping.loader.yaml_files_loader.mapping_files', $this->getValidatorYamlMappingFiles($container));
|
||||
|
||||
if (isset($config['annotations'])) {
|
||||
$namespaces = array('assert' => 'Symfony\\Component\\Validator\\Constraints\\');
|
||||
// Register prefixes for constraint namespaces
|
||||
if (!empty($config['annotations']['namespaces'])) {
|
||||
$namespaces = array_merge($namespaces, $config['annotations']['namespaces']);
|
||||
}
|
||||
|
||||
// Register annotation loader
|
||||
$container->setParameter('validator.mapping.loader.annotation_loader.namespaces', $namespaces);
|
||||
|
||||
if ($config['enable_annotations']) {
|
||||
$loaderChain = $container->getDefinition('validator.mapping.loader.loader_chain');
|
||||
$arguments = $loaderChain->getArguments();
|
||||
array_unshift($arguments[0], new Reference('validator.mapping.loader.annotation_loader'));
|
||||
$loaderChain->setArguments($arguments);
|
||||
} else {
|
||||
$container->setParameter('validator.mapping.loader.annotation_loader.namespaces', array());
|
||||
}
|
||||
|
||||
if (isset($config['cache'])) {
|
||||
@ -520,6 +512,31 @@ class FrameworkExtension extends Extension
|
||||
return $files;
|
||||
}
|
||||
|
||||
private function registerAnnotationsConfiguration(array $config, ContainerBuilder $container,$loader)
|
||||
{
|
||||
$loader->load('annotations.xml');
|
||||
|
||||
if ('file' === $config['cache']) {
|
||||
$cacheDir = $container->getParameterBag()->resolveValue($config['file_cache']['dir']);
|
||||
if (!is_dir($cacheDir) && false === @mkdir($cacheDir, 0777, true)) {
|
||||
throw new \RuntimeException(sprintf('Could not create cache directory "%s".', $cacheDir));
|
||||
}
|
||||
|
||||
$container
|
||||
->getDefinition('annotations.cache.file_cache')
|
||||
->replaceArgument(0, $cacheDir)
|
||||
->replaceArgument(1, $config['file_cache']['debug'])
|
||||
;
|
||||
} else if ('none' === $config['cache']) {
|
||||
$container->setAlias('annotation_reader', 'annotations.reader');
|
||||
} else {
|
||||
$container
|
||||
->getDefinition('annotations.cached_reader')
|
||||
->replaceArgument(1, new Reference($config['cache']))
|
||||
;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the base path for the XSD files.
|
||||
*
|
||||
|
@ -9,14 +9,14 @@
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Bundle\FrameworkBundle\Util;
|
||||
namespace Symfony\Bundle\FrameworkBundle\Generator;
|
||||
|
||||
/**
|
||||
* Mustache.
|
||||
* Generator is the base class for all generators.
|
||||
*
|
||||
* @author Fabien Potencier <fabien@symfony.com>
|
||||
*/
|
||||
class Mustache
|
||||
class Generator
|
||||
{
|
||||
/**
|
||||
* Renders a single line. Looks for {{ var }}
|
@ -0,0 +1,29 @@
|
||||
<?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="annotations.cache.file_cache.class">Doctrine\Common\Annotations\Cache\FileCache</parameter>
|
||||
|
||||
<parameter key="annotations.reader.class">Doctrine\Common\Annotations\AnnotationReader</parameter>
|
||||
<parameter key="annotations.cached_reader.class">Doctrine\Common\Annotations\CachedReader</parameter>
|
||||
</parameters>
|
||||
|
||||
<services>
|
||||
<service id="annotations.cache.file_cache" class="%annotations.cache.file_cache.class%" public="false">
|
||||
<argument /><!-- Cache Directory -->
|
||||
<argument /><!-- Debug-Flag -->
|
||||
</service>
|
||||
|
||||
<service id="annotations.reader" class="%annotations.reader.class%" public="false" />
|
||||
|
||||
<service id="annotations.cached_reader" class="%annotations.cached_reader.class%" public="false">
|
||||
<argument type="service" id="annotations.reader" />
|
||||
<argument type="service" id="annotations.cache.file_cache" />
|
||||
</service>
|
||||
|
||||
<service id="annotation_reader" alias="annotations.cached_reader" />
|
||||
</services>
|
||||
</container>
|
@ -129,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>
|
||||
|
@ -18,6 +18,7 @@
|
||||
<xsd:element name="templating" type="templating" minOccurs="0" maxOccurs="1" />
|
||||
<xsd:element name="translator" type="translator" minOccurs="0" maxOccurs="1" />
|
||||
<xsd:element name="validation" type="validation" minOccurs="0" maxOccurs="1" />
|
||||
<xsd:element name="annotations" type="annotations" minOccurs="0" maxOccurs="1" />
|
||||
</xsd:all>
|
||||
|
||||
<xsd:attribute name="cache-warmer" type="cache_warmer" />
|
||||
@ -121,20 +122,21 @@
|
||||
</xsd:complexType>
|
||||
|
||||
<xsd:complexType name="validation">
|
||||
<xsd:sequence>
|
||||
<xsd:element name="namespace" type="validation_namespace" minOccurs="0" maxOccurs="1" />
|
||||
</xsd:sequence>
|
||||
|
||||
<xsd:attribute name="enabled" type="xsd:boolean" />
|
||||
<xsd:attribute name="cache" type="xsd:string" />
|
||||
<xsd:attribute name="annotations" type="xsd:boolean" />
|
||||
<xsd:attribute name="enable-annotations" type="xsd:boolean" />
|
||||
</xsd:complexType>
|
||||
|
||||
<xsd:complexType name="annotations">
|
||||
<xsd:sequence>
|
||||
<xsd:element name="file-cache" type="annotations.file_cache" minOccurs="0" maxOccurs="1" />
|
||||
</xsd:sequence>
|
||||
|
||||
<xsd:complexType name="validation_namespace">
|
||||
<xsd:simpleContent>
|
||||
<xsd:extension base="xsd:string">
|
||||
<xsd:attribute name="prefix" type="xsd:string" />
|
||||
</xsd:extension>
|
||||
</xsd:simpleContent>
|
||||
<xsd:attribute name="cache" type="xsd:string" />
|
||||
</xsd:complexType>
|
||||
|
||||
<xsd:complexType name="annotations.file_cache">
|
||||
<xsd:attribute name="dir" type="xsd:string" />
|
||||
<xsd:attribute name="debug" type="xsd:string" />
|
||||
</xsd:complexType>
|
||||
</xsd:schema>
|
||||
|
@ -15,7 +15,6 @@
|
||||
<parameter key="validator.mapping.loader.xml_files_loader.class">Symfony\Component\Validator\Mapping\Loader\XmlFilesLoader</parameter>
|
||||
<parameter key="validator.mapping.loader.yaml_files_loader.class">Symfony\Component\Validator\Mapping\Loader\YamlFilesLoader</parameter>
|
||||
<parameter key="validator.validator_factory.class">Symfony\Bundle\FrameworkBundle\Validator\ConstraintValidatorFactory</parameter>
|
||||
<parameter key="validator.mapping.loader.annotation_loader.namespaces" type="collection" />
|
||||
<parameter key="validator.mapping.loader.xml_files_loader.mapping_files" type="collection" />
|
||||
<parameter key="validator.mapping.loader.yaml_files_loader.mapping_files" type="collection" />
|
||||
</parameters>
|
||||
@ -51,7 +50,7 @@
|
||||
<service id="validator.mapping.loader.static_method_loader" class="%validator.mapping.loader.static_method_loader.class%" public="false" />
|
||||
|
||||
<service id="validator.mapping.loader.annotation_loader" class="%validator.mapping.loader.annotation_loader.class%" public="false">
|
||||
<argument>%validator.mapping.loader.annotation_loader.namespaces%</argument>
|
||||
<argument type="service" id="annotation_reader" />
|
||||
</service>
|
||||
|
||||
<service id="validator.mapping.loader.xml_files_loader" class="%validator.mapping.loader.xml_files_loader.class%" public="false">
|
||||
|
@ -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]);
|
||||
|
||||
@ -156,7 +156,7 @@ class FormHelper extends Helper
|
||||
$template = $this->templateDir.':'.$template;
|
||||
}
|
||||
*/
|
||||
$template = 'FrameworkBundle:Form:'.$template;
|
||||
$template = 'FrameworkBundle:Form:'.$template;
|
||||
if (!$this->engine->exists($template)) {
|
||||
$template = false;
|
||||
}
|
||||
|
@ -57,4 +57,11 @@ $container->loadFromExtension('framework', array(
|
||||
'enabled' => true,
|
||||
'cache' => 'apc',
|
||||
),
|
||||
'annotations' => array(
|
||||
'cache' => 'file',
|
||||
'file_cache' => array(
|
||||
'dir' => '%kernel.cache_dir%/annotations',
|
||||
'debug' => true,
|
||||
)
|
||||
),
|
||||
));
|
||||
|
@ -4,10 +4,6 @@ $container->loadFromExtension('framework', array(
|
||||
'secret' => 's3cr3t',
|
||||
'validation' => array(
|
||||
'enabled' => true,
|
||||
'annotations' => array(
|
||||
'namespaces' => array(
|
||||
'app' => 'Application\\Validator\\Constraints\\',
|
||||
),
|
||||
),
|
||||
'enable_annotations' => true,
|
||||
),
|
||||
));
|
||||
|
@ -31,5 +31,8 @@
|
||||
</framework:templating>
|
||||
<framework:translator enabled="true" fallback="fr" />
|
||||
<framework:validation enabled="true" cache="apc" />
|
||||
<framework:annotations cache="file">
|
||||
<framework:file-cache dir="%kernel.cache_dir%/annotations" debug="true" />
|
||||
</framework:annotations>
|
||||
</framework:config>
|
||||
</container>
|
||||
|
@ -7,8 +7,6 @@
|
||||
http://symfony.com/schema/dic/symfony http://symfony.com/schema/dic/symfony/symfony-1.0.xsd">
|
||||
|
||||
<framework:config secret="s3cr3t">
|
||||
<framework:validation enabled="true" annotations="true">
|
||||
<framework:namespace prefix="app">Application\Validator\Constraints\</framework:namespace>
|
||||
</framework:validation>
|
||||
<framework:validation enabled="true" enable-annotations="true" />
|
||||
</framework:config>
|
||||
</container>
|
||||
|
@ -43,3 +43,8 @@ framework:
|
||||
validation:
|
||||
enabled: true
|
||||
cache: apc
|
||||
annotations:
|
||||
cache: file
|
||||
file_cache:
|
||||
dir: %kernel.cache_dir%/annotations
|
||||
debug: true
|
||||
|
@ -2,6 +2,4 @@ framework:
|
||||
secret: s3cr3t
|
||||
validation:
|
||||
enabled: true
|
||||
annotations:
|
||||
namespaces:
|
||||
app: Application\Validator\Constraints\
|
||||
enable_annotations: true
|
||||
|
@ -168,15 +168,27 @@ abstract class FrameworkExtensionTest extends TestCase
|
||||
);
|
||||
}
|
||||
|
||||
public function testAnnotations()
|
||||
{
|
||||
$container = $this->createContainerFromFile('full');
|
||||
|
||||
$this->assertEquals($container->getParameter('kernel.cache_dir').'/annotations', $container->getDefinition('annotations.cache.file_cache')->getArgument(0));
|
||||
$this->assertEquals('annotations.cached_reader', (string) $container->getAlias('annotation_reader'));
|
||||
}
|
||||
|
||||
public function testValidationAnnotations()
|
||||
{
|
||||
$container = $this->createContainerFromFile('validation_annotations');
|
||||
|
||||
$this->assertTrue($container->hasDefinition('validator.mapping.loader.annotation_loader'), '->registerValidationConfiguration() defines the annotation loader');
|
||||
|
||||
$argument = $container->getParameter('validator.mapping.loader.annotation_loader.namespaces');
|
||||
$this->assertEquals('Symfony\\Component\\Validator\\Constraints\\', $argument['assert'], '->registerValidationConfiguration() loads the default "assert" prefix');
|
||||
$this->assertEquals('Application\\Validator\\Constraints\\', $argument['app'], '->registerValidationConfiguration() loads custom validation namespaces');
|
||||
$loaders = $container->getDefinition('validator.mapping.loader.loader_chain')->getArgument(0);
|
||||
$found = false;
|
||||
foreach ($loaders as $loader) {
|
||||
if ('validator.mapping.loader.annotation_loader' === (string) $loader) {
|
||||
$found = true;
|
||||
}
|
||||
}
|
||||
$this->assertTrue($found, 'validator.mapping.loader.annotation_loader is added to the loader chain.');
|
||||
}
|
||||
|
||||
public function testValidationPaths()
|
||||
|
@ -9,13 +9,13 @@
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Bundle\FrameworkBundle\Tests\Util;
|
||||
namespace Symfony\Bundle\FrameworkBundle\Tests\Generator;
|
||||
|
||||
use Symfony\Bundle\FrameworkBundle\Tests\TestCase;
|
||||
use Symfony\Bundle\FrameworkBundle\Util\Mustache;
|
||||
use Symfony\Bundle\FrameworkBundle\Generator\Generator;
|
||||
use Symfony\Component\HttpKernel\Util\Filesystem;
|
||||
|
||||
class MustacheTest extends TestCase
|
||||
class GeneratorTest extends TestCase
|
||||
{
|
||||
protected $dir;
|
||||
|
||||
@ -23,7 +23,7 @@ class MustacheTest extends TestCase
|
||||
{
|
||||
$dir = __DIR__.'/fixtures/';
|
||||
|
||||
$this->dir = sys_get_temp_dir().'/mustache';
|
||||
$this->dir = sys_get_temp_dir().'/symfony2gen';
|
||||
$filesystem = new Filesystem();
|
||||
$filesystem->mirror($dir, $this->dir);
|
||||
}
|
||||
@ -39,19 +39,19 @@ class MustacheTest extends TestCase
|
||||
$template = 'Hi {{ you }}, my name is {{ me }}!';
|
||||
$expected = 'Hi {{ you }}, my name is Kris!';
|
||||
|
||||
$this->assertEquals(Mustache::renderString($template, array('me' => 'Kris')), $expected, '::renderString() does not modify unknown parameters');
|
||||
$this->assertEquals(Generator::renderString($template, array('me' => 'Kris')), $expected, '::renderString() does not modify unknown parameters');
|
||||
}
|
||||
|
||||
public function testRenderFile()
|
||||
{
|
||||
Mustache::renderFile($this->dir.'/template.txt', array('me' => 'Fabien'));
|
||||
Generator::renderFile($this->dir.'/template.txt', array('me' => 'Fabien'));
|
||||
|
||||
$this->assertEquals('Hello Fabien', file_get_contents($this->dir.'/template.txt'), '::renderFile() renders a file');
|
||||
}
|
||||
|
||||
public function testRenderDir()
|
||||
{
|
||||
Mustache::renderDir($this->dir, array('me' => 'Fabien'));
|
||||
Generator::renderDir($this->dir, array('me' => 'Fabien'));
|
||||
|
||||
$this->assertEquals('Hello Fabien', file_get_contents($this->dir.'/template.txt'), '::renderDir() renders a directory');
|
||||
$this->assertEquals('Hello Fabien', file_get_contents($this->dir.'/foo/bar.txt'), '::renderDir() renders a directory');
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -43,7 +43,7 @@
|
||||
|
||||
{% 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 %}
|
||||
@ -208,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') %}
|
||||
|
@ -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
|
||||
*/
|
||||
|
@ -32,7 +32,7 @@ class DialogHelper extends Helper
|
||||
public function ask(OutputInterface $output, $question, $default = null)
|
||||
{
|
||||
// @codeCoverageIgnoreStart
|
||||
$output->writeln($question);
|
||||
$output->write($question);
|
||||
|
||||
$ret = trim(fgets(STDIN));
|
||||
|
||||
@ -78,12 +78,13 @@ class DialogHelper extends Helper
|
||||
* @param string|array $question
|
||||
* @param callback $validator A PHP callback
|
||||
* @param integer $attempts Max number of times to ask before giving up (false by default, which means infinite)
|
||||
* @param string $default The default answer if none is given by the user
|
||||
*
|
||||
* @return mixed
|
||||
*
|
||||
* @throws \Exception When any of the validator returns an error
|
||||
*/
|
||||
public function askAndValidate(OutputInterface $output, $question, $validator, $attempts = false)
|
||||
public function askAndValidate(OutputInterface $output, $question, $validator, $attempts = false, $default = null)
|
||||
{
|
||||
// @codeCoverageIgnoreStart
|
||||
$error = null;
|
||||
@ -92,7 +93,7 @@ class DialogHelper extends Helper
|
||||
$output->writeln($this->getHelperSet()->get('formatter')->formatBlock($error->getMessage(), 'error'));
|
||||
}
|
||||
|
||||
$value = $this->ask($output, $question, null);
|
||||
$value = $this->ask($output, $question, $default);
|
||||
|
||||
try {
|
||||
return call_user_func($validator, $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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -106,7 +106,7 @@ class ChoiceType extends AbstractType
|
||||
// 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').'[]');
|
||||
}
|
||||
}
|
||||
|
||||
@ -121,7 +121,6 @@ class ChoiceType extends AbstractType
|
||||
'choice_list' => null,
|
||||
'choices' => array(),
|
||||
'preferred_choices' => array(),
|
||||
'csrf_protection' => false,
|
||||
'empty_data' => $multiple || $expanded ? array() : '',
|
||||
'error_bubbling' => false,
|
||||
);
|
||||
|
@ -22,15 +22,16 @@ 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,
|
||||
));
|
||||
'required' => false,
|
||||
), $options['options']));
|
||||
}
|
||||
|
||||
$listener = new ResizeFormListener(
|
||||
$builder->getFormFactory(),
|
||||
$options['type'],
|
||||
$options['options'],
|
||||
$options['allow_add'],
|
||||
$options['allow_delete']
|
||||
);
|
||||
@ -57,6 +58,7 @@ class CollectionType extends AbstractType
|
||||
'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'];
|
||||
}
|
||||
@ -103,10 +97,8 @@ class DateTimeType extends AbstractType
|
||||
// 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,
|
||||
/* Defaults for date field */
|
||||
'years' => range(date('Y') - 5, date('Y') + 5),
|
||||
@ -131,6 +123,7 @@ class DateTimeType extends AbstractType
|
||||
),
|
||||
'date_widget' => array(
|
||||
null, // inherit default from DateType
|
||||
'single-text',
|
||||
'text',
|
||||
'choice',
|
||||
),
|
||||
|
@ -119,11 +119,9 @@ class DateType extends AbstractType
|
||||
'days' => range(1, 31),
|
||||
'widget' => 'choice',
|
||||
'input' => 'datetime',
|
||||
'pattern' => null,
|
||||
'format' => \IntlDateFormatter::MEDIUM,
|
||||
'data_timezone' => null,
|
||||
'user_timezone' => null,
|
||||
'csrf_protection' => false,
|
||||
// Don't modify \DateTime classes by reference, we treat
|
||||
// them like immutable value objects
|
||||
'by_reference' => false,
|
||||
|
@ -44,6 +44,7 @@ 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())
|
||||
@ -56,36 +57,40 @@ class FieldType extends AbstractType
|
||||
|
||||
public function buildView(FormView $view, FormInterface $form)
|
||||
{
|
||||
$name = $form->getName();
|
||||
|
||||
if ($view->hasParent()) {
|
||||
$parentId = $view->getParent()->get('id');
|
||||
$parentName = $view->getParent()->get('name');
|
||||
$id = sprintf('%s_%s', $parentId, $form->getName());
|
||||
$name = sprintf('%s[%s]', $parentName, $form->getName());
|
||||
$parentFullName = $view->getParent()->get('full_name');
|
||||
$id = sprintf('%s_%s', $parentId, $name);
|
||||
$fullName = sprintf('%s[%s]', $parentFullName, $name);
|
||||
} else {
|
||||
$id = $form->getName();
|
||||
$name = $form->getName();
|
||||
$id = $name;
|
||||
$fullName = $name;
|
||||
}
|
||||
|
||||
$types = array();
|
||||
foreach (array_reverse((array) $form->getTypes()) as $type) {
|
||||
$types[] = $type->getName();
|
||||
}
|
||||
|
||||
$view
|
||||
->set('form', $view)
|
||||
->set('id', $id)
|
||||
->set('name', $name)
|
||||
->set('full_name', $fullName)
|
||||
->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())
|
||||
->set('types', $types)
|
||||
;
|
||||
|
||||
$types = array();
|
||||
foreach (array_reverse((array) $form->getTypes()) as $type) {
|
||||
$types[] = $type->getName();
|
||||
}
|
||||
$view->set('types', $types);
|
||||
}
|
||||
|
||||
public function getDefaultOptions(array $options)
|
||||
@ -97,6 +102,7 @@ class FieldType extends AbstractType
|
||||
'required' => true,
|
||||
'read_only' => false,
|
||||
'max_length' => null,
|
||||
'pattern' => null,
|
||||
'property_path' => null,
|
||||
'by_reference' => true,
|
||||
'error_bubbling' => false,
|
||||
|
@ -52,13 +52,13 @@ class FileType extends AbstractType
|
||||
{
|
||||
$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,
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -29,7 +29,7 @@ class FormType extends AbstractType
|
||||
{
|
||||
$multipart = false;
|
||||
|
||||
foreach ($view as $child) {
|
||||
foreach ($view->getChildren() as $child) {
|
||||
if ($child->get('multipart')) {
|
||||
$multipart = true;
|
||||
break;
|
||||
|
@ -35,7 +35,7 @@ class RadioType extends AbstractType
|
||||
;
|
||||
|
||||
if ($view->hasParent()) {
|
||||
$view->set('name', $view->getParent()->get('name'));
|
||||
$view->set('full_name', $view->getParent()->get('full_name'));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -36,7 +36,6 @@ class RepeatedType extends AbstractType
|
||||
'options' => array(),
|
||||
'first_name' => 'first',
|
||||
'second_name' => 'second',
|
||||
'csrf_protection' => false,
|
||||
'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';
|
||||
}
|
||||
}
|
@ -94,10 +94,8 @@ class TimeType extends AbstractType
|
||||
'widget' => 'choice',
|
||||
'input' => 'datetime',
|
||||
'with_seconds' => false,
|
||||
'pattern' => null,
|
||||
'data_timezone' => null,
|
||||
'user_timezone' => null,
|
||||
'csrf_protection' => false,
|
||||
// Don't modify \DateTime classes by reference, we treat
|
||||
// them like immutable value objects
|
||||
'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(),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -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,11 +22,25 @@ 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'];
|
||||
@ -47,20 +61,31 @@ class CsrfType extends AbstractType
|
||||
;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function getDefaultOptions(array $options)
|
||||
{
|
||||
return array(
|
||||
'csrf_provider' => $this->csrfProvider,
|
||||
'intention' => 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,6 +27,12 @@ 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']) {
|
||||
@ -36,11 +42,19 @@ class FormTypeCsrfExtension extends AbstractTypeExtension
|
||||
$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,
|
||||
'intention' => 'unknown',
|
||||
'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,6 +452,8 @@ class Form implements \IteratorAggregate, FormInterface
|
||||
public function bind($clientData)
|
||||
{
|
||||
if ($this->readOnly) {
|
||||
$this->bound = true;
|
||||
|
||||
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);
|
||||
|
||||
}
|
@ -142,7 +142,7 @@ class PropertyPath implements \IteratorAggregate
|
||||
*/
|
||||
public function isProperty($index)
|
||||
{
|
||||
return !$this->isIndex($index);
|
||||
return !$this->isIndex[$index];
|
||||
}
|
||||
|
||||
/**
|
||||
@ -186,7 +186,25 @@ class PropertyPath implements \IteratorAggregate
|
||||
*/
|
||||
public function getValue($objectOrArray)
|
||||
{
|
||||
return $this->readPropertyPath($objectOrArray, 0);
|
||||
for ($i = 0; $i < $this->length; ++$i) {
|
||||
if (is_object($objectOrArray)) {
|
||||
$value = $this->readProperty($objectOrArray, $i);
|
||||
// arrays need to be treated separately (due to PHP bug?)
|
||||
// http://bugs.php.net/bug.php?id=52133
|
||||
} else if (is_array($objectOrArray)){
|
||||
$property = $this->elements[$i];
|
||||
if (!array_key_exists($property, $objectOrArray)) {
|
||||
$objectOrArray[$property] = $i + 1 < $this->length ? array() : null;
|
||||
}
|
||||
$value =& $objectOrArray[$property];
|
||||
} else {
|
||||
throw new UnexpectedTypeException($objectOrArray, 'object or array');
|
||||
}
|
||||
|
||||
$objectOrArray =& $value;
|
||||
}
|
||||
|
||||
return $value;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -219,78 +237,30 @@ class PropertyPath implements \IteratorAggregate
|
||||
*/
|
||||
public function setValue(&$objectOrArray, $value)
|
||||
{
|
||||
$this->writePropertyPath($objectOrArray, 0, $value);
|
||||
}
|
||||
for ($i = 0, $l = $this->length - 1; $i < $l; ++$i) {
|
||||
|
||||
/**
|
||||
* Recursive implementation of getValue()
|
||||
*
|
||||
* @param object|array $objectOrArray The object or array to traverse
|
||||
* @param integer $currentIndex The current index in the property path
|
||||
* @return mixed The value at the end of the path
|
||||
*/
|
||||
protected function readPropertyPath(&$objectOrArray, $currentIndex)
|
||||
{
|
||||
if (!is_object($objectOrArray) && !is_array($objectOrArray)) {
|
||||
throw new UnexpectedTypeException($objectOrArray, 'object or array');
|
||||
}
|
||||
|
||||
$property = $this->elements[$currentIndex];
|
||||
|
||||
if (is_object($objectOrArray)) {
|
||||
$value = $this->readProperty($objectOrArray, $currentIndex);
|
||||
// arrays need to be treated separately (due to PHP bug?)
|
||||
// http://bugs.php.net/bug.php?id=52133
|
||||
} else {
|
||||
if (!array_key_exists($property, $objectOrArray)) {
|
||||
$objectOrArray[$property] = $currentIndex + 1 < $this->length ? array() : null;
|
||||
}
|
||||
|
||||
$value =& $objectOrArray[$property];
|
||||
}
|
||||
|
||||
++$currentIndex;
|
||||
|
||||
if ($currentIndex < $this->length) {
|
||||
return $this->readPropertyPath($value, $currentIndex);
|
||||
}
|
||||
|
||||
return $value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Recursive implementation of setValue()
|
||||
*
|
||||
* @param object|array $objectOrArray The object or array to traverse
|
||||
* @param integer $currentIndex The current index in the property path
|
||||
* @param mixed $value The value to set at the end of the
|
||||
* property path
|
||||
*/
|
||||
protected function writePropertyPath(&$objectOrArray, $currentIndex, $value)
|
||||
{
|
||||
if (!is_object($objectOrArray) && !is_array($objectOrArray)) {
|
||||
throw new UnexpectedTypeException($objectOrArray, 'object or array');
|
||||
}
|
||||
|
||||
$property = $this->elements[$currentIndex];
|
||||
|
||||
if ($currentIndex + 1 < $this->length) {
|
||||
if (is_object($objectOrArray)) {
|
||||
$nestedObject = $this->readProperty($objectOrArray, $currentIndex);
|
||||
$nestedObject = $this->readProperty($objectOrArray, $i);
|
||||
// arrays need to be treated separately (due to PHP bug?)
|
||||
// http://bugs.php.net/bug.php?id=52133
|
||||
} else {
|
||||
} else if (is_array($objectOrArray)) {
|
||||
$property = $this->elements[$i];
|
||||
if (!array_key_exists($property, $objectOrArray)) {
|
||||
$objectOrArray[$property] = array();
|
||||
}
|
||||
|
||||
$nestedObject =& $objectOrArray[$property];
|
||||
} else {
|
||||
throw new UnexpectedTypeException($objectOrArray, 'object or array');
|
||||
}
|
||||
|
||||
$this->writePropertyPath($nestedObject, $currentIndex + 1, $value);
|
||||
} else {
|
||||
$this->writeProperty($objectOrArray, $currentIndex, $value);
|
||||
$objectOrArray =& $nestedObject;
|
||||
}
|
||||
|
||||
if (!is_object($objectOrArray) && !is_array($objectOrArray)) {
|
||||
throw new UnexpectedTypeException($objectOrArray, 'object or array');
|
||||
}
|
||||
|
||||
$this->writeProperty($objectOrArray, $i, $value);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -311,9 +281,10 @@ class PropertyPath implements \IteratorAggregate
|
||||
|
||||
return $object[$property];
|
||||
} else {
|
||||
$camelProp = $this->camelize($property);
|
||||
$reflClass = new \ReflectionClass($object);
|
||||
$getter = 'get'.$this->camelize($property);
|
||||
$isser = 'is'.$this->camelize($property);
|
||||
$getter = 'get'.$camelProp;
|
||||
$isser = 'is'.$camelProp;
|
||||
|
||||
if ($reflClass->hasMethod($getter)) {
|
||||
if (!$reflClass->getMethod($getter)->isPublic()) {
|
||||
|
@ -61,6 +61,39 @@ class Cookie
|
||||
$this->httpOnly = (Boolean) $httpOnly;
|
||||
}
|
||||
|
||||
public function __toString()
|
||||
{
|
||||
$str = urlencode($this->getName()).'=';
|
||||
|
||||
if ('' === (string) $this->getValue()) {
|
||||
$str .= 'deleted; expires='.gmdate("D, d-M-Y H:i:s T", time() - 31536001);
|
||||
} else {
|
||||
$str .= urlencode($this->getValue());
|
||||
|
||||
if ($this->getExpiresTime() !== 0) {
|
||||
$str .= '; expires='.gmdate("D, d-M-Y H:i:s T", $this->getExpiresTime());
|
||||
}
|
||||
}
|
||||
|
||||
if (null !== $this->getPath()) {
|
||||
$str .= '; path='.$this->getPath();
|
||||
}
|
||||
|
||||
if (null !== $this->getDomain()) {
|
||||
$str .= '; domain='.$this->getDomain();
|
||||
}
|
||||
|
||||
if (true === $this->isSecure()) {
|
||||
$str .= '; secure';
|
||||
}
|
||||
|
||||
if (true === $this->isHttpOnly()) {
|
||||
$str .= '; httponly';
|
||||
}
|
||||
|
||||
return $str;
|
||||
}
|
||||
|
||||
public function getName()
|
||||
{
|
||||
return $this->name;
|
||||
|
@ -602,7 +602,7 @@ class Request
|
||||
if (null === $this->method) {
|
||||
$this->method = strtoupper($this->server->get('REQUEST_METHOD', 'GET'));
|
||||
if ('POST' === $this->method) {
|
||||
$this->method = strtoupper($this->request->get('_method', 'POST'));
|
||||
$this->method = strtoupper($this->server->get('X-HTTP-METHOD-OVERRIDE', $this->request->get('_method', 'POST')));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -33,6 +33,19 @@ class ResponseHeaderBag extends HeaderBag
|
||||
$this->set('cache-control', '');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function __toString()
|
||||
{
|
||||
$cookies = '';
|
||||
foreach ($this->cookies as $cookie) {
|
||||
$cookies .= 'Set-Cookie: '.$cookie."\r\n";
|
||||
}
|
||||
|
||||
return parent::__toString().$cookies;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
|
@ -36,7 +36,7 @@ class Session implements \Serializable
|
||||
{
|
||||
$this->storage = $storage;
|
||||
$this->defaultLocale = $defaultLocale;
|
||||
$this->attributes = array('_flash' => array(), '_locale' => $this->getDefaultLocale());
|
||||
$this->attributes = array('_flash' => array(), '_locale' => $this->defaultLocale);
|
||||
$this->started = false;
|
||||
}
|
||||
|
||||
@ -58,7 +58,7 @@ class Session implements \Serializable
|
||||
}
|
||||
|
||||
if (!isset($this->attributes['_locale'])) {
|
||||
$this->attributes['_locale'] = $this->getDefaultLocale();
|
||||
$this->attributes['_locale'] = $this->defaultLocale;
|
||||
}
|
||||
|
||||
// flag current flash messages to be removed at shutdown
|
||||
@ -194,6 +194,10 @@ class Session implements \Serializable
|
||||
*/
|
||||
public function getLocale()
|
||||
{
|
||||
if (!isset($this->attributes['_locale'])) {
|
||||
$this->attributes['_locale'] = $this->defaultLocale;
|
||||
}
|
||||
|
||||
return $this->attributes['_locale'];
|
||||
}
|
||||
|
||||
@ -228,7 +232,7 @@ class Session implements \Serializable
|
||||
|
||||
public function getFlash($name, $default = null)
|
||||
{
|
||||
return array_key_exists($name, $this->attributes['_flash']) ? $this->attributes['_flash'][$name] : $default;
|
||||
return array_key_exists($name, $this->getFlashes()) ? $this->attributes['_flash'][$name] : $default;
|
||||
}
|
||||
|
||||
public function setFlash($name, $value)
|
||||
@ -283,7 +287,9 @@ class Session implements \Serializable
|
||||
|
||||
public function __destruct()
|
||||
{
|
||||
$this->save();
|
||||
if (true === $this->started) {
|
||||
$this->save();
|
||||
}
|
||||
}
|
||||
|
||||
public function serialize()
|
||||
@ -297,9 +303,4 @@ class Session implements \Serializable
|
||||
$this->attributes = array();
|
||||
$this->started = false;
|
||||
}
|
||||
|
||||
private function getDefaultLocale()
|
||||
{
|
||||
return $this->defaultLocale;
|
||||
}
|
||||
}
|
||||
|
45
src/Symfony/Component/Locale/Resources/stubs/functions.php
Normal file
45
src/Symfony/Component/Locale/Resources/stubs/functions.php
Normal file
@ -0,0 +1,45 @@
|
||||
<?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.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Stub implementation for the intl_is_failure function of the intl extension
|
||||
*
|
||||
* @author Bernhard Schussek <bernhard.schussek@symfony.com>
|
||||
* @param integer $errorCode The error code returned by intl_get_error_code()
|
||||
* @return Boolean Whether the error code indicates an error
|
||||
* @see Symfony\Component\Locale\Stub\StubIntl::isFailure
|
||||
*/
|
||||
function intl_is_failure($errorCode) {
|
||||
return \Symfony\Component\Locale\Stub\StubIntl::isFailure($errorCode);
|
||||
}
|
||||
|
||||
/**
|
||||
* Stub implementation for the intl_get_error_code function of the intl extension
|
||||
*
|
||||
* @author Bernhard Schussek <bernhard.schussek@symfony.com>
|
||||
* @return Boolean The error code of the last intl function call or
|
||||
* StubIntl::U_ZERO_ERROR if no error occurred
|
||||
* @see Symfony\Component\Locale\Stub\StubIntl::getErrorCode
|
||||
*/
|
||||
function intl_get_error_code() {
|
||||
return \Symfony\Component\Locale\Stub\StubIntl::getErrorCode();
|
||||
}
|
||||
/**
|
||||
* Stub implementation for the intl_get_error_code function of the intl extension
|
||||
*
|
||||
* @author Bernhard Schussek <bernhard.schussek@symfony.com>
|
||||
* @return Boolean The error message of the last intl function call or
|
||||
* "U_ZERO_ERROR" if no error occurred
|
||||
* @see Symfony\Component\Locale\Stub\StubIntl::getErrorMessage
|
||||
*/
|
||||
function intl_get_error_message() {
|
||||
return \Symfony\Component\Locale\Stub\StubIntl::getErrorMessage();
|
||||
}
|
@ -12,6 +12,7 @@
|
||||
namespace Symfony\Component\Locale\Stub\DateFormat;
|
||||
|
||||
use Symfony\Component\Locale\Exception\NotImplementedException;
|
||||
use Symfony\Component\Locale\Stub\StubIntl;
|
||||
use Symfony\Component\Locale\Stub\DateFormat\MonthTransformer;
|
||||
|
||||
/**
|
||||
@ -275,6 +276,8 @@ class FullTransformer
|
||||
|
||||
// If month is false, return immediately (intl behavior)
|
||||
if (false === $month) {
|
||||
StubIntl::setErrorCode(StubIntl::U_PARSE_ERROR);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
112
src/Symfony/Component/Locale/Stub/StubIntl.php
Normal file
112
src/Symfony/Component/Locale/Stub/StubIntl.php
Normal file
@ -0,0 +1,112 @@
|
||||
<?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\Locale\Stub;
|
||||
|
||||
/**
|
||||
* Provides fake static versions of the global functions in the intl extension
|
||||
*
|
||||
* @author Bernhard Schussek <bernhard.schussek@symfony.com>
|
||||
*/
|
||||
abstract class StubIntl
|
||||
{
|
||||
/**
|
||||
* Indicates that no error occurred
|
||||
* @var integer
|
||||
*/
|
||||
const U_ZERO_ERROR = 0;
|
||||
|
||||
/**
|
||||
* Indicates that an invalid argument was passed
|
||||
* @var integer
|
||||
*/
|
||||
const U_ILLEGAL_ARGUMENT_ERROR = 1;
|
||||
|
||||
/**
|
||||
* Indicates that the parse() operation failed
|
||||
* @var integer
|
||||
*/
|
||||
const U_PARSE_ERROR = 9;
|
||||
|
||||
/**
|
||||
* All known error codes
|
||||
* @var array
|
||||
*/
|
||||
private static $errorCodes = array(
|
||||
self::U_ZERO_ERROR,
|
||||
self::U_ILLEGAL_ARGUMENT_ERROR,
|
||||
self::U_PARSE_ERROR,
|
||||
);
|
||||
|
||||
/**
|
||||
* The error messages of all known error codes
|
||||
* @var array
|
||||
*/
|
||||
private static $errorMessages = array(
|
||||
self::U_ZERO_ERROR => 'U_ZERO_ERROR',
|
||||
self::U_ILLEGAL_ARGUMENT_ERROR => 'datefmt_format: takes either an array or an integer timestamp value : U_ILLEGAL_ARGUMENT_ERROR',
|
||||
self::U_PARSE_ERROR => 'Date parsing failed: U_PARSE_ERROR',
|
||||
);
|
||||
|
||||
/**
|
||||
* The error code of the last operation
|
||||
* @var integer
|
||||
*/
|
||||
private static $errorCode = self::U_ZERO_ERROR;
|
||||
|
||||
/**
|
||||
* Returns whether the error code indicates a failure
|
||||
*
|
||||
* @param integer $errorCode The error code returned by StubIntl::getErrorCode()
|
||||
* @return Boolean
|
||||
*/
|
||||
public static function isFailure($errorCode) {
|
||||
return in_array($errorCode, static::$errorCodes, true)
|
||||
&& $errorCode !== self::U_ZERO_ERROR;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the error code of the last operation
|
||||
*
|
||||
* Returns StubIntl::U_ZERO_ERROR if no error occurred.
|
||||
*
|
||||
* @return integer
|
||||
*/
|
||||
public static function getErrorCode() {
|
||||
return static::$errorCode;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the error message of the last operation
|
||||
*
|
||||
* Returns "U_ZERO_ERROR" if no error occurred.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function getErrorMessage() {
|
||||
return static::$errorMessages[static::$errorCode];
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the current error code
|
||||
*
|
||||
* @param integer $code One of the error constants in this class
|
||||
* @throws \InvalidArgumentException If the code is not one of the error
|
||||
* constants in this class
|
||||
*/
|
||||
public static function setErrorCode($code) {
|
||||
if (!isset(static::$errorMessages[$code])) {
|
||||
throw new \InvalidArgumentException(sprintf('No such error code: "%s"', $code));
|
||||
}
|
||||
|
||||
static::$errorCode = $code;
|
||||
}
|
||||
}
|
@ -160,10 +160,18 @@ class StubIntlDateFormatter
|
||||
*/
|
||||
public function format($timestamp)
|
||||
{
|
||||
if (!is_int($timestamp)) {
|
||||
// intl allows timestamps to be passed as arrays - we don't
|
||||
if (is_array($timestamp)) {
|
||||
throw new MethodArgumentValueNotImplementedException(__METHOD__, 'timestamp', $timestamp, 'Only integer unix timestamps are supported');
|
||||
}
|
||||
|
||||
if (!is_int($timestamp)) {
|
||||
// behave like the intl extension
|
||||
StubIntl::setErrorCode(StubIntl::U_ILLEGAL_ARGUMENT_ERROR);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
$transformer = new FullTransformer($this->getPattern(), $this->getTimeZoneId());
|
||||
$formatted = $transformer->format($this->createDateTime($timestamp));
|
||||
|
||||
@ -311,6 +319,8 @@ class StubIntlDateFormatter
|
||||
throw new MethodArgumentNotImplementedException(__METHOD__, 'position');
|
||||
}
|
||||
|
||||
StubIntl::setErrorCode(StubIntl::U_ZERO_ERROR);
|
||||
|
||||
$dateTime = $this->createDateTime(0);
|
||||
$transformer = new FullTransformer($this->getPattern(), $this->getTimeZoneId());
|
||||
return $transformer->parse($dateTime, $value);
|
||||
|
@ -46,7 +46,7 @@ class Process
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
public function __construct($commandline, $cwd = null, array $env = array(), $stdin = null, $timeout = 60, array $options = array())
|
||||
public function __construct($commandline, $cwd = null, array $env = null, $stdin = null, $timeout = 60, array $options = array())
|
||||
{
|
||||
if (!function_exists('proc_open')) {
|
||||
throw new \RuntimeException('The Process class relies on proc_open, which is not available on your PHP installation.');
|
||||
@ -54,13 +54,17 @@ class Process
|
||||
|
||||
$this->commandline = $commandline;
|
||||
$this->cwd = null === $cwd ? getcwd() : $cwd;
|
||||
$this->env = array();
|
||||
foreach ($env as $key => $value) {
|
||||
$this->env[(binary) $key] = (binary) $value;
|
||||
if (null !== $env) {
|
||||
$this->env = array();
|
||||
foreach ($env as $key => $value) {
|
||||
$this->env[(binary) $key] = (binary) $value;
|
||||
}
|
||||
} else {
|
||||
$this->env = null;
|
||||
}
|
||||
$this->stdin = $stdin;
|
||||
$this->timeout = $timeout;
|
||||
$this->options = array_merge(array('suppress_errors' => true, 'binary_pipes' => true, 'bypass_shell' => true), $options);
|
||||
$this->options = array_merge(array('suppress_errors' => true, 'binary_pipes' => true, 'bypass_shell' => false), $options);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1,46 +0,0 @@
|
||||
<?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\Routing\Annotation;
|
||||
|
||||
/**
|
||||
* Annotation class for @Routes().
|
||||
*
|
||||
* @author Fabien Potencier <fabien@symfony.com>
|
||||
*/
|
||||
class Routes
|
||||
{
|
||||
private $routes;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param array $data An array of key/value parameters.
|
||||
*/
|
||||
public function __construct(array $data)
|
||||
{
|
||||
if (!isset($data['value']) || !is_array($data['value'])) {
|
||||
throw new \LogicException('A @Routes annotation must have an array of @Route annotation as argument.');
|
||||
}
|
||||
|
||||
$this->routes = $data['value'];
|
||||
}
|
||||
|
||||
public function setRoutes($routes)
|
||||
{
|
||||
$this->routes = $routes;
|
||||
}
|
||||
|
||||
public function getRoutes()
|
||||
{
|
||||
return $this->routes;
|
||||
}
|
||||
}
|
@ -11,7 +11,7 @@
|
||||
|
||||
namespace Symfony\Component\Routing\Loader;
|
||||
|
||||
use Doctrine\Common\Annotations\AnnotationReader;
|
||||
use Doctrine\Common\Annotations\Reader;
|
||||
use Symfony\Component\Routing\Annotation\Route as RouteAnnotation;
|
||||
use Symfony\Component\Config\Resource\FileResource;
|
||||
use Symfony\Component\Routing\Route;
|
||||
@ -59,14 +59,13 @@ abstract class AnnotationClassLoader implements LoaderInterface
|
||||
{
|
||||
protected $reader;
|
||||
protected $routeAnnotationClass = 'Symfony\\Component\\Routing\\Annotation\\Route';
|
||||
protected $routesAnnotationClass = 'Symfony\\Component\\Routing\\Annotation\\Routes';
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param AnnotationReader $reader
|
||||
* @param Reader $reader
|
||||
*/
|
||||
public function __construct(AnnotationReader $reader)
|
||||
public function __construct(Reader $reader)
|
||||
{
|
||||
$this->reader = $reader;
|
||||
}
|
||||
@ -81,16 +80,6 @@ abstract class AnnotationClassLoader implements LoaderInterface
|
||||
$this->routeAnnotationClass = $class;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the annotation class to read routes properties from.
|
||||
*
|
||||
* @param string $class A fully-qualified class name
|
||||
*/
|
||||
public function setRoutesAnnotationClass($class)
|
||||
{
|
||||
$this->routesAnnotationClass = $class;
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads from annotations from a class.
|
||||
*
|
||||
@ -137,12 +126,10 @@ abstract class AnnotationClassLoader implements LoaderInterface
|
||||
$collection->addResource(new FileResource($class->getFileName()));
|
||||
|
||||
foreach ($class->getMethods() as $method) {
|
||||
if ($annots = $this->reader->getMethodAnnotation($method, $this->routesAnnotationClass)) {
|
||||
foreach ($annots->getRoutes() as $annot) {
|
||||
foreach ($this->reader->getMethodAnnotations($method) as $annot) {
|
||||
if ($annot instanceof $this->routeAnnotationClass) {
|
||||
$this->addRoute($collection, $annot, $globals, $class, $method);
|
||||
}
|
||||
} elseif ($annot = $this->reader->getMethodAnnotation($method, $this->routeAnnotationClass)) {
|
||||
$this->addRoute($collection, $annot, $globals, $class, $method);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -65,10 +65,8 @@ class YamlFileLoader extends FileLoader
|
||||
$prefix = isset($config['prefix']) ? $config['prefix'] : null;
|
||||
$this->setCurrentDir(dirname($path));
|
||||
$collection->addCollection($this->import($config['resource'], $type, false, $file), $prefix);
|
||||
} elseif (isset($config['pattern'])) {
|
||||
$this->parseRoute($collection, $name, $config, $path);
|
||||
} else {
|
||||
throw new \InvalidArgumentException(sprintf('Unable to parse the "%s" route.', $name));
|
||||
$this->parseRoute($collection, $name, $config, $path);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -156,7 +156,7 @@ class Serializer implements SerializerInterface
|
||||
return $this->denormalizerCache[$class][$format]->denormalize($data, $class, $format);
|
||||
}
|
||||
foreach ($this->normalizers as $normalizer) {
|
||||
if ($normalizer->supportsDenormalization($class, $format)) {
|
||||
if ($normalizer->supportsDenormalization($data, $class, $format)) {
|
||||
$this->denormalizerCache[$class][$format] = $normalizer;
|
||||
return $normalizer->denormalize($data, $class, $format);
|
||||
}
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user