Merge branch '3.4'

* 3.4:
  [VarDumper] Fix tests with phpredis 3.1.3
  [Routing] Use "controller" keyword for configuring routes controllers
  [VarDumper] Fix interval caster with PT3600S-like spec
  [DI] Fix reading env vars from fastcgi params
  [HttpKernel] Remove old container files
  Allow phpdocumentor/reflection-docblock 4.
  [VarDumper] play nice with open_basedir when looking for composer.json
This commit is contained in:
Nicolas Grekas 2017-08-17 15:45:39 +02:00
commit 8a58d96111
31 changed files with 399 additions and 37 deletions

View File

@ -95,7 +95,7 @@
"symfony/phpunit-bridge": "~3.2",
"symfony/polyfill-apcu": "~1.1",
"symfony/security-acl": "~2.8|~3.0",
"phpdocumentor/reflection-docblock": "^3.0"
"phpdocumentor/reflection-docblock": "^3.0|^4.0"
},
"conflict": {
"phpdocumentor/reflection-docblock": "<3.0||>=3.2.0,<3.2.2",

View File

@ -55,7 +55,7 @@
"symfony/property-info": "~3.4|~4.0",
"symfony/web-link": "~3.4|~4.0",
"doctrine/annotations": "~1.0",
"phpdocumentor/reflection-docblock": "^3.0",
"phpdocumentor/reflection-docblock": "^3.0|^4.0",
"twig/twig": "~1.34|~2.4"
},
"conflict": {

View File

@ -54,20 +54,17 @@ final class ServiceLocatorTagPass extends AbstractRecursivePass
$value->setArguments($arguments);
if ($public = $value->isPublic()) {
$value->setPublic(false);
}
$id = 'service_locator.'.ContainerBuilder::hash($value);
if ($isRoot) {
if ($id !== $this->currentId) {
$this->container->setAlias($id, new Alias($this->currentId, $public));
$this->container->setAlias($id, new Alias($this->currentId, false));
}
return $value;
}
$this->container->setDefinition($id, $value);
$this->container->setDefinition($id, $value->setPublic(false));
return new Reference($id);
}

View File

@ -332,7 +332,7 @@ class Container implements ResettableContainerInterface
*
* @param string $name The name of the environment variable
*
* @return scalar The value to use for the provided environment variable name
* @return mixed The value to use for the provided environment variable name
*
* @throws EnvNotFoundException When the environment variable is not found and has no default value
*/
@ -341,6 +341,9 @@ class Container implements ResettableContainerInterface
if (isset($this->envCache[$name]) || array_key_exists($name, $this->envCache)) {
return $this->envCache[$name];
}
if (0 !== strpos($name, 'HTTP_') && isset($_SERVER[$name])) {
return $this->envCache[$name] = $_SERVER[$name];
}
if (isset($_ENV[$name])) {
return $this->envCache[$name] = $_ENV[$name];
}

View File

@ -682,9 +682,10 @@ class ContainerBuilder extends Container implements TaggedContainerInterface
$bag = $this->getParameterBag();
if ($resolveEnvPlaceholders && $bag instanceof EnvPlaceholderParameterBag) {
$this->parameterBag = new ParameterBag($this->resolveEnvPlaceholders($bag->all(), true));
$bag->resolveEnvReferences();
$this->parameterBag = new ParameterBag($bag->all());
$this->envPlaceholders = $bag->getEnvPlaceholders();
$this->parameterBag = $bag = new ParameterBag($this->resolveEnvPlaceholders($this->parameterBag->all()));
$this->parameterBag = $bag = new ParameterBag($this->resolveEnvPlaceholders($bag->all(), true));
}
$compiler->compile($this);
@ -699,7 +700,9 @@ class ContainerBuilder extends Container implements TaggedContainerInterface
parent::compile();
$this->envPlaceholders = $bag instanceof EnvPlaceholderParameterBag ? $bag->getEnvPlaceholders() : array();
if ($bag instanceof EnvPlaceholderParameterBag) {
$this->envPlaceholders = $bag->getEnvPlaceholders();
}
}
/**
@ -1251,10 +1254,10 @@ class ContainerBuilder extends Container implements TaggedContainerInterface
foreach ($envPlaceholders as $env => $placeholders) {
foreach ($placeholders as $placeholder) {
if (false !== stripos($value, $placeholder)) {
if (true === $format) {
$resolved = $bag->escapeValue($this->getEnv($env));
} else {
if (true !== $format) {
$resolved = sprintf($format, $env);
} elseif ($placeholder === $resolved = $bag->escapeValue($this->getEnv($env))) {
$resolved = $bag->all()[strtolower("env($env)")];
}
$value = str_ireplace($placeholder, $resolved, $value);
$usedEnvs[$env] = $env;

View File

@ -20,6 +20,7 @@ use Symfony\Component\DependencyInjection\Exception\InvalidArgumentException;
class EnvPlaceholderParameterBag extends ParameterBag
{
private $envPlaceholders = array();
private $resolveEnvReferences = false;
/**
* {@inheritdoc}
@ -101,4 +102,29 @@ class EnvPlaceholderParameterBag extends ParameterBag
}
}
}
/**
* Replaces "%env(FOO)%" references by their placeholder, keeping regular "%parameters%" references as is.
*/
public function resolveEnvReferences()
{
$this->resolveEnvReferences = true;
try {
$this->resolve();
} finally {
$this->resolveEnvReferences = false;
}
}
/**
* {@inheritdoc}
*/
public function resolveString($value, array $resolving = array())
{
if ($this->resolveEnvReferences) {
return preg_replace_callback('/%%|%(env\([^%\s]+\))%/', function ($match) { return isset($match[1]) ? $this->get($match[1]) : '%%'; }, $value);
}
return parent::resolveString($value, $resolving);
}
}

View File

@ -603,29 +603,37 @@ class ContainerBuilderTest extends TestCase
public function testResolveEnvValues()
{
$_ENV['DUMMY_ENV_VAR'] = 'du%%y';
$_SERVER['DUMMY_SERVER_VAR'] = 'ABC';
$_SERVER['HTTP_DUMMY_VAR'] = 'DEF';
$container = new ContainerBuilder();
$container->setParameter('bar', '%% %env(DUMMY_ENV_VAR)%');
$container->setParameter('bar', '%% %env(DUMMY_ENV_VAR)% %env(DUMMY_SERVER_VAR)% %env(HTTP_DUMMY_VAR)%');
$container->setParameter('env(HTTP_DUMMY_VAR)', '123');
$this->assertSame('%% du%%%%y', $container->resolveEnvPlaceholders('%bar%', true));
$this->assertSame('%% du%%%%y ABC 123', $container->resolveEnvPlaceholders('%bar%', true));
unset($_ENV['DUMMY_ENV_VAR']);
unset($_ENV['DUMMY_ENV_VAR'], $_SERVER['DUMMY_SERVER_VAR'], $_SERVER['HTTP_DUMMY_VAR']);
}
public function testCompileWithResolveEnv()
{
$_ENV['DUMMY_ENV_VAR'] = 'du%%y';
putenv('DUMMY_ENV_VAR=du%%y');
$_SERVER['DUMMY_SERVER_VAR'] = 'ABC';
$_SERVER['HTTP_DUMMY_VAR'] = 'DEF';
$container = new ContainerBuilder();
$container->setParameter('env(FOO)', 'Foo');
$container->setParameter('bar', '%% %env(DUMMY_ENV_VAR)%');
$container->setParameter('bar', '%% %env(DUMMY_ENV_VAR)% %env(DUMMY_SERVER_VAR)% %env(HTTP_DUMMY_VAR)%');
$container->setParameter('foo', '%env(FOO)%');
$container->setParameter('baz', '%foo%');
$container->setParameter('env(HTTP_DUMMY_VAR)', '123');
$container->compile(true);
$this->assertSame('% du%%y', $container->getParameter('bar'));
$this->assertSame('Foo', $container->getParameter('foo'));
$this->assertSame('% du%%y ABC 123', $container->getParameter('bar'));
$this->assertSame('Foo', $container->getParameter('baz'));
unset($_ENV['DUMMY_ENV_VAR']);
unset($_SERVER['DUMMY_SERVER_VAR'], $_SERVER['HTTP_DUMMY_VAR']);
putenv('DUMMY_ENV_VAR');
}
/**

View File

@ -527,6 +527,11 @@ abstract class Kernel implements KernelInterface, TerminableInterface
file_put_contents($this->getCacheDir().'/'.$class.'Compiler.log', null !== $container ? implode("\n", $container->getCompiler()->getLog()) : '');
}
}
if ($oldContainer = file_exists($cache->getPath()) ? @include $cache->getPath() : false) {
$oldContainer = new \ReflectionClass($oldContainer);
}
$this->dumpContainer($cache, $container, $class, $this->getContainerBaseClass());
$fresh = false;
@ -535,7 +540,15 @@ abstract class Kernel implements KernelInterface, TerminableInterface
$this->container = require $cache->getPath();
$this->container->set('kernel', $this);
if (!$fresh && $this->container->has('cache_warmer')) {
if ($fresh) {
return;
}
if ($oldContainer && get_class($this->container) !== $oldContainer->name) {
(new Filesystem())->remove(dirname($oldContainer->getFileName()));
}
if ($this->container->has('cache_warmer')) {
$this->container->get('cache_warmer')->warmUp($this->container->getParameter('kernel.cache_dir'));
}
}
@ -687,6 +700,9 @@ abstract class Kernel implements KernelInterface, TerminableInterface
@chmod($dir.$file, 0666 & ~umask());
}
// track changes made to the container directory
$container->fileExists(dirname($dir.$file));
$cache->write($rootCode, $container->getResources());
}

View File

@ -725,6 +725,40 @@ EOF;
$this->assertEquals('_123', $kernel->getName());
}
public function testProjectDirExtension()
{
$kernel = new CustomProjectDirKernel();
$kernel->boot();
$this->assertSame('foo', $kernel->getProjectDir());
$this->assertSame('foo', $kernel->getContainer()->getParameter('kernel.project_dir'));
}
public function testKernelReset()
{
(new Filesystem())->remove(__DIR__.'/Fixtures/cache');
$kernel = new CustomProjectDirKernel();
$kernel->boot();
$containerClass = get_class($kernel->getContainer());
$containerFile = (new \ReflectionClass($kernel->getContainer()))->getFileName();
unlink(__DIR__.'/Fixtures/cache/custom/FixturesCustomDebugProjectContainer.php.meta');
$kernel = new CustomProjectDirKernel();
$kernel->boot();
$this->assertSame($containerClass, get_class($kernel->getContainer()));
$this->assertFileExists($containerFile);
unlink(__DIR__.'/Fixtures/cache/custom/FixturesCustomDebugProjectContainer.php.meta');
$kernel = new CustomProjectDirKernel(function ($container) { $container->register('foo', 'stdClass'); });
$kernel->boot();
$this->assertTrue(get_class($kernel->getContainer()) !== $containerClass);
$this->assertFileNotExists($containerFile);
}
/**
* Returns a mock for the BundleInterface.
*
@ -825,12 +859,14 @@ class TestKernel implements HttpKernelInterface
class CustomProjectDirKernel extends Kernel
{
private $baseDir;
private $buildContainer;
public function __construct()
public function __construct(\Closure $buildContainer = null)
{
parent::__construct('test', false);
parent::__construct('custom', true);
$this->baseDir = 'foo';
$this->buildContainer = $buildContainer;
}
public function registerBundles()
@ -851,4 +887,11 @@ class CustomProjectDirKernel extends Kernel
{
return __DIR__.'/Fixtures';
}
protected function build(ContainerBuilder $container)
{
if ($build = $this->buildContainer) {
$build($container);
}
}
}

View File

@ -30,7 +30,7 @@
"symfony/serializer": "~3.4|~4.0",
"symfony/cache": "~3.4|~4.0",
"symfony/dependency-injection": "~3.4|~4.0",
"phpdocumentor/reflection-docblock": "^3.0",
"phpdocumentor/reflection-docblock": "^3.0|^4.0",
"doctrine/annotations": "~1.0"
},
"conflict": {

View File

@ -12,6 +12,7 @@ CHANGELOG
* Added support for prioritized routing loaders.
* Add matched and default parameters to redirect responses
* Added support for a `controller` keyword for configuring route controllers in YAML and XML configurations.
3.3.0
-----

View File

@ -229,6 +229,16 @@ class XmlFileLoader extends FileLoader
}
}
if ($controller = $node->getAttribute('controller')) {
if (isset($defaults['_controller'])) {
$name = $node->hasAttribute('id') ? sprintf('"%s"', $node->getAttribute('id')) : sprintf('the "%s" tag', $node->tagName);
throw new \InvalidArgumentException(sprintf('The routing file "%s" must not specify both the "controller" attribute and the defaults key "_controller" for %s.', $path, $name));
}
$defaults['_controller'] = $controller;
}
return array($defaults, $requirements, $options, $condition);
}

View File

@ -27,7 +27,7 @@ use Symfony\Component\Config\Loader\FileLoader;
class YamlFileLoader extends FileLoader
{
private static $availableKeys = array(
'resource', 'type', 'prefix', 'path', 'host', 'schemes', 'methods', 'defaults', 'requirements', 'options', 'condition',
'resource', 'type', 'prefix', 'path', 'host', 'schemes', 'methods', 'defaults', 'requirements', 'options', 'condition', 'controller',
);
private $yamlParser;
@ -115,6 +115,10 @@ class YamlFileLoader extends FileLoader
$methods = isset($config['methods']) ? $config['methods'] : array();
$condition = isset($config['condition']) ? $config['condition'] : null;
if (isset($config['controller'])) {
$defaults['_controller'] = $config['controller'];
}
$route = new Route($config['path'], $defaults, $requirements, $options, $host, $schemes, $methods, $condition);
$collection->add($name, $route);
@ -140,6 +144,10 @@ class YamlFileLoader extends FileLoader
$schemes = isset($config['schemes']) ? $config['schemes'] : null;
$methods = isset($config['methods']) ? $config['methods'] : null;
if (isset($config['controller'])) {
$defaults['_controller'] = $config['controller'];
}
$this->setCurrentDir(dirname($path));
$subCollection = $this->import($config['resource'], $type, false, $file);
@ -203,5 +211,8 @@ class YamlFileLoader extends FileLoader
$name, $path
));
}
if (isset($config['controller']) && isset($config['defaults']['_controller'])) {
throw new \InvalidArgumentException(sprintf('The routing file "%s" must not specify both the "controller" key and the defaults key "_controller" for "%s".', $path, $name));
}
}
}

View File

@ -41,6 +41,7 @@
<xsd:attribute name="host" type="xsd:string" />
<xsd:attribute name="schemes" type="xsd:string" />
<xsd:attribute name="methods" type="xsd:string" />
<xsd:attribute name="controller" type="xsd:string" />
</xsd:complexType>
<xsd:complexType name="import">
@ -52,6 +53,7 @@
<xsd:attribute name="host" type="xsd:string" />
<xsd:attribute name="schemes" type="xsd:string" />
<xsd:attribute name="methods" type="xsd:string" />
<xsd:attribute name="controller" type="xsd:string" />
</xsd:complexType>
<xsd:complexType name="default" mixed="true">

View File

@ -0,0 +1,10 @@
<?xml version="1.0" encoding="UTF-8" ?>
<routes xmlns="http://symfony.com/schema/routing"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://symfony.com/schema/routing
http://symfony.com/schema/routing/routing-1.0.xsd">
<import resource="routing.xml">
<default key="_controller">FrameworkBundle:Template:template</default>
</import>
</routes>

View File

@ -0,0 +1,4 @@
_static:
resource: routing.yml
defaults:
_controller: FrameworkBundle:Template:template

View File

@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8" ?>
<routes xmlns="http://symfony.com/schema/routing"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://symfony.com/schema/routing
http://symfony.com/schema/routing/routing-1.0.xsd">
<import resource="routing.xml" controller="FrameworkBundle:Template:template" />
</routes>

View File

@ -0,0 +1,3 @@
_static:
resource: routing.yml
controller: FrameworkBundle:Template:template

View File

@ -0,0 +1,10 @@
<?xml version="1.0" encoding="UTF-8" ?>
<routes xmlns="http://symfony.com/schema/routing"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://symfony.com/schema/routing
http://symfony.com/schema/routing/routing-1.0.xsd">
<import resource="routing.xml" controller="FrameworkBundle:Template:template">
<default key="_controller">AppBundle:Blog:index</default>
</import>
</routes>

View File

@ -0,0 +1,5 @@
_static:
resource: routing.yml
controller: FrameworkBundle:Template:template
defaults:
_controller: AppBundle:Homepage:show

View File

@ -0,0 +1,10 @@
<?xml version="1.0" encoding="UTF-8" ?>
<routes xmlns="http://symfony.com/schema/routing"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://symfony.com/schema/routing
http://symfony.com/schema/routing/routing-1.0.xsd">
<route id="app_blog" path="/blog" controller="AppBundle:Homepage:show">
<default key="_controller">AppBundle:Blog:index</default>
</route>
</routes>

View File

@ -0,0 +1,5 @@
app_blog:
path: /blog
controller: AppBundle:Homepage:show
defaults:
_controller: AppBundle:Blog:index

View File

@ -0,0 +1,14 @@
<?xml version="1.0" encoding="UTF-8" ?>
<routes xmlns="http://symfony.com/schema/routing"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://symfony.com/schema/routing
http://symfony.com/schema/routing/routing-1.0.xsd">
<route id="app_homepage" path="/" controller="AppBundle:Homepage:show" />
<route id="app_blog" path="/blog">
<default key="_controller">AppBundle:Blog:list</default>
</route>
<route id="app_logout" path="/logout" />
</routes>

View File

@ -0,0 +1,11 @@
app_homepage:
path: /
controller: AppBundle:Homepage:show
app_blog:
path: /blog
defaults:
_controller: AppBundle:Blog:list
app_logout:
path: /logout

View File

@ -287,4 +287,78 @@ class XmlFileLoaderTest extends TestCase
$route->getDefault('map')
);
}
public function testLoadRouteWithControllerAttribute()
{
$loader = new XmlFileLoader(new FileLocator(array(__DIR__.'/../Fixtures/controller')));
$routeCollection = $loader->load('routing.xml');
$route = $routeCollection->get('app_homepage');
$this->assertSame('AppBundle:Homepage:show', $route->getDefault('_controller'));
}
public function testLoadRouteWithoutControllerAttribute()
{
$loader = new XmlFileLoader(new FileLocator(array(__DIR__.'/../Fixtures/controller')));
$routeCollection = $loader->load('routing.xml');
$route = $routeCollection->get('app_logout');
$this->assertNull($route->getDefault('_controller'));
}
public function testLoadRouteWithControllerSetInDefaults()
{
$loader = new XmlFileLoader(new FileLocator(array(__DIR__.'/../Fixtures/controller')));
$routeCollection = $loader->load('routing.xml');
$route = $routeCollection->get('app_blog');
$this->assertSame('AppBundle:Blog:list', $route->getDefault('_controller'));
}
/**
* @expectedException \InvalidArgumentException
* @expectedExceptionMessageRegExp /The routing file "[^"]*" must not specify both the "controller" attribute and the defaults key "_controller" for "app_blog"/
*/
public function testOverrideControllerInDefaults()
{
$loader = new XmlFileLoader(new FileLocator(array(__DIR__.'/../Fixtures/controller')));
$loader->load('override_defaults.xml');
}
/**
* @dataProvider provideFilesImportingRoutesWithControllers
*/
public function testImportRouteWithController($file)
{
$loader = new XmlFileLoader(new FileLocator(array(__DIR__.'/../Fixtures/controller')));
$routeCollection = $loader->load($file);
$route = $routeCollection->get('app_homepage');
$this->assertSame('FrameworkBundle:Template:template', $route->getDefault('_controller'));
$route = $routeCollection->get('app_blog');
$this->assertSame('FrameworkBundle:Template:template', $route->getDefault('_controller'));
$route = $routeCollection->get('app_logout');
$this->assertSame('FrameworkBundle:Template:template', $route->getDefault('_controller'));
}
public function provideFilesImportingRoutesWithControllers()
{
yield array('import_controller.xml');
yield array('import__controller.xml');
}
/**
* @expectedException \InvalidArgumentException
* @expectedExceptionMessageRegExp /The routing file "[^"]*" must not specify both the "controller" attribute and the defaults key "_controller" for the "import" tag/
*/
public function testImportWithOverriddenController()
{
$loader = new XmlFileLoader(new FileLocator(array(__DIR__.'/../Fixtures/controller')));
$loader->load('import_override_defaults.xml');
}
}

View File

@ -108,4 +108,78 @@ class YamlFileLoaderTest extends TestCase
$this->assertSame('context.getMethod() == "POST"', $route->getCondition());
}
}
public function testLoadRouteWithControllerAttribute()
{
$loader = new YamlFileLoader(new FileLocator(array(__DIR__.'/../Fixtures/controller')));
$routeCollection = $loader->load('routing.yml');
$route = $routeCollection->get('app_homepage');
$this->assertSame('AppBundle:Homepage:show', $route->getDefault('_controller'));
}
public function testLoadRouteWithoutControllerAttribute()
{
$loader = new YamlFileLoader(new FileLocator(array(__DIR__.'/../Fixtures/controller')));
$routeCollection = $loader->load('routing.yml');
$route = $routeCollection->get('app_logout');
$this->assertNull($route->getDefault('_controller'));
}
public function testLoadRouteWithControllerSetInDefaults()
{
$loader = new YamlFileLoader(new FileLocator(array(__DIR__.'/../Fixtures/controller')));
$routeCollection = $loader->load('routing.yml');
$route = $routeCollection->get('app_blog');
$this->assertSame('AppBundle:Blog:list', $route->getDefault('_controller'));
}
/**
* @expectedException \InvalidArgumentException
* @expectedExceptionMessageRegExp /The routing file "[^"]*" must not specify both the "controller" key and the defaults key "_controller" for "app_blog"/
*/
public function testOverrideControllerInDefaults()
{
$loader = new YamlFileLoader(new FileLocator(array(__DIR__.'/../Fixtures/controller')));
$loader->load('override_defaults.yml');
}
/**
* @dataProvider provideFilesImportingRoutesWithControllers
*/
public function testImportRouteWithController($file)
{
$loader = new YamlFileLoader(new FileLocator(array(__DIR__.'/../Fixtures/controller')));
$routeCollection = $loader->load($file);
$route = $routeCollection->get('app_homepage');
$this->assertSame('FrameworkBundle:Template:template', $route->getDefault('_controller'));
$route = $routeCollection->get('app_blog');
$this->assertSame('FrameworkBundle:Template:template', $route->getDefault('_controller'));
$route = $routeCollection->get('app_logout');
$this->assertSame('FrameworkBundle:Template:template', $route->getDefault('_controller'));
}
public function provideFilesImportingRoutesWithControllers()
{
yield array('import_controller.yml');
yield array('import__controller.yml');
}
/**
* @expectedException \InvalidArgumentException
* @expectedExceptionMessageRegExp /The routing file "[^"]*" must not specify both the "controller" key and the defaults key "_controller" for "_static"/
*/
public function testImportWithOverriddenController()
{
$loader = new YamlFileLoader(new FileLocator(array(__DIR__.'/../Fixtures/controller')));
$loader->load('import_override_defaults.yml');
}
}

View File

@ -28,7 +28,7 @@
"doctrine/annotations": "~1.0",
"symfony/dependency-injection": "~3.4|~4.0",
"doctrine/cache": "~1.0",
"phpdocumentor/reflection-docblock": "~3.0"
"phpdocumentor/reflection-docblock": "^3.0|^4.0"
},
"conflict": {
"symfony/dependency-injection": "<3.4",

View File

@ -52,13 +52,16 @@ class DateCaster
private static function formatInterval(\DateInterval $i)
{
$format = '%R '
.($i->y ? '%yy ' : '')
.($i->m ? '%mm ' : '')
.($i->d ? '%dd ' : '')
.($i->h || $i->i || $i->s || $i->f ? '%H:%I:'.self::formatSeconds($i->s, $i->f) : '')
;
$format = '%R ';
if ($i->y === 0 && $i->m === 0 && ($i->h >= 24 || $i->i >= 60 || $i->s >= 60)) {
$i = date_diff($d = new \DateTime(), date_add(clone $d, $i)); // recalculate carry over points
$format .= 0 < $i->days ? '%ad ' : '';
} else {
$format .= ($i->y ? '%yy ' : '').($i->m ? '%mm ' : '').($i->d ? '%dd ' : '');
}
$format .= $i->h || $i->i || $i->s || $i->f ? '%H:%I:'.self::formatSeconds($i->s, $i->f) : '';
$format = '%R ' === $format ? '0s' : $format;
return $i->format(rtrim($format));

View File

@ -89,7 +89,11 @@ class LinkStub extends ConstStub
}
$parent = $dir;
while (!file_exists($parent.'/composer.json')) {
while (!@file_exists($parent.'/composer.json')) {
if (!@file_exists($parent)) {
// open_basedir restriction in effect
break;
}
if ($parent === dirname($parent)) {
return self::$composerRoots[$dir] = false;
}

View File

@ -173,6 +173,10 @@ EODUMP;
array('P5M', 0, '+ 5m', null),
array('P6Y', 0, '+ 6y', null),
array('P1Y2M3DT4H5M6S', 0, '+ 1y 2m 3d 04:05:06.0', null),
array('PT1M60S', 0, '+ 00:02:00.0', null),
array('PT1H60M', 0, '+ 02:00:00.0', null),
array('P1DT24H', 0, '+ 2d', null),
array('P1M32D', 0, '+ 1m 32d', null),
array('PT0S', 1, '0s', '0s'),
array('PT1S', 1, '- 00:00:01.0', '-1s'),
@ -182,6 +186,10 @@ EODUMP;
array('P5M', 1, '- 5m', null),
array('P6Y', 1, '- 6y', null),
array('P1Y2M3DT4H5M6S', 1, '- 1y 2m 3d 04:05:06.0', null),
array('PT1M60S', 1, '- 00:02:00.0', null),
array('PT1H60M', 1, '- 02:00:00.0', null),
array('P1DT24H', 1, '- 2d', null),
array('P1M32D', 1, '- 1m 32d', null),
);
}

View File

@ -44,8 +44,7 @@ EODUMP;
}
$xCast = <<<'EODUMP'
Redis {
+"socket": Redis Socket Buffer resource
Redis {%A
isConnected: true
host: "127.0.0.1"
port: 6379