diff --git a/.php_cs b/.php_cs index 290e9bf5fb..02d15784e6 100644 --- a/.php_cs +++ b/.php_cs @@ -3,6 +3,10 @@ return Symfony\CS\Config\Config::create() ->setUsingLinter(false) ->setUsingCache(true) + ->fixers(array( + 'long_array_syntax', + 'php_unit_construct', + )) ->finder( Symfony\CS\Finder\DefaultFinder::create() ->in(__DIR__) @@ -12,6 +16,9 @@ return Symfony\CS\Config\Config::create() 'src/Symfony/Component/Routing/Tests/Fixtures/dumper', // fixture templates 'src/Symfony/Component/Templating/Tests/Fixtures/templates', + 'src/Symfony/Bundle/FrameworkBundle/Tests/Templating/Helper/Resources/Custom', + // generated fixtures + 'src/Symfony/Component/VarDumper/Tests/Fixtures', // resource templates 'src/Symfony/Bundle/FrameworkBundle/Resources/views/Form', )) diff --git a/UPGRADE-3.0.md b/UPGRADE-3.0.md index f9933d8b63..6476cbcad1 100644 --- a/UPGRADE-3.0.md +++ b/UPGRADE-3.0.md @@ -939,6 +939,30 @@ UPGRADE FROM 2.x to 3.0 * The `getMatcherDumperInstance()` and `getGeneratorDumperInstance()` methods in the `Symfony\Component\Routing\Router` have been changed from `public` to `protected`. + * Use the constants defined in the UrlGeneratorInterface for the $referenceType argument of the UrlGeneratorInterface::generate method. + + Before: + + ```php + // url generated in controller + $this->generateUrl('blog_show', array('slug' => 'my-blog-post'), true); + + // url generated in @router service + $router->generate('blog_show', array('slug' => 'my-blog-post'), true); + ``` + + After: + + ```php + use Symfony\Component\Routing\Generator\UrlGeneratorInterface; + + // url generated in controller + $this->generateUrl('blog_show', array('slug' => 'my-blog-post'), UrlGeneratorInterface::ABSOLUTE_URL); + + // url generated in @router service + $router->generate('blog_show', array('slug' => 'my-blog-post'), UrlGeneratorInterface::ABSOLUTE_URL); + ``` + ### Security * The `vote()` method from the `VoterInterface` was changed to now accept arbitrary diff --git a/src/Symfony/Bridge/Monolog/composer.json b/src/Symfony/Bridge/Monolog/composer.json index 9e943ad2e6..c22c7e7a0d 100644 --- a/src/Symfony/Bridge/Monolog/composer.json +++ b/src/Symfony/Bridge/Monolog/composer.json @@ -17,10 +17,10 @@ ], "require": { "php": ">=5.5.9", - "monolog/monolog": "~1.11" + "monolog/monolog": "~1.11", + "symfony/http-kernel": "~2.8|~3.0" }, "require-dev": { - "symfony/http-kernel": "~2.8|~3.0", "symfony/console": "~2.8|~3.0", "symfony/event-dispatcher": "~2.8|~3.0" }, diff --git a/src/Symfony/Bundle/FrameworkBundle/Command/AbstractConfigCommand.php b/src/Symfony/Bundle/FrameworkBundle/Command/AbstractConfigCommand.php index 758b25c58d..5560748c0b 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Command/AbstractConfigCommand.php +++ b/src/Symfony/Bundle/FrameworkBundle/Command/AbstractConfigCommand.php @@ -31,7 +31,7 @@ abstract class AbstractConfigCommand extends ContainerDebugCommand $rows = array(); $bundles = $this->getContainer()->get('kernel')->getBundles(); - usort($bundles, function($bundleA, $bundleB) { + usort($bundles, function ($bundleA, $bundleB) { return strcmp($bundleA->getName(), $bundleB->getName()); }); diff --git a/src/Symfony/Component/Console/Helper/HelperSet.php b/src/Symfony/Component/Console/Helper/HelperSet.php index f7d703ab9f..399b634646 100644 --- a/src/Symfony/Component/Console/Helper/HelperSet.php +++ b/src/Symfony/Component/Console/Helper/HelperSet.php @@ -21,6 +21,9 @@ use Symfony\Component\Console\Exception\InvalidArgumentException; */ class HelperSet implements \IteratorAggregate { + /** + * @var Helper[] + */ private $helpers = array(); private $command; @@ -102,6 +105,9 @@ class HelperSet implements \IteratorAggregate return $this->command; } + /** + * @return Helper[] + */ public function getIterator() { return new \ArrayIterator($this->helpers); diff --git a/src/Symfony/Component/Console/Input/ArgvInput.php b/src/Symfony/Component/Console/Input/ArgvInput.php index fec04e21c9..1e466e8523 100644 --- a/src/Symfony/Component/Console/Input/ArgvInput.php +++ b/src/Symfony/Component/Console/Input/ArgvInput.php @@ -46,8 +46,8 @@ class ArgvInput extends Input /** * Constructor. * - * @param array $argv An array of parameters from the CLI (in the argv format) - * @param InputDefinition $definition A InputDefinition instance + * @param array|null $argv An array of parameters from the CLI (in the argv format) + * @param InputDefinition|null $definition A InputDefinition instance */ public function __construct(array $argv = null, InputDefinition $definition = null) { @@ -69,7 +69,7 @@ class ArgvInput extends Input } /** - * Processes command line arguments. + * {@inheritdoc} */ protected function parse() { @@ -253,9 +253,7 @@ class ArgvInput extends Input } /** - * Returns the first argument from the raw parameters (not parsed). - * - * @return string The value of the first argument or null otherwise + * {@inheritdoc} */ public function getFirstArgument() { @@ -269,15 +267,7 @@ class ArgvInput extends Input } /** - * Returns true if the raw parameters (not parsed) contain a value. - * - * This method is to be used to introspect the input parameters - * before they have been validated. It must be used carefully. - * - * @param string|array $values The value(s) to look for in the raw parameters (can be an array) - * @param bool $onlyParams Only check real parameters, skip those following an end of options (--) signal - * - * @return bool true if the value is contained in the raw parameters + * {@inheritdoc} */ public function hasParameterOption($values, $onlyParams = false) { @@ -298,16 +288,7 @@ class ArgvInput extends Input } /** - * Returns the value of a raw option (not parsed). - * - * This method is to be used to introspect the input parameters - * before they have been validated. It must be used carefully. - * - * @param string|array $values The value(s) to look for in the raw parameters (can be an array) - * @param mixed $default The default value to return if no result is found - * @param bool $onlyParams Only check real parameters, skip those following an end of options (--) signal - * - * @return mixed The option value + * {@inheritdoc} */ public function getParameterOption($values, $default = false, $onlyParams = false) { diff --git a/src/Symfony/Component/Console/Input/ArrayInput.php b/src/Symfony/Component/Console/Input/ArrayInput.php index 6705d4bb94..a44b6b2815 100644 --- a/src/Symfony/Component/Console/Input/ArrayInput.php +++ b/src/Symfony/Component/Console/Input/ArrayInput.php @@ -30,8 +30,8 @@ class ArrayInput extends Input /** * Constructor. * - * @param array $parameters An array of parameters - * @param InputDefinition $definition A InputDefinition instance + * @param array $parameters An array of parameters + * @param InputDefinition|null $definition A InputDefinition instance */ public function __construct(array $parameters, InputDefinition $definition = null) { @@ -41,9 +41,7 @@ class ArrayInput extends Input } /** - * Returns the first argument from the raw parameters (not parsed). - * - * @return string The value of the first argument or null otherwise + * {@inheritdoc} */ public function getFirstArgument() { @@ -57,15 +55,7 @@ class ArrayInput extends Input } /** - * Returns true if the raw parameters (not parsed) contain a value. - * - * This method is to be used to introspect the input parameters - * before they have been validated. It must be used carefully. - * - * @param string|array $values The values to look for in the raw parameters (can be an array) - * @param bool $onlyParams Only check real parameters, skip those following an end of options (--) signal - * - * @return bool true if the value is contained in the raw parameters + * {@inheritdoc} */ public function hasParameterOption($values, $onlyParams = false) { @@ -89,16 +79,7 @@ class ArrayInput extends Input } /** - * Returns the value of a raw option (not parsed). - * - * This method is to be used to introspect the input parameters - * before they have been validated. It must be used carefully. - * - * @param string|array $values The value(s) to look for in the raw parameters (can be an array) - * @param mixed $default The default value to return if no result is found - * @param bool $onlyParams Only check real parameters, skip those following an end of options (--) signal - * - * @return mixed The option value + * {@inheritdoc} */ public function getParameterOption($values, $default = false, $onlyParams = false) { @@ -141,7 +122,7 @@ class ArrayInput extends Input } /** - * Processes command line arguments. + * {@inheritdoc} */ protected function parse() { diff --git a/src/Symfony/Component/Console/Input/Input.php b/src/Symfony/Component/Console/Input/Input.php index 85499fc489..817292ed73 100644 --- a/src/Symfony/Component/Console/Input/Input.php +++ b/src/Symfony/Component/Console/Input/Input.php @@ -38,7 +38,7 @@ abstract class Input implements InputInterface /** * Constructor. * - * @param InputDefinition $definition A InputDefinition instance + * @param InputDefinition|null $definition A InputDefinition instance */ public function __construct(InputDefinition $definition = null) { @@ -51,9 +51,7 @@ abstract class Input implements InputInterface } /** - * Binds the current Input instance with the given arguments and options. - * - * @param InputDefinition $definition A InputDefinition instance + * {@inheritdoc} */ public function bind(InputDefinition $definition) { @@ -70,9 +68,7 @@ abstract class Input implements InputInterface abstract protected function parse(); /** - * Validates the input. - * - * @throws RuntimeException When not enough arguments are given + * {@inheritdoc} */ public function validate() { @@ -89,9 +85,7 @@ abstract class Input implements InputInterface } /** - * Checks if the input is interactive. - * - * @return bool Returns true if the input is interactive + * {@inheritdoc} */ public function isInteractive() { @@ -99,9 +93,7 @@ abstract class Input implements InputInterface } /** - * Sets the input interactivity. - * - * @param bool $interactive If the input should be interactive + * {@inheritdoc} */ public function setInteractive($interactive) { @@ -109,9 +101,7 @@ abstract class Input implements InputInterface } /** - * Returns the argument values. - * - * @return array An array of argument values + * {@inheritdoc} */ public function getArguments() { @@ -119,13 +109,7 @@ abstract class Input implements InputInterface } /** - * Returns the argument value for a given argument name. - * - * @param string $name The argument name - * - * @return mixed The argument value - * - * @throws InvalidArgumentException When argument given doesn't exist + * {@inheritdoc} */ public function getArgument($name) { @@ -137,12 +121,7 @@ abstract class Input implements InputInterface } /** - * Sets an argument value by name. - * - * @param string $name The argument name - * @param string $value The argument value - * - * @throws InvalidArgumentException When argument given doesn't exist + * {@inheritdoc} */ public function setArgument($name, $value) { @@ -154,11 +133,7 @@ abstract class Input implements InputInterface } /** - * Returns true if an InputArgument object exists by name or position. - * - * @param string|int $name The InputArgument name or position - * - * @return bool true if the InputArgument object exists, false otherwise + * {@inheritdoc} */ public function hasArgument($name) { @@ -166,9 +141,7 @@ abstract class Input implements InputInterface } /** - * Returns the options values. - * - * @return array An array of option values + * {@inheritdoc} */ public function getOptions() { @@ -176,13 +149,7 @@ abstract class Input implements InputInterface } /** - * Returns the option value for a given option name. - * - * @param string $name The option name - * - * @return mixed The option value - * - * @throws InvalidArgumentException When option given doesn't exist + * {@inheritdoc} */ public function getOption($name) { @@ -194,12 +161,7 @@ abstract class Input implements InputInterface } /** - * Sets an option value by name. - * - * @param string $name The option name - * @param string|bool $value The option value - * - * @throws InvalidArgumentException When option given doesn't exist + * {@inheritdoc} */ public function setOption($name, $value) { @@ -211,11 +173,7 @@ abstract class Input implements InputInterface } /** - * Returns true if an InputOption object exists by name. - * - * @param string $name The InputOption name - * - * @return bool true if the InputOption object exists, false otherwise + * {@inheritdoc} */ public function hasOption($name) { diff --git a/src/Symfony/Component/Console/Input/InputInterface.php b/src/Symfony/Component/Console/Input/InputInterface.php index 2e1fb9fe4f..bc66466437 100644 --- a/src/Symfony/Component/Console/Input/InputInterface.php +++ b/src/Symfony/Component/Console/Input/InputInterface.php @@ -11,6 +11,9 @@ namespace Symfony\Component\Console\Input; +use Symfony\Component\Console\Exception\InvalidArgumentException; +use Symfony\Component\Console\Exception\RuntimeException; + /** * InputInterface is the interface implemented by all input classes. * @@ -60,11 +63,9 @@ interface InputInterface public function bind(InputDefinition $definition); /** - * Validates if arguments given are correct. + * Validates the input. * - * Throws an exception when not enough arguments are given. - * - * @throws \RuntimeException + * @throws RuntimeException When not enough arguments are given */ public function validate(); @@ -76,11 +77,13 @@ interface InputInterface public function getArguments(); /** - * Gets argument by name. + * Returns the argument value for a given argument name. * - * @param string $name The name of the argument + * @param string $name The argument name * - * @return mixed + * @return mixed The argument value + * + * @throws InvalidArgumentException When argument given doesn't exist */ public function getArgument($name); @@ -111,11 +114,13 @@ interface InputInterface public function getOptions(); /** - * Gets an option by name. + * Returns the option value for a given option name. * - * @param string $name The name of the option + * @param string $name The option name * - * @return mixed + * @return mixed The option value + * + * @throws InvalidArgumentException When option given doesn't exist */ public function getOption($name); diff --git a/src/Symfony/Component/DependencyInjection/Compiler/AutowirePass.php b/src/Symfony/Component/DependencyInjection/Compiler/AutowirePass.php index 5065ed1880..cd5b61b290 100644 --- a/src/Symfony/Component/DependencyInjection/Compiler/AutowirePass.php +++ b/src/Symfony/Component/DependencyInjection/Compiler/AutowirePass.php @@ -229,7 +229,6 @@ class AutowirePass implements CompilerPassInterface $matchingServices = implode(', ', $this->types[$typeHint->name]); throw new RuntimeException(sprintf('Unable to autowire argument of type "%s" for the service "%s". Multiple services exist for this %s (%s).', $typeHint->name, $id, $classOrInterface, $matchingServices)); - } if (!$typeHint->isInstantiable()) { diff --git a/src/Symfony/Component/Finder/Finder.php b/src/Symfony/Component/Finder/Finder.php index 6862fd7c28..22e0869c59 100644 --- a/src/Symfony/Component/Finder/Finder.php +++ b/src/Symfony/Component/Finder/Finder.php @@ -557,7 +557,7 @@ class Finder implements \IteratorAggregate, \Countable * * This method implements the IteratorAggregate interface. * - * @return \Iterator An iterator + * @return \Iterator|SplFileInfo[] An iterator * * @throws \LogicException if the in() method has not been called */ diff --git a/src/Symfony/Component/Form/ChoiceList/View/ChoiceGroupView.php b/src/Symfony/Component/Form/ChoiceList/View/ChoiceGroupView.php index 05d7533306..ce7989359a 100644 --- a/src/Symfony/Component/Form/ChoiceList/View/ChoiceGroupView.php +++ b/src/Symfony/Component/Form/ChoiceList/View/ChoiceGroupView.php @@ -47,6 +47,8 @@ class ChoiceGroupView implements \IteratorAggregate /** * {@inheritdoc} + * + * @return ChoiceGroupView[]|ChoiceView[] */ public function getIterator() { diff --git a/src/Symfony/Component/Form/Form.php b/src/Symfony/Component/Form/Form.php index 74ff45b297..677642a28a 100644 --- a/src/Symfony/Component/Form/Form.php +++ b/src/Symfony/Component/Form/Form.php @@ -968,7 +968,7 @@ class Form implements \IteratorAggregate, FormInterface /** * Returns the iterator for this group. * - * @return \Traversable + * @return \Traversable|FormInterface[] */ public function getIterator() { diff --git a/src/Symfony/Component/Form/FormBuilder.php b/src/Symfony/Component/Form/FormBuilder.php index b4dd78c105..a347b02a47 100644 --- a/src/Symfony/Component/Form/FormBuilder.php +++ b/src/Symfony/Component/Form/FormBuilder.php @@ -231,6 +231,8 @@ class FormBuilder extends FormConfigBuilder implements \IteratorAggregate, FormB /** * {@inheritdoc} + * + * @return FormBuilderInterface[] */ public function getIterator() { diff --git a/src/Symfony/Component/Form/FormBuilderInterface.php b/src/Symfony/Component/Form/FormBuilderInterface.php index 412874567f..54d50449a2 100644 --- a/src/Symfony/Component/Form/FormBuilderInterface.php +++ b/src/Symfony/Component/Form/FormBuilderInterface.php @@ -81,7 +81,7 @@ interface FormBuilderInterface extends \Traversable, \Countable, FormConfigBuild /** * Creates the form. * - * @return Form The form + * @return FormInterface The form */ public function getForm(); } diff --git a/src/Symfony/Component/Form/FormView.php b/src/Symfony/Component/Form/FormView.php index ac50dc336f..e424b3c773 100644 --- a/src/Symfony/Component/Form/FormView.php +++ b/src/Symfony/Component/Form/FormView.php @@ -143,7 +143,7 @@ class FormView implements \ArrayAccess, \IteratorAggregate, \Countable /** * Returns an iterator to iterate over children (implements \IteratorAggregate). * - * @return \ArrayIterator The iterator + * @return \ArrayIterator|FormView[] The iterator */ public function getIterator() { diff --git a/src/Symfony/Component/Form/Tests/Extension/Core/DataTransformer/ChoicesToValuesTransformerTest.php b/src/Symfony/Component/Form/Tests/Extension/Core/DataTransformer/ChoicesToValuesTransformerTest.php index d6fe4edd31..5eb01a2ccb 100644 --- a/src/Symfony/Component/Form/Tests/Extension/Core/DataTransformer/ChoicesToValuesTransformerTest.php +++ b/src/Symfony/Component/Form/Tests/Extension/Core/DataTransformer/ChoicesToValuesTransformerTest.php @@ -68,7 +68,7 @@ class ChoicesToValuesTransformerTest extends \PHPUnit_Framework_TestCase $this->assertSame($out, $this->transformer->reverseTransform($in)); // values are expected to be valid choices and stay the same - $inWithNull = array('0','1','2','3'); + $inWithNull = array('0', '1', '2', '3'); $out[] = null; $this->assertSame($out, $this->transformerWithNull->reverseTransform($inWithNull)); diff --git a/src/Symfony/Component/HttpFoundation/File/File.php b/src/Symfony/Component/HttpFoundation/File/File.php index f1b28b4b7d..4736b45c34 100644 --- a/src/Symfony/Component/HttpFoundation/File/File.php +++ b/src/Symfony/Component/HttpFoundation/File/File.php @@ -68,7 +68,7 @@ class File extends \SplFileInfo * mime_content_type() and the system binary "file" (in this order), depending on * which of those are available. * - * @return string|null The guessed mime type (i.e. "application/pdf") + * @return string|null The guessed mime type (e.g. "application/pdf") * * @see MimeTypeGuesser */ diff --git a/src/Symfony/Component/HttpFoundation/Response.php b/src/Symfony/Component/HttpFoundation/Response.php index 12b8db98b4..a61fa49e24 100644 --- a/src/Symfony/Component/HttpFoundation/Response.php +++ b/src/Symfony/Component/HttpFoundation/Response.php @@ -373,12 +373,6 @@ class Response $this->sendHeaders(); $this->sendContent(); - if (function_exists('fastcgi_finish_request')) { - fastcgi_finish_request(); - } elseif ('cli' !== PHP_SAPI) { - static::closeOutputBuffers(0, true); - } - return $this; } diff --git a/src/Symfony/Component/HttpFoundation/Session/Storage/Handler/PdoSessionHandler.php b/src/Symfony/Component/HttpFoundation/Session/Storage/Handler/PdoSessionHandler.php index 54d94f7c05..8909a5f401 100644 --- a/src/Symfony/Component/HttpFoundation/Session/Storage/Handler/PdoSessionHandler.php +++ b/src/Symfony/Component/HttpFoundation/Session/Storage/Handler/PdoSessionHandler.php @@ -325,14 +325,8 @@ class PdoSessionHandler implements \SessionHandlerInterface try { // We use a single MERGE SQL query when supported by the database. - $mergeSql = $this->getMergeSql(); - - if (null !== $mergeSql) { - $mergeStmt = $this->pdo->prepare($mergeSql); - $mergeStmt->bindParam(':id', $sessionId, \PDO::PARAM_STR); - $mergeStmt->bindParam(':data', $data, \PDO::PARAM_LOB); - $mergeStmt->bindParam(':lifetime', $maxlifetime, \PDO::PARAM_INT); - $mergeStmt->bindValue(':time', time(), \PDO::PARAM_INT); + $mergeStmt = $this->getMergeStatement($sessionId, $data, $maxlifetime); + if (null !== $mergeStmt) { $mergeStmt->execute(); return true; @@ -510,54 +504,51 @@ class PdoSessionHandler implements \SessionHandlerInterface $selectSql = $this->getSelectSql(); $selectStmt = $this->pdo->prepare($selectSql); $selectStmt->bindParam(':id', $sessionId, \PDO::PARAM_STR); - $selectStmt->execute(); - $sessionRows = $selectStmt->fetchAll(\PDO::FETCH_NUM); + do { + $selectStmt->execute(); + $sessionRows = $selectStmt->fetchAll(\PDO::FETCH_NUM); - if ($sessionRows) { - if ($sessionRows[0][1] + $sessionRows[0][2] < time()) { - $this->sessionExpired = true; - - return ''; - } - - return is_resource($sessionRows[0][0]) ? stream_get_contents($sessionRows[0][0]) : $sessionRows[0][0]; - } - - if (self::LOCK_TRANSACTIONAL === $this->lockMode && 'sqlite' !== $this->driver) { - // Exclusive-reading of non-existent rows does not block, so we need to do an insert to block - // until other connections to the session are committed. - try { - $insertStmt = $this->pdo->prepare( - "INSERT INTO $this->table ($this->idCol, $this->dataCol, $this->lifetimeCol, $this->timeCol) VALUES (:id, :data, :lifetime, :time)" - ); - $insertStmt->bindParam(':id', $sessionId, \PDO::PARAM_STR); - $insertStmt->bindValue(':data', '', \PDO::PARAM_LOB); - $insertStmt->bindValue(':lifetime', 0, \PDO::PARAM_INT); - $insertStmt->bindValue(':time', time(), \PDO::PARAM_INT); - $insertStmt->execute(); - } catch (\PDOException $e) { - // Catch duplicate key error because other connection created the session already. - // It would only not be the case when the other connection destroyed the session. - if (0 === strpos($e->getCode(), '23')) { - // Retrieve finished session data written by concurrent connection. SELECT - // FOR UPDATE is necessary to avoid deadlock of connection that starts reading - // before we write (transform intention to real lock). - $selectStmt->execute(); - $sessionRows = $selectStmt->fetchAll(\PDO::FETCH_NUM); - - if ($sessionRows) { - return is_resource($sessionRows[0][0]) ? stream_get_contents($sessionRows[0][0]) : $sessionRows[0][0]; - } + if ($sessionRows) { + if ($sessionRows[0][1] + $sessionRows[0][2] < time()) { + $this->sessionExpired = true; return ''; } - throw $e; + return is_resource($sessionRows[0][0]) ? stream_get_contents($sessionRows[0][0]) : $sessionRows[0][0]; } - } - return ''; + if (self::LOCK_TRANSACTIONAL === $this->lockMode && 'sqlite' !== $this->driver) { + // Exclusive-reading of non-existent rows does not block, so we need to do an insert to block + // until other connections to the session are committed. + try { + $insertStmt = $this->pdo->prepare( + "INSERT INTO $this->table ($this->idCol, $this->dataCol, $this->lifetimeCol, $this->timeCol) VALUES (:id, :data, :lifetime, :time)" + ); + $insertStmt->bindParam(':id', $sessionId, \PDO::PARAM_STR); + $insertStmt->bindValue(':data', '', \PDO::PARAM_LOB); + $insertStmt->bindValue(':lifetime', 0, \PDO::PARAM_INT); + $insertStmt->bindValue(':time', time(), \PDO::PARAM_INT); + $insertStmt->execute(); + } catch (\PDOException $e) { + // Catch duplicate key error because other connection created the session already. + // It would only not be the case when the other connection destroyed the session. + if (0 === strpos($e->getCode(), '23')) { + // Retrieve finished session data written by concurrent connection by restarting the loop. + // We have to start a new transaction as a failed query will mark the current transaction as + // aborted in PostgreSQL and disallow further queries within it. + $this->rollback(); + $this->beginTransaction(); + continue; + } + + throw $e; + } + } + + return ''; + } while (true); } /** @@ -653,32 +644,64 @@ class PdoSessionHandler implements \SessionHandlerInterface } /** - * Returns a merge/upsert (i.e. insert or update) SQL query when supported by the database for writing session data. + * Returns a merge/upsert (i.e. insert or update) statement when supported by the database for writing session data. * - * @return string|null The SQL string or null when not supported + * @param string $sessionId Session ID + * @param string $data Encoded session data + * @param int $maxlifetime session.gc_maxlifetime + * + * @return \PDOStatement|null The merge statement or null when not supported */ - private function getMergeSql() + private function getMergeStatement($sessionId, $data, $maxlifetime) { + $mergeSql = null; switch (true) { case 'mysql' === $this->driver: - return "INSERT INTO $this->table ($this->idCol, $this->dataCol, $this->lifetimeCol, $this->timeCol) VALUES (:id, :data, :lifetime, :time) ". + $mergeSql = "INSERT INTO $this->table ($this->idCol, $this->dataCol, $this->lifetimeCol, $this->timeCol) VALUES (:id, :data, :lifetime, :time) ". "ON DUPLICATE KEY UPDATE $this->dataCol = VALUES($this->dataCol), $this->lifetimeCol = VALUES($this->lifetimeCol), $this->timeCol = VALUES($this->timeCol)"; + break; case 'oci' === $this->driver: // DUAL is Oracle specific dummy table - return "MERGE INTO $this->table USING DUAL ON ($this->idCol = :id) ". - "WHEN NOT MATCHED THEN INSERT ($this->idCol, $this->dataCol, $this->lifetimeCol, $this->timeCol) VALUES (:id, :data, :lifetime, :time) ". - "WHEN MATCHED THEN UPDATE SET $this->dataCol = :data, $this->lifetimeCol = :lifetime, $this->timeCol = :time"; + $mergeSql = "MERGE INTO $this->table USING DUAL ON ($this->idCol = ?) ". + "WHEN NOT MATCHED THEN INSERT ($this->idCol, $this->dataCol, $this->lifetimeCol, $this->timeCol) VALUES (?, ?, ?, ?) ". + "WHEN MATCHED THEN UPDATE SET $this->dataCol = ?, $this->lifetimeCol = ?, $this->timeCol = ?"; + break; case 'sqlsrv' === $this->driver && version_compare($this->pdo->getAttribute(\PDO::ATTR_SERVER_VERSION), '10', '>='): // MERGE is only available since SQL Server 2008 and must be terminated by semicolon // It also requires HOLDLOCK according to http://weblogs.sqlteam.com/dang/archive/2009/01/31/UPSERT-Race-Condition-With-MERGE.aspx - return "MERGE INTO $this->table WITH (HOLDLOCK) USING (SELECT 1 AS dummy) AS src ON ($this->idCol = :id) ". - "WHEN NOT MATCHED THEN INSERT ($this->idCol, $this->dataCol, $this->lifetimeCol, $this->timeCol) VALUES (:id, :data, :lifetime, :time) ". - "WHEN MATCHED THEN UPDATE SET $this->dataCol = :data, $this->lifetimeCol = :lifetime, $this->timeCol = :time;"; + $mergeSql = "MERGE INTO $this->table WITH (HOLDLOCK) USING (SELECT 1 AS dummy) AS src ON ($this->idCol = ?) ". + "WHEN NOT MATCHED THEN INSERT ($this->idCol, $this->dataCol, $this->lifetimeCol, $this->timeCol) VALUES (?, ?, ?, ?) ". + "WHEN MATCHED THEN UPDATE SET $this->dataCol = ?, $this->lifetimeCol = ?, $this->timeCol = ?;"; + break; case 'sqlite' === $this->driver: - return "INSERT OR REPLACE INTO $this->table ($this->idCol, $this->dataCol, $this->lifetimeCol, $this->timeCol) VALUES (:id, :data, :lifetime, :time)"; + $mergeSql = "INSERT OR REPLACE INTO $this->table ($this->idCol, $this->dataCol, $this->lifetimeCol, $this->timeCol) VALUES (:id, :data, :lifetime, :time)"; + break; case 'pgsql' === $this->driver && version_compare($this->pdo->getAttribute(\PDO::ATTR_SERVER_VERSION), '9.5', '>='): - return "INSERT INTO $this->table ($this->idCol, $this->dataCol, $this->lifetimeCol, $this->timeCol) VALUES (:id, :data, :lifetime, :time) ". + $mergeSql = "INSERT INTO $this->table ($this->idCol, $this->dataCol, $this->lifetimeCol, $this->timeCol) VALUES (:id, :data, :lifetime, :time) ". "ON CONFLICT ($this->idCol) DO UPDATE SET ($this->dataCol, $this->lifetimeCol, $this->timeCol) = (EXCLUDED.$this->dataCol, EXCLUDED.$this->lifetimeCol, EXCLUDED.$this->timeCol)"; + break; + } + + if (null !== $mergeSql) { + $mergeStmt = $this->pdo->prepare($mergeSql); + + if ('sqlsrv' === $this->driver || 'oci' === $this->driver) { + $mergeStmt->bindParam(1, $sessionId, \PDO::PARAM_STR); + $mergeStmt->bindParam(2, $sessionId, \PDO::PARAM_STR); + $mergeStmt->bindParam(3, $data, \PDO::PARAM_LOB); + $mergeStmt->bindParam(4, $maxlifetime, \PDO::PARAM_INT); + $mergeStmt->bindValue(5, time(), \PDO::PARAM_INT); + $mergeStmt->bindParam(6, $data, \PDO::PARAM_LOB); + $mergeStmt->bindParam(7, $maxlifetime, \PDO::PARAM_INT); + $mergeStmt->bindValue(8, time(), \PDO::PARAM_INT); + } else { + $mergeStmt->bindParam(':id', $sessionId, \PDO::PARAM_STR); + $mergeStmt->bindParam(':data', $data, \PDO::PARAM_LOB); + $mergeStmt->bindParam(':lifetime', $maxlifetime, \PDO::PARAM_INT); + $mergeStmt->bindValue(':time', time(), \PDO::PARAM_INT); + } + + return $mergeStmt; } } diff --git a/src/Symfony/Component/HttpFoundation/Tests/Session/Storage/Handler/PdoSessionHandlerTest.php b/src/Symfony/Component/HttpFoundation/Tests/Session/Storage/Handler/PdoSessionHandlerTest.php index 9612320976..1f88d00d8f 100644 --- a/src/Symfony/Component/HttpFoundation/Tests/Session/Storage/Handler/PdoSessionHandlerTest.php +++ b/src/Symfony/Component/HttpFoundation/Tests/Session/Storage/Handler/PdoSessionHandlerTest.php @@ -362,4 +362,8 @@ class MockPdo extends \PDO public function beginTransaction() { } + + public function rollBack() + { + } } diff --git a/src/Symfony/Component/HttpKernel/Kernel.php b/src/Symfony/Component/HttpKernel/Kernel.php index c908c11652..c2fee027f9 100644 --- a/src/Symfony/Component/HttpKernel/Kernel.php +++ b/src/Symfony/Component/HttpKernel/Kernel.php @@ -134,6 +134,14 @@ abstract class Kernel implements KernelInterface, TerminableInterface } if ($this->getHttpKernel() instanceof TerminableInterface) { + if (!$this->debug) { + if (function_exists('fastcgi_finish_request')) { + fastcgi_finish_request(); + } elseif ('cli' !== PHP_SAPI) { + Response::closeOutputBuffers(0, true); + } + } + $this->getHttpKernel()->terminate($request, $response); } } diff --git a/src/Symfony/Component/Process/Tests/ProcessTest.php b/src/Symfony/Component/Process/Tests/ProcessTest.php index af4ec5231e..2138bd558e 100644 --- a/src/Symfony/Component/Process/Tests/ProcessTest.php +++ b/src/Symfony/Component/Process/Tests/ProcessTest.php @@ -1162,7 +1162,8 @@ class ProcessTest extends \PHPUnit_Framework_TestCase /** * @dataProvider provideVariousIncrementals */ - public function testIncrementalOutputDoesNotRequireAnotherCall($stream, $method) { + public function testIncrementalOutputDoesNotRequireAnotherCall($stream, $method) + { $process = $this->getProcess(self::$phpBin.' -r '.escapeshellarg('$n = 0; while ($n < 3) { file_put_contents(\''.$stream.'\', $n, 1); $n++; usleep(1000); }'), null, null, null, null); $process->start(); $result = ''; @@ -1177,7 +1178,8 @@ class ProcessTest extends \PHPUnit_Framework_TestCase $process->stop(); } - public function provideVariousIncrementals() { + public function provideVariousIncrementals() + { return array( array('php://stdout', 'getIncrementalOutput'), array('php://stderr', 'getIncrementalErrorOutput'), diff --git a/src/Symfony/Component/Routing/CHANGELOG.md b/src/Symfony/Component/Routing/CHANGELOG.md index 7f5d9f0ec0..04ac1d3198 100644 --- a/src/Symfony/Component/Routing/CHANGELOG.md +++ b/src/Symfony/Component/Routing/CHANGELOG.md @@ -7,6 +7,22 @@ CHANGELOG * allowed specifying a directory to recursively load all routing configuration files it contains * Added ObjectRouteLoader and ServiceRouteLoader that allow routes to be loaded by calling a method on an object/service. + * [DEPRECATION] Deprecated the hardcoded value for the `$referenceType` argument of the `UrlGeneratorInterface::generate` method. + Use the constants defined in the `UrlGeneratorInterface` instead. + + Before: + + ```php + $router->generate('blog_show', array('slug' => 'my-blog-post'), true); + ``` + + After: + + ```php + use Symfony\Component\Routing\Generator\UrlGeneratorInterface; + + $router->generate('blog_show', array('slug' => 'my-blog-post'), UrlGeneratorInterface::ABSOLUTE_URL); + ``` 2.5.0 ----- diff --git a/src/Symfony/Component/Routing/Loader/AnnotationDirectoryLoader.php b/src/Symfony/Component/Routing/Loader/AnnotationDirectoryLoader.php index f6b99a16ae..f66b928971 100644 --- a/src/Symfony/Component/Routing/Loader/AnnotationDirectoryLoader.php +++ b/src/Symfony/Component/Routing/Loader/AnnotationDirectoryLoader.php @@ -69,7 +69,7 @@ class AnnotationDirectoryLoader extends AnnotationFileLoader if (!is_string($resource)) { return false; } - + try { $path = $this->locator->locate($resource); } catch (\Exception $e) { diff --git a/src/Symfony/Component/Routing/Matcher/Dumper/DumperCollection.php b/src/Symfony/Component/Routing/Matcher/Dumper/DumperCollection.php index e7dea88ed3..0f2815b73e 100644 --- a/src/Symfony/Component/Routing/Matcher/Dumper/DumperCollection.php +++ b/src/Symfony/Component/Routing/Matcher/Dumper/DumperCollection.php @@ -26,7 +26,7 @@ class DumperCollection implements \IteratorAggregate private $parent; /** - * @var (DumperCollection|DumperRoute)[] + * @var DumperCollection[]|DumperRoute[] */ private $children = array(); @@ -38,7 +38,7 @@ class DumperCollection implements \IteratorAggregate /** * Returns the children routes and collections. * - * @return (DumperCollection|DumperRoute)[] Array of DumperCollection|DumperRoute + * @return DumperCollection[]|DumperRoute[] Array of DumperCollection|DumperRoute */ public function all() { @@ -76,7 +76,7 @@ class DumperCollection implements \IteratorAggregate /** * Returns an iterator over the children. * - * @return \Iterator The iterator + * @return \Iterator|DumperCollection[]|DumperRoute[] The iterator */ public function getIterator() { diff --git a/src/Symfony/Component/Routing/RouteCollection.php b/src/Symfony/Component/Routing/RouteCollection.php index d6ac840ca6..2ccb90f3b0 100644 --- a/src/Symfony/Component/Routing/RouteCollection.php +++ b/src/Symfony/Component/Routing/RouteCollection.php @@ -49,7 +49,7 @@ class RouteCollection implements \IteratorAggregate, \Countable * * @see all() * - * @return \ArrayIterator An \ArrayIterator object for iterating over routes + * @return \ArrayIterator|Route[] An \ArrayIterator object for iterating over routes */ public function getIterator() { diff --git a/src/Symfony/Component/Serializer/Tests/Encoder/XmlEncoderTest.php b/src/Symfony/Component/Serializer/Tests/Encoder/XmlEncoderTest.php index 717004af05..5742b0c70a 100644 --- a/src/Symfony/Component/Serializer/Tests/Encoder/XmlEncoderTest.php +++ b/src/Symfony/Component/Serializer/Tests/Encoder/XmlEncoderTest.php @@ -249,7 +249,8 @@ XML; $this->assertEquals($expected, $serializer->serialize($array, 'xml', $options)); } - public function testEncodeTraversableWhenNormalizable() { + public function testEncodeTraversableWhenNormalizable() + { $this->encoder = new XmlEncoder(); $serializer = new Serializer(array(new CustomNormalizer()), array('xml' => new XmlEncoder())); $this->encoder->setSerializer($serializer); @@ -261,7 +262,6 @@ XML; XML; $this->assertEquals($expected, $serializer->serialize(new NormalizableTraversableDummy(), 'xml')); - } public function testDecode() diff --git a/src/Symfony/Component/Translation/Tests/TranslatorTest.php b/src/Symfony/Component/Translation/Tests/TranslatorTest.php index 0e8df69660..0f65d3e5ef 100644 --- a/src/Symfony/Component/Translation/Tests/TranslatorTest.php +++ b/src/Symfony/Component/Translation/Tests/TranslatorTest.php @@ -285,12 +285,12 @@ class TranslatorTest extends \PHPUnit_Framework_TestCase $resources = $translator->getCatalogue('en')->getResources(); $this->assertCount(1, $resources); - $this->assertContains( __DIR__.DIRECTORY_SEPARATOR.'fixtures'.DIRECTORY_SEPARATOR.'resources.yml', $resources); + $this->assertContains(__DIR__.DIRECTORY_SEPARATOR.'fixtures'.DIRECTORY_SEPARATOR.'resources.yml', $resources); $resources = $translator->getCatalogue('en_GB')->getResources(); $this->assertCount(2, $resources); - $this->assertContains( __DIR__.DIRECTORY_SEPARATOR.'fixtures'.DIRECTORY_SEPARATOR.'empty.yml', $resources); - $this->assertContains( __DIR__.DIRECTORY_SEPARATOR.'fixtures'.DIRECTORY_SEPARATOR.'resources.yml', $resources); + $this->assertContains(__DIR__.DIRECTORY_SEPARATOR.'fixtures'.DIRECTORY_SEPARATOR.'empty.yml', $resources); + $this->assertContains(__DIR__.DIRECTORY_SEPARATOR.'fixtures'.DIRECTORY_SEPARATOR.'resources.yml', $resources); } /** diff --git a/src/Symfony/Component/Validator/ConstraintViolationList.php b/src/Symfony/Component/Validator/ConstraintViolationList.php index cccfa86aea..d43d5431dd 100644 --- a/src/Symfony/Component/Validator/ConstraintViolationList.php +++ b/src/Symfony/Component/Validator/ConstraintViolationList.php @@ -107,6 +107,8 @@ class ConstraintViolationList implements \IteratorAggregate, ConstraintViolation /** * {@inheritdoc} + * + * @return \ArrayIterator|ConstraintViolationInterface[] */ public function getIterator() {