Merge branch '3.3' into 3.4
* 3.3: [Security] added more tests [Security] fixed default target path when referer contains a query string [Security] simplified tests [Security] refactored tests [WebProfilerBundle][TwigBundle] Fix infinite js loop on exception pages [FrameworkBundle] fix ValidatorCacheWarmer: use serializing ArrayAdapter Change "this" to "that" to avoid confusion [VarDumper] Move locale sniffing to dump() time [VarDumper] Use "C" locale when using "comma" flags [Config] Make ClassExistenceResource throw on invalid parents
This commit is contained in:
commit
8c028bd956
@ -0,0 +1,92 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Bundle\FrameworkBundle\CacheWarmer;
|
||||
|
||||
use Psr\Cache\CacheItemPoolInterface;
|
||||
use Symfony\Component\Cache\Adapter\AdapterInterface;
|
||||
use Symfony\Component\Cache\Adapter\ArrayAdapter;
|
||||
use Symfony\Component\Cache\Adapter\PhpArrayAdapter;
|
||||
use Symfony\Component\Cache\Adapter\ProxyAdapter;
|
||||
use Symfony\Component\HttpKernel\CacheWarmer\CacheWarmerInterface;
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
abstract class AbstractPhpFileCacheWarmer implements CacheWarmerInterface
|
||||
{
|
||||
private $phpArrayFile;
|
||||
private $fallbackPool;
|
||||
|
||||
/**
|
||||
* @param string $phpArrayFile The PHP file where metadata are cached
|
||||
* @param CacheItemPoolInterface $fallbackPool The pool where runtime-discovered metadata are cached
|
||||
*/
|
||||
public function __construct($phpArrayFile, CacheItemPoolInterface $fallbackPool)
|
||||
{
|
||||
$this->phpArrayFile = $phpArrayFile;
|
||||
if (!$fallbackPool instanceof AdapterInterface) {
|
||||
$fallbackPool = new ProxyAdapter($fallbackPool);
|
||||
}
|
||||
$this->fallbackPool = $fallbackPool;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function isOptional()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function warmUp($cacheDir)
|
||||
{
|
||||
$arrayAdapter = new ArrayAdapter();
|
||||
|
||||
spl_autoload_register(array(PhpArrayAdapter::class, 'throwOnRequiredClass'));
|
||||
try {
|
||||
if (!$this->doWarmUp($cacheDir, $arrayAdapter)) {
|
||||
return;
|
||||
}
|
||||
} finally {
|
||||
spl_autoload_unregister(array(PhpArrayAdapter::class, 'throwOnRequiredClass'));
|
||||
}
|
||||
|
||||
// the ArrayAdapter stores the values serialized
|
||||
// to avoid mutation of the data after it was written to the cache
|
||||
// so here we un-serialize the values first
|
||||
$values = array_map(function ($val) { return null !== $val ? unserialize($val) : null; }, $arrayAdapter->getValues());
|
||||
|
||||
$this->warmUpPhpArrayAdapter(new PhpArrayAdapter($this->phpArrayFile, $this->fallbackPool), $values);
|
||||
|
||||
foreach ($values as $k => $v) {
|
||||
$item = $this->fallbackPool->getItem($k);
|
||||
$this->fallbackPool->saveDeferred($item->set($v));
|
||||
}
|
||||
$this->fallbackPool->commit();
|
||||
}
|
||||
|
||||
protected function warmUpPhpArrayAdapter(PhpArrayAdapter $phpArrayAdapter, array $values)
|
||||
{
|
||||
$phpArrayAdapter->warmUp($values);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $cacheDir
|
||||
* @param ArrayAdapter $arrayAdapter
|
||||
*
|
||||
* @return bool false if there is nothing to warm-up
|
||||
*/
|
||||
abstract protected function doWarmUp($cacheDir, ArrayAdapter $arrayAdapter);
|
||||
}
|
@ -15,12 +15,8 @@ use Doctrine\Common\Annotations\AnnotationException;
|
||||
use Doctrine\Common\Annotations\CachedReader;
|
||||
use Doctrine\Common\Annotations\Reader;
|
||||
use Psr\Cache\CacheItemPoolInterface;
|
||||
use Symfony\Component\Cache\Adapter\AdapterInterface;
|
||||
use Symfony\Component\Cache\Adapter\ArrayAdapter;
|
||||
use Symfony\Component\Cache\Adapter\PhpArrayAdapter;
|
||||
use Symfony\Component\Cache\Adapter\ProxyAdapter;
|
||||
use Symfony\Component\Cache\DoctrineProvider;
|
||||
use Symfony\Component\HttpKernel\CacheWarmer\CacheWarmerInterface;
|
||||
|
||||
/**
|
||||
* Warms up annotation caches for classes found in composer's autoload class map
|
||||
@ -28,11 +24,9 @@ use Symfony\Component\HttpKernel\CacheWarmer\CacheWarmerInterface;
|
||||
*
|
||||
* @author Titouan Galopin <galopintitouan@gmail.com>
|
||||
*/
|
||||
class AnnotationsCacheWarmer implements CacheWarmerInterface
|
||||
class AnnotationsCacheWarmer extends AbstractPhpFileCacheWarmer
|
||||
{
|
||||
private $annotationReader;
|
||||
private $phpArrayFile;
|
||||
private $fallbackPool;
|
||||
|
||||
/**
|
||||
* @param Reader $annotationReader
|
||||
@ -41,70 +35,41 @@ class AnnotationsCacheWarmer implements CacheWarmerInterface
|
||||
*/
|
||||
public function __construct(Reader $annotationReader, $phpArrayFile, CacheItemPoolInterface $fallbackPool)
|
||||
{
|
||||
parent::__construct($phpArrayFile, $fallbackPool);
|
||||
$this->annotationReader = $annotationReader;
|
||||
$this->phpArrayFile = $phpArrayFile;
|
||||
if (!$fallbackPool instanceof AdapterInterface) {
|
||||
$fallbackPool = new ProxyAdapter($fallbackPool);
|
||||
}
|
||||
$this->fallbackPool = $fallbackPool;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function warmUp($cacheDir)
|
||||
protected function doWarmUp($cacheDir, ArrayAdapter $arrayAdapter)
|
||||
{
|
||||
$adapter = new PhpArrayAdapter($this->phpArrayFile, $this->fallbackPool);
|
||||
$annotatedClassPatterns = $cacheDir.'/annotations.map';
|
||||
|
||||
if (!is_file($annotatedClassPatterns)) {
|
||||
$adapter->warmUp(array());
|
||||
|
||||
return;
|
||||
return true;
|
||||
}
|
||||
|
||||
$annotatedClasses = include $annotatedClassPatterns;
|
||||
$reader = new CachedReader($this->annotationReader, new DoctrineProvider($arrayAdapter));
|
||||
|
||||
$arrayPool = new ArrayAdapter(0, false);
|
||||
$reader = new CachedReader($this->annotationReader, new DoctrineProvider($arrayPool));
|
||||
|
||||
spl_autoload_register(array($adapter, 'throwOnRequiredClass'));
|
||||
try {
|
||||
foreach ($annotatedClasses as $class) {
|
||||
try {
|
||||
$this->readAllComponents($reader, $class);
|
||||
} catch (\ReflectionException $e) {
|
||||
// ignore failing reflection
|
||||
} catch (AnnotationException $e) {
|
||||
/*
|
||||
* Ignore any AnnotationException to not break the cache warming process if an Annotation is badly
|
||||
* configured or could not be found / read / etc.
|
||||
*
|
||||
* In particular cases, an Annotation in your code can be used and defined only for a specific
|
||||
* environment but is always added to the annotations.map file by some Symfony default behaviors,
|
||||
* and you always end up with a not found Annotation.
|
||||
*/
|
||||
}
|
||||
foreach ($annotatedClasses as $class) {
|
||||
try {
|
||||
$this->readAllComponents($reader, $class);
|
||||
} catch (\ReflectionException $e) {
|
||||
// ignore failing reflection
|
||||
} catch (AnnotationException $e) {
|
||||
/*
|
||||
* Ignore any AnnotationException to not break the cache warming process if an Annotation is badly
|
||||
* configured or could not be found / read / etc.
|
||||
*
|
||||
* In particular cases, an Annotation in your code can be used and defined only for a specific
|
||||
* environment but is always added to the annotations.map file by some Symfony default behaviors,
|
||||
* and you always end up with a not found Annotation.
|
||||
*/
|
||||
}
|
||||
} finally {
|
||||
spl_autoload_unregister(array($adapter, 'throwOnRequiredClass'));
|
||||
}
|
||||
|
||||
$values = $arrayPool->getValues();
|
||||
$adapter->warmUp($values);
|
||||
|
||||
foreach ($values as $k => $v) {
|
||||
$item = $this->fallbackPool->getItem($k);
|
||||
$this->fallbackPool->saveDeferred($item->set($v));
|
||||
}
|
||||
$this->fallbackPool->commit();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function isOptional()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -13,11 +13,7 @@ namespace Symfony\Bundle\FrameworkBundle\CacheWarmer;
|
||||
|
||||
use Doctrine\Common\Annotations\AnnotationException;
|
||||
use Psr\Cache\CacheItemPoolInterface;
|
||||
use Symfony\Component\Cache\Adapter\AdapterInterface;
|
||||
use Symfony\Component\Cache\Adapter\ArrayAdapter;
|
||||
use Symfony\Component\Cache\Adapter\PhpArrayAdapter;
|
||||
use Symfony\Component\Cache\Adapter\ProxyAdapter;
|
||||
use Symfony\Component\HttpKernel\CacheWarmer\CacheWarmerInterface;
|
||||
use Symfony\Component\Serializer\Mapping\Factory\CacheClassMetadataFactory;
|
||||
use Symfony\Component\Serializer\Mapping\Factory\ClassMetadataFactory;
|
||||
use Symfony\Component\Serializer\Mapping\Loader\LoaderChain;
|
||||
@ -30,11 +26,9 @@ use Symfony\Component\Serializer\Mapping\Loader\YamlFileLoader;
|
||||
*
|
||||
* @author Titouan Galopin <galopintitouan@gmail.com>
|
||||
*/
|
||||
class SerializerCacheWarmer implements CacheWarmerInterface
|
||||
class SerializerCacheWarmer extends AbstractPhpFileCacheWarmer
|
||||
{
|
||||
private $loaders;
|
||||
private $phpArrayFile;
|
||||
private $fallbackPool;
|
||||
|
||||
/**
|
||||
* @param LoaderInterface[] $loaders The serializer metadata loaders
|
||||
@ -43,60 +37,33 @@ class SerializerCacheWarmer implements CacheWarmerInterface
|
||||
*/
|
||||
public function __construct(array $loaders, $phpArrayFile, CacheItemPoolInterface $fallbackPool)
|
||||
{
|
||||
parent::__construct($phpArrayFile, $fallbackPool);
|
||||
$this->loaders = $loaders;
|
||||
$this->phpArrayFile = $phpArrayFile;
|
||||
if (!$fallbackPool instanceof AdapterInterface) {
|
||||
$fallbackPool = new ProxyAdapter($fallbackPool);
|
||||
}
|
||||
$this->fallbackPool = $fallbackPool;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function warmUp($cacheDir)
|
||||
protected function doWarmUp($cacheDir, ArrayAdapter $arrayAdapter)
|
||||
{
|
||||
if (!class_exists(CacheClassMetadataFactory::class) || !method_exists(XmlFileLoader::class, 'getMappedClasses') || !method_exists(YamlFileLoader::class, 'getMappedClasses')) {
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
|
||||
$adapter = new PhpArrayAdapter($this->phpArrayFile, $this->fallbackPool);
|
||||
$arrayPool = new ArrayAdapter(0, false);
|
||||
$metadataFactory = new CacheClassMetadataFactory(new ClassMetadataFactory(new LoaderChain($this->loaders)), $arrayAdapter);
|
||||
|
||||
$metadataFactory = new CacheClassMetadataFactory(new ClassMetadataFactory(new LoaderChain($this->loaders)), $arrayPool);
|
||||
|
||||
spl_autoload_register(array($adapter, 'throwOnRequiredClass'));
|
||||
try {
|
||||
foreach ($this->extractSupportedLoaders($this->loaders) as $loader) {
|
||||
foreach ($loader->getMappedClasses() as $mappedClass) {
|
||||
try {
|
||||
$metadataFactory->getMetadataFor($mappedClass);
|
||||
} catch (\ReflectionException $e) {
|
||||
// ignore failing reflection
|
||||
} catch (AnnotationException $e) {
|
||||
// ignore failing annotations
|
||||
}
|
||||
foreach ($this->extractSupportedLoaders($this->loaders) as $loader) {
|
||||
foreach ($loader->getMappedClasses() as $mappedClass) {
|
||||
try {
|
||||
$metadataFactory->getMetadataFor($mappedClass);
|
||||
} catch (\ReflectionException $e) {
|
||||
// ignore failing reflection
|
||||
} catch (AnnotationException $e) {
|
||||
// ignore failing annotations
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
spl_autoload_unregister(array($adapter, 'throwOnRequiredClass'));
|
||||
}
|
||||
|
||||
$values = $arrayPool->getValues();
|
||||
$adapter->warmUp($values);
|
||||
|
||||
foreach ($values as $k => $v) {
|
||||
$item = $this->fallbackPool->getItem($k);
|
||||
$this->fallbackPool->saveDeferred($item->set($v));
|
||||
}
|
||||
$this->fallbackPool->commit();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function isOptional()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -13,11 +13,8 @@ namespace Symfony\Bundle\FrameworkBundle\CacheWarmer;
|
||||
|
||||
use Doctrine\Common\Annotations\AnnotationException;
|
||||
use Psr\Cache\CacheItemPoolInterface;
|
||||
use Symfony\Component\Cache\Adapter\AdapterInterface;
|
||||
use Symfony\Component\Cache\Adapter\ArrayAdapter;
|
||||
use Symfony\Component\Cache\Adapter\PhpArrayAdapter;
|
||||
use Symfony\Component\Cache\Adapter\ProxyAdapter;
|
||||
use Symfony\Component\HttpKernel\CacheWarmer\CacheWarmerInterface;
|
||||
use Symfony\Component\Validator\Mapping\Cache\Psr6Cache;
|
||||
use Symfony\Component\Validator\Mapping\Factory\LazyLoadingMetadataFactory;
|
||||
use Symfony\Component\Validator\Mapping\Loader\LoaderChain;
|
||||
@ -31,11 +28,9 @@ use Symfony\Component\Validator\ValidatorBuilderInterface;
|
||||
*
|
||||
* @author Titouan Galopin <galopintitouan@gmail.com>
|
||||
*/
|
||||
class ValidatorCacheWarmer implements CacheWarmerInterface
|
||||
class ValidatorCacheWarmer extends AbstractPhpFileCacheWarmer
|
||||
{
|
||||
private $validatorBuilder;
|
||||
private $phpArrayFile;
|
||||
private $fallbackPool;
|
||||
|
||||
/**
|
||||
* @param ValidatorBuilderInterface $validatorBuilder
|
||||
@ -44,64 +39,43 @@ class ValidatorCacheWarmer implements CacheWarmerInterface
|
||||
*/
|
||||
public function __construct(ValidatorBuilderInterface $validatorBuilder, $phpArrayFile, CacheItemPoolInterface $fallbackPool)
|
||||
{
|
||||
parent::__construct($phpArrayFile, $fallbackPool);
|
||||
$this->validatorBuilder = $validatorBuilder;
|
||||
$this->phpArrayFile = $phpArrayFile;
|
||||
if (!$fallbackPool instanceof AdapterInterface) {
|
||||
$fallbackPool = new ProxyAdapter($fallbackPool);
|
||||
}
|
||||
$this->fallbackPool = $fallbackPool;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function warmUp($cacheDir)
|
||||
protected function doWarmUp($cacheDir, ArrayAdapter $arrayAdapter)
|
||||
{
|
||||
if (!method_exists($this->validatorBuilder, 'getLoaders')) {
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
|
||||
$adapter = new PhpArrayAdapter($this->phpArrayFile, $this->fallbackPool);
|
||||
$arrayPool = new ArrayAdapter(0, false);
|
||||
|
||||
$loaders = $this->validatorBuilder->getLoaders();
|
||||
$metadataFactory = new LazyLoadingMetadataFactory(new LoaderChain($loaders), new Psr6Cache($arrayPool));
|
||||
$metadataFactory = new LazyLoadingMetadataFactory(new LoaderChain($loaders), new Psr6Cache($arrayAdapter));
|
||||
|
||||
spl_autoload_register(array($adapter, 'throwOnRequiredClass'));
|
||||
try {
|
||||
foreach ($this->extractSupportedLoaders($loaders) as $loader) {
|
||||
foreach ($loader->getMappedClasses() as $mappedClass) {
|
||||
try {
|
||||
if ($metadataFactory->hasMetadataFor($mappedClass)) {
|
||||
$metadataFactory->getMetadataFor($mappedClass);
|
||||
}
|
||||
} catch (\ReflectionException $e) {
|
||||
// ignore failing reflection
|
||||
} catch (AnnotationException $e) {
|
||||
// ignore failing annotations
|
||||
foreach ($this->extractSupportedLoaders($loaders) as $loader) {
|
||||
foreach ($loader->getMappedClasses() as $mappedClass) {
|
||||
try {
|
||||
if ($metadataFactory->hasMetadataFor($mappedClass)) {
|
||||
$metadataFactory->getMetadataFor($mappedClass);
|
||||
}
|
||||
} catch (\ReflectionException $e) {
|
||||
// ignore failing reflection
|
||||
} catch (AnnotationException $e) {
|
||||
// ignore failing annotations
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
spl_autoload_unregister(array($adapter, 'throwOnRequiredClass'));
|
||||
}
|
||||
|
||||
$values = $arrayPool->getValues();
|
||||
$adapter->warmUp(array_filter($values));
|
||||
|
||||
foreach ($values as $k => $v) {
|
||||
$item = $this->fallbackPool->getItem($k);
|
||||
$this->fallbackPool->saveDeferred($item->set($v));
|
||||
}
|
||||
$this->fallbackPool->commit();
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function isOptional()
|
||||
protected function warmUpPhpArrayAdapter(PhpArrayAdapter $phpArrayAdapter, array $values)
|
||||
{
|
||||
return true;
|
||||
// make sure we don't cache null values
|
||||
parent::warmUpPhpArrayAdapter($phpArrayAdapter, array_filter($values));
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -512,14 +512,14 @@
|
||||
var altContent = toggle.getAttribute('data-toggle-alt-content');
|
||||
toggle.innerHTML = currentContent !== altContent ? altContent : originalContent;
|
||||
});
|
||||
}
|
||||
|
||||
/* Prevents from disallowing clicks on links inside toggles */
|
||||
var toggleLinks = document.querySelectorAll('.sf-toggle a');
|
||||
for (var i = 0; i < toggleLinks.length; i++) {
|
||||
addEventListener(toggleLinks[i], 'click', function(e) {
|
||||
e.stopPropagation();
|
||||
});
|
||||
}
|
||||
/* Prevents from disallowing clicks on links inside toggles */
|
||||
var toggleLinks = document.querySelectorAll('.sf-toggle a');
|
||||
for (var i = 0; i < toggleLinks.length; i++) {
|
||||
addEventListener(toggleLinks[i], 'click', function(e) {
|
||||
e.stopPropagation();
|
||||
});
|
||||
}
|
||||
}
|
||||
};
|
||||
|
@ -25,6 +25,7 @@ class ClassExistenceResource implements SelfCheckingResourceInterface, \Serializ
|
||||
private $exists;
|
||||
|
||||
private static $autoloadLevel = 0;
|
||||
private static $autoloadedClass;
|
||||
private static $existsCache = array();
|
||||
|
||||
/**
|
||||
@ -57,6 +58,8 @@ class ClassExistenceResource implements SelfCheckingResourceInterface, \Serializ
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*
|
||||
* @throws \ReflectionException when a parent class/interface/trait is not found
|
||||
*/
|
||||
public function isFresh($timestamp)
|
||||
{
|
||||
@ -68,12 +71,13 @@ class ClassExistenceResource implements SelfCheckingResourceInterface, \Serializ
|
||||
if (!self::$autoloadLevel++) {
|
||||
spl_autoload_register(__CLASS__.'::throwOnRequiredClass');
|
||||
}
|
||||
$autoloadedClass = self::$autoloadedClass;
|
||||
self::$autoloadedClass = $this->resource;
|
||||
|
||||
try {
|
||||
$exists = class_exists($this->resource) || interface_exists($this->resource, false) || trait_exists($this->resource, false);
|
||||
} catch (\ReflectionException $e) {
|
||||
$exists = false;
|
||||
} finally {
|
||||
self::$autoloadedClass = $autoloadedClass;
|
||||
if (!--self::$autoloadLevel) {
|
||||
spl_autoload_unregister(__CLASS__.'::throwOnRequiredClass');
|
||||
}
|
||||
@ -112,7 +116,10 @@ class ClassExistenceResource implements SelfCheckingResourceInterface, \Serializ
|
||||
*/
|
||||
private static function throwOnRequiredClass($class)
|
||||
{
|
||||
$e = new \ReflectionException("Class $class does not exist");
|
||||
if (self::$autoloadedClass === $class) {
|
||||
return;
|
||||
}
|
||||
$e = new \ReflectionException("Class $class not found");
|
||||
$trace = $e->getTrace();
|
||||
$autoloadFrame = array(
|
||||
'function' => 'spl_autoload_call',
|
||||
@ -138,6 +145,18 @@ class ClassExistenceResource implements SelfCheckingResourceInterface, \Serializ
|
||||
case 'is_callable':
|
||||
return;
|
||||
}
|
||||
|
||||
$props = array(
|
||||
'file' => $trace[$i]['file'],
|
||||
'line' => $trace[$i]['line'],
|
||||
'trace' => array_slice($trace, 0, 1 + $i),
|
||||
);
|
||||
|
||||
foreach ($props as $p => $v) {
|
||||
$r = new \ReflectionProperty('Exception', $p);
|
||||
$r->setAccessible(true);
|
||||
$r->setValue($e, $v);
|
||||
}
|
||||
}
|
||||
|
||||
throw $e;
|
||||
|
@ -124,8 +124,8 @@ class AutowirePass extends AbstractRecursivePass
|
||||
if (!$value instanceof Definition || !$value->isAutowired() || $value->isAbstract() || !$value->getClass()) {
|
||||
return $value;
|
||||
}
|
||||
if (!$reflectionClass = $this->container->getReflectionClass($value->getClass())) {
|
||||
$this->container->log($this, sprintf('Skipping service "%s": Class or interface "%s" does not exist.', $this->currentId, $value->getClass()));
|
||||
if (!$reflectionClass = $this->container->getReflectionClass($value->getClass(), false)) {
|
||||
$this->container->log($this, sprintf('Skipping service "%s": Class or interface "%s" cannot be loaded.', $this->currentId, $value->getClass()));
|
||||
|
||||
return $value;
|
||||
}
|
||||
@ -388,7 +388,7 @@ class AutowirePass extends AbstractRecursivePass
|
||||
unset($this->ambiguousServiceTypes[$type]);
|
||||
}
|
||||
|
||||
if ($definition->isDeprecated() || !$reflectionClass = $this->container->getReflectionClass($definition->getClass())) {
|
||||
if ($definition->isDeprecated() || !$reflectionClass = $this->container->getReflectionClass($definition->getClass(), false)) {
|
||||
return;
|
||||
}
|
||||
|
||||
@ -444,7 +444,7 @@ class AutowirePass extends AbstractRecursivePass
|
||||
*/
|
||||
private function createAutowiredDefinition($type)
|
||||
{
|
||||
if (!($typeHint = $this->container->getReflectionClass($type)) || !$typeHint->isInstantiable()) {
|
||||
if (!($typeHint = $this->container->getReflectionClass($type, false)) || !$typeHint->isInstantiable()) {
|
||||
return;
|
||||
}
|
||||
|
||||
@ -478,8 +478,8 @@ class AutowirePass extends AbstractRecursivePass
|
||||
|
||||
private function createTypeNotFoundMessage(TypedReference $reference, $label)
|
||||
{
|
||||
if (!$r = $this->container->getReflectionClass($type = $reference->getType())) {
|
||||
$message = sprintf('has type "%s" but this class does not exist.', $type);
|
||||
if (!$r = $this->container->getReflectionClass($type = $reference->getType(), false)) {
|
||||
$message = sprintf('has type "%s" but this class cannot be loaded.', $type);
|
||||
} else {
|
||||
$message = $this->container->has($type) ? 'this service is abstract' : 'no such service exists';
|
||||
$message = sprintf('references %s "%s" but %s.%s', $r->isInterface() ? 'interface' : 'class', $type, $message, $this->createTypeAlternatives($reference));
|
||||
|
@ -81,7 +81,7 @@ class FactoryReturnTypePass implements CompilerPassInterface
|
||||
$class = $factory[0];
|
||||
}
|
||||
|
||||
if (!$m = $container->getReflectionClass($class)) {
|
||||
if (!$m = $container->getReflectionClass($class, false)) {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
|
@ -26,7 +26,7 @@ trait PriorityTaggedServiceTrait
|
||||
*
|
||||
* The order of additions must be respected for services having the same priority,
|
||||
* and knowing that the \SplPriorityQueue class does not respect the FIFO method,
|
||||
* we should not use this class.
|
||||
* we should not use that class.
|
||||
*
|
||||
* @see https://bugs.php.net/bug.php?id=53710
|
||||
* @see https://bugs.php.net/bug.php?id=60926
|
||||
|
@ -66,7 +66,7 @@ class ResolveInstanceofConditionalsPass implements CompilerPassInterface
|
||||
$instanceofTags = array();
|
||||
|
||||
foreach ($conditionals as $interface => $instanceofDefs) {
|
||||
if ($interface !== $class && (!$container->getReflectionClass($class))) {
|
||||
if ($interface !== $class && (!$container->getReflectionClass($class, false))) {
|
||||
continue;
|
||||
}
|
||||
|
||||
|
@ -337,12 +337,15 @@ class ContainerBuilder extends Container implements TaggedContainerInterface
|
||||
* Retrieves the requested reflection class and registers it for resource tracking.
|
||||
*
|
||||
* @param string $class
|
||||
* @param bool $throw
|
||||
*
|
||||
* @return \ReflectionClass|null
|
||||
*
|
||||
* @throws \ReflectionException when a parent class/interface/trait is not found and $throw is true
|
||||
*
|
||||
* @final
|
||||
*/
|
||||
public function getReflectionClass($class)
|
||||
public function getReflectionClass($class, $throw = true)
|
||||
{
|
||||
if (!$class = $this->getParameterBag()->resolveValue($class)) {
|
||||
return;
|
||||
@ -357,6 +360,9 @@ class ContainerBuilder extends Container implements TaggedContainerInterface
|
||||
$classReflector = $resource->isFresh(0) ? false : new \ReflectionClass($class);
|
||||
}
|
||||
} catch (\ReflectionException $e) {
|
||||
if ($throw) {
|
||||
throw $e;
|
||||
}
|
||||
$classReflector = false;
|
||||
}
|
||||
|
||||
|
@ -359,7 +359,7 @@ class AutowirePassTest extends TestCase
|
||||
|
||||
/**
|
||||
* @expectedException \Symfony\Component\DependencyInjection\Exception\AutowiringFailedException
|
||||
* @expectedExceptionMessage Cannot autowire service "a": argument "$r" of method "Symfony\Component\DependencyInjection\Tests\Compiler\BadTypeHintedArgument::__construct()" has type "Symfony\Component\DependencyInjection\Tests\Compiler\NotARealClass" but this class does not exist.
|
||||
* @expectedExceptionMessage Cannot autowire service "a": argument "$r" of method "Symfony\Component\DependencyInjection\Tests\Compiler\BadTypeHintedArgument::__construct()" has type "Symfony\Component\DependencyInjection\Tests\Compiler\NotARealClass" but this class cannot be loaded.
|
||||
*/
|
||||
public function testClassNotFoundThrowsException()
|
||||
{
|
||||
@ -374,7 +374,7 @@ class AutowirePassTest extends TestCase
|
||||
|
||||
/**
|
||||
* @expectedException \Symfony\Component\DependencyInjection\Exception\AutowiringFailedException
|
||||
* @expectedExceptionMessage Cannot autowire service "a": argument "$r" of method "Symfony\Component\DependencyInjection\Tests\Compiler\BadParentTypeHintedArgument::__construct()" has type "Symfony\Component\DependencyInjection\Tests\Compiler\OptionalServiceClass" but this class does not exist.
|
||||
* @expectedExceptionMessage Cannot autowire service "a": argument "$r" of method "Symfony\Component\DependencyInjection\Tests\Compiler\BadParentTypeHintedArgument::__construct()" has type "Symfony\Component\DependencyInjection\Tests\Compiler\OptionalServiceClass" but this class cannot be loaded.
|
||||
*/
|
||||
public function testParentClassNotFoundThrowsException()
|
||||
{
|
||||
@ -744,7 +744,7 @@ class AutowirePassTest extends TestCase
|
||||
public function provideNotWireableCalls()
|
||||
{
|
||||
return array(
|
||||
array('setNotAutowireable', 'Cannot autowire service "foo": argument "$n" of method "Symfony\Component\DependencyInjection\Tests\Compiler\NotWireable::setNotAutowireable()" has type "Symfony\Component\DependencyInjection\Tests\Compiler\NotARealClass" but this class does not exist.'),
|
||||
array('setNotAutowireable', 'Cannot autowire service "foo": argument "$n" of method "Symfony\Component\DependencyInjection\Tests\Compiler\NotWireable::setNotAutowireable()" has type "Symfony\Component\DependencyInjection\Tests\Compiler\NotARealClass" but this class cannot be loaded.'),
|
||||
array('setDifferentNamespace', 'Cannot autowire service "foo": argument "$n" of method "Symfony\Component\DependencyInjection\Tests\Compiler\NotWireable::setDifferentNamespace()" references class "stdClass" but no such service exists. It cannot be auto-registered because it is from a different root namespace.'),
|
||||
array(null, 'Cannot autowire service "foo": method "Symfony\Component\DependencyInjection\Tests\Compiler\NotWireable::setProtectedMethod()" must be public.'),
|
||||
);
|
||||
|
@ -122,8 +122,14 @@ class DefaultAuthenticationSuccessHandler implements AuthenticationSuccessHandle
|
||||
return $targetUrl;
|
||||
}
|
||||
|
||||
if ($this->options['use_referer'] && ($targetUrl = $request->headers->get('Referer')) && parse_url($targetUrl, PHP_URL_PATH) !== $this->httpUtils->generateUri($request, $this->options['login_path'])) {
|
||||
return $targetUrl;
|
||||
if ($this->options['use_referer']) {
|
||||
$targetUrl = $request->headers->get('Referer');
|
||||
if (false !== $pos = strpos($targetUrl, '?')) {
|
||||
$targetUrl = substr($targetUrl, 0, $pos);
|
||||
}
|
||||
if ($targetUrl !== $this->httpUtils->generateUri($request, $this->options['login_path'])) {
|
||||
return $targetUrl;
|
||||
}
|
||||
}
|
||||
|
||||
return $this->options['default_target_path'];
|
||||
|
@ -12,193 +12,92 @@
|
||||
namespace Symfony\Component\Security\Http\Tests\Authentication;
|
||||
|
||||
use PHPUnit\Framework\TestCase;
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
use Symfony\Component\Security\Http\Authentication\DefaultAuthenticationSuccessHandler;
|
||||
use Symfony\Component\Security\Http\HttpUtils;
|
||||
|
||||
class DefaultAuthenticationSuccessHandlerTest extends TestCase
|
||||
{
|
||||
private $httpUtils = null;
|
||||
|
||||
private $request = null;
|
||||
|
||||
private $token = null;
|
||||
|
||||
protected function setUp()
|
||||
/**
|
||||
* @dataProvider getRequestRedirections
|
||||
*/
|
||||
public function testRequestRedirections(Request $request, $options, $redirectedUrl)
|
||||
{
|
||||
$this->httpUtils = $this->getMockBuilder('Symfony\Component\Security\Http\HttpUtils')->getMock();
|
||||
$this->request = $this->getMockBuilder('Symfony\Component\HttpFoundation\Request')->getMock();
|
||||
$this->request->headers = $this->getMockBuilder('Symfony\Component\HttpFoundation\HeaderBag')->getMock();
|
||||
$this->token = $this->getMockBuilder('Symfony\Component\Security\Core\Authentication\Token\TokenInterface')->getMock();
|
||||
$urlGenerator = $this->getMockBuilder('Symfony\Component\Routing\Generator\UrlGeneratorInterface')->getMock();
|
||||
$urlGenerator->expects($this->any())->method('generate')->will($this->returnValue('http://localhost/login'));
|
||||
$httpUtils = new HttpUtils($urlGenerator);
|
||||
$token = $this->getMockBuilder('Symfony\Component\Security\Core\Authentication\Token\TokenInterface')->getMock();
|
||||
$handler = new DefaultAuthenticationSuccessHandler($httpUtils, $options);
|
||||
if ($request->hasSession()) {
|
||||
$handler->setProviderKey('admin');
|
||||
}
|
||||
$this->assertSame('http://localhost'.$redirectedUrl, $handler->onAuthenticationSuccess($request, $token)->getTargetUrl());
|
||||
}
|
||||
|
||||
public function testRequestIsRedirected()
|
||||
{
|
||||
$response = $this->expectRedirectResponse('/');
|
||||
|
||||
$handler = new DefaultAuthenticationSuccessHandler($this->httpUtils, array());
|
||||
$result = $handler->onAuthenticationSuccess($this->request, $this->token);
|
||||
|
||||
$this->assertSame($response, $result);
|
||||
}
|
||||
|
||||
public function testDefaultTargetPathCanBeForced()
|
||||
{
|
||||
$options = array(
|
||||
'always_use_default_target_path' => true,
|
||||
'default_target_path' => '/dashboard',
|
||||
);
|
||||
|
||||
$response = $this->expectRedirectResponse('/dashboard');
|
||||
|
||||
$handler = new DefaultAuthenticationSuccessHandler($this->httpUtils, $options);
|
||||
$result = $handler->onAuthenticationSuccess($this->request, $this->token);
|
||||
|
||||
$this->assertSame($response, $result);
|
||||
}
|
||||
|
||||
public function testTargetPathIsPassedWithRequest()
|
||||
{
|
||||
$this->request->expects($this->once())
|
||||
->method('get')->with('_target_path')
|
||||
->will($this->returnValue('/dashboard'));
|
||||
|
||||
$response = $this->expectRedirectResponse('/dashboard');
|
||||
|
||||
$handler = new DefaultAuthenticationSuccessHandler($this->httpUtils, array());
|
||||
$result = $handler->onAuthenticationSuccess($this->request, $this->token);
|
||||
|
||||
$this->assertSame($response, $result);
|
||||
}
|
||||
|
||||
public function testTargetPathIsPassedAsNestedParameterWithRequest()
|
||||
{
|
||||
$this->request->expects($this->once())
|
||||
->method('get')->with('_target_path')
|
||||
->will($this->returnValue(array('value' => '/dashboard')));
|
||||
|
||||
$response = $this->expectRedirectResponse('/dashboard');
|
||||
|
||||
$handler = new DefaultAuthenticationSuccessHandler($this->httpUtils, array('target_path_parameter' => '_target_path[value]'));
|
||||
$result = $handler->onAuthenticationSuccess($this->request, $this->token);
|
||||
|
||||
$this->assertSame($response, $result);
|
||||
}
|
||||
|
||||
public function testTargetPathParameterIsCustomised()
|
||||
{
|
||||
$options = array('target_path_parameter' => '_my_target_path');
|
||||
|
||||
$this->request->expects($this->once())
|
||||
->method('get')->with('_my_target_path')
|
||||
->will($this->returnValue('/dashboard'));
|
||||
|
||||
$response = $this->expectRedirectResponse('/dashboard');
|
||||
|
||||
$handler = new DefaultAuthenticationSuccessHandler($this->httpUtils, $options);
|
||||
$result = $handler->onAuthenticationSuccess($this->request, $this->token);
|
||||
|
||||
$this->assertSame($response, $result);
|
||||
}
|
||||
|
||||
public function testTargetPathIsTakenFromTheSession()
|
||||
public function getRequestRedirections()
|
||||
{
|
||||
$session = $this->getMockBuilder('Symfony\Component\HttpFoundation\Session\SessionInterface')->getMock();
|
||||
$session->expects($this->once())
|
||||
->method('get')->with('_security.admin.target_path')
|
||||
->will($this->returnValue('/admin/dashboard'));
|
||||
$session->expects($this->once())
|
||||
->method('remove')->with('_security.admin.target_path');
|
||||
$session->expects($this->once())->method('get')->with('_security.admin.target_path')->will($this->returnValue('/admin/dashboard'));
|
||||
$session->expects($this->once())->method('remove')->with('_security.admin.target_path');
|
||||
$requestWithSession = Request::create('/');
|
||||
$requestWithSession->setSession($session);
|
||||
|
||||
$this->request->expects($this->any())
|
||||
->method('getSession')
|
||||
->will($this->returnValue($session));
|
||||
|
||||
$response = $this->expectRedirectResponse('/admin/dashboard');
|
||||
|
||||
$handler = new DefaultAuthenticationSuccessHandler($this->httpUtils, array());
|
||||
$handler->setProviderKey('admin');
|
||||
|
||||
$result = $handler->onAuthenticationSuccess($this->request, $this->token);
|
||||
|
||||
$this->assertSame($response, $result);
|
||||
}
|
||||
|
||||
public function testTargetPathIsPassedAsReferer()
|
||||
{
|
||||
$options = array('use_referer' => true);
|
||||
|
||||
$this->request->headers->expects($this->once())
|
||||
->method('get')->with('Referer')
|
||||
->will($this->returnValue('/dashboard'));
|
||||
|
||||
$response = $this->expectRedirectResponse('/dashboard');
|
||||
|
||||
$handler = new DefaultAuthenticationSuccessHandler($this->httpUtils, $options);
|
||||
$result = $handler->onAuthenticationSuccess($this->request, $this->token);
|
||||
|
||||
$this->assertSame($response, $result);
|
||||
}
|
||||
|
||||
public function testRefererHasToBeDifferentThanLoginUrl()
|
||||
{
|
||||
$options = array('use_referer' => true);
|
||||
|
||||
$this->request->headers->expects($this->any())
|
||||
->method('get')->with('Referer')
|
||||
->will($this->returnValue('/login'));
|
||||
|
||||
$this->httpUtils->expects($this->once())
|
||||
->method('generateUri')->with($this->request, '/login')
|
||||
->will($this->returnValue('/login'));
|
||||
|
||||
$response = $this->expectRedirectResponse('/');
|
||||
|
||||
$handler = new DefaultAuthenticationSuccessHandler($this->httpUtils, $options);
|
||||
$result = $handler->onAuthenticationSuccess($this->request, $this->token);
|
||||
|
||||
$this->assertSame($response, $result);
|
||||
}
|
||||
|
||||
public function testRefererWithoutParametersHasToBeDifferentThanLoginUrl()
|
||||
{
|
||||
$options = array('use_referer' => true);
|
||||
|
||||
$this->request->headers->expects($this->any())
|
||||
->method('get')->with('Referer')
|
||||
->will($this->returnValue('/subfolder/login?t=1&p=2'));
|
||||
|
||||
$this->httpUtils->expects($this->once())
|
||||
->method('generateUri')->with($this->request, '/login')
|
||||
->will($this->returnValue('/subfolder/login'));
|
||||
|
||||
$response = $this->expectRedirectResponse('/');
|
||||
|
||||
$handler = new DefaultAuthenticationSuccessHandler($this->httpUtils, $options);
|
||||
$result = $handler->onAuthenticationSuccess($this->request, $this->token);
|
||||
|
||||
$this->assertSame($response, $result);
|
||||
}
|
||||
|
||||
public function testRefererTargetPathIsIgnoredByDefault()
|
||||
{
|
||||
$this->request->headers->expects($this->never())->method('get');
|
||||
|
||||
$response = $this->expectRedirectResponse('/');
|
||||
|
||||
$handler = new DefaultAuthenticationSuccessHandler($this->httpUtils, array());
|
||||
$result = $handler->onAuthenticationSuccess($this->request, $this->token);
|
||||
|
||||
$this->assertSame($response, $result);
|
||||
}
|
||||
|
||||
private function expectRedirectResponse($path)
|
||||
{
|
||||
$response = new Response();
|
||||
$this->httpUtils->expects($this->once())
|
||||
->method('createRedirectResponse')
|
||||
->with($this->request, $path)
|
||||
->will($this->returnValue($response));
|
||||
|
||||
return $response;
|
||||
return array(
|
||||
'default' => array(
|
||||
Request::create('/'),
|
||||
array(),
|
||||
'/',
|
||||
),
|
||||
'forced target path' => array(
|
||||
Request::create('/'),
|
||||
array('always_use_default_target_path' => true, 'default_target_path' => '/dashboard'),
|
||||
'/dashboard',
|
||||
),
|
||||
'target path as query string' => array(
|
||||
Request::create('/?_target_path=/dashboard'),
|
||||
array(),
|
||||
'/dashboard',
|
||||
),
|
||||
'target path name as query string is customized' => array(
|
||||
Request::create('/?_my_target_path=/dashboard'),
|
||||
array('target_path_parameter' => '_my_target_path'),
|
||||
'/dashboard',
|
||||
),
|
||||
'target path name as query string is customized and nested' => array(
|
||||
Request::create('/?_target_path[value]=/dashboard'),
|
||||
array('target_path_parameter' => '_target_path[value]'),
|
||||
'/dashboard',
|
||||
),
|
||||
'target path in session' => array(
|
||||
$requestWithSession,
|
||||
array(),
|
||||
'/admin/dashboard',
|
||||
),
|
||||
'target path as referer' => array(
|
||||
Request::create('/', 'GET', array(), array(), array(), array('HTTP_REFERER' => 'http://localhost/dashboard')),
|
||||
array('use_referer' => true),
|
||||
'/dashboard',
|
||||
),
|
||||
'target path as referer is ignored if not configured' => array(
|
||||
Request::create('/', 'GET', array(), array(), array(), array('HTTP_REFERER' => 'http://localhost/dashboard')),
|
||||
array(),
|
||||
'/',
|
||||
),
|
||||
'target path should be different than login URL' => array(
|
||||
Request::create('/', 'GET', array(), array(), array(), array('HTTP_REFERER' => 'http://localhost/login')),
|
||||
array('use_referer' => true, 'login_path' => '/login'),
|
||||
'/',
|
||||
),
|
||||
'target path should be different than login URL (query string does not matter)' => array(
|
||||
Request::create('/', 'GET', array(), array(), array(), array('HTTP_REFERER' => 'http://localhost/login?t=1&p=2')),
|
||||
array('use_referer' => true, 'login_path' => '/login'),
|
||||
'/',
|
||||
),
|
||||
'target path should be different than login URL (login_path as a route)' => array(
|
||||
Request::create('/', 'GET', array(), array(), array(), array('HTTP_REFERER' => 'http://localhost/login?t=1&p=2')),
|
||||
array('use_referer' => true, 'login_path' => 'login_route'),
|
||||
'/',
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -46,8 +46,8 @@ abstract class AbstractDumper implements DataDumperInterface, DumperInterface
|
||||
{
|
||||
$this->flags = (int) $flags;
|
||||
$this->setCharset($charset ?: ini_get('php.output_encoding') ?: ini_get('default_charset') ?: 'UTF-8');
|
||||
$this->decimalPoint = (string) 0.5;
|
||||
$this->decimalPoint = $this->decimalPoint[1];
|
||||
$this->decimalPoint = localeconv();
|
||||
$this->decimalPoint = $this->decimalPoint['decimal_point'];
|
||||
$this->setOutput($output ?: static::$defaultOutput);
|
||||
if (!$output && is_string(static::$defaultOutput)) {
|
||||
static::$defaultOutput = $this->outputStream;
|
||||
@ -123,6 +123,13 @@ abstract class AbstractDumper implements DataDumperInterface, DumperInterface
|
||||
*/
|
||||
public function dump(Data $data, $output = null)
|
||||
{
|
||||
$this->decimalPoint = localeconv();
|
||||
$this->decimalPoint = $this->decimalPoint['decimal_point'];
|
||||
|
||||
if ($locale = $this->flags & (self::DUMP_COMMA_SEPARATOR | self::DUMP_TRAILING_COMMA) ? setlocale(LC_NUMERIC, 0) : null) {
|
||||
setlocale(LC_NUMERIC, 'C');
|
||||
}
|
||||
|
||||
if ($returnDump = true === $output) {
|
||||
$output = fopen('php://memory', 'r+b');
|
||||
}
|
||||
@ -143,6 +150,9 @@ abstract class AbstractDumper implements DataDumperInterface, DumperInterface
|
||||
if ($output) {
|
||||
$this->setOutput($prevOutput);
|
||||
}
|
||||
if ($locale) {
|
||||
setlocale(LC_NUMERIC, $locale);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
Reference in New Issue
Block a user