diff --git a/.travis.yml b/.travis.yml index 98e64d7865..7829e9f4df 100644 --- a/.travis.yml +++ b/.travis.yml @@ -6,9 +6,9 @@ matrix: - php: 5.5 - php: 5.6 - php: 5.5.9 - env: components=low + env: deps=low - php: 5.6 - env: components=high + env: deps=high - php: hhvm-nightly allow_failures: - php: hhvm-nightly @@ -18,8 +18,8 @@ services: mongodb env: global: - - components=no - - SYMFONY_DEPRECATIONS_HELPER=strict + - deps=no + - SYMFONY_DEPRECATIONS_HELPER=weak before_install: - travis_retry sudo apt-get install parallel @@ -35,11 +35,11 @@ before_install: - if [ "$TRAVIS_BRANCH" = "master" ]; then export COMPOSER_ROOT_VERSION=dev-master; else export COMPOSER_ROOT_VERSION="$TRAVIS_BRANCH".x-dev; fi; install: - - if [ "$components" = "no" ]; then composer --prefer-source install; fi; + - if [ "$deps" = "no" ]; then composer --prefer-source install; fi; script: - - if [ "$components" = "no" ]; then ls -d src/Symfony/*/* | parallel --gnu --keep-order 'echo -e "\\nRunning {} tests"; phpunit --exclude-group tty,benchmark,intl-data {} || (echo -e "\\e[41mKO\\e[0m {}" && $(exit 1));'; fi; - - if [ "$components" = "no" ]; then echo -e "\\nRunning tests requiring tty"; phpunit --group tty || (echo -e "\\e[41mKO\\e[0m tty group" && $(exit 1)); fi; - - if [ "$components" != "no" ]; then export SYMFONY_DEPRECATIONS_HELPER=weak; fi; - - if [ "$components" = "high" ]; then find src/Symfony -mindepth 3 -type f -name phpunit.xml.dist | sed 's#\(.*\)/.*#\1#' | parallel --gnu --keep-order -j25% 'echo -e "\\nRunning {} tests"; cd {}; composer --prefer-source update; phpunit --exclude-group tty,benchmark,intl-data,legacy || (echo -e "\\e[41mKO\\e[0m {}" && $(exit 1));'; fi; - - if [ "$components" = "low" ]; then find src/Symfony -mindepth 3 -type f -name phpunit.xml.dist | sed 's#\(.*\)/.*#\1#' | parallel --gnu --keep-order -j25% 'echo -e "\\nRunning {} tests"; cd {}; composer --prefer-source --prefer-lowest --prefer-stable update; phpunit --exclude-group tty,benchmark,intl-data || (echo -e "\\e[41mKO\\e[0m {}" && $(exit 1));'; fi; + - if [ "$deps" = "no" ]; then export SYMFONY_DEPRECATIONS_HELPER=strict; fi; + - if [ "$deps" = "no" ]; then ls -d src/Symfony/*/* | parallel --gnu --keep-order 'echo -e "\\nRunning {} tests"; phpunit --exclude-group tty,benchmark,intl-data {} || (echo -e "\\e[41mKO\\e[0m {}" && $(exit 1));'; fi; + - if [ "$deps" = "no" ]; then echo -e "\\nRunning tests requiring tty"; phpunit --group tty || (echo -e "\\e[41mKO\\e[0m tty group" && $(exit 1)); fi; + - if [ "$deps" = "high" ]; then find src/Symfony -mindepth 3 -type f -name phpunit.xml.dist | sed 's#\(.*\)/.*#\1#' | parallel --gnu --keep-order -j25% 'echo -e "\\nRunning {} tests"; cd {}; composer --prefer-source update; phpunit --exclude-group tty,benchmark,intl-data,legacy || (echo -e "\\e[41mKO\\e[0m {}" && $(exit 1));'; fi; + - if [ "$deps" = "low" ]; then find src/Symfony -mindepth 3 -type f -name phpunit.xml.dist | sed 's#\(.*\)/.*#\1#' | parallel --gnu --keep-order -j25% 'echo -e "\\nRunning {} tests"; cd {}; composer --prefer-source --prefer-lowest --prefer-stable update; phpunit --exclude-group tty,benchmark,intl-data || (echo -e "\\e[41mKO\\e[0m {}" && $(exit 1));'; fi; diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 4479b927cf..4def05128a 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -1,7 +1,7 @@ Contributing ------------ -Symfony2 is an open source, community-driven project. +Symfony is an open source, community-driven project. If you'd like to contribute, please read the following documents: @@ -12,6 +12,19 @@ If you'd like to contribute, please read the following documents: * [Pull Request Template][3]: Template header to use in your pull request description; +```markdown +| Q | A +| ------------- | --- +| Bug fix? | yes/no +| New feature? | yes/no +| BC breaks? | no +| Deprecations? | no +| Tests pass? | yes +| Fixed tickets | #1234 +| License | MIT +| Doc PR | symfony/symfony-docs#1234 +``` + * [Backwards Compatibility][4]: Backward compatibility rules. [1]: http://symfony.com/doc/current/contributing/code/index.html diff --git a/src/Symfony/Bundle/FrameworkBundle/Console/Shell.php b/src/Symfony/Bundle/FrameworkBundle/Console/Shell.php index 33100bdaca..80daebd4cd 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Console/Shell.php +++ b/src/Symfony/Bundle/FrameworkBundle/Console/Shell.php @@ -29,12 +29,12 @@ class Shell extends BaseShell { return << - _____ __ ___ - / ____| / _| |__ \ - | (___ _ _ _ __ ___ | |_ ___ _ __ _ _ ) | - \___ \| | | | '_ ` _ \| _/ _ \| '_ \| | | | / / - ____) | |_| | | | | | | || (_) | | | | |_| |/ /_ - |_____/ \__, |_| |_| |_|_| \___/|_| |_|\__, |____| + _____ __ + / ____| / _| + | (___ _ _ _ __ ___ | |_ ___ _ __ _ _ + \___ \| | | | '_ ` _ \| _/ _ \| '_ \| | | | + ____) | |_| | | | | | | || (_) | | | | |_| | + |_____/ \__, |_| |_| |_|_| \___/|_| |_|\__, | __/ | __/ | |___/ |___/ diff --git a/src/Symfony/Bundle/TwigBundle/Controller/ExceptionController.php b/src/Symfony/Bundle/TwigBundle/Controller/ExceptionController.php index 3bab43b523..226661e40e 100644 --- a/src/Symfony/Bundle/TwigBundle/Controller/ExceptionController.php +++ b/src/Symfony/Bundle/TwigBundle/Controller/ExceptionController.php @@ -62,7 +62,7 @@ class ExceptionController $code = $exception->getStatusCode(); - return new Response($this->twig->render( + return Response::create($this->twig->render( $this->findTemplate($request, $request->getRequestFormat(), $code, $showException), array( 'status_code' => $code, @@ -71,7 +71,7 @@ class ExceptionController 'logger' => $logger, 'currentContent' => $currentContent, ) - )); + ))->setCharset('UTF-8'); } /** diff --git a/src/Symfony/Bundle/TwigBundle/Tests/Controller/ExceptionControllerTest.php b/src/Symfony/Bundle/TwigBundle/Tests/Controller/ExceptionControllerTest.php index 5eddf232d6..15a453f2fe 100644 --- a/src/Symfony/Bundle/TwigBundle/Tests/Controller/ExceptionControllerTest.php +++ b/src/Symfony/Bundle/TwigBundle/Tests/Controller/ExceptionControllerTest.php @@ -40,7 +40,8 @@ class ExceptionControllerTest extends TestCase $request->headers->set('X-Php-Ob-Level', 1); $controller = new ExceptionController($twig, false); - $controller->showAction($request, $flatten); + $response = $controller->showAction($request, $flatten); + $this->assertEquals('UTF-8', $response->getCharset(), 'Request charset is explicitly set to UTF-8'); } public function testShowActionCanBeForcedToShowErrorPage() diff --git a/src/Symfony/Bundle/WebProfilerBundle/Controller/ExceptionController.php b/src/Symfony/Bundle/WebProfilerBundle/Controller/ExceptionController.php index 0b5db752ee..abd75d440e 100644 --- a/src/Symfony/Bundle/WebProfilerBundle/Controller/ExceptionController.php +++ b/src/Symfony/Bundle/WebProfilerBundle/Controller/ExceptionController.php @@ -62,16 +62,17 @@ class ExceptionController $code = $exception->getStatusCode(); - return new Response($this->twig->render( - $template, - array( + return Response::create( + $this->twig->render($template, array( 'status_code' => $code, 'status_text' => Response::$statusTexts[$code], 'exception' => $exception, 'logger' => null, 'currentContent' => '', - ) - ), 200, array('Content-Type' => 'text/html')); + )), + 200, + array('Content-Type' => 'text/html') + )->setCharset('UTF-8'); } /** @@ -97,10 +98,14 @@ class ExceptionController if (!$this->templateExists($template)) { $handler = new ExceptionHandler(); - return new Response($handler->getStylesheet($exception), 200, array('Content-Type' => 'text/css')); + $response = new Response($handler->getStylesheet($exception), 200, array('Content-Type' => 'text/css')); + } else { + $response = new Response($this->twig->render('@WebProfiler/Collector/exception.css.twig'), 200, array('Content-Type' => 'text/css')); } - return new Response($this->twig->render('@WebProfiler/Collector/exception.css.twig'), 200, array('Content-Type' => 'text/css')); + $response->setCharset('UTF-8'); + + return $response; } protected function getTemplate() diff --git a/src/Symfony/Bundle/WebProfilerBundle/Controller/ProfilerController.php b/src/Symfony/Bundle/WebProfilerBundle/Controller/ProfilerController.php index fdc849f6d4..d78ce2f675 100644 --- a/src/Symfony/Bundle/WebProfilerBundle/Controller/ProfilerController.php +++ b/src/Symfony/Bundle/WebProfilerBundle/Controller/ProfilerController.php @@ -99,16 +99,20 @@ class ProfilerController throw new NotFoundHttpException(sprintf('Panel "%s" is not available for token "%s".', $panel, $token)); } - return new Response($this->twig->render($this->getTemplateManager()->getName($profile, $panel), array( - 'token' => $token, - 'profile' => $profile, - 'collector' => $profile->getCollector($panel), - 'panel' => $panel, - 'page' => $page, - 'request' => $request, - 'templates' => $this->getTemplateManager()->getTemplates($profile), - 'is_ajax' => $request->isXmlHttpRequest(), - )), 200, array('Content-Type' => 'text/html')); + return Response::create( + $this->twig->render($this->getTemplateManager()->getName($profile, $panel), array( + 'token' => $token, + 'profile' => $profile, + 'collector' => $profile->getCollector($panel), + 'panel' => $panel, + 'page' => $page, + 'request' => $request, + 'templates' => $this->getTemplateManager()->getTemplates($profile), + 'is_ajax' => $request->isXmlHttpRequest(), + )), + 200, + array('Content-Type' => 'text/html') + )->setCharset('UTF-8'); } /** @@ -147,9 +151,13 @@ class ProfilerController $this->profiler->disable(); - return new Response($this->twig->render('@WebProfiler/Profiler/info.html.twig', array( - 'about' => $about, - )), 200, array('Content-Type' => 'text/html')); + return Response::create( + $this->twig->render('@WebProfiler/Profiler/info.html.twig', array( + 'about' => $about, + )), + 200, + array('Content-Type' => 'text/html') + )->setCharset('UTF-8'); } /** @@ -197,13 +205,17 @@ class ProfilerController // the profiler is not enabled } - return new Response($this->twig->render('@WebProfiler/Profiler/toolbar.html.twig', array( - 'position' => $position, - 'profile' => $profile, - 'templates' => $this->getTemplateManager()->getTemplates($profile), - 'profiler_url' => $url, - 'token' => $token, - )), 200, array('Content-Type' => 'text/html')); + return Response::create( + $this->twig->render('@WebProfiler/Profiler/toolbar.html.twig', array( + 'position' => $position, + 'profile' => $profile, + 'templates' => $this->getTemplateManager()->getTemplates($profile), + 'profiler_url' => $url, + 'token' => $token, + )), + 200, + array('Content-Type' => 'text/html') + )->setCharset('UTF-8'); } /** @@ -241,16 +253,20 @@ class ProfilerController $token = $session->get('_profiler_search_token'); } - return new Response($this->twig->render('@WebProfiler/Profiler/search.html.twig', array( - 'token' => $token, - 'ip' => $ip, - 'method' => $method, - 'url' => $url, - 'start' => $start, - 'end' => $end, - 'limit' => $limit, - 'request' => $request, - )), 200, array('Content-Type' => 'text/html')); + return Response::create( + $this->twig->render('@WebProfiler/Profiler/search.html.twig', array( + 'token' => $token, + 'ip' => $ip, + 'method' => $method, + 'url' => $url, + 'start' => $start, + 'end' => $end, + 'limit' => $limit, + 'request' => $request, + )), + 200, + array('Content-Type' => 'text/html') + )->setCharset('UTF-8'); } /** @@ -280,18 +296,22 @@ class ProfilerController $end = $request->query->get('end', null); $limit = $request->query->get('limit'); - return new Response($this->twig->render('@WebProfiler/Profiler/results.html.twig', array( - 'token' => $token, - 'profile' => $profile, - 'tokens' => $this->profiler->find($ip, $url, $limit, $method, $start, $end), - 'ip' => $ip, - 'method' => $method, - 'url' => $url, - 'start' => $start, - 'end' => $end, - 'limit' => $limit, - 'panel' => null, - )), 200, array('Content-Type' => 'text/html')); + return Response::create( + $this->twig->render('@WebProfiler/Profiler/results.html.twig', array( + 'token' => $token, + 'profile' => $profile, + 'tokens' => $this->profiler->find($ip, $url, $limit, $method, $start, $end), + 'ip' => $ip, + 'method' => $method, + 'url' => $url, + 'start' => $start, + 'end' => $end, + 'limit' => $limit, + 'panel' => null, + )), + 200, + array('Content-Type' => 'text/html') + )->setCharset('UTF-8'); } /** @@ -365,7 +385,7 @@ class ProfilerController phpinfo(); $phpinfo = ob_get_clean(); - return new Response($phpinfo, 200, array('Content-Type' => 'text/html')); + return Response::create($phpinfo, 200, array('Content-Type' => 'text/html'))->setCharset('UTF-8'); } /** diff --git a/src/Symfony/Bundle/WebProfilerBundle/Controller/RouterController.php b/src/Symfony/Bundle/WebProfilerBundle/Controller/RouterController.php index f4a84bf568..800f209a6f 100644 --- a/src/Symfony/Bundle/WebProfilerBundle/Controller/RouterController.php +++ b/src/Symfony/Bundle/WebProfilerBundle/Controller/RouterController.php @@ -68,10 +68,14 @@ class RouterController $request = $profile->getCollector('request'); - return new Response($this->twig->render('@WebProfiler/Router/panel.html.twig', array( - 'request' => $request, - 'router' => $profile->getCollector('router'), - 'traces' => $matcher->getTraces($request->getPathInfo()), - )), 200, array('Content-Type' => 'text/html')); + return Response::create( + $this->twig->render('@WebProfiler/Router/panel.html.twig', array( + 'request' => $request, + 'router' => $profile->getCollector('router'), + 'traces' => $matcher->getTraces($request->getPathInfo()), + )), + 200, + array('Content-Type' => 'text/html') + )->setCharset('UTF-8'); } } diff --git a/src/Symfony/Bundle/WebProfilerBundle/Resources/views/Profiler/base_js.html.twig b/src/Symfony/Bundle/WebProfilerBundle/Resources/views/Profiler/base_js.html.twig index b21c515c92..2d0a56e668 100644 --- a/src/Symfony/Bundle/WebProfilerBundle/Resources/views/Profiler/base_js.html.twig +++ b/src/Symfony/Bundle/WebProfilerBundle/Resources/views/Profiler/base_js.html.twig @@ -173,7 +173,8 @@ var addEventListener; - if (document.attachEvent) { + var el = document.createElement('div'); + if (!'addEventListener' in el) { addEventListener = function (element, eventName, callback) { element.attachEvent('on' + eventName, callback); }; @@ -184,40 +185,42 @@ } {% if excluded_ajax_paths is defined %} - var proxied = XMLHttpRequest.prototype.open; + if (window.XMLHttpRequest) { + var proxied = XMLHttpRequest.prototype.open; - XMLHttpRequest.prototype.open = function(method, url, async, user, pass) { - var self = this; + XMLHttpRequest.prototype.open = function(method, url, async, user, pass) { + var self = this; - /* prevent logging AJAX calls to static and inline files, like templates */ - if (url.substr(0, 1) === '/' && !url.match(new RegExp("{{ excluded_ajax_paths }}"))) { - var stackElement = { - loading: true, - error: false, - url: url, - method: method, - start: new Date() - }; + /* prevent logging AJAX calls to static and inline files, like templates */ + if (url.substr(0, 1) === '/' && !url.match(new RegExp("{{ excluded_ajax_paths }}"))) { + var stackElement = { + loading: true, + error: false, + url: url, + method: method, + start: new Date() + }; - requestStack.push(stackElement); + requestStack.push(stackElement); - addEventListener(this, 'readystatechange', function() { - if (self.readyState == 4) { - stackElement.duration = new Date() - stackElement.start; - stackElement.loading = false; - stackElement.error = self.status < 200 || self.status >= 400; - stackElement.profile = self.getResponseHeader("X-Debug-Token"); - stackElement.profilerUrl = self.getResponseHeader("X-Debug-Token-Link"); + this.addEventListener('readystatechange', function() { + if (self.readyState == 4) { + stackElement.duration = new Date() - stackElement.start; + stackElement.loading = false; + stackElement.error = self.status < 200 || self.status >= 400; + stackElement.profile = self.getResponseHeader("X-Debug-Token"); + stackElement.profilerUrl = self.getResponseHeader("X-Debug-Token-Link"); - Sfjs.renderAjaxRequests(); - } - }); + Sfjs.renderAjaxRequests(); + } + }, false); - Sfjs.renderAjaxRequests(); - } + Sfjs.renderAjaxRequests(); + } - proxied.apply(this, Array.prototype.slice.call(arguments)); - }; + proxied.apply(this, Array.prototype.slice.call(arguments)); + }; + } {% endif %} return { diff --git a/src/Symfony/Bundle/WebProfilerBundle/Tests/Controller/ProfilerControllerTest.php b/src/Symfony/Bundle/WebProfilerBundle/Tests/Controller/ProfilerControllerTest.php index 1ed32ca676..c661825cda 100644 --- a/src/Symfony/Bundle/WebProfilerBundle/Tests/Controller/ProfilerControllerTest.php +++ b/src/Symfony/Bundle/WebProfilerBundle/Tests/Controller/ProfilerControllerTest.php @@ -69,6 +69,7 @@ class ProfilerControllerTest extends \PHPUnit_Framework_TestCase $response = $controller->toolbarAction(Request::create('/_wdt/found'), 'found'); $this->assertEquals(200, $response->getStatusCode()); + $this->assertEquals('UTF-8', $response->getCharset(), 'Request charset is explicitly set to UTF-8'); $response = $controller->toolbarAction(Request::create('/_wdt/notFound'), 'notFound'); $this->assertEquals(404, $response->getStatusCode()); diff --git a/src/Symfony/Component/Console/Tests/Input/ArgvInputTest.php b/src/Symfony/Component/Console/Tests/Input/ArgvInputTest.php index bdbe3543b8..d2c540e6fe 100644 --- a/src/Symfony/Component/Console/Tests/Input/ArgvInputTest.php +++ b/src/Symfony/Component/Console/Tests/Input/ArgvInputTest.php @@ -257,7 +257,7 @@ class ArgvInputTest extends \PHPUnit_Framework_TestCase public function testGetFirstArgument() { $input = new ArgvInput(array('cli.php', '-fbbar')); - $this->assertEquals('', $input->getFirstArgument(), '->getFirstArgument() returns the first argument from the raw input'); + $this->assertNull($input->getFirstArgument(), '->getFirstArgument() returns null when there is no arguments'); $input = new ArgvInput(array('cli.php', '-fbbar', 'foo')); $this->assertEquals('foo', $input->getFirstArgument(), '->getFirstArgument() returns the first argument from the raw input'); diff --git a/src/Symfony/Component/Debug/DebugClassLoader.php b/src/Symfony/Component/Debug/DebugClassLoader.php index c2b5ba25c3..e0e21f13f4 100644 --- a/src/Symfony/Component/Debug/DebugClassLoader.php +++ b/src/Symfony/Component/Debug/DebugClassLoader.php @@ -180,16 +180,28 @@ class DebugClassLoader if (preg_match('#\n \* @deprecated (.*?)\r?\n \*(?: @|/$)#s', $refl->getDocComment(), $notice)) { self::$deprecated[$name] = preg_replace('#\s*\r?\n \* +#', ' ', $notice[1]); } else { - $len = 1 + (strpos($name, '\\', 1 + strpos($name, '\\')) ?: strpos($name, '_')); + if (2 > $len = 1 + (strpos($name, '\\', 1 + strpos($name, '\\')) ?: strpos($name, '_'))) { + $len = 0; + $ns = ''; + } else { + switch ($ns = substr($name, 0, $len)) { + case 'Symfony\Bridge\\': + case 'Symfony\Bundle\\': + case 'Symfony\Component\\': + $ns = 'Symfony\\'; + $len = strlen($ns); + break; + } + } $parent = $refl->getParentClass(); - if (!$parent || $len < 2 || strncmp($name, $parent, $len)) { - if ($parent && isset(self::$deprecated[$parent->name]) && ($len < 2 || strncmp($name, $parent->name, $len))) { + if (!$parent || strncmp($ns, $parent, $len)) { + if ($parent && isset(self::$deprecated[$parent->name]) && strncmp($ns, $parent->name, $len)) { trigger_error(sprintf('The %s class extends %s that is deprecated %s', $name, $parent->name, self::$deprecated[$parent->name]), E_USER_DEPRECATED); } foreach ($refl->getInterfaceNames() as $interface) { - if (isset(self::$deprecated[$interface]) && ($len < 2 || strncmp($name, $interface, $len)) && !($parent && $parent->implementsInterface($interface))) { + if (isset(self::$deprecated[$interface]) && strncmp($ns, $interface, $len) && !($parent && $parent->implementsInterface($interface))) { trigger_error(sprintf('The %s %s %s that is deprecated %s', $name, $refl->isInterface() ? 'interface extends' : 'class implements', $interface, self::$deprecated[$interface]), E_USER_DEPRECATED); } } diff --git a/src/Symfony/Component/Debug/Tests/DebugClassLoaderTest.php b/src/Symfony/Component/Debug/Tests/DebugClassLoaderTest.php index cf1b5730f2..8bbdce1301 100644 --- a/src/Symfony/Component/Debug/Tests/DebugClassLoaderTest.php +++ b/src/Symfony/Component/Debug/Tests/DebugClassLoaderTest.php @@ -193,7 +193,7 @@ class DebugClassLoaderTest extends \PHPUnit_Framework_TestCase $e = error_reporting(0); trigger_error('', E_USER_NOTICE); - class_exists(__NAMESPACE__.'\Fixtures\ExtendsDeprecatedParent', true); + class_exists('Symfony\Bridge\Debug\Tests\Fixtures\ExtendsDeprecatedParent', true); error_reporting($e); restore_error_handler(); @@ -239,8 +239,8 @@ class ClassLoader return __DIR__.'/Fixtures/notPsr0Bis.php'; } elseif (__NAMESPACE__.'\Fixtures\DeprecatedInterface' === $class) { return __DIR__.'/Fixtures/DeprecatedInterface.php'; - } elseif (__NAMESPACE__.'\Fixtures\ExtendsDeprecatedParent' === $class) { - eval('namespace '.__NAMESPACE__.'\Fixtures; class ExtendsDeprecatedParent extends DeprecatedClass {}'); + } elseif ('Symfony\Bridge\Debug\Tests\Fixtures\ExtendsDeprecatedParent' === $class) { + eval('namespace Symfony\Bridge\Debug\Tests\Fixtures; class ExtendsDeprecatedParent extends \\'.__NAMESPACE__.'\Fixtures\DeprecatedClass {}'); } elseif ('Test\\'.__NAMESPACE__.'\DeprecatedParentClass' === $class) { eval('namespace Test\\'.__NAMESPACE__.'; class DeprecatedParentClass extends \\'.__NAMESPACE__.'\Fixtures\DeprecatedClass {}'); } elseif ('Test\\'.__NAMESPACE__.'\DeprecatedInterfaceClass' === $class) { diff --git a/src/Symfony/Component/HttpKernel/Client.php b/src/Symfony/Component/HttpKernel/Client.php index 593facb702..0503f5de58 100644 --- a/src/Symfony/Component/HttpKernel/Client.php +++ b/src/Symfony/Component/HttpKernel/Client.php @@ -107,7 +107,7 @@ class Client extends BaseClient $code = <<find()) { + $php = null; + } - $this->executableFinder = new PhpExecutableFinder(); + parent::__construct($php, $cwd, $env, $script, $timeout, $options); } /** @@ -62,10 +63,7 @@ class PhpProcess extends Process public function start($callback = null) { if (null === $this->getCommandLine()) { - if (false === $php = $this->executableFinder->find()) { - throw new RuntimeException('Unable to find the PHP executable.'); - } - $this->setCommandLine($php); + throw new RuntimeException('Unable to find the PHP executable.'); } parent::start($callback); diff --git a/src/Symfony/Component/Process/Process.php b/src/Symfony/Component/Process/Process.php index b5cdc7f053..002df9ea7d 100644 --- a/src/Symfony/Component/Process/Process.php +++ b/src/Symfony/Component/Process/Process.php @@ -949,6 +949,9 @@ class Process if ('\\' === DIRECTORY_SEPARATOR && $tty) { throw new RuntimeException('TTY mode is not supported on Windows platform.'); } + if ($tty && (!file_exists('/dev/tty') || !is_readable('/dev/tty'))) { + throw new RuntimeException('TTY mode requires /dev/tty to be readable.'); + } $this->tty = (bool) $tty; diff --git a/src/Symfony/Component/Process/Tests/PhpProcessTest.php b/src/Symfony/Component/Process/Tests/PhpProcessTest.php index df66ad624b..5dc546cc1c 100644 --- a/src/Symfony/Component/Process/Tests/PhpProcessTest.php +++ b/src/Symfony/Component/Process/Tests/PhpProcessTest.php @@ -11,6 +11,7 @@ namespace Symfony\Component\Process\Tests; +use Symfony\Component\Process\PhpExecutableFinder; use Symfony\Component\Process\PhpProcess; class PhpProcessTest extends \PHPUnit_Framework_TestCase @@ -26,4 +27,23 @@ PHP $process->wait(); $this->assertEquals($expected, $process->getOutput()); } + + public function testCommandLine() + { + $process = new PhpProcess(<<find(); + + $this->assertSame($commandLine, $process->getCommandLine(), '::getCommandLine() returns the command line of PHP before start'); + + $process->start(); + $this->assertSame($commandLine, $process->getCommandLine(), '::getCommandLine() returns the command line of PHP after start'); + + $process->wait(); + $this->assertSame($commandLine, $process->getCommandLine(), '::getCommandLine() returns the command line of PHP after wait'); + } } diff --git a/src/Symfony/Component/PropertyAccess/PropertyAccessor.php b/src/Symfony/Component/PropertyAccess/PropertyAccessor.php index 8187c1dd3c..8a2e375410 100644 --- a/src/Symfony/Component/PropertyAccess/PropertyAccessor.php +++ b/src/Symfony/Component/PropertyAccess/PropertyAccessor.php @@ -200,8 +200,9 @@ class PropertyAccessor implements PropertyAccessorInterface if (!is_array($objectOrArray)) { if (!$objectOrArray instanceof \Traversable) { throw new NoSuchIndexException(sprintf( - 'Cannot read property "%s".', - $property + 'Cannot read index "%s" while trying to traverse path "%s".', + $property, + (string) $propertyPath )); } @@ -209,8 +210,9 @@ class PropertyAccessor implements PropertyAccessorInterface } throw new NoSuchIndexException(sprintf( - 'Cannot read property "%s". Available properties are "%s"', + 'Cannot read index "%s" while trying to traverse path "%s". Available indices are "%s".', $property, + (string) $propertyPath, print_r(array_keys($objectOrArray), true) )); } @@ -250,7 +252,7 @@ class PropertyAccessor implements PropertyAccessorInterface private function &readIndex(&$array, $index) { if (!$array instanceof \ArrayAccess && !is_array($array)) { - throw new NoSuchIndexException(sprintf('Index "%s" cannot be read from object of type "%s" because it doesn\'t implement \ArrayAccess', $index, get_class($array))); + throw new NoSuchIndexException(sprintf('Cannot read index "%s" from object of type "%s" because it doesn\'t implement \ArrayAccess.', $index, get_class($array))); } // Use an array instead of an object since performance is very crucial here @@ -294,7 +296,7 @@ class PropertyAccessor implements PropertyAccessorInterface ); if (!is_object($object)) { - throw new NoSuchPropertyException(sprintf('Cannot read property "%s" from an array. Maybe you should write the property path as "[%s]" instead?', $property, $property)); + throw new NoSuchPropertyException(sprintf('Cannot read property "%s" from an array. Maybe you intended to write the property path as "[%s]" instead.', $property, $property)); } $camelized = $this->camelize($property); @@ -364,7 +366,7 @@ class PropertyAccessor implements PropertyAccessorInterface private function writeIndex(&$array, $index, $value) { if (!$array instanceof \ArrayAccess && !is_array($array)) { - throw new NoSuchIndexException(sprintf('Index "%s" cannot be modified in object of type "%s" because it doesn\'t implement \ArrayAccess', $index, get_class($array))); + throw new NoSuchIndexException(sprintf('Cannot modify index "%s" in object of type "%s" because it doesn\'t implement \ArrayAccess', $index, get_class($array))); } $array[$index] = $value; diff --git a/src/Symfony/Component/PropertyAccess/PropertyAccessorBuilder.php b/src/Symfony/Component/PropertyAccess/PropertyAccessorBuilder.php index 738e5062fd..fc8ac4ed2d 100644 --- a/src/Symfony/Component/PropertyAccess/PropertyAccessorBuilder.php +++ b/src/Symfony/Component/PropertyAccess/PropertyAccessorBuilder.php @@ -12,7 +12,7 @@ namespace Symfony\Component\PropertyAccess; /** - * A configurable builder for PropertyAccessorInterface objects. + * A configurable builder to create a PropertyAccessor. * * @author Jérémie Augustin */ @@ -53,7 +53,7 @@ class PropertyAccessorBuilder } /** - * @return bool true if the use of "__call" by the PropertyAccessor is enabled + * @return bool whether the use of "__call" by the PropertyAccessor is enabled */ public function isMagicCallEnabled() { @@ -61,7 +61,10 @@ class PropertyAccessorBuilder } /** - * Enables exceptions in read context for array by PropertyAccessor + * Enables exceptions when reading a non-existing index. + * + * This has no influence on writing non-existing indices with PropertyAccessorInterface::setValue() + * which are always created on-the-fly. * * @return PropertyAccessorBuilder The builder object */ @@ -73,7 +76,9 @@ class PropertyAccessorBuilder } /** - * Disables exceptions in read context for array by PropertyAccessor + * Disables exceptions when reading a non-existing index. + * + * Instead, null is returned when calling PropertyAccessorInterface::getValue() on a non-existing index. * * @return PropertyAccessorBuilder The builder object */ @@ -85,7 +90,7 @@ class PropertyAccessorBuilder } /** - * @return bool true is exceptions in read context for array is enabled + * @return bool whether an exception is thrown or null is returned when reading a non-existing index */ public function isExceptionOnInvalidIndexEnabled() { @@ -93,9 +98,9 @@ class PropertyAccessorBuilder } /** - * Builds and returns a new propertyAccessor object. + * Builds and returns a new PropertyAccessor object. * - * @return PropertyAccessorInterface The built propertyAccessor + * @return PropertyAccessorInterface The built PropertyAccessor */ public function getPropertyAccessor() {