Merge branch '3.1'

* 3.1: (24 commits)
  [Yaml] fix exception contexts
  Added people - person inflection
  People - person singularization
  [Yaml] properly handle unindented collections
  [Serializer] Add test for ignored attributes during denormalization
  chomp newlines only at the end of YAML documents
  Fixed server status command when port has been omitted
  Update UPGRADE FROM 2.x to 3.0
  [Config] Allow schemed path in FileResource
  fix removed commands wording in upgrade file
  Catch \Throwable
  Catch \Throwable
  [DependencyInjection] Avoid generating call_user_func in more cases
  [Validator] Support for DateTimeImmutable
  [YAML] fixed "dump" signature in upgrade file
  [Cache] Rename nonce to version
  [FrameworkBundle] update upgrade instructions
  Use levenshtein level for better Bundle matching
  [WebProfilerBundle] Fix CORS ajax security issues
  remove methods that were needed for PHP 5.3
  ...
This commit is contained in:
Fabien Potencier 2016-05-24 12:07:02 +02:00
commit cf4e2e9cea
33 changed files with 451 additions and 82 deletions

136
CHANGELOG-3.1.md Normal file
View File

@ -0,0 +1,136 @@
CHANGELOG for 3.1.x
===================
This changelog references the relevant changes (bug and security fixes) done
in 3.1 minor versions.
To get the diff for a specific change, go to https://github.com/symfony/symfony/commit/XXX where XXX is the change hash
To get the diff between two versions, go to https://github.com/symfony/symfony/compare/v3.1.0...v3.1.1
* 3.1.0-BETA1 (2016-05-13)
* feature #18725 [Ldap] Added the possibility to configure all available Ldap options for connection (csarrazi)
* feature #18715 [FrameworkBundle] Default to Apcu+Filesystem cache chain (nicolas-grekas)
* feature #18184 [DomCrawler] Expose getter for uri (hason)
* feature #18654 [Bridge/Doctrine] Use better exception in the register mapping pass (dantleech)
* feature #18676 [HttpKernel] Add request method to logger messages (gnat42)
* feature #18716 [Cache] Add nonce based cache invalidation to ApcuAdapter (nicolas-grekas)
* feature #18762 [Translation] XLIFF Add `id` to meta data. (SpacePossum)
* feature #18689 [Cache] Add support for Predis, RedisArray and RedisCluster (nicolas-grekas)
* feature #18667 [FrameworkBundle] Semantic config for app/system/pool caches (tgalopin, nicolas-grekas)
* feature #18685 move event listener method type hint docs to @Event annotations defau… (Haehnchen)
* feature #18681 [Cache] Add DSN based Redis connection factory (nicolas-grekas)
* feature #18656 Updating the error message of an AuthenticationEntryPointInterface (weaverryan)
* feature #18069 [DoctrineBridge] deprecate `MergeDoctrineCollectionListener::onBind()` (HeahDude)
* feature #18492 [LDAP] Check whether an entry attribute exists (hiddewie)
* feature #18359 [Form] [DoctrineBridge] optimized LazyChoiceList and DoctrineChoiceLoader (HeahDude)
* feature #18357 [Form] Let `TextType` implement `DataTransformerInterface` (HeahDude)
* feature #18631 [FrameworkBundle] Add optional logger to cache pools (nicolas-grekas)
* feature #18597 [Cache] Add CacheItem::validateKey utility method (nicolas-grekas)
* feature #17660 [Serializer] Integrate the PropertyInfo Component (recursive denormalization and hardening) (mihai-stancu, dunglas)
* feature #18561 [FrameworkBundle] Fallback to default cache system in production for serializer (tgalopin)
* feature #18567 [FrameworkBundle][Serializer] Fix APC cache service name (tgalopin)
* feature #17959 [Serializer] Harden the ObjectNormalizer (dunglas)
* feature #18547 DX: better error message if factory class is empty (dbu)
* feature #18020 fix #17993 - Deprecated callable strings (hamza)
* feature #18487 [Cache] Add DoctrineProvider, for using PSR-6 pools in Doctrine Cache (nicolas-grekas)
* feature #18544 [FrameworkBundle] Fallback to default cache system in production for validation (tgalopin)
* feature #18416 [FrameworkBundle] Calls support for debug:container (JhonnyL)
* feature #18513 [Process] Turn getIterator() args to flags & add ITER_SKIP_OUT/ERR modes (nicolas-grekas)
* feature #18371 [FrameworkBundle] integrate the Cache component (xabbuh, nicolas-grekas)
* feature #18440 Add the kernel.controller_arguments event (stof)
* feature #18308 Added an ArgumentResolver with clean extension point (iltar, HeahDude)
* feature #18414 [Process] Implement IteratorAggregate to stream output (nicolas-grekas)
* feature #18144 [DI] Only rebuild autowiring cache when actually needed (weaverryan)
* feature #18386 [Process] Add InputStream to seamlessly feed running processes (nicolas-grekas)
* feature #18167 [DependencyInjection] Fix a limitation of the PhpDumper (Ener-Getick)
* feature #18387 [DX] [LDAP] Added default service name for the Security component's Ldap providers (csarrazi)
* feature #18290 [Translation] deprecate the backup feature (xabbuh)
* feature #18036 [Serializer] XmlEncoder: Make load flags configurable (dunglas)
* feature #17589 [WebProfilerBundle] [DX] Feature allow forward and redirection detection in wdt (HeahDude)
* feature #18260 Add Inflector component (from StringUtil of PropertyAccess) (teohhanhui)
* feature #18356 [FrameworkBundle] Deprecated form types as services (HeahDude)
* feature #17458 Add strict image validation (Koc)
* feature #18350 [Process] Accept Traversable input (nicolas-grekas)
* feature #18135 [Security] Deprecate onAuthenticationSuccess() (weaverryan)
* feature #18294 [Yaml] dump non UTF-8 encoded strings as binary data (xabbuh)
* feature #18215 [Cache] Add a Chain adapter (dunglas, nicolas-grekas)
* feature #18242 [FrameworkBundle][TwigBundle] Make EngineInterface autowirable (dunglas)
* feature #18197 Make Request::isFromTrustedProxy() public. (Peter Bex)
* feature #18211 [Security] Use auth trust resolver to determine anonymous in ContextListener (WouterJ)
* feature #18232 [Bridge\PhpUnit] Add "disabled" mode to SYMFONY_DEPRECATIONS_HELPER (nicolas-grekas)
* feature #18181 [PhpUnitBridge] Mock DNS functions (nicolas-grekas)
* feature #18176 [Cache] Restrict flushes to namespace scopes (nicolas-grekas)
* feature #18172 [Cache] Redis adapter (gcds, nicolas-grekas)
* feature #18101 [Console] Allow to register commands privately (Ener-Getick)
* feature #18143 [DomCrawler] Exposed getter for baseHref (AAstakhov)
* feature #18034 [FrameworkBundle] Deprecate absolute template paths (jakzal)
* feature #18105 [HttpFoundation] Add support for sending raw cookies in the response (jakzal)
* feature #17255 [Console] ApplicationTester - test stdout and stderr (SpacePossum)
* feature #18024 [Cache] Add namespace handling to all adapters (nicolas-grekas)
* feature #17734 [Cache] Count cache hits/misses in ProxyAdapter (nicolas-grekas)
* feature #17887 Show more information in the security profiler (javiereguiluz)
* feature #17642 [FrameworkBundle] [DX] Add `Controller::json` method to make it easy to send json (mcfedr)
* feature #17484 [FrameworkBundle][DX] Add Levenshtein suggesters to AbstractConfigCommand (kix)
* feature #17690 [FrameworkBundle] Use canBeEnabled() instead of canBeUnset() for consistency (Ener-Getick)
* feature #17714 Adding new TargetPathTrait to get/set the authentication "target_path" (weaverryan)
* feature #17852 Improved the logger panel when the log context is very long (javiereguiluz)
* feature #17761 [Console] Add non-auto column width functionality (akeeman)
* feature #17943 [Yaml] option to dump multi line strings as scalar blocks (xabbuh)
* feature #17553 [Validator] Added a format option to the DateTime constraint. (dosten)
* feature #17728 [Yaml] add option to dump objects as maps (xabbuh)
* feature #17863 [Yaml] add support for parsing the !!binary tag (xabbuh)
* feature #17738 [PropertyAccess] Throw an InvalidArgumentException when the type do not match (dunglas)
* feature #17531 [PropertyInfo] Use last version of reflection docblock (joelwurtz)
* feature #17782 Support autowiring for Doctrine\Common\Annotations\Reader (maryo)
* feature #17603 [Serializer] Add a normalizer that support JsonSerializable objects (mcfedr)
* feature #17630 [FrameworkBundle] Register the DateTimeNormalizer (dunglas)
* feature #17631 [FrameworkBundle] Register the DataUriNormalizer (dunglas)
* feature #17545 [Serializer] Add normalizer / denormalizer awarness (joelwurtz)
* feature #17877 [DependencyInjection] Improving autowiring error messages (weaverryan)
* feature #17732 [DEPRECATION] : deprecated support for Traversable in method ResizeFormListener::PreSubmit (ybensacq)
* feature #17721 [Cache] Add FilesystemAdapter (nicolas-grekas)
* feature #17836 [Yaml] support to parse and dump DateTime objects (xabbuh)
* feature #17809 [Yaml] deprecate starting plain scalars with characters (xabbuh)
* feature #17817 [Ldap] Add write support for the Ldap component (csarrazi)
* feature #17560 [Ldap] Improving the LDAP component (csarrazi)
* feature #17726 [FrameworkBundle] Improve debug:container command (voronkovich)
* feature #17743 [Yaml] dumper flag for enabling exceptions on invalid type (xabbuh)
* feature #17746 [Yaml] deprecate the Dumper::setIndentation() method (xabbuh)
* feature #17730 [Yaml] introduce flags to customize the parser behavior (xabbuh)
* feature #17125 Webprofiler add status code to search form (oktapodia)
* feature #17705 [TwigBridge] deprecate the boolean object support trigger (xabbuh)
* feature #17578 [Yaml] dump customization option with dumper flags (xabbuh)
* feature #17585 [DomCrawler] Abstract URI logic and crawl images (valeriangalliat)
* feature #17654 [Cache] Don't clone, serialize (nicolas-grekas)
* feature #16947 [FrameworkBundle] PropertyInfo: register the SerializerExtractor (dunglas)
* feature #17611 [HttpKernel] Deprecate passing objects as URI attributes to the ESI and SSI renderers (jakzal)
* feature #14288 [Console] Add getters for Application::$autoExit and $catchExceptions (VasekPurchart)
* feature #17504 [Console] Show code when an exception is thrown (maidmaid)
* feature #17540 [WebProfilerBundle] Add HTTP return code in the Ajax request list table (kucharovic)
* feature #17446 [Serializer] Add PSR-6 adapter (dunglas)
* feature #16917 [PropertyInfo] Cache support (dunglas)
* feature #17532 [Asset] Version as service (ewgRa)
* feature #17440 [Validator] Add a PSR-6 adapter (dunglas)
* feature #17113 [Serializer] Add a MaxDepth option (dunglas)
* feature #17530 [Cache] Handle and log errors properly (nicolas-grekas)
* feature #17522 [Cache] Use generator in ArrayAdapter (gcds)
* feature #16164 [Serializer] Add a data: URI normalizer (dunglas)
* feature #15279 Added {{ value }} message placeholder to UniqueEntityValidator (jperovic)
* feature #16652 [console] Add truncate method to FormatterHelper (mheki)
* feature #17438 [Cache] Allow and use generators in AbstractAdapter (nicolas-grekas)
* feature #17111 [HttpKernel] added a setter for the headers property in the HttpException (smatyas)
* feature #17132 [DependencyInjection] Properly ignore invalid reference arguments in collection arguments (ogizanagi)
* feature #17427 [Process] Allow a callback whenever the output is disabled (romainneutron)
* feature #17327 Added support links to exception and toolbar (peterrehm)
* feature #16909 Allows access to payload in callback validator (conradkleinespel)
* feature #17402 [Profiler] make it possible to omit the link var (xabbuh)
* feature #17411 [Serializer] Add a new DateTime normalizer (dunglas)
* feature #17462 [Yaml] deprecate parsing the !!php/object tag (xabbuh)
* feature #17408 [Cache] Symfony PSR-6 implementation (nicolas-grekas)
* feature #17323 [DependencyInjection] Deprecate unsupported attributes/elements for alias (Ener-Getick)
* feature #17305 [VarDumper] Add flags to allow fine tuning dumps representation (nicolas-grekas)
* feature #17318 [HttpFoundation] Allow to get all the mime types associated to a format in the Request (Ener-Getick)
* feature #17133 [DependencyInjection] Make YamlFileLoader raise a deprecation notice if a service definition contains unsupported keywords. (hhamon)
* feature #17191 [Serializer] Move the normalization logic in an abstract class (dunglas)
* feature #16994 [Form] Deprecate the "choices_as_values" option of ChoiceType (nicolas-grekas)

View File

@ -398,8 +398,11 @@ UPGRADE FROM 2.x to 3.0
</service>
```
* The `ChoiceToBooleanArrayTransformer`, `ChoicesToBooleanArrayTransformer`,
`FixRadioInputListener`, and `FixCheckboxInputListener` classes were removed.
* The `max_length` option was removed. Use the `attr` option instead by setting it to
an `array` with a `maxlength` key.
* The `ChoiceToBooleanArrayTransformer`, `ChoicesToBooleanArrayTransformer`,
`FixRadioInputListener`, and `FixCheckboxInputListener` classes were removed.
* The `choice_list` option of `ChoiceType` was removed.
@ -636,6 +639,11 @@ UPGRADE FROM 2.x to 3.0
be removed in Symfony 3.0. Use the `debug:config`, `debug:container`,
`debug:router`, `debug:translation` and `lint:yaml` commands instead.
* The base `Controller`class is now abstract.
* The visibility of all methods of the base `Controller` class has been changed from
`public` to `protected`.
* The `getRequest` method of the base `Controller` class has been deprecated
since Symfony 2.4 and must be therefore removed in 3.0. The only reliable
way to get the `Request` object is to inject it in the action method.
@ -1737,8 +1745,7 @@ UPGRADE FROM 2.x to 3.0
### WebProfiler
* The `profiler:import` and `profiler:export` commands have been deprecated and
will be removed in 3.0.
* The `profiler:import` and `profiler:export` commands have been removed.
* All the profiler storages different than `FileProfilerStorage` have been
removed. The removed classes are:

View File

@ -202,7 +202,7 @@ Yaml
After:
```php
Yaml::dump(array('foo' => new A(), 'bar' => 1), 0, 0, false, Yaml::DUMP_OBJECT);
Yaml::dump(array('foo' => new A(), 'bar' => 1), 0, 0, Yaml::DUMP_OBJECT);
```
* The `!!php/object` tag to indicate dumped PHP objects has been deprecated

View File

@ -13,6 +13,7 @@ namespace Symfony\Bundle\FrameworkBundle\Command;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Console\Style\SymfonyStyle;
@ -32,6 +33,7 @@ class ServerStatusCommand extends ServerCommand
$this
->setDefinition(array(
new InputArgument('address', InputArgument::OPTIONAL, 'Address:port', '127.0.0.1:8000'),
new InputOption('port', 'p', InputOption::VALUE_REQUIRED, 'Address port number', '8000'),
))
->setName('server:status')
->setDescription('Outputs the status of the built-in web server for the given address')
@ -46,6 +48,10 @@ class ServerStatusCommand extends ServerCommand
$io = new SymfonyStyle($input, $output);
$address = $input->getArgument('address');
if (false === strpos($address, ':')) {
$address = $address.':'.$input->getOption('port');
}
// remove an orphaned lock file
if (file_exists($this->getLockFile($address)) && !$this->isServerRunning($address)) {
unlink($this->getLockFile($address));

View File

@ -142,6 +142,7 @@ class ControllerNameParser
$lev = levenshtein($nonExistentBundleName, $bundleName);
if ($lev <= strlen($nonExistentBundleName) / 3 && ($alternative === null || $lev < $shortest)) {
$alternative = $bundleName;
$shortest = $lev;
}
}

View File

@ -1037,9 +1037,9 @@ class FrameworkExtension extends Extension
private function registerCacheConfiguration(array $config, ContainerBuilder $container, XmlFileLoader $loader)
{
$nonce = substr(str_replace('/', '-', base64_encode(md5(uniqid(mt_rand(), true), true))), 0, -2);
$container->getDefinition('cache.adapter.apcu')->replaceArgument(2, $nonce);
$container->getDefinition('cache.adapter.system')->replaceArgument(2, $nonce);
$version = substr(str_replace('/', '-', base64_encode(md5(uniqid(mt_rand(), true), true))), 0, -2);
$container->getDefinition('cache.adapter.apcu')->replaceArgument(2, $version);
$container->getDefinition('cache.adapter.system')->replaceArgument(2, $version);
$container->getDefinition('cache.adapter.filesystem')->replaceArgument(2, $config['directory']);
foreach (array('doctrine', 'psr6', 'redis') as $name) {

View File

@ -28,7 +28,7 @@
<tag name="monolog.logger" channel="cache" />
<argument /> <!-- namespace -->
<argument /> <!-- default lifetime -->
<argument /> <!-- nonce -->
<argument /> <!-- version -->
<argument>%kernel.cache_dir%/pools</argument>
<argument type="service" id="logger" on-invalid="ignore" />
</service>
@ -38,7 +38,7 @@
<tag name="monolog.logger" channel="cache" />
<argument /> <!-- namespace -->
<argument /> <!-- default lifetime -->
<argument /> <!-- nonce -->
<argument /> <!-- version -->
<call method="setLogger">
<argument type="service" id="logger" on-invalid="ignore" />
</call>

View File

@ -59,8 +59,8 @@ class ControllerNameParserTest extends TestCase
{
$parser = $this->createParser();
$this->assertEquals('FooBundle:Default:index', $parser->build('TestBundle\FooBundle\Controller\DefaultController::indexAction'), '->parse() converts a class::method string to a short a:b:c notation string');
$this->assertEquals('FooBundle:Sub\Default:index', $parser->build('TestBundle\FooBundle\Controller\Sub\DefaultController::indexAction'), '->parse() converts a class::method string to a short a:b:c notation string');
$this->assertEquals('FoooooBundle:Default:index', $parser->build('TestBundle\FooBundle\Controller\DefaultController::indexAction'), '->parse() converts a class::method string to a short a:b:c notation string');
$this->assertEquals('FoooooBundle:Sub\Default:index', $parser->build('TestBundle\FooBundle\Controller\Sub\DefaultController::indexAction'), '->parse() converts a class::method string to a short a:b:c notation string');
try {
$parser->build('TestBundle\FooBundle\Controller\DefaultController::index');
@ -132,8 +132,9 @@ class ControllerNameParserTest extends TestCase
public function getInvalidBundleNameTests()
{
return array(
array('FoodBundle:Default:index', 'FooBundle:Default:index'),
array('CrazyBundle:Default:index', false),
'Alternative will be found using levenshtein' => array('FoodBundle:Default:index', 'FooBundle:Default:index'),
'Alternative will be found using partial match' => array('FabpotFooBund:Default:index', 'FabpotFooBundle:Default:index'),
'Bundle does not exist at all' => array('CrazyBundle:Default:index', false),
);
}
@ -162,6 +163,7 @@ class ControllerNameParserTest extends TestCase
$bundles = array(
'SensioFooBundle' => $this->getBundle('TestBundle\Fabpot\FooBundle', 'FabpotFooBundle'),
'SensioCmsFooBundle' => $this->getBundle('TestBundle\Sensio\Cms\FooBundle', 'SensioCmsFooBundle'),
'FoooooBundle' => $this->getBundle('TestBundle\FooBundle', 'FoooooBundle'),
'FooBundle' => $this->getBundle('TestBundle\FooBundle', 'FooBundle'),
'FabpotFooBundle' => $this->getBundle('TestBundle\Fabpot\FooBundle', 'FabpotFooBundle'),
);

View File

@ -82,6 +82,20 @@
requestStack = [],
extractHeaders = function(xhr, stackElement) {
// Here we avoid to call xhr.getResponseHeader in order to
// prevent polluting the console with CORS security errors
var allHeaders = xhr.getAllResponseHeaders();
var ret;
if (ret = allHeaders.match(/^x-debug-token:\s+(.*)$/im)) {
stackElement.profile = ret[1];
}
if (ret = allHeaders.match(/^x-debug-token-link:\s+(.*)$/im)) {
stackElement.profilerUrl = ret[1];
}
},
renderAjaxRequests = function() {
var requestCounter = document.querySelectorAll('.sf-toolbar-ajax-requests');
if (!requestCounter.length) {
@ -255,8 +269,7 @@
stackElement.loading = false;
stackElement.error = self.status < 200 || self.status >= 400;
stackElement.statusCode = self.status;
stackElement.profile = self.getResponseHeader("X-Debug-Token");
stackElement.profilerUrl = self.getResponseHeader("X-Debug-Token-Link");
extractHeaders(self, stackElement);
Sfjs.renderAjaxRequests();
}

View File

@ -68,7 +68,7 @@ abstract class AbstractAdapter implements AdapterInterface, LoggerAwareInterface
);
}
public static function createSystemCache($namespace, $defaultLifetime, $nonce, $directory, LoggerInterface $logger = null)
public static function createSystemCache($namespace, $defaultLifetime, $version, $directory, LoggerInterface $logger = null)
{
$fs = new FilesystemAdapter($namespace, $defaultLifetime, $directory);
if (null !== $logger) {
@ -78,7 +78,7 @@ abstract class AbstractAdapter implements AdapterInterface, LoggerAwareInterface
return $fs;
}
$apcu = new ApcuAdapter($namespace, $defaultLifetime / 5, $nonce);
$apcu = new ApcuAdapter($namespace, $defaultLifetime / 5, $version);
if (null !== $logger) {
$apcu->setLogger($logger);
}

View File

@ -24,7 +24,7 @@ class ApcuAdapter extends AbstractAdapter
return function_exists('apcu_fetch') && ini_get('apc.enabled') && !('cli' === PHP_SAPI && !ini_get('apc.enable_cli'));
}
public function __construct($namespace = '', $defaultLifetime = 0, $nonce = null)
public function __construct($namespace = '', $defaultLifetime = 0, $version = null)
{
if (!static::isSupported()) {
throw new CacheException('APCu is not enabled');
@ -34,12 +34,12 @@ class ApcuAdapter extends AbstractAdapter
}
parent::__construct($namespace, $defaultLifetime);
if (null !== $nonce) {
CacheItem::validateKey($nonce);
if (null !== $version) {
CacheItem::validateKey($version);
if (!apcu_exists($nonce.':nonce'.$namespace)) {
if (!apcu_exists($version.':'.$namespace)) {
$this->clear($namespace);
apcu_add($nonce.':nonce'.$namespace, null);
apcu_add($version.':'.$namespace, null);
}
}
}

View File

@ -44,7 +44,7 @@ class ApcuAdapterTest extends CachePoolTest
$this->assertFalse($item->isHit());
}
public function testNonce()
public function testVersion()
{
$namespace = str_replace('\\', '.', __CLASS__);

View File

@ -36,6 +36,10 @@ class FileResource implements SelfCheckingResourceInterface, \Serializable
{
$this->resource = realpath($resource);
if (false === $this->resource && file_exists($resource)) {
$this->resource = $resource;
}
if (false === $this->resource) {
throw new \InvalidArgumentException(sprintf('The file "%s" does not exist.', $resource));
}

View File

@ -21,7 +21,7 @@ class FileResourceTest extends \PHPUnit_Framework_TestCase
protected function setUp()
{
$this->file = realpath(sys_get_temp_dir()).'/tmp.xml';
$this->file = sys_get_temp_dir().'/tmp.xml';
$this->time = time();
touch($this->file, $this->time);
$this->resource = new FileResource($this->file);
@ -41,6 +41,12 @@ class FileResourceTest extends \PHPUnit_Framework_TestCase
$this->assertSame(realpath($this->file), $this->resource->getResource(), '->getResource() returns the path to the resource');
}
public function testGetResourceWithScheme()
{
$resource = new FileResource('file://'.$this->file);
$this->assertSame('file://'.$this->file, $resource->getResource(), '->getResource() returns the path to the schemed resource');
}
public function testToString()
{
$this->assertSame(realpath($this->file), (string) $this->resource);

View File

@ -76,42 +76,6 @@ class ProgressIndicator
$this->display();
}
/**
* Gets the current indicator message.
*
* @return string|null
*
* @internal for PHP 5.3 compatibility
*/
public function getMessage()
{
return $this->message;
}
/**
* Gets the progress bar start time.
*
* @return int The progress bar start time
*
* @internal for PHP 5.3 compatibility
*/
public function getStartTime()
{
return $this->startTime;
}
/**
* Gets the current animated indicator character.
*
* @return string
*
* @internal for PHP 5.3 compatibility
*/
public function getCurrentValue()
{
return $this->indicatorValues[$this->indicatorCurrent % count($this->indicatorValues)];
}
/**
* Starts the indicator output.
*
@ -294,13 +258,13 @@ class ProgressIndicator
{
return array(
'indicator' => function (ProgressIndicator $indicator) {
return $indicator->getCurrentValue();
return $indicator->indicatorValues[$indicator->indicatorCurrent % count($indicator->indicatorValues)];
},
'message' => function (ProgressIndicator $indicator) {
return $indicator->getMessage();
return $indicator->message;
},
'elapsed' => function (ProgressIndicator $indicator) {
return Helper::formatTime(time() - $indicator->getStartTime());
return Helper::formatTime(time() - $indicator->startTime);
},
'memory' => function () {
return Helper::formatMemory(memory_get_usage(true));

View File

@ -580,6 +580,8 @@ class ErrorHandler
}
} catch (\Exception $exception) {
// Handled below
} catch (\Throwable $exception) {
// Handled below
}
if ($error && $error['type'] &= E_PARSE | E_ERROR | E_CORE_ERROR | E_COMPILE_ERROR) {

View File

@ -45,8 +45,8 @@ class AutowirePass implements CompilerPassInterface
$this->completeDefinition($id, $definition);
}
}
} catch (\Error $e) {
} catch (\Exception $e) {
} catch (\Throwable $e) {
}
spl_autoload_unregister($throwingAutoloader);
@ -283,7 +283,7 @@ class AutowirePass implements CompilerPassInterface
try {
$this->completeDefinition($argumentId, $argumentDefinition);
} catch (\RuntimeException $e) {
} catch (RuntimeException $e) {
$classOrInterface = $typeHint->isInterface() ? 'interface' : 'class';
$message = sprintf('Unable to autowire argument of type "%s" for the service "%s". No services were found matching this %s and it cannot be auto-registered.', $typeHint->name, $id, $classOrInterface);
throw new RuntimeException($message, 0, $e);

View File

@ -542,6 +542,10 @@ class PhpDumper extends Dumper
return sprintf(" %s::%s(\$%s);\n", $this->dumpLiteralClass($class), $callable[1], $variableName);
}
if (0 === strpos($class, 'new ')) {
return sprintf(" (%s)->%s(\$%s);\n", $this->dumpValue($callable[0]), $callable[1], $variableName);
}
return sprintf(" call_user_func(array(%s, '%s'), \$%s);\n", $this->dumpValue($callable[0]), $callable[1], $variableName);
}
@ -723,6 +727,10 @@ EOF;
return sprintf(" $return{$instantiation}%s::%s(%s);\n", $this->dumpLiteralClass($class), $callable[1], $arguments ? implode(', ', $arguments) : '');
}
if (0 === strpos($class, 'new ')) {
return sprintf(" $return{$instantiation}(%s)->%s(%s);\n", $this->dumpValue($callable[0]), $callable[1], $arguments ? implode(', ', $arguments) : '');
}
return sprintf(" $return{$instantiation}call_user_func(array(%s, '%s')%s);\n", $this->dumpValue($callable[0]), $callable[1], $arguments ? ', '.implode(', ', $arguments) : '');
}

View File

@ -78,6 +78,15 @@ $container
->register('configured_service', 'stdClass')
->setConfigurator(array(new Reference('configurator_service'), 'configureStdClass'))
;
$container
->register('configurator_service_simple', 'ConfClass')
->addArgument('bar')
->setPublic(false)
;
$container
->register('configured_service_simple', 'stdClass')
->setConfigurator(array(new Reference('configurator_service_simple'), 'configureStdClass'))
;
$container
->register('decorated', 'stdClass')
;
@ -111,5 +120,14 @@ $container
->register('service_from_static_method', 'Bar\FooClass')
->setFactory(array('Bar\FooClass', 'getInstance'))
;
$container
->register('factory_simple', 'SimpleFactoryClass')
->addArgument('foo')
->setPublic(false)
;
$container
->register('factory_service_simple', 'Bar')
->setFactory(array(new Reference('factory_simple'), 'getInstance'))
;
return $container;

View File

@ -14,6 +14,8 @@ digraph sc {
node_request [label="request\nRequest\n", shape=record, fillcolor="#eeeeee", style="filled"];
node_configurator_service [label="configurator_service\nConfClass\n", shape=record, fillcolor="#eeeeee", style="filled"];
node_configured_service [label="configured_service\nstdClass\n", shape=record, fillcolor="#eeeeee", style="filled"];
node_configurator_service_simple [label="configurator_service_simple\nConfClass\n", shape=record, fillcolor="#eeeeee", style="filled"];
node_configured_service_simple [label="configured_service_simple\nstdClass\n", shape=record, fillcolor="#eeeeee", style="filled"];
node_decorated [label="decorated\nstdClass\n", shape=record, fillcolor="#eeeeee", style="filled"];
node_decorator_service [label="decorator_service\nstdClass\n", shape=record, fillcolor="#eeeeee", style="filled"];
node_decorator_service_with_name [label="decorator_service_with_name\nstdClass\n", shape=record, fillcolor="#eeeeee", style="filled"];
@ -22,6 +24,8 @@ digraph sc {
node_factory_service [label="factory_service\nBar\n", shape=record, fillcolor="#eeeeee", style="filled"];
node_new_factory_service [label="new_factory_service\nFooBarBaz\n", shape=record, fillcolor="#eeeeee", style="filled"];
node_service_from_static_method [label="service_from_static_method\nBar\\FooClass\n", shape=record, fillcolor="#eeeeee", style="filled"];
node_factory_simple [label="factory_simple\nSimpleFactoryClass\n", shape=record, fillcolor="#eeeeee", style="filled"];
node_factory_service_simple [label="factory_service_simple\nBar\n", shape=record, fillcolor="#eeeeee", style="filled"];
node_service_container [label="service_container\nSymfony\\Component\\DependencyInjection\\ContainerBuilder\n", shape=record, fillcolor="#9999ff", style="filled"];
node_foo2 [label="foo2\n\n", shape=record, fillcolor="#ff9999", style="filled"];
node_foo3 [label="foo3\n\n", shape=record, fillcolor="#ff9999", style="filled"];

View File

@ -40,7 +40,7 @@ class ProjectServiceContainer extends Container
*/
protected function getServiceFromAnonymousFactoryService()
{
return $this->services['service_from_anonymous_factory'] = call_user_func(array(new \Bar\FooClass(), 'getInstance'));
return $this->services['service_from_anonymous_factory'] = (new \Bar\FooClass())->getInstance();
}
/**

View File

@ -28,12 +28,16 @@ class ProjectServiceContainer extends Container
'bar' => 'getBarService',
'baz' => 'getBazService',
'configurator_service' => 'getConfiguratorServiceService',
'configurator_service_simple' => 'getConfiguratorServiceSimpleService',
'configured_service' => 'getConfiguredServiceService',
'configured_service_simple' => 'getConfiguredServiceSimpleService',
'decorated' => 'getDecoratedService',
'decorator_service' => 'getDecoratorServiceService',
'decorator_service_with_name' => 'getDecoratorServiceWithNameService',
'deprecated_service' => 'getDeprecatedServiceService',
'factory_service' => 'getFactoryServiceService',
'factory_service_simple' => 'getFactoryServiceSimpleService',
'factory_simple' => 'getFactorySimpleService',
'foo' => 'getFooService',
'foo.baz' => 'getFoo_BazService',
'foo_bar' => 'getFooBarService',
@ -104,6 +108,23 @@ class ProjectServiceContainer extends Container
return $instance;
}
/**
* Gets the 'configured_service_simple' service.
*
* This service is shared.
* This method always returns the same instance of the service.
*
* @return \stdClass A stdClass instance.
*/
protected function getConfiguredServiceSimpleService()
{
$this->services['configured_service_simple'] = $instance = new \stdClass();
$this->get('configurator_service_simple')->configureStdClass($instance);
return $instance;
}
/**
* Gets the 'decorated' service.
*
@ -173,6 +194,19 @@ class ProjectServiceContainer extends Container
return $this->services['factory_service'] = $this->get('foo.baz')->getInstance();
}
/**
* Gets the 'factory_service_simple' service.
*
* This service is shared.
* This method always returns the same instance of the service.
*
* @return \Bar A Bar instance.
*/
protected function getFactoryServiceSimpleService()
{
return $this->services['factory_service_simple'] = $this->get('factory_simple')->getInstance();
}
/**
* Gets the 'foo' service.
*
@ -334,6 +368,40 @@ class ProjectServiceContainer extends Container
return $instance;
}
/**
* Gets the 'configurator_service_simple' service.
*
* This service is shared.
* This method always returns the same instance of the service.
*
* This service is private.
* If you want to be able to request this service from the container directly,
* make it public, otherwise you might end up with broken code.
*
* @return \ConfClass A ConfClass instance.
*/
protected function getConfiguratorServiceSimpleService()
{
return $this->services['configurator_service_simple'] = new \ConfClass('bar');
}
/**
* Gets the 'factory_simple' service.
*
* This service is shared.
* This method always returns the same instance of the service.
*
* This service is private.
* If you want to be able to request this service from the container directly,
* make it public, otherwise you might end up with broken code.
*
* @return \SimpleFactoryClass A SimpleFactoryClass instance.
*/
protected function getFactorySimpleService()
{
return $this->services['factory_simple'] = new \SimpleFactoryClass('foo');
}
/**
* Gets the 'inlined' service.
*

View File

@ -30,10 +30,12 @@ class ProjectServiceContainer extends Container
'bar' => 'getBarService',
'baz' => 'getBazService',
'configured_service' => 'getConfiguredServiceService',
'configured_service_simple' => 'getConfiguredServiceSimpleService',
'decorator_service' => 'getDecoratorServiceService',
'decorator_service_with_name' => 'getDecoratorServiceWithNameService',
'deprecated_service' => 'getDeprecatedServiceService',
'factory_service' => 'getFactoryServiceService',
'factory_service_simple' => 'getFactoryServiceSimpleService',
'foo' => 'getFooService',
'foo.baz' => 'getFoo_BazService',
'foo_bar' => 'getFooBarService',
@ -114,6 +116,23 @@ class ProjectServiceContainer extends Container
return $instance;
}
/**
* Gets the 'configured_service_simple' service.
*
* This service is shared.
* This method always returns the same instance of the service.
*
* @return \stdClass A stdClass instance.
*/
protected function getConfiguredServiceSimpleService()
{
$this->services['configured_service_simple'] = $instance = new \stdClass();
(new \ConfClass('bar'))->configureStdClass($instance);
return $instance;
}
/**
* Gets the 'decorator_service' service.
*
@ -170,6 +189,19 @@ class ProjectServiceContainer extends Container
return $this->services['factory_service'] = $this->get('foo.baz')->getInstance();
}
/**
* Gets the 'factory_service_simple' service.
*
* This service is shared.
* This method always returns the same instance of the service.
*
* @return \Bar A Bar instance.
*/
protected function getFactoryServiceSimpleService()
{
return $this->services['factory_service_simple'] = (new \SimpleFactoryClass('foo'))->getInstance();
}
/**
* Gets the 'foo' service.
*

View File

@ -84,6 +84,12 @@
<service id="configured_service" class="stdClass">
<configurator service="configurator_service" method="configureStdClass"/>
</service>
<service id="configurator_service_simple" class="ConfClass" public="false">
<argument>bar</argument>
</service>
<service id="configured_service_simple" class="stdClass">
<configurator service="configurator_service_simple" method="configureStdClass"/>
</service>
<service id="decorated" class="stdClass"/>
<service id="decorator_service" class="stdClass" decorates="decorated"/>
<service id="decorator_service_with_name" class="stdClass" decorates="decorated" decoration-inner-name="decorated.pif-pouf"/>
@ -103,6 +109,12 @@
<service id="service_from_static_method" class="Bar\FooClass">
<factory class="Bar\FooClass" method="getInstance"/>
</service>
<service id="factory_simple" class="SimpleFactoryClass" public="false">
<argument>foo</argument>
</service>
<service id="factory_service_simple" class="Bar">
<factory service="factory_simple" method="getInstance"/>
</service>
<service id="alias_for_foo" alias="foo"/>
<service id="alias_for_alias" alias="foo"/>
</services>

View File

@ -67,6 +67,13 @@ services:
configured_service:
class: stdClass
configurator: ['@configurator_service', configureStdClass]
configurator_service_simple:
class: ConfClass
public: false
arguments: ['bar']
configured_service_simple:
class: stdClass
configurator: ['@configurator_service_simple', configureStdClass]
decorated:
class: stdClass
decorator_service:
@ -93,5 +100,12 @@ services:
service_from_static_method:
class: Bar\FooClass
factory: [Bar\FooClass, getInstance]
factory_simple:
class: SimpleFactoryClass
public: false
arguments: ['foo']
factory_service_simple:
class: Bar
factory: ['@factory_simple', getInstance]
alias_for_foo: '@foo'
alias_for_alias: '@foo'

View File

@ -312,6 +312,19 @@ class ObjectNormalizerTest extends \PHPUnit_Framework_TestCase
);
}
public function testIgnoredAttributesDenormalize()
{
$this->normalizer->setIgnoredAttributes(array('fooBar', 'bar', 'baz'));
$obj = new ObjectDummy();
$obj->setFoo('foo');
$this->assertEquals(
$obj,
$this->normalizer->denormalize(array('fooBar' => 'fooBar', 'foo' => 'foo', 'baz' => 'baz'), __NAMESPACE__.'\ObjectDummy')
);
}
public function provideCallbacks()
{
return array(

View File

@ -34,7 +34,7 @@ class DateTimeValidator extends DateValidator
throw new UnexpectedTypeException($constraint, __NAMESPACE__.'\DateTime');
}
if (null === $value || '' === $value || $value instanceof \DateTime) {
if (null === $value || '' === $value || $value instanceof \DateTimeInterface) {
return;
}

View File

@ -47,7 +47,7 @@ class DateValidator extends ConstraintValidator
throw new UnexpectedTypeException($constraint, __NAMESPACE__.'\Date');
}
if (null === $value || '' === $value || $value instanceof \DateTime) {
if (null === $value || '' === $value || $value instanceof \DateTimeInterface) {
return;
}

View File

@ -42,6 +42,13 @@ class DateTimeValidatorTest extends AbstractConstraintValidatorTest
$this->assertNoViolation();
}
public function testDateTimeImmutableClassIsValid()
{
$this->validator->validate(new \DateTimeImmutable(), new DateTime());
$this->assertNoViolation();
}
/**
* @expectedException \Symfony\Component\Validator\Exception\UnexpectedTypeException
*/

View File

@ -42,6 +42,13 @@ class DateValidatorTest extends AbstractConstraintValidatorTest
$this->assertNoViolation();
}
public function testDateTimeImmutableClassIsValid()
{
$this->validator->validate(new \DateTimeImmutable(), new Date());
$this->assertNoViolation();
}
/**
* @expectedException \Symfony\Component\Validator\Exception\UnexpectedTypeException
*/

View File

@ -128,6 +128,8 @@ abstract class AbstractDumper implements DataDumperInterface, DumperInterface
$this->dumpLine(-1);
} catch (\Exception $exception) {
// Re-thrown below
} catch (\Throwable $exception) {
// Re-thrown below
}
if ($output) {
$this->setOutput($prevOutput);

View File

@ -24,6 +24,7 @@ class Parser
const BLOCK_SCALAR_HEADER_PATTERN = '(?P<separator>\||>)(?P<modifiers>\+|\-|\d+|\+\d+|\-\d+|\d+\+|\d+\-)?(?P<comments> +#.*)?';
private $offset = 0;
private $totalNumberOfLines;
private $lines = array();
private $currentLineNb = -1;
private $currentLine = '';
@ -32,11 +33,13 @@ class Parser
/**
* Constructor.
*
* @param int $offset The offset of YAML document (used for line numbers in error messages)
* @param int $offset The offset of YAML document (used for line numbers in error messages)
* @param int|null $totalNumberOfLines The overall number of lines being parsed
*/
public function __construct($offset = 0)
public function __construct($offset = 0, $totalNumberOfLines = null)
{
$this->offset = $offset;
$this->totalNumberOfLines = $totalNumberOfLines;
}
/**
@ -85,6 +88,10 @@ class Parser
$value = $this->cleanup($value);
$this->lines = explode("\n", $value);
if (null === $this->totalNumberOfLines) {
$this->totalNumberOfLines = count($this->lines);
}
if (2 /* MB_OVERLOAD_STRING */ & (int) ini_get('mbstring.func_overload')) {
$mbEncoding = mb_internal_encoding();
mb_internal_encoding('UTF-8');
@ -106,7 +113,7 @@ class Parser
$isRef = $mergeNode = false;
if (preg_match('#^\-((?P<leadspaces>\s+)(?P<value>.+?))?\s*$#u', $this->currentLine, $values)) {
if ($context && 'mapping' == $context) {
throw new ParseException('You cannot define a sequence item when in a mapping');
throw new ParseException('You cannot define a sequence item when in a mapping', $this->getRealCurrentLineNb() + 1, $this->currentLine);
}
$context = 'sequence';
@ -118,7 +125,7 @@ class Parser
// array
if (!isset($values['value']) || '' == trim($values['value'], ' ') || 0 === strpos(ltrim($values['value'], ' '), '#')) {
$c = $this->getRealCurrentLineNb() + 1;
$parser = new self($c);
$parser = new self($c, $this->totalNumberOfLines);
$parser->refs = &$this->refs;
$data[] = $parser->parse($this->getNextEmbedBlock(null, true), $flags);
} else {
@ -127,7 +134,7 @@ class Parser
) {
// this is a compact notation element, add to next block and parse
$c = $this->getRealCurrentLineNb();
$parser = new self($c);
$parser = new self($c, $this->totalNumberOfLines);
$parser->refs = &$this->refs;
$block = $values['value'];
@ -145,7 +152,7 @@ class Parser
}
} elseif (preg_match('#^(?P<key>'.Inline::REGEX_QUOTED_STRING.'|[^ \'"\[\{].*?) *\:(\s+(?P<value>.+?))?\s*$#u', $this->currentLine, $values) && (false === strpos($values['key'], ' #') || in_array($values['key'][0], array('"', "'")))) {
if ($context && 'sequence' == $context) {
throw new ParseException('You cannot define a mapping item when in a sequence');
throw new ParseException('You cannot define a mapping item when in a sequence', $this->currentLineNb + 1, $this->currentLine);
}
$context = 'mapping';
@ -192,7 +199,7 @@ class Parser
$value = $this->getNextEmbedBlock();
}
$c = $this->getRealCurrentLineNb() + 1;
$parser = new self($c);
$parser = new self($c, $this->totalNumberOfLines);
$parser->refs = &$this->refs;
$parsed = $parser->parse($value, $flags);
@ -243,7 +250,7 @@ class Parser
}
} else {
$c = $this->getRealCurrentLineNb() + 1;
$parser = new self($c);
$parser = new self($c, $this->totalNumberOfLines);
$parser->refs = &$this->refs;
$value = $parser->parse($this->getNextEmbedBlock(), $flags);
// Spec: Keys MUST be unique; first one wins.
@ -266,7 +273,7 @@ class Parser
} else {
// multiple documents are not supported
if ('---' === $this->currentLine) {
throw new ParseException('Multiple documents are not supported.');
throw new ParseException('Multiple documents are not supported.', $this->currentLineNb + 1, $this->currentLine);
}
// 1-liner optionally followed by newline(s)
@ -511,7 +518,7 @@ class Parser
}
if (!array_key_exists($value, $this->refs)) {
throw new ParseException(sprintf('Reference "%s" does not exist.', $value), $this->currentLine);
throw new ParseException(sprintf('Reference "%s" does not exist.', $value), $this->currentLineNb + 1, $this->currentLine);
}
return $this->refs[$value];
@ -609,6 +616,8 @@ class Parser
if ($notEOF) {
$blockLines[] = '';
$this->moveToPreviousLine();
} elseif (!$notEOF && !$this->isCurrentLineLastLineInDocument()) {
$blockLines[] = '';
}
// folded style
@ -715,6 +724,11 @@ class Parser
return '' !== $ltrimmedLine && $ltrimmedLine[0] === '#';
}
private function isCurrentLineLastLineInDocument()
{
return ($this->offset + $this->currentLineNb) >= ($this->totalNumberOfLines - 1);
}
/**
* Cleanups a YAML string to be parsed.
*
@ -792,7 +806,7 @@ class Parser
*/
private function isStringUnIndentedCollectionItem()
{
return 0 === strpos($this->currentLine, '- ');
return '-' === rtrim($this->currentLine) || 0 === strpos($this->currentLine, '- ');
}
/**

View File

@ -654,7 +654,7 @@ EOF;
/**
* @expectedException \Symfony\Component\Yaml\Exception\ParseException
* @expectedExceptionMessage Multiple documents are not supported.
* @expectedExceptionMessageRegExp /^Multiple documents are not supported.+/
*/
public function testMultipleDocumentsNotSupportedException()
{
@ -686,6 +686,34 @@ EOF
);
}
public function testSequenceInMappingStartedBySingleDashLine()
{
$yaml = <<<EOT
a:
-
b:
-
bar: baz
- foo
d: e
EOT;
$expected = array(
'a' => array(
array(
'b' => array(
array(
'bar' => 'baz',
),
),
),
'foo',
),
'd' => 'e',
);
$this->assertSame($expected, $this->parser->parse($yaml));
}
/**
* @expectedException \Symfony\Component\Yaml\Exception\ParseException
*/
@ -1035,6 +1063,7 @@ EOT
foo
# bar
baz
EOT
,
),
@ -1063,7 +1092,7 @@ EOT;
$expected = array(
'foo' => array(
'bar' => array(
'scalar-block' => 'line1 line2>',
'scalar-block' => "line1 line2>\n",
),
'baz' => array(
'foobar' => null,