feature #18533 [FrameworkBundle] Wire PhpArrayAdapter with a new cache warmer for annotations (tgalopin)
This PR was squashed before being merged into the 3.2-dev branch (closes #18533).
Discussion
----------
[FrameworkBundle] Wire PhpArrayAdapter with a new cache warmer for annotations
| Q | A
| ------------- | ---
| Branch? | master
| Bug fix? | no
| New feature? | yes
| BC breaks? | no
| Deprecations? | no
| Tests pass? | WIP
| Fixed tickets | -
| License | MIT
| Doc PR | -
Depends on https://github.com/symfony/symfony/pull/18825 and https://github.com/symfony/symfony/pull/18823
This PR implements the usage of the new OpCacheAdapter in the annotations caching system. The idea to use this adapter as much as possible in Symfony (validator, serializer, ...). These other implementations will be the object of different PRs.
Commits
-------
f950a2b
[FrameworkBundle] Wire PhpArrayAdapter with a new cache warmer for annotations
This commit is contained in:
commit
35b0ab9527
@ -0,0 +1,105 @@
|
||||
<?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 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
|
||||
* and declared in DI bundle extensions using the addAnnotatedClassesToCache method.
|
||||
*
|
||||
* @author Titouan Galopin <galopintitouan@gmail.com>
|
||||
*/
|
||||
class AnnotationsCacheWarmer implements CacheWarmerInterface
|
||||
{
|
||||
private $annotationReader;
|
||||
private $phpArrayFile;
|
||||
private $fallbackPool;
|
||||
|
||||
/**
|
||||
* @param Reader $annotationReader
|
||||
* @param string $phpArrayFile The PHP file where annotations are cached.
|
||||
* @param CacheItemPoolInterface $fallbackPool The pool where runtime-discovered annotations are cached.
|
||||
*/
|
||||
public function __construct(Reader $annotationReader, $phpArrayFile, CacheItemPoolInterface $fallbackPool)
|
||||
{
|
||||
$this->annotationReader = $annotationReader;
|
||||
$this->phpArrayFile = $phpArrayFile;
|
||||
if (!$fallbackPool instanceof AdapterInterface) {
|
||||
$fallbackPool = new ProxyAdapter($fallbackPool);
|
||||
}
|
||||
$this->fallbackPool = $fallbackPool;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function warmUp($cacheDir)
|
||||
{
|
||||
$adapter = new PhpArrayAdapter($this->phpArrayFile, $this->fallbackPool);
|
||||
$annotatedClassPatterns = $cacheDir.'/annotations.map';
|
||||
|
||||
if (!is_file($annotatedClassPatterns)) {
|
||||
$adapter->warmUp(array());
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
$annotatedClasses = include $annotatedClassPatterns;
|
||||
|
||||
$arrayPool = new ArrayAdapter(0, false);
|
||||
$reader = new CachedReader($this->annotationReader, new DoctrineProvider($arrayPool));
|
||||
|
||||
foreach ($annotatedClasses as $class) {
|
||||
$this->readAllComponents($reader, $class);
|
||||
}
|
||||
|
||||
$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;
|
||||
}
|
||||
|
||||
private function readAllComponents(Reader $reader, $class)
|
||||
{
|
||||
$reflectionClass = new \ReflectionClass($class);
|
||||
$reader->getClassAnnotations($reflectionClass);
|
||||
|
||||
foreach ($reflectionClass->getMethods() as $reflectionMethod) {
|
||||
$reader->getMethodAnnotations($reflectionMethod);
|
||||
}
|
||||
|
||||
foreach ($reflectionClass->getProperties() as $reflectionProperty) {
|
||||
$reader->getPropertyAnnotations($reflectionProperty);
|
||||
}
|
||||
}
|
||||
}
|
@ -594,7 +594,7 @@ class Configuration implements ConfigurationInterface
|
||||
->info('annotation configuration')
|
||||
->addDefaultsIfNotSet()
|
||||
->children()
|
||||
->scalarNode('cache')->defaultValue('file')->end()
|
||||
->scalarNode('cache')->defaultValue('php_array')->end()
|
||||
->scalarNode('file_cache_dir')->defaultValue('%kernel.cache_dir%/annotations')->end()
|
||||
->booleanNode('debug')->defaultValue($this->debug)->end()
|
||||
->end()
|
||||
|
@ -168,6 +168,14 @@ class FrameworkExtension extends Extension
|
||||
$definition->replaceArgument(1, null);
|
||||
}
|
||||
|
||||
$this->addAnnotatedClassesToCompile(array(
|
||||
'**Bundle\\Controller\\',
|
||||
'**Bundle\\Entity\\',
|
||||
|
||||
// Added explicitly so that we don't rely on the class map being dumped to make it work
|
||||
'Symfony\\Bundle\\FrameworkBundle\\Controller\\Controller',
|
||||
));
|
||||
|
||||
$this->addClassesToCompile(array(
|
||||
'Symfony\\Component\\Config\\ConfigCache',
|
||||
'Symfony\\Component\\Config\\FileLocator',
|
||||
@ -905,8 +913,22 @@ class FrameworkExtension extends Extension
|
||||
$loader->load('annotations.xml');
|
||||
|
||||
if ('none' !== $config['cache']) {
|
||||
if ('file' === $config['cache']) {
|
||||
$cacheService = $config['cache'];
|
||||
|
||||
if ('php_array' === $config['cache']) {
|
||||
$cacheService = 'annotations.cache';
|
||||
|
||||
// Enable warmer only if PHP array is used for cache
|
||||
$definition = $container->findDefinition('annotations.cache_warmer');
|
||||
$definition->addTag('kernel.cache_warmer');
|
||||
|
||||
$this->addClassesToCompile(array(
|
||||
'Symfony\Component\Cache\Adapter\PhpArrayAdapter',
|
||||
'Symfony\Component\Cache\DoctrineProvider',
|
||||
));
|
||||
} elseif ('file' === $config['cache']) {
|
||||
$cacheDir = $container->getParameterBag()->resolveValue($config['file_cache_dir']);
|
||||
|
||||
if (!is_dir($cacheDir) && false === @mkdir($cacheDir, 0777, true) && !is_dir($cacheDir)) {
|
||||
throw new \RuntimeException(sprintf('Could not create cache directory "%s".', $cacheDir));
|
||||
}
|
||||
@ -915,11 +937,13 @@ class FrameworkExtension extends Extension
|
||||
->getDefinition('annotations.filesystem_cache')
|
||||
->replaceArgument(0, $cacheDir)
|
||||
;
|
||||
|
||||
$cacheService = 'annotations.filesystem_cache';
|
||||
}
|
||||
|
||||
$container
|
||||
->getDefinition('annotations.cached_reader')
|
||||
->replaceArgument(1, new Reference('file' !== $config['cache'] ? $config['cache'] : 'annotations.filesystem_cache'))
|
||||
->replaceArgument(1, new Reference($cacheService))
|
||||
->replaceArgument(2, $config['debug'])
|
||||
->addAutowiringType(Reader::class)
|
||||
;
|
||||
@ -1129,10 +1153,8 @@ class FrameworkExtension extends Extension
|
||||
}
|
||||
|
||||
$this->addClassesToCompile(array(
|
||||
'Psr\Cache\CacheItemInterface',
|
||||
'Psr\Cache\CacheItemPoolInterface',
|
||||
'Symfony\Component\Cache\Adapter\AdapterInterface',
|
||||
'Symfony\Component\Cache\Adapter\AbstractAdapter',
|
||||
'Symfony\Component\Cache\Adapter\ApcuAdapter',
|
||||
'Symfony\Component\Cache\Adapter\FilesystemAdapter',
|
||||
'Symfony\Component\Cache\CacheItem',
|
||||
));
|
||||
}
|
||||
|
@ -19,6 +19,22 @@
|
||||
<argument /><!-- Cache-Directory -->
|
||||
</service>
|
||||
|
||||
<service id="annotations.cache_warmer" class="Symfony\Bundle\FrameworkBundle\CacheWarmer\AnnotationsCacheWarmer" public="false">
|
||||
<argument type="service" id="annotations.reader" />
|
||||
<argument>%kernel.cache_dir%/annotations.php</argument>
|
||||
<argument type="service" id="cache.annotations" />
|
||||
</service>
|
||||
|
||||
<service id="annotations.cache" class="Symfony\Component\Cache\DoctrineProvider" public="false">
|
||||
<argument type="service">
|
||||
<service class="Symfony\Component\Cache\Adapter\PhpArrayAdapter">
|
||||
<factory class="Symfony\Component\Cache\Adapter\PhpArrayAdapter" method="create" />
|
||||
<argument>%kernel.cache_dir%/annotations.php</argument>
|
||||
<argument type="service" id="cache.annotations" />
|
||||
</service>
|
||||
</argument>
|
||||
</service>
|
||||
|
||||
<service id="annotation_reader" alias="annotations.reader" />
|
||||
</services>
|
||||
</container>
|
||||
|
@ -22,6 +22,10 @@
|
||||
<tag name="cache.pool" />
|
||||
</service>
|
||||
|
||||
<service id="cache.annotations" parent="cache.system" public="false">
|
||||
<tag name="cache.pool" />
|
||||
</service>
|
||||
|
||||
<service id="cache.adapter.system" class="Symfony\Component\Cache\Adapter\AdapterInterface" abstract="true">
|
||||
<factory class="Symfony\Component\Cache\Adapter\AbstractAdapter" method="createSystemCache" />
|
||||
<tag name="cache.pool" clearer="cache.default_clearer" />
|
||||
|
@ -214,7 +214,7 @@ class ConfigurationTest extends \PHPUnit_Framework_TestCase
|
||||
'cache' => 'validator.mapping.cache.symfony',
|
||||
),
|
||||
'annotations' => array(
|
||||
'cache' => 'file',
|
||||
'cache' => 'php_array',
|
||||
'file_cache_dir' => '%kernel.cache_dir%/annotations',
|
||||
'debug' => true,
|
||||
),
|
||||
|
@ -18,13 +18,13 @@
|
||||
"require": {
|
||||
"php": ">=5.5.9",
|
||||
"symfony/asset": "~2.8|~3.0",
|
||||
"symfony/cache": "~3.1",
|
||||
"symfony/cache": "~3.2",
|
||||
"symfony/class-loader": "~3.2",
|
||||
"symfony/dependency-injection": "~3.2",
|
||||
"symfony/config": "~2.8|~3.0",
|
||||
"symfony/event-dispatcher": "~2.8|~3.0",
|
||||
"symfony/http-foundation": "~3.1",
|
||||
"symfony/http-kernel": "~3.1.2|~3.2",
|
||||
"symfony/http-kernel": "~3.2",
|
||||
"symfony/polyfill-mbstring": "~1.0",
|
||||
"symfony/filesystem": "~2.8|~3.0",
|
||||
"symfony/finder": "~2.8|~3.0",
|
||||
|
@ -56,7 +56,7 @@ class ArrayAdapter implements AdapterInterface, LoggerAwareInterface
|
||||
public function getItem($key)
|
||||
{
|
||||
if (!$isHit = $this->hasItem($key)) {
|
||||
$value = null;
|
||||
$this->values[$key] = $value = null;
|
||||
} elseif ($this->storeSerialized) {
|
||||
$value = unserialize($this->values[$key]);
|
||||
} else {
|
||||
@ -79,6 +79,16 @@ class ArrayAdapter implements AdapterInterface, LoggerAwareInterface
|
||||
return $this->generateItems($keys, time());
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns all cached values, with cache miss as null.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getValues()
|
||||
{
|
||||
return $this->values;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
@ -183,7 +193,7 @@ class ArrayAdapter implements AdapterInterface, LoggerAwareInterface
|
||||
|
||||
foreach ($keys as $key) {
|
||||
if (!$isHit = isset($this->expiries[$key]) && ($this->expiries[$key] >= $now || !$this->deleteItem($key))) {
|
||||
$value = null;
|
||||
$this->values[$key] = $value = null;
|
||||
} elseif ($this->storeSerialized) {
|
||||
$value = unserialize($this->values[$key]);
|
||||
} else {
|
||||
|
@ -27,4 +27,30 @@ class ArrayAdapterTest extends AdapterTestCase
|
||||
{
|
||||
return new ArrayAdapter($defaultLifetime);
|
||||
}
|
||||
|
||||
public function testGetValuesHitAndMiss()
|
||||
{
|
||||
/** @var ArrayAdapter $cache */
|
||||
$cache = $this->createCachePool();
|
||||
|
||||
// Hit
|
||||
$item = $cache->getItem('foo');
|
||||
$item->set('4711');
|
||||
$cache->save($item);
|
||||
|
||||
$fooItem = $cache->getItem('foo');
|
||||
$this->assertTrue($fooItem->isHit());
|
||||
$this->assertEquals('4711', $fooItem->get());
|
||||
|
||||
// Miss (should be present as NULL in $values)
|
||||
$cache->getItem('bar');
|
||||
|
||||
$values = $cache->getValues();
|
||||
|
||||
$this->assertCount(2, $values);
|
||||
$this->assertArrayHasKey('foo', $values);
|
||||
$this->assertSame(serialize('4711'), $values['foo']);
|
||||
$this->assertArrayHasKey('bar', $values);
|
||||
$this->assertNull($values['bar']);
|
||||
}
|
||||
}
|
||||
|
@ -11,6 +11,8 @@
|
||||
|
||||
namespace Symfony\Component\HttpKernel\DependencyInjection;
|
||||
|
||||
use Composer\Autoload\ClassLoader;
|
||||
use Symfony\Component\Debug\DebugClassLoader;
|
||||
use Symfony\Component\DependencyInjection\ContainerBuilder;
|
||||
use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
|
||||
use Symfony\Component\HttpKernel\Kernel;
|
||||
@ -35,12 +37,113 @@ class AddClassesToCachePass implements CompilerPassInterface
|
||||
public function process(ContainerBuilder $container)
|
||||
{
|
||||
$classes = array();
|
||||
$annotatedClasses = array();
|
||||
foreach ($container->getExtensions() as $extension) {
|
||||
if ($extension instanceof Extension) {
|
||||
$classes = array_merge($classes, $extension->getClassesToCompile());
|
||||
$annotatedClasses = array_merge($annotatedClasses, $extension->getAnnotatedClassesToCompile());
|
||||
}
|
||||
}
|
||||
|
||||
$this->kernel->setClassCache(array_unique($container->getParameterBag()->resolveValue($classes)));
|
||||
$classes = $container->getParameterBag()->resolveValue($classes);
|
||||
$annotatedClasses = $container->getParameterBag()->resolveValue($annotatedClasses);
|
||||
$existingClasses = $this->getClassesInComposerClassMaps();
|
||||
|
||||
$this->kernel->setClassCache($this->expandClasses($classes, $existingClasses));
|
||||
$this->kernel->setAnnotatedClassCache($this->expandClasses($annotatedClasses, $existingClasses));
|
||||
}
|
||||
|
||||
/**
|
||||
* Expands the given class patterns using a list of existing classes.
|
||||
*
|
||||
* @param array $patterns The class patterns to expand
|
||||
* @param array $classes The existing classes to match against the patterns
|
||||
*
|
||||
* @return array A list of classes derivated from the patterns
|
||||
*/
|
||||
private function expandClasses(array $patterns, array $classes)
|
||||
{
|
||||
$expanded = array();
|
||||
|
||||
// Explicit classes declared in the patterns are returned directly
|
||||
foreach ($patterns as $key => $pattern) {
|
||||
if (substr($pattern, -1) !== '\\' && false === strpos($pattern, '*')) {
|
||||
unset($patterns[$key]);
|
||||
$expanded[] = ltrim($pattern, '\\');
|
||||
}
|
||||
}
|
||||
|
||||
// Match patterns with the classes list
|
||||
$regexps = $this->patternsToRegexps($patterns);
|
||||
|
||||
foreach ($classes as $class) {
|
||||
$class = ltrim($class, '\\');
|
||||
|
||||
if ($this->matchAnyRegexps($class, $regexps)) {
|
||||
$expanded[] = $class;
|
||||
}
|
||||
}
|
||||
|
||||
return array_unique($expanded);
|
||||
}
|
||||
|
||||
private function getClassesInComposerClassMaps()
|
||||
{
|
||||
$classes = array();
|
||||
|
||||
foreach (spl_autoload_functions() as $function) {
|
||||
if (!is_array($function)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if ($function[0] instanceof DebugClassLoader) {
|
||||
$function = $function[0]->getClassLoader();
|
||||
}
|
||||
|
||||
if (is_array($function) && $function[0] instanceof ClassLoader) {
|
||||
$classes += $function[0]->getClassMap();
|
||||
}
|
||||
}
|
||||
|
||||
return array_keys($classes);
|
||||
}
|
||||
|
||||
private function patternsToRegexps($patterns)
|
||||
{
|
||||
$regexps = array();
|
||||
|
||||
foreach ($patterns as $pattern) {
|
||||
// Escape user input
|
||||
$regex = preg_quote(ltrim($pattern, '\\'));
|
||||
|
||||
// Wildcards * and **
|
||||
$regex = strtr($regex, array('\\*\\*' => '.*?', '\\*' => '[^\\\\]*?'));
|
||||
|
||||
// If this class does not end by a slash, anchor the end
|
||||
if (substr($regex, -1) !== '\\') {
|
||||
$regex .= '$';
|
||||
}
|
||||
|
||||
$regexps[] = '{^\\\\'.$regex.'}';
|
||||
}
|
||||
|
||||
return $regexps;
|
||||
}
|
||||
|
||||
private function matchAnyRegexps($class, $regexps)
|
||||
{
|
||||
$blacklisted = false !== strpos($class, 'Test');
|
||||
|
||||
foreach ($regexps as $regex) {
|
||||
if ($blacklisted && false === strpos($regex, 'Test')) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (preg_match($regex, '\\'.$class)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
@ -21,6 +21,7 @@ use Symfony\Component\DependencyInjection\Extension\Extension as BaseExtension;
|
||||
abstract class Extension extends BaseExtension
|
||||
{
|
||||
private $classes = array();
|
||||
private $annotatedClasses = array();
|
||||
|
||||
/**
|
||||
* Gets the classes to cache.
|
||||
@ -32,13 +33,33 @@ abstract class Extension extends BaseExtension
|
||||
return $this->classes;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the annotated classes to cache.
|
||||
*
|
||||
* @return array An array of classes
|
||||
*/
|
||||
public function getAnnotatedClassesToCompile()
|
||||
{
|
||||
return $this->annotatedClasses;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds classes to the class cache.
|
||||
*
|
||||
* @param array $classes An array of classes
|
||||
* @param array $classes An array of class patterns
|
||||
*/
|
||||
public function addClassesToCompile(array $classes)
|
||||
{
|
||||
$this->classes = array_merge($this->classes, $classes);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds annotated classes to the class cache.
|
||||
*
|
||||
* @param array $annotatedClasses An array of class patterns
|
||||
*/
|
||||
public function addAnnotatedClassesToCompile(array $annotatedClasses)
|
||||
{
|
||||
$this->annotatedClasses = array_merge($this->annotatedClasses, $annotatedClasses);
|
||||
}
|
||||
}
|
||||
|
@ -329,13 +329,21 @@ abstract class Kernel implements KernelInterface, TerminableInterface
|
||||
}
|
||||
|
||||
/**
|
||||
* Used internally.
|
||||
* @internal
|
||||
*/
|
||||
public function setClassCache(array $classes)
|
||||
{
|
||||
file_put_contents($this->getCacheDir().'/classes.map', sprintf('<?php return %s;', var_export($classes, true)));
|
||||
}
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
public function setAnnotatedClassCache(array $annotatedClasses)
|
||||
{
|
||||
file_put_contents($this->getCacheDir().'/annotations.map', sprintf('<?php return %s;', var_export($annotatedClasses, true)));
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
|
@ -0,0 +1,97 @@
|
||||
<?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\HttpKernel\Tests\DependencyInjection;
|
||||
|
||||
use Symfony\Component\HttpKernel\DependencyInjection\AddClassesToCachePass;
|
||||
|
||||
class AddClassesToCachePassTest extends \PHPUnit_Framework_TestCase
|
||||
{
|
||||
public function testExpandClasses()
|
||||
{
|
||||
$r = new \ReflectionClass(AddClassesToCachePass::class);
|
||||
$pass = $r->newInstanceWithoutConstructor();
|
||||
$r = new \ReflectionMethod(AddClassesToCachePass::class, 'expandClasses');
|
||||
$expand = $r->getClosure($pass);
|
||||
|
||||
$this->assertSame('Foo', $expand(array('Foo'), array())[0]);
|
||||
$this->assertSame('Foo', $expand(array('\\Foo'), array())[0]);
|
||||
$this->assertSame('Foo', $expand(array('Foo'), array('\\Foo'))[0]);
|
||||
$this->assertSame('Foo', $expand(array('Foo'), array('Foo'))[0]);
|
||||
$this->assertSame('Foo', $expand(array('\\Foo'), array('\\Foo\\Bar'))[0]);
|
||||
$this->assertSame('Foo', $expand(array('Foo'), array('\\Foo\\Bar'))[0]);
|
||||
$this->assertSame('Foo', $expand(array('\\Foo'), array('\\Foo\\Bar\\Acme'))[0]);
|
||||
|
||||
$this->assertSame('Foo\\Bar', $expand(array('Foo\\'), array('\\Foo\\Bar'))[0]);
|
||||
$this->assertSame('Foo\\Bar\\Acme', $expand(array('Foo\\'), array('\\Foo\\Bar\\Acme'))[0]);
|
||||
$this->assertEmpty($expand(array('Foo\\'), array('\\Foo')));
|
||||
|
||||
$this->assertSame('Acme\\Foo\\Bar', $expand(array('**\\Foo\\'), array('\\Acme\\Foo\\Bar'))[0]);
|
||||
$this->assertEmpty($expand(array('**\\Foo\\'), array('\\Foo\\Bar')));
|
||||
$this->assertEmpty($expand(array('**\\Foo\\'), array('\\Acme\\Foo')));
|
||||
$this->assertEmpty($expand(array('**\\Foo\\'), array('\\Foo')));
|
||||
|
||||
$this->assertSame('Acme\\Foo', $expand(array('**\\Foo'), array('\\Acme\\Foo'))[0]);
|
||||
$this->assertEmpty($expand(array('**\\Foo'), array('\\Acme\\Foo\\AcmeBundle')));
|
||||
$this->assertEmpty($expand(array('**\\Foo'), array('\\Acme\\FooBar\\AcmeBundle')));
|
||||
|
||||
$this->assertSame('Foo\\Acme\\Bar', $expand(array('Foo\\*\\Bar'), array('\\Foo\\Acme\\Bar'))[0]);
|
||||
$this->assertEmpty($expand(array('Foo\\*\\Bar'), array('\\Foo\\Acme\\Bundle\\Bar')));
|
||||
|
||||
$this->assertSame('Foo\\Acme\\Bar', $expand(array('Foo\\**\\Bar'), array('\\Foo\\Acme\\Bar'))[0]);
|
||||
$this->assertSame('Foo\\Acme\\Bundle\\Bar', $expand(array('Foo\\**\\Bar'), array('\\Foo\\Acme\\Bundle\\Bar'))[0]);
|
||||
|
||||
$this->assertSame('Acme\\Bar', $expand(array('*\\Bar'), array('\\Acme\\Bar'))[0]);
|
||||
$this->assertEmpty($expand(array('*\\Bar'), array('\\Bar')));
|
||||
$this->assertEmpty($expand(array('*\\Bar'), array('\\Foo\\Acme\\Bar')));
|
||||
|
||||
$this->assertSame('Foo\\Acme\\Bar', $expand(array('**\\Bar'), array('\\Foo\\Acme\\Bar'))[0]);
|
||||
$this->assertSame('Foo\\Acme\\Bundle\\Bar', $expand(array('**\\Bar'), array('\\Foo\\Acme\\Bundle\\Bar'))[0]);
|
||||
$this->assertEmpty($expand(array('**\\Bar'), array('\\Bar')));
|
||||
|
||||
$this->assertSame('Foo\\Bar', $expand(array('Foo\\*'), array('\\Foo\\Bar'))[0]);
|
||||
$this->assertEmpty($expand(array('Foo\\*'), array('\\Foo\\Acme\\Bar')));
|
||||
|
||||
$this->assertSame('Foo\\Bar', $expand(array('Foo\\**'), array('\\Foo\\Bar'))[0]);
|
||||
$this->assertSame('Foo\\Acme\\Bar', $expand(array('Foo\\**'), array('\\Foo\\Acme\\Bar'))[0]);
|
||||
|
||||
$this->assertSame(array('Foo\\Bar'), $expand(array('Foo\\*'), array('Foo\\Bar', 'Foo\\BarTest')));
|
||||
$this->assertSame(array('Foo\\Bar', 'Foo\\BarTest'), $expand(array('Foo\\*', 'Foo\\*Test'), array('Foo\\Bar', 'Foo\\BarTest')));
|
||||
|
||||
$this->assertSame(
|
||||
'Acme\\FooBundle\\Controller\\DefaultController',
|
||||
$expand(array('**Bundle\\Controller\\'), array('\\Acme\\FooBundle\\Controller\\DefaultController'))[0]
|
||||
);
|
||||
|
||||
$this->assertSame(
|
||||
'FooBundle\\Controller\\DefaultController',
|
||||
$expand(array('**Bundle\\Controller\\'), array('\\FooBundle\\Controller\\DefaultController'))[0]
|
||||
);
|
||||
|
||||
$this->assertSame(
|
||||
'Acme\\FooBundle\\Controller\\Bar\\DefaultController',
|
||||
$expand(array('**Bundle\\Controller\\'), array('\\Acme\\FooBundle\\Controller\\Bar\\DefaultController'))[0]
|
||||
);
|
||||
|
||||
$this->assertSame(
|
||||
'Bundle\\Controller\\Bar\\DefaultController',
|
||||
$expand(array('**Bundle\\Controller\\'), array('\\Bundle\\Controller\\Bar\\DefaultController'))[0]
|
||||
);
|
||||
|
||||
$this->assertSame(
|
||||
'Acme\\Bundle\\Controller\\Bar\\DefaultController',
|
||||
$expand(array('**Bundle\\Controller\\'), array('\\Acme\\Bundle\\Controller\\Bar\\DefaultController'))[0]
|
||||
);
|
||||
|
||||
$this->assertSame('Foo\\Bar', $expand(array('Foo\\Bar'), array())[0]);
|
||||
$this->assertSame('Foo\\Acme\\Bar', $expand(array('Foo\\**'), array('\\Foo\\Acme\\Bar'))[0]);
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user