diff --git a/.travis.yml b/.travis.yml
index b5b7da55bc..8a87800c5f 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -6,10 +6,6 @@ php:
- 5.4
- 5.5
-matrix:
- allow_failures:
- - php: 5.5
-
before_script:
- echo '' > ~/.phpenv/versions/$(phpenv version-name)/etc/conf.d/xdebug.ini
- sh -c 'if [ $(php -r "echo PHP_MINOR_VERSION;") -le 4 ]; then echo "extension = apc.so" >> ~/.phpenv/versions/$(phpenv version-name)/etc/php.ini; fi;'
diff --git a/CHANGELOG-2.2.md b/CHANGELOG-2.2.md
index a0ec21c0a5..62cc761cb5 100644
--- a/CHANGELOG-2.2.md
+++ b/CHANGELOG-2.2.md
@@ -7,6 +7,26 @@ in 2.2 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/v2.2.0...v2.2.1
+* 2.2.3 (2013-06-19)
+
+ * c0da3ae: [Process] Disable exception on stream_select timeout
+ * 77f2aa8: [HttpFoundation] fixed issue with session_regenerate_id (closes #7380)
+ * bcbbb28: Throw exception if value is passed to VALUE_NONE input, long syntax
+ * 6b71513: fixed date type format pattern regex
+ * 842f3fa: do not re-register commands each time a Console\Application is run
+ * 0991cd0: [Process] moved env check to the Process class (refs #8227)
+ * 8764944: fix issue where $_ENV contains array vals
+ * 4139936: [DomCrawler] Fix handling file:// without a host
+ * de289d2: [Form] corrected interface bind() method defined against in deprecation notice
+ * 0c0a3e9: [Console] fixed regression when calling a command foo:bar if there is another one like foo:bar:baz (closes #8245)
+ * 849f3ed: [Finder] Fix SplFileInfo::getContents isn't working with ssh2 protocol
+ * 25e3abd: fix many-to-many Propel1 ModelChoiceList
+ * bce6bd2: [DomCrawler] Fixed a fatal error when setting a value in a malformed field name.
+ * 445b2e3: [Console] fix status code when Exception::getCode returns something like 0.1
+ * bbfde62: Fixed exit code for exceptions with error code 0
+ * afad9c7: instantiate valid commands only
+ * 6d2135b: force the Content-Type to html in the web profiler controllers
+
* 2.2.2 (2013-06-02)
* 2038329: [Form] [Validator] Fixed post_max_size = 0 bug (Issue #8065)
diff --git a/CHANGELOG-2.3.md b/CHANGELOG-2.3.md
index 2617dfb023..1392c6d1df 100644
--- a/CHANGELOG-2.3.md
+++ b/CHANGELOG-2.3.md
@@ -7,6 +7,19 @@ in 2.3 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/v2.3.0...v2.3.1
+* 2.3.1 (2013-06-11)
+
+ * 25e3abd: fix many-to-many Propel1 ModelChoiceList
+ * bce6bd2: [DomCrawler] Fixed a fatal error when setting a value in a malformed field name.
+ * e3561ce: [FrameworkBundle] Fixed OutOfBoundException when session handler_id is null
+ * 81b122d: [DependencyInjection] Add support for aliases of aliases + regression test
+ * 445b2e3: [Console] fix status code when Exception::getCode returns something like 0.1
+ * bbfde62: Fixed exit code for exceptions with error code 0
+ * d8c0ef7: [DependencyInjection] Rename ContainerBuilder::$aliases to avoid conflicting with the parent class
+ * bb797ee: [DependencyInjection] Remove get*Alias*Service methods from compiled containers
+ * 379f5e0: [DependencyInjection] Fix aliased access of shared services, fixes #8096
+ * afad9c7: instantiate valid commands only
+
* 2.3.0 (2013-06-03)
* e93fc7a: [FrameworkBundle] set the dispatcher in the console application
diff --git a/CONTRIBUTORS.md b/CONTRIBUTORS.md
index 4cc61bf785..5d9190350e 100644
--- a/CONTRIBUTORS.md
+++ b/CONTRIBUTORS.md
@@ -9,8 +9,8 @@ Symfony2 is the result of the work of many people who made the code better
- Victor Berchet (victor)
- Jordi Boggiano (seldaek)
- Johannes S (johannes)
- - Kris Wallsmith (kriswallsmith)
- Tobias Schultze (tobion)
+ - Kris Wallsmith (kriswallsmith)
- Christophe Coevoet (stof)
- Pascal Borreli (pborreli)
- Karma Dordrak (drak)
@@ -51,20 +51,20 @@ Symfony2 is the result of the work of many people who made the code better
- Hidenori Goto (hidenorigoto)
- Fran Moreno (franmomu)
- Andrej Hudec (pulzarraider)
+ - Grégoire Pineau (lyrixx)
- Lee McDermott
- Brandon Turner
- Daniel Holmes (dholmes)
- Brikou Carré (brikou)
- John Wards (johnwards)
- - Grégoire Pineau (lyrixx)
- Antoine Hérault (herzult)
- Bart van den Burg (burgov)
+ - Toni Uebernickel (havvg)
- Tim Nagel (merk)
- Włodzimierz Gajda (gajdaw)
- Michel Weimerskirch (mweimerskirch)
- Christian Raue
- Michal Piotrowski (eventhorizon)
- - Toni Uebernickel (havvg)
- Colin Frei
- lenar
- Fabien Pennequin (fabienpennequin)
@@ -220,6 +220,7 @@ Symfony2 is the result of the work of many people who made the code better
- Emanuele Gaspari (inmarelibero)
- Brian King
- Jan Schumann
+ - Ruben Gonzalez (rubenrua)
- Antonio J. García Lagar (ajgarlag)
- Olivier Dolbeau (odolbeau)
- Robert Kiss (kepten)
@@ -233,7 +234,9 @@ Symfony2 is the result of the work of many people who made the code better
- Marcin Sikoń (marphi)
- Miquel Rodríguez Telep (mrtorrent)
- Filippo Tessarotto
+ - Mark Sonnabaum
- Adam Harvey
+ - Pierre-Yves LEBECQ (pylebecq)
- Laurent Bachelier (laurentb)
- Fabian Lange (codingfabian)
- Yoshio HANAWA
@@ -255,6 +258,7 @@ Symfony2 is the result of the work of many people who made the code better
- alexpods
- Erik Trapman (eriktrapman)
- De Cock Xavier (xdecock)
+ - Vitaliy Zakharov (zakharovvi)
- Matthijs van den Bos
- Joel Wurtz
- Nils Adermann (naderman)
@@ -295,7 +299,6 @@ Symfony2 is the result of the work of many people who made the code better
- Markus Bachmann (baachi)
- aubx
- Max Rath (drak3)
- - Ruben Gonzalez (rubenrua)
- Sinan Eldem
- DerManoMann
- alquerci
@@ -322,12 +325,10 @@ Symfony2 is the result of the work of many people who made the code better
- cedric lombardot (cedriclombardot)
- John Kary (johnkary)
- Hossein Bukhamsin
- - Pierre-Yves LEBECQ (pylebecq)
- Fabrice Bernhard (fabriceb)
- Oleg Zinchenko (cystbear)
- Johannes Klauss (cloppy)
- fzerorubigd
- - Mark Sonnabaum
- develop
- Atsuhiro KUBO (iteman)
- Samy Dindane (dinduks)
@@ -374,7 +375,6 @@ Symfony2 is the result of the work of many people who made the code better
- Luis Cordova (cordoval)
- Philipp Kräutli (pkraeutli)
- Stefano Sala (stefano.sala)
- - Vitaliy Zakharov (zakharovvi)
- frost-nzcr4
- Abhoryo
- Fabian Vogler (fabian)
@@ -430,6 +430,7 @@ Symfony2 is the result of the work of many people who made the code better
- xaav
- Mahmoud Mostafa (mahmoud)
- Juti Noppornpitak
+ - lancergr
- Mei Gwilym
- ttomor
- Sander Coolen
@@ -479,6 +480,7 @@ Symfony2 is the result of the work of many people who made the code better
- DerManoMann
- Roland Franssen (ro0)
- Jochen Bayer (jocl)
+ - Jerome TAMARELLE
- Jeremy Bush
- Evan Villemez
- Péter Buri (burci)
@@ -486,6 +488,7 @@ Symfony2 is the result of the work of many people who made the code better
- kaiwa
- Albert Ganiev (helios-ag)
- Neil Katin
+ - peter
- Gustavo Adrian
- Brooks Boyd
- Roger Webb
@@ -493,6 +496,7 @@ Symfony2 is the result of the work of many people who made the code better
- Felicitus
- Paul Matthews
- Philipp Strube
+ - Christian Sciberras
- Clement Herreman (clemherreman)
- Marco
- Alberto Aldegheri
@@ -511,6 +515,7 @@ Symfony2 is the result of the work of many people who made the code better
- Ludek Stepan
- Balázs Benyó (duplabe)
- Marc Morera (mmoreram)
+ - Saem Ghani
- Sebastian Utz
- Keri Henare (kerihenare)
- Cédric Lahouste (rapotor)
@@ -524,6 +529,7 @@ Symfony2 is the result of the work of many people who made the code better
- Lance McNearney
- Alberto Pirovano (geezmo)
- Gabor Toth (tgabi333)
+ - Martin Pärtel
- Xavier Briand (xavierbriand)
- Evan Kaufman
- Romain Geissler
@@ -554,6 +560,7 @@ Symfony2 is the result of the work of many people who made the code better
- Benjamin Bender
- Konrad Mohrfeldt
- Benoit Lévêque (benoit_leveque)
+ - Stelian Mocanita (stelian)
- jskvara
- Mephistofeles
- Hoffmann András
@@ -641,6 +648,7 @@ Symfony2 is the result of the work of many people who made the code better
- partugal
- Robert Campbell
- Matt Lehner
+ - Aleksey Podskrebyshev
- cyrillej
- Alex Pods
- timaschew
@@ -686,15 +694,18 @@ Symfony2 is the result of the work of many people who made the code better
- Nicolas A. Bérard-Nault
- Gladhon
- Saem Ghani
+ - Stefan Oderbolz
- Alexey Popkov
- Piotr Błasiak
- Arnaud Buathier (arnapou)
- chesteroni (chesteroni)
+ - Daniele Cesarini (ijanki)
- Simon CONSTANS (kosssi)
- Mauricio Lopez (sanctuary29)
- Wotre
- goohib
- Xavier HAUSHERR
+ - ghazy ben ahmed
- Myke79
- Brian Debuire
- Lars Vierbergen
diff --git a/src/Symfony/Bundle/FrameworkBundle/Console/Application.php b/src/Symfony/Bundle/FrameworkBundle/Console/Application.php
index 06a8698cf1..90d19c60e3 100644
--- a/src/Symfony/Bundle/FrameworkBundle/Console/Application.php
+++ b/src/Symfony/Bundle/FrameworkBundle/Console/Application.php
@@ -27,6 +27,7 @@ use Symfony\Component\HttpKernel\Bundle\Bundle;
class Application extends BaseApplication
{
private $kernel;
+ private $commandsRegistered = false;
/**
* Constructor.
@@ -65,7 +66,11 @@ class Application extends BaseApplication
*/
public function doRun(InputInterface $input, OutputInterface $output)
{
- $this->registerCommands();
+ if (!$this->commandsRegistered) {
+ $this->registerCommands();
+
+ $this->commandsRegistered = true;
+ }
$this->setDispatcher($this->kernel->getContainer()->get('event_dispatcher'));
diff --git a/src/Symfony/Bundle/WebProfilerBundle/Controller/ExceptionController.php b/src/Symfony/Bundle/WebProfilerBundle/Controller/ExceptionController.php
index c89f346413..97021c8a46 100644
--- a/src/Symfony/Bundle/WebProfilerBundle/Controller/ExceptionController.php
+++ b/src/Symfony/Bundle/WebProfilerBundle/Controller/ExceptionController.php
@@ -55,7 +55,7 @@ class ExceptionController
if (!$this->twig->getLoader()->exists($template)) {
$handler = new ExceptionHandler();
- return new Response($handler->getContent($exception));
+ return new Response($handler->getContent($exception), 200, array('Content-Type' => 'text/html'));
}
$code = $exception->getStatusCode();
@@ -69,7 +69,7 @@ class ExceptionController
'logger' => null,
'currentContent' => '',
)
- ));
+ ), 200, array('Content-Type' => 'text/html'));
}
/**
@@ -96,7 +96,7 @@ class ExceptionController
return new Response($handler->getStylesheet($exception));
}
- return new Response($this->twig->render('@WebProfiler/Collector/exception.css.twig'));
+ return new Response($this->twig->render('@WebProfiler/Collector/exception.css.twig'), 200, 'text/css');
}
protected function getTemplate()
diff --git a/src/Symfony/Bundle/WebProfilerBundle/Controller/ProfilerController.php b/src/Symfony/Bundle/WebProfilerBundle/Controller/ProfilerController.php
index 31bda0393b..bd60fb3751 100644
--- a/src/Symfony/Bundle/WebProfilerBundle/Controller/ProfilerController.php
+++ b/src/Symfony/Bundle/WebProfilerBundle/Controller/ProfilerController.php
@@ -65,7 +65,7 @@ class ProfilerController
$this->profiler->disable();
- return new RedirectResponse($this->generator->generate('_profiler_search_results', array('token' => 'empty', 'limit' => 10)));
+ return new RedirectResponse($this->generator->generate('_profiler_search_results', array('token' => 'empty', 'limit' => 10)), 302, array('Content-Type' => 'text/html'));
}
/**
@@ -90,7 +90,7 @@ class ProfilerController
$page = $request->query->get('page', 'home');
if (!$profile = $this->profiler->loadProfile($token)) {
- return new Response($this->twig->render('@WebProfiler/Profiler/info.html.twig', array('about' => 'no_token', 'token' => $token)));
+ return new Response($this->twig->render('@WebProfiler/Profiler/info.html.twig', array('about' => 'no_token', 'token' => $token)), 200, array('Content-Type' => 'text/html'));
}
if (!$profile->hasCollector($panel)) {
@@ -106,7 +106,7 @@ class ProfilerController
'request' => $request,
'templates' => $this->getTemplateManager()->getTemplates($profile),
'is_ajax' => $request->isXmlHttpRequest(),
- )));
+ )), 200, array('Content-Type' => 'text/html'));
}
/**
@@ -150,7 +150,7 @@ class ProfilerController
$this->profiler->disable();
$this->profiler->purge();
- return new RedirectResponse($this->generator->generate('_profiler_info', array('about' => 'purge')));
+ return new RedirectResponse($this->generator->generate('_profiler_info', array('about' => 'purge')), 302, array('Content-Type' => 'text/html'));
}
/**
@@ -171,14 +171,14 @@ class ProfilerController
$file = $request->files->get('file');
if (empty($file) || !$file->isValid()) {
- return new RedirectResponse($this->generator->generate('_profiler_info', array('about' => 'upload_error')));
+ return new RedirectResponse($this->generator->generate('_profiler_info', array('about' => 'upload_error')), 302, array('Content-Type' => 'text/html'));
}
if (!$profile = $this->profiler->import(file_get_contents($file->getPathname()))) {
- return new RedirectResponse($this->generator->generate('_profiler_info', array('about' => 'already_exists')));
+ return new RedirectResponse($this->generator->generate('_profiler_info', array('about' => 'already_exists')), 302, array('Content-Type' => 'text/html'));
}
- return new RedirectResponse($this->generator->generate('_profiler', array('token' => $profile->getToken())));
+ return new RedirectResponse($this->generator->generate('_profiler', array('token' => $profile->getToken())), 302, array('Content-Type' => 'text/html'));
}
/**
@@ -198,7 +198,7 @@ class ProfilerController
return new Response($this->twig->render('@WebProfiler/Profiler/info.html.twig', array(
'about' => $about
- )));
+ )), 200, array('Content-Type' => 'text/html'));
}
/**
@@ -223,13 +223,13 @@ class ProfilerController
}
if (null === $token) {
- return new Response();
+ return new Response('', 200, array('Content-Type' => 'text/html'));
}
$this->profiler->disable();
if (!$profile = $this->profiler->loadProfile($token)) {
- return new Response();
+ return new Response('', 200, array('Content-Type' => 'text/html'));
}
// the toolbar position (top, bottom, normal, or null -- use the configuration)
@@ -250,7 +250,7 @@ class ProfilerController
'templates' => $this->getTemplateManager()->getTemplates($profile),
'profiler_url' => $url,
'token' => $token,
- )));
+ )), 200, array('Content-Type' => 'text/html'));
}
/**
@@ -294,7 +294,7 @@ class ProfilerController
'start' => $start,
'end' => $end,
'limit' => $limit,
- )));
+ )), 200, array('Content-Type' => 'text/html'));
}
/**
@@ -333,7 +333,7 @@ class ProfilerController
'end' => $end,
'limit' => $limit,
'panel' => null,
- )));
+ )), 200, array('Content-Type' => 'text/html'));
}
/**
@@ -370,7 +370,7 @@ class ProfilerController
}
if (!empty($token)) {
- return new RedirectResponse($this->generator->generate('_profiler', array('token' => $token)));
+ return new RedirectResponse($this->generator->generate('_profiler', array('token' => $token)), 302, array('Content-Type' => 'text/html'));
}
$tokens = $this->profiler->find($ip, $url, $limit, $method, $start, $end);
@@ -383,7 +383,7 @@ class ProfilerController
'start' => $start,
'end' => $end,
'limit' => $limit,
- )));
+ )), 302, array('Content-Type' => 'text/html'));
}
/**
@@ -403,7 +403,7 @@ class ProfilerController
phpinfo();
$phpinfo = ob_get_clean();
- return new Response($phpinfo);
+ return new Response($phpinfo, 200, array('Content-Type' => 'text/html'));
}
/**
diff --git a/src/Symfony/Bundle/WebProfilerBundle/Controller/RouterController.php b/src/Symfony/Bundle/WebProfilerBundle/Controller/RouterController.php
index 55fd7d1d33..591bedc13a 100644
--- a/src/Symfony/Bundle/WebProfilerBundle/Controller/RouterController.php
+++ b/src/Symfony/Bundle/WebProfilerBundle/Controller/RouterController.php
@@ -58,7 +58,7 @@ class RouterController
$this->profiler->disable();
if (null === $this->matcher || null === $this->routes) {
- return new Response('The Router is not enabled.');
+ return new Response('The Router is not enabled.', 200, array('Content-Type' => 'text/html'));
}
$profile = $this->profiler->loadProfile($token);
@@ -73,6 +73,6 @@ class RouterController
'request' => $request,
'router' => $profile->getCollector('router'),
'traces' => $matcher->getTraces($request->getPathInfo()),
- )));
+ )), 200, array('Content-Type' => 'text/html'));
}
}
diff --git a/src/Symfony/Component/Console/Helper/ProgressHelper.php b/src/Symfony/Component/Console/Helper/ProgressHelper.php
index 4301818e21..1285be2fb8 100644
--- a/src/Symfony/Component/Console/Helper/ProgressHelper.php
+++ b/src/Symfony/Component/Console/Helper/ProgressHelper.php
@@ -186,6 +186,8 @@ class ProgressHelper extends Helper
$this->current = 0;
$this->max = (int) $max;
$this->output = $output;
+ $this->lastMessagesLength = 0;
+ $this->barCharOriginal = '';
if (null === $this->format) {
switch ($output->getVerbosity()) {
diff --git a/src/Symfony/Component/Console/Helper/TableHelper.php b/src/Symfony/Component/Console/Helper/TableHelper.php
index cf18e4913c..c18f29598a 100644
--- a/src/Symfony/Component/Console/Helper/TableHelper.php
+++ b/src/Symfony/Component/Console/Helper/TableHelper.php
@@ -359,12 +359,18 @@ class TableHelper extends Helper
private function renderCell(array $row, $column, $cellFormat)
{
$cell = isset($row[$column]) ? $row[$column] : '';
+ $width = $this->getColumnWidth($column);
+
+ // str_pad won't work properly with multi-byte strings, we need to fix the padding
+ if (function_exists('mb_strlen') && false !== $encoding = mb_detect_encoding($cell)) {
+ $width += strlen($cell) - mb_strlen($cell, $encoding);
+ }
$this->output->write(sprintf(
$cellFormat,
str_pad(
$this->paddingChar.$cell.$this->paddingChar,
- $this->getColumnWidth($column),
+ $width,
$this->paddingChar,
$this->padType
)
diff --git a/src/Symfony/Component/Console/Input/ArgvInput.php b/src/Symfony/Component/Console/Input/ArgvInput.php
index 6a4d1d506f..e19f629550 100644
--- a/src/Symfony/Component/Console/Input/ArgvInput.php
+++ b/src/Symfony/Component/Console/Input/ArgvInput.php
@@ -134,7 +134,7 @@ class ArgvInput extends Input
break;
} else {
- $this->addLongOption($option->getName(), true);
+ $this->addLongOption($option->getName(), null);
}
}
}
@@ -220,6 +220,10 @@ class ArgvInput extends Input
$value = null;
}
+ if (null !== $value && !$option->acceptValue()) {
+ throw new \RuntimeException(sprintf('The "--%s" option does not accept a value.', $name, $value));
+ }
+
if (null === $value && $option->acceptValue() && count($this->parsed)) {
// if option accepts an optional or mandatory argument
// let's see if there is one provided
diff --git a/src/Symfony/Component/Console/Tests/Helper/TableHelperTest.php b/src/Symfony/Component/Console/Tests/Helper/TableHelperTest.php
index b2aa82b2de..5873a7fda6 100644
--- a/src/Symfony/Component/Console/Tests/Helper/TableHelperTest.php
+++ b/src/Symfony/Component/Console/Tests/Helper/TableHelperTest.php
@@ -174,6 +174,33 @@ TABLE
);
}
+ public function testRenderMultiByte()
+ {
+ if (!function_exists('mb_strlen')) {
+ $this->markTestSkipped('The "mbstring" extension is not available');
+ }
+
+ $table = new TableHelper();
+ $table
+ ->setHeaders(array('■■'))
+ ->setRows(array(array(1234)))
+ ->setLayout(TableHelper::LAYOUT_DEFAULT)
+ ;
+ $table->render($output = $this->getOutputStream());
+
+ $expected =
+<<
assertEquals($expected, $this->getOutputContent($output));
+ }
+
protected function getOutputStream()
{
return new StreamOutput($this->stream, StreamOutput::VERBOSITY_NORMAL, false);
diff --git a/src/Symfony/Component/Console/Tests/Input/ArgvInputTest.php b/src/Symfony/Component/Console/Tests/Input/ArgvInputTest.php
index 8e07c4c558..c6ad757e23 100644
--- a/src/Symfony/Component/Console/Tests/Input/ArgvInputTest.php
+++ b/src/Symfony/Component/Console/Tests/Input/ArgvInputTest.php
@@ -175,6 +175,11 @@ class ArgvInputTest extends \PHPUnit_Framework_TestCase
new InputDefinition(array(new InputOption('foo', 'f', InputOption::VALUE_NONE))),
'The "-o" option does not exist.'
),
+ array(
+ array('cli.php', '--foo=bar'),
+ new InputDefinition(array(new InputOption('foo', 'f', InputOption::VALUE_NONE))),
+ 'The "--foo" option does not accept a value.'
+ ),
array(
array('cli.php', 'foo', 'bar'),
new InputDefinition(),
diff --git a/src/Symfony/Component/CssSelector/README.md b/src/Symfony/Component/CssSelector/README.md
index c4409fef6c..5075cdb7eb 100644
--- a/src/Symfony/Component/CssSelector/README.md
+++ b/src/Symfony/Component/CssSelector/README.md
@@ -10,6 +10,25 @@ equivalents:
print CssSelector::toXPath('div.item > h4 > a');
+HTML and XML are different
+--------------------------
+
+The `CssSelector` component comes with an `HTML` extension which is enabled by
+default. If you need to use this component with `XML` documents, you have to
+disable this `HTML` extension. That's because, `HTML` tag & attribute names
+are always lower-cased, but case-sensitive in `XML`:
+
+ // disable `HTML` extension:
+ CssSelector::disableHtmlExtension();
+
+ // re-enable `HTML` extension:
+ CssSelector::enableHtmlExtension();
+
+When the `HTML` extension is enabled, tag names are lower-cased, attribute
+names are lower-cased, the following extra pseudo-classes are supported:
+`checked`, `link`, `disabled`, `enabled`, `selected`, `invalid`, `hover`,
+`visited`, and the `lang()` function is also added.
+
Resources
---------
diff --git a/src/Symfony/Component/DependencyInjection/Container.php b/src/Symfony/Component/DependencyInjection/Container.php
index ef561e1ded..b97f8a2c03 100644
--- a/src/Symfony/Component/DependencyInjection/Container.php
+++ b/src/Symfony/Component/DependencyInjection/Container.php
@@ -88,6 +88,7 @@ class Container implements IntrospectableContainerInterface
$this->parameterBag = null === $parameterBag ? new ParameterBag() : $parameterBag;
$this->services = array();
+ $this->aliases = array();
$this->scopes = array();
$this->scopeChildren = array();
$this->scopedServices = array();
@@ -228,7 +229,10 @@ class Container implements IntrospectableContainerInterface
{
$id = strtolower($id);
- return array_key_exists($id, $this->services) || method_exists($this, 'get'.strtr($id, array('_' => '', '.' => '_')).'Service');
+ return array_key_exists($id, $this->services)
+ || array_key_exists($id, $this->aliases)
+ || method_exists($this, 'get'.strtr($id, array('_' => '', '.' => '_')).'Service')
+ ;
}
/**
diff --git a/src/Symfony/Component/DependencyInjection/Tests/ContainerTest.php b/src/Symfony/Component/DependencyInjection/Tests/ContainerTest.php
index f49a567f52..c87f2c2b9a 100644
--- a/src/Symfony/Component/DependencyInjection/Tests/ContainerTest.php
+++ b/src/Symfony/Component/DependencyInjection/Tests/ContainerTest.php
@@ -477,6 +477,14 @@ class ContainerTest extends \PHPUnit_Framework_TestCase
return $reflection->getValue($obj);
}
+
+ public function testAlias()
+ {
+ $c = new ProjectServiceContainer();
+
+ $this->assertTrue($c->has('alias'));
+ $this->assertSame($c->get('alias'), $c->get('bar'));
+ }
}
class ProjectServiceContainer extends Container
@@ -490,6 +498,7 @@ class ProjectServiceContainer extends Container
$this->__bar = new \stdClass();
$this->__foo_bar = new \stdClass();
$this->__foo_baz = new \stdClass();
+ $this->aliases = array('alias' => 'bar');
}
protected function getScopedService()
diff --git a/src/Symfony/Component/DependencyInjection/Tests/Loader/IniFileLoaderTest.php b/src/Symfony/Component/DependencyInjection/Tests/Loader/IniFileLoaderTest.php
index bba9c8c85f..220ad7fe4d 100644
--- a/src/Symfony/Component/DependencyInjection/Tests/Loader/IniFileLoaderTest.php
+++ b/src/Symfony/Component/DependencyInjection/Tests/Loader/IniFileLoaderTest.php
@@ -50,31 +50,25 @@ class IniFileLoaderTest extends \PHPUnit_Framework_TestCase
/**
* @covers Symfony\Component\DependencyInjection\Loader\IniFileLoader::__construct
* @covers Symfony\Component\DependencyInjection\Loader\IniFileLoader::load
+ *
+ * @expectedException \InvalidArgumentException
+ * @expectedExceptionMessage The file "foo.ini" does not exist (in:
*/
public function testExceptionIsRaisedWhenIniFileDoesNotExist()
{
- try {
- $this->loader->load('foo.ini');
- $this->fail('->load() throws an InvalidArgumentException if the loaded file does not exist');
- } catch (\Exception $e) {
- $this->assertInstanceOf('\InvalidArgumentException', $e, '->load() throws an InvalidArgumentException if the loaded file does not exist');
- $this->assertStringStartsWith('The file "foo.ini" does not exist (in: ', $e->getMessage(), '->load() throws an InvalidArgumentException if the loaded file does not exist');
- }
+ $this->loader->load('foo.ini');
}
/**
* @covers Symfony\Component\DependencyInjection\Loader\IniFileLoader::__construct
* @covers Symfony\Component\DependencyInjection\Loader\IniFileLoader::load
+ *
+ * @expectedException \InvalidArgumentException
+ * @expectedExceptionMessage The "nonvalid.ini" file is not valid.
*/
public function testExceptionIsRaisedWhenIniFileCannotBeParsed()
{
- try {
- @$this->loader->load('nonvalid.ini');
- $this->fail('->load() throws an InvalidArgumentException if the loaded file is not parseable');
- } catch (\Exception $e) {
- $this->assertInstanceOf('\InvalidArgumentException', $e, '->load() throws an InvalidArgumentException if the loaded file is not parseable');
- $this->assertEquals('The "nonvalid.ini" file is not valid.', $e->getMessage(), '->load() throws an InvalidArgumentException if the loaded file is not parseable');
- }
+ @$this->loader->load('nonvalid.ini');
}
/**
diff --git a/src/Symfony/Component/DomCrawler/Crawler.php b/src/Symfony/Component/DomCrawler/Crawler.php
index cc2e68209f..c2be830bf9 100644
--- a/src/Symfony/Component/DomCrawler/Crawler.php
+++ b/src/Symfony/Component/DomCrawler/Crawler.php
@@ -82,6 +82,10 @@ class Crawler extends \SplObjectStorage
/**
* Adds HTML/XML content.
*
+ * If the charset is not set via the content type, it is assumed
+ * to be ISO-8859-1, which is the default charset defined by the
+ * HTTP 1.1 specification.
+ *
* @param string $content A string to parse as HTML/XML
* @param null|string $type The content type of the string
*
diff --git a/src/Symfony/Component/DomCrawler/Link.php b/src/Symfony/Component/DomCrawler/Link.php
index 293d4e03f4..d1d1e518da 100644
--- a/src/Symfony/Component/DomCrawler/Link.php
+++ b/src/Symfony/Component/DomCrawler/Link.php
@@ -125,7 +125,7 @@ class Link
return preg_replace('#^([^/]*)//.*$#', '$1', $this->currentUri).$uri;
}
- $baseUri = preg_replace('#^(.*?//[^/]+)(?:\/.*)?$#', '$1', $this->currentUri);
+ $baseUri = preg_replace('#^(.*?//[^/]*)(?:\/.*)?$#', '$1', $this->currentUri);
// absolute path
if ('/' === $uri[0]) {
diff --git a/src/Symfony/Component/DomCrawler/Tests/LinkTest.php b/src/Symfony/Component/DomCrawler/Tests/LinkTest.php
index 1761470500..136723a668 100644
--- a/src/Symfony/Component/DomCrawler/Tests/LinkTest.php
+++ b/src/Symfony/Component/DomCrawler/Tests/LinkTest.php
@@ -122,6 +122,11 @@ class LinkTest extends \PHPUnit_Framework_TestCase
array('../bar/./../../foo', 'http://localhost/bar/foo/', 'http://localhost/foo'),
array('../../', 'http://localhost/', 'http://localhost/'),
array('../../', 'http://localhost', 'http://localhost/'),
+
+ array('/foo', 'file:///', 'file:///foo'),
+ array('/foo', 'file:///bar/baz', 'file:///foo'),
+ array('foo', 'file:///', 'file:///foo'),
+ array('foo', 'file:///bar/baz', 'file:///bar/foo'),
);
}
}
diff --git a/src/Symfony/Component/Finder/SplFileInfo.php b/src/Symfony/Component/Finder/SplFileInfo.php
index e7e58f757c..d911fe06e8 100644
--- a/src/Symfony/Component/Finder/SplFileInfo.php
+++ b/src/Symfony/Component/Finder/SplFileInfo.php
@@ -65,7 +65,7 @@ class SplFileInfo extends \SplFileInfo
public function getContents()
{
$level = error_reporting(0);
- $content = file_get_contents($this->getRealpath());
+ $content = file_get_contents($this->getPathname());
error_reporting($level);
if (false === $content) {
$error = error_get_last();
diff --git a/src/Symfony/Component/Form/Extension/Core/DataTransformer/NumberToLocalizedStringTransformer.php b/src/Symfony/Component/Form/Extension/Core/DataTransformer/NumberToLocalizedStringTransformer.php
index 689c74a94a..b0c59b3ede 100644
--- a/src/Symfony/Component/Form/Extension/Core/DataTransformer/NumberToLocalizedStringTransformer.php
+++ b/src/Symfony/Component/Form/Extension/Core/DataTransformer/NumberToLocalizedStringTransformer.php
@@ -128,7 +128,7 @@ class NumberToLocalizedStringTransformer implements DataTransformerInterface
throw new TransformationFailedException($formatter->getErrorMessage());
}
- if ($result >= INF || $result <= -INF) {
+ if ($result >= PHP_INT_MAX || $result <= -PHP_INT_MAX) {
throw new TransformationFailedException('I don\'t have a clear idea what infinity looks like');
}
diff --git a/src/Symfony/Component/Form/Extension/Core/Type/DateType.php b/src/Symfony/Component/Form/Extension/Core/Type/DateType.php
index a4a55a2af5..93d3502e95 100644
--- a/src/Symfony/Component/Form/Extension/Core/Type/DateType.php
+++ b/src/Symfony/Component/Form/Extension/Core/Type/DateType.php
@@ -144,7 +144,7 @@ class DateType extends AbstractType
// set right order with respect to locale (e.g.: de_DE=dd.MM.yy; en_US=M/d/yy)
// lookup various formats at http://userguide.icu-project.org/formatparse/datetime
- if (preg_match('/^([yMd]+).+([yMd]+).+([yMd]+)$/', $pattern)) {
+ if (preg_match('/^([yMd]+)[^yMd]*([yMd]+)[^yMd]*([yMd]+)$/', $pattern)) {
$pattern = preg_replace(array('/y+/', '/M+/', '/d+/'), array('{{ year }}', '{{ month }}', '{{ day }}'), $pattern);
} else {
// default fallback
diff --git a/src/Symfony/Component/Form/Tests/Extension/Core/Type/DateTypeTest.php b/src/Symfony/Component/Form/Tests/Extension/Core/Type/DateTypeTest.php
index da6b4657fa..2aa155e753 100644
--- a/src/Symfony/Component/Form/Tests/Extension/Core/Type/DateTypeTest.php
+++ b/src/Symfony/Component/Form/Tests/Extension/Core/Type/DateTypeTest.php
@@ -271,6 +271,29 @@ class DateTypeTest extends TypeTestCase
$this->assertEquals('06*2010*02', $form->getViewData());
}
+ /**
+ * @dataProvider provideDateFormats
+ */
+ public function testDatePatternWithFormatOption($format, $pattern)
+ {
+ $form = $this->factory->create('date', null, array(
+ 'format' => $format,
+ ));
+
+ $view = $form->createView();
+
+ $this->assertEquals($pattern, $view->vars['date_pattern']);
+ }
+
+ public function provideDateFormats()
+ {
+ return array(
+ array('dMy', '{{ day }}{{ month }}{{ year }}'),
+ array('d-M-yyyy', '{{ day }}-{{ month }}-{{ year }}'),
+ array('M d y', '{{ month }} {{ day }} {{ year }}'),
+ );
+ }
+
/**
* This test is to check that the strings '0', '1', '2', '3' are no accepted
* as valid IntlDateFormatter constants for FULL, LONG, MEDIUM or SHORT respectively.
diff --git a/src/Symfony/Component/HttpFoundation/Session/Storage/NativeSessionStorage.php b/src/Symfony/Component/HttpFoundation/Session/Storage/NativeSessionStorage.php
index 36d87a707e..755d1dcc27 100644
--- a/src/Symfony/Component/HttpFoundation/Session/Storage/NativeSessionStorage.php
+++ b/src/Symfony/Component/HttpFoundation/Session/Storage/NativeSessionStorage.php
@@ -207,7 +207,15 @@ class NativeSessionStorage implements SessionStorageInterface
$this->metadataBag->stampNew();
}
- return session_regenerate_id($destroy);
+ $ret = session_regenerate_id($destroy);
+
+ // workaround for https://bugs.php.net/bug.php?id=61470 as suggested by David Grudl
+ session_write_close();
+ $backup = $_SESSION;
+ session_start();
+ $_SESSION = $backup;
+
+ return $ret;
}
/**
diff --git a/src/Symfony/Component/Intl/Tests/DateFormatter/AbstractIntlDateFormatterTest.php b/src/Symfony/Component/Intl/Tests/DateFormatter/AbstractIntlDateFormatterTest.php
index 6dde36a704..84f6433a57 100644
--- a/src/Symfony/Component/Intl/Tests/DateFormatter/AbstractIntlDateFormatterTest.php
+++ b/src/Symfony/Component/Intl/Tests/DateFormatter/AbstractIntlDateFormatterTest.php
@@ -850,27 +850,16 @@ abstract class AbstractIntlDateFormatterTest extends \PHPUnit_Framework_TestCase
public function setTimeZoneIdProvider()
{
- $data = array(
+ return array(
array('UTC', 'UTC'),
array('GMT', 'GMT'),
array('GMT-03:00', 'GMT-03:00'),
array('Europe/Zurich', 'Europe/Zurich'),
+ array('GMT-0300', 'GMT-0300'),
+ array('Foo/Bar', 'Foo/Bar'),
+ array('GMT+00:AA', 'GMT+00:AA'),
+ array('GMT+00AA', 'GMT+00AA'),
);
-
- // When time zone not exists, uses UTC by default
- if (version_compare(PHP_VERSION, '5.5.0-dev', '>=')) {
- $data[] = array('GMT-0300', 'UTC');
- $data[] = array('Foo/Bar', 'UTC');
- $data[] = array('GMT+00:AA', 'UTC');
- $data[] = array('GMT+00AA', 'UTC');
- } else {
- $data[] = array('GMT-0300', 'GMT-0300');
- $data[] = array('Foo/Bar', 'Foo/Bar');
- $data[] = array('GMT+00:AA', 'GMT+00:AA');
- $data[] = array('GMT+00AA', 'GMT+00AA');
- }
-
- return $data;
}
protected function getDefaultDateFormatter($pattern = null)
diff --git a/src/Symfony/Component/Process/Process.php b/src/Symfony/Component/Process/Process.php
index 4822e8863e..134d8f6004 100644
--- a/src/Symfony/Component/Process/Process.php
+++ b/src/Symfony/Component/Process/Process.php
@@ -147,10 +147,7 @@ class Process
$this->cwd = getcwd();
}
if (null !== $env) {
- $this->env = array();
- foreach ($env as $key => $value) {
- $this->env[(binary) $key] = (binary) $value;
- }
+ $this->setEnv($env);
} else {
$this->env = null;
}
@@ -289,15 +286,17 @@ class Process
$w = $writePipes;
$e = null;
- $n = @stream_select($r, $w, $e, 0, ceil(static::TIMEOUT_PRECISION * 1E6));
-
- if (false === $n) {
+ if (false === $n = @stream_select($r, $w, $e, 0, ceil(static::TIMEOUT_PRECISION * 1E6))) {
+ // if a system call has been interrupted, forget about it, let's try again
+ if ($this->hasSystemCallBeenInterrupted()) {
+ continue;
+ }
break;
}
- if ($n === 0) {
- proc_terminate($this->process);
- throw new RuntimeException('The process timed out.');
+ // nothing has changed, let's wait until the process is ready
+ if (0 === $n) {
+ continue;
}
if ($w) {
@@ -387,10 +386,9 @@ class Process
// let's have a look if something changed in streams
if (false === $n = @stream_select($r, $w, $e, 0, ceil(static::TIMEOUT_PRECISION * 1E6))) {
- $lastError = error_get_last();
-
- // stream_select returns false when the `select` system call is interrupted by an incoming signal
- if (isset($lastError['message']) && false === stripos($lastError['message'], 'interrupted system call')) {
+ // if a system call has been interrupted, forget about it, let's try again
+ // otherwise, an error occured, let's reset pipes
+ if (!$this->hasSystemCallBeenInterrupted()) {
$this->pipes = array();
}
@@ -942,13 +940,25 @@ class Process
/**
* Sets the environment variables.
*
+ * An environment variable value should be a string.
+ * If it is an array, the variable is ignored.
+ *
+ * That happens in PHP when 'argv' is registered into
+ * the $_ENV array for instance.
+ *
* @param array $env The new environment variables
*
* @return self The current Process instance
*/
public function setEnv(array $env)
{
- $this->env = $env;
+ // Process can not handle env values that are arrays
+ $env = array_filter($env, function ($value) { if (!is_array($value)) { return true; } });
+
+ $this->env = array();
+ foreach ($env as $key => $value) {
+ $this->env[(binary) $key] = (binary) $value;
+ }
return $this;
}
@@ -1230,4 +1240,17 @@ class Process
}
}
}
+
+ /**
+ * Returns true if a system call has been interrupted.
+ *
+ * @return Boolean
+ */
+ private function hasSystemCallBeenInterrupted()
+ {
+ $lastError = error_get_last();
+
+ // stream_select returns false when the `select` system call is interrupted by an incoming signal
+ return isset($lastError['message']) && false !== stripos($lastError['message'], 'interrupted system call');
+ }
}
diff --git a/src/Symfony/Component/Process/Tests/AbstractProcessTest.php b/src/Symfony/Component/Process/Tests/AbstractProcessTest.php
index 5cd52efbd9..0415ca5647 100644
--- a/src/Symfony/Component/Process/Tests/AbstractProcessTest.php
+++ b/src/Symfony/Component/Process/Tests/AbstractProcessTest.php
@@ -47,9 +47,7 @@ abstract class AbstractProcessTest extends \PHPUnit_Framework_TestCase
public function testStopWithTimeoutIsActuallyWorking()
{
- if (defined('PHP_WINDOWS_VERSION_BUILD')) {
- $this->markTestSkipped('Stop with timeout does not work on windows, it requires posix signals');
- }
+ $this->verifyPosixIsEnabled();
// exec is mandatory here since we send a signal to the process
// see https://github.com/symfony/symfony/issues/5030 about prepending
@@ -454,9 +452,7 @@ abstract class AbstractProcessTest extends \PHPUnit_Framework_TestCase
public function testSignal()
{
- if (defined('PHP_WINDOWS_VERSION_BUILD')) {
- $this->markTestSkipped('POSIX signals do not work on windows');
- }
+ $this->verifyPosixIsEnabled();
$process = $this->getProcess('exec php -f ' . __DIR__ . '/SignalListener.php');
$process->start();
@@ -474,13 +470,20 @@ abstract class AbstractProcessTest extends \PHPUnit_Framework_TestCase
* @expectedException Symfony\Component\Process\Exception\LogicException
*/
public function testSignalProcessNotRunning()
+ {
+ $this->verifyPosixIsEnabled();
+ $process = $this->getProcess('php -m');
+ $process->signal(SIGHUP);
+ }
+
+ private function verifyPosixIsEnabled()
{
if (defined('PHP_WINDOWS_VERSION_BUILD')) {
$this->markTestSkipped('POSIX signals do not work on windows');
}
-
- $process = $this->getProcess('php -m');
- $process->signal(SIGHUP);
+ if (!defined('SIGUSR1')) {
+ $this->markTestSkipped('The pcntl extension is not enabled');
+ }
}
/**
diff --git a/src/Symfony/Component/Process/Tests/ProcessBuilderTest.php b/src/Symfony/Component/Process/Tests/ProcessBuilderTest.php
index 1f95396891..4c88b55ce1 100644
--- a/src/Symfony/Component/Process/Tests/ProcessBuilderTest.php
+++ b/src/Symfony/Component/Process/Tests/ProcessBuilderTest.php
@@ -45,6 +45,22 @@ class ProcessBuilderTest extends \PHPUnit_Framework_TestCase
$_ENV = $snapshot;
}
+ public function testProcessBuilderShouldNotPassEnvArrays()
+ {
+ $snapshot = $_ENV;
+ $_ENV = array('a' => array('b', 'c'), 'd' => 'e', 'f' => 'g');
+ $expected = array('d' => 'e', 'f' => 'g');
+
+ $pb = new ProcessBuilder();
+ $pb->add('a')->inheritEnvironmentVariables()
+ ->setEnv('d', 'e');
+ $proc = $pb->getProcess();
+
+ $this->assertEquals($expected, $proc->getEnv(), '->inheritEnvironmentVariables() removes array values from $_ENV');
+
+ $_ENV = $snapshot;
+ }
+
public function testInheritEnvironmentVarsByDefault()
{
$pb = new ProcessBuilder();
diff --git a/src/Symfony/Component/Routing/Generator/UrlGenerator.php b/src/Symfony/Component/Routing/Generator/UrlGenerator.php
index 69e3ea832e..f224cb3f6d 100644
--- a/src/Symfony/Component/Routing/Generator/UrlGenerator.php
+++ b/src/Symfony/Component/Routing/Generator/UrlGenerator.php
@@ -141,7 +141,7 @@ class UrlGenerator implements UrlGeneratorInterface, ConfigurableRequirementsInt
}
/**
- * @throws MissingMandatoryParametersException When some parameters are missing that mandatory for the route
+ * @throws MissingMandatoryParametersException When some parameters are missing that are mandatory for the route
* @throws InvalidParameterException When a parameter value for a placeholder is not correct because
* it does not match the requirement
*/
diff --git a/src/Symfony/Component/Security/Core/Encoder/BCryptPasswordEncoder.php b/src/Symfony/Component/Security/Core/Encoder/BCryptPasswordEncoder.php
index 3609f64b81..a355421580 100644
--- a/src/Symfony/Component/Security/Core/Encoder/BCryptPasswordEncoder.php
+++ b/src/Symfony/Component/Security/Core/Encoder/BCryptPasswordEncoder.php
@@ -53,14 +53,24 @@ class BCryptPasswordEncoder extends BasePasswordEncoder
* the "$2y$" salt prefix (which is not available in the early PHP versions).
* @see https://github.com/ircmaxell/password_compat/issues/10#issuecomment-11203833
*
+ * It is almost best to **not** pass a salt and let PHP generate one for you.
+ *
* @param string $raw The password to encode
* @param string $salt The salt
*
* @return string The encoded password
+ *
+ * @link http://lxr.php.net/xref/PHP_5_5/ext/standard/password.c#111
*/
public function encodePassword($raw, $salt)
{
- return password_hash($raw, PASSWORD_BCRYPT, array('cost' => $this->cost));
+ $options = array('cost' => $this->cost);
+
+ if ($salt) {
+ $options['salt'] = $salt;
+ }
+
+ return password_hash($raw, PASSWORD_BCRYPT, $options);
}
/**