Merge branch '2.6' into 2.7

* 2.6:
  Minor hot fix
  [PROCESS] make sure /dev/tty is readable
  [2.3] require-dev PHPUnit bridge
  [FrameworkBundle] Fixed Shell logo
  [2.3] Update CONTRIBUTING.md
  [2.3][Process] Fixed PhpProcess::getCommandLine() result
  [Console] explicit assertion for ArgvInput::getFirstArgument() with no arguments
  [PropertyAccess] unify and fix doc
  Enforce UTF-8 charset for core controllers
  Fix the toolbar JS for IE

Conflicts:
	.travis.yml
	src/Symfony/Bridge/Doctrine/composer.json
	src/Symfony/Bridge/Monolog/composer.json
	src/Symfony/Bridge/Propel1/composer.json
	src/Symfony/Bridge/ProxyManager/composer.json
	src/Symfony/Bridge/Swiftmailer/composer.json
	src/Symfony/Bridge/Twig/composer.json
	src/Symfony/Bundle/DebugBundle/composer.json
	src/Symfony/Bundle/FrameworkBundle/composer.json
	src/Symfony/Bundle/SecurityBundle/composer.json
	src/Symfony/Bundle/TwigBundle/composer.json
	src/Symfony/Bundle/WebProfilerBundle/composer.json
	src/Symfony/Component/Asset/Exception/ExceptionInterface.php
	src/Symfony/Component/Asset/Exception/LogicException.php
	src/Symfony/Component/BrowserKit/composer.json
	src/Symfony/Component/ClassLoader/composer.json
	src/Symfony/Component/Console/composer.json
	src/Symfony/Component/Debug/composer.json
	src/Symfony/Component/DependencyInjection/composer.json
	src/Symfony/Component/DomCrawler/composer.json
	src/Symfony/Component/EventDispatcher/composer.json
	src/Symfony/Component/Form/composer.json
	src/Symfony/Component/HttpFoundation/composer.json
	src/Symfony/Component/HttpKernel/composer.json
	src/Symfony/Component/Intl/composer.json
	src/Symfony/Component/Routing/composer.json
	src/Symfony/Component/Security/Acl/composer.json
	src/Symfony/Component/Security/Core/composer.json
	src/Symfony/Component/Security/Csrf/composer.json
	src/Symfony/Component/Security/Http/composer.json
	src/Symfony/Component/Security/composer.json
	src/Symfony/Component/Templating/composer.json
	src/Symfony/Component/Translation/composer.json
	src/Symfony/Component/Validator/composer.json
This commit is contained in:
Nicolas Grekas 2015-02-24 13:09:34 +01:00
commit d4802aa92b
17 changed files with 201 additions and 126 deletions

View File

@ -7,9 +7,9 @@ matrix:
- php: 5.5 - php: 5.5
- php: 5.6 - php: 5.6
- php: 5.3 - php: 5.3
env: components=low env: deps=low
- php: 5.6 - php: 5.6
env: components=high env: deps=high
- php: hhvm-nightly - php: hhvm-nightly
allow_failures: allow_failures:
- php: hhvm-nightly - php: hhvm-nightly
@ -19,8 +19,8 @@ services: mongodb
env: env:
global: global:
- components=no - deps=no
- SYMFONY_DEPRECATIONS_HELPER=strict - SYMFONY_DEPRECATIONS_HELPER=weak
before_install: before_install:
- travis_retry sudo apt-get install parallel - travis_retry sudo apt-get install parallel
@ -36,11 +36,11 @@ before_install:
- if [ "$TRAVIS_BRANCH" = "master" ]; then export COMPOSER_ROOT_VERSION=dev-master; else export COMPOSER_ROOT_VERSION="$TRAVIS_BRANCH".x-dev; fi; - if [ "$TRAVIS_BRANCH" = "master" ]; then export COMPOSER_ROOT_VERSION=dev-master; else export COMPOSER_ROOT_VERSION="$TRAVIS_BRANCH".x-dev; fi;
install: install:
- if [ "$components" = "no" ]; then composer --prefer-source install; fi; - if [ "$deps" = "no" ]; then composer --prefer-source install; fi;
script: 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 [ "$deps" = "no" ]; then export SYMFONY_DEPRECATIONS_HELPER=strict; 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 [ "$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 [ "$components" != "no" ]; then export SYMFONY_DEPRECATIONS_HELPER=weak; 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 [ "$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 [ "$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 [ "$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" = "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;

View File

@ -1,7 +1,7 @@
Contributing 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: 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 * [Pull Request Template][3]: Template header to use in your pull request
description; 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. * [Backwards Compatibility][4]: Backward compatibility rules.
[1]: http://symfony.com/doc/current/contributing/code/index.html [1]: http://symfony.com/doc/current/contributing/code/index.html

View File

@ -29,12 +29,12 @@ class Shell extends BaseShell
{ {
return <<<EOF return <<<EOF
<info> <info>
_____ __ ___ _____ __
/ ____| / _| |__ \ / ____| / _|
| (___ _ _ _ __ ___ | |_ ___ _ __ _ _ ) | | (___ _ _ _ __ ___ | |_ ___ _ __ _ _
\___ \| | | | '_ ` _ \| _/ _ \| '_ \| | | | / / \___ \| | | | '_ ` _ \| _/ _ \| '_ \| | | |
____) | |_| | | | | | | || (_) | | | | |_| |/ /_ ____) | |_| | | | | | | || (_) | | | | |_| |
|_____/ \__, |_| |_| |_|_| \___/|_| |_|\__, |____| |_____/ \__, |_| |_| |_|_| \___/|_| |_|\__, |
__/ | __/ | __/ | __/ |
|___/ |___/ |___/ |___/

View File

@ -62,7 +62,7 @@ class ExceptionController
$code = $exception->getStatusCode(); $code = $exception->getStatusCode();
return new Response($this->twig->render( return Response::create($this->twig->render(
$this->findTemplate($request, $request->getRequestFormat(), $code, $showException), $this->findTemplate($request, $request->getRequestFormat(), $code, $showException),
array( array(
'status_code' => $code, 'status_code' => $code,
@ -71,7 +71,7 @@ class ExceptionController
'logger' => $logger, 'logger' => $logger,
'currentContent' => $currentContent, 'currentContent' => $currentContent,
) )
)); ))->setCharset('UTF-8');
} }
/** /**

View File

@ -40,7 +40,8 @@ class ExceptionControllerTest extends TestCase
$request->headers->set('X-Php-Ob-Level', 1); $request->headers->set('X-Php-Ob-Level', 1);
$controller = new ExceptionController($twig, false); $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() public function testShowActionCanBeForcedToShowErrorPage()

View File

@ -62,16 +62,17 @@ class ExceptionController
$code = $exception->getStatusCode(); $code = $exception->getStatusCode();
return new Response($this->twig->render( return Response::create(
$template, $this->twig->render($template, array(
array(
'status_code' => $code, 'status_code' => $code,
'status_text' => Response::$statusTexts[$code], 'status_text' => Response::$statusTexts[$code],
'exception' => $exception, 'exception' => $exception,
'logger' => null, 'logger' => null,
'currentContent' => '', '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)) { if (!$this->templateExists($template)) {
$handler = new ExceptionHandler(); $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() protected function getTemplate()

View File

@ -99,16 +99,20 @@ class ProfilerController
throw new NotFoundHttpException(sprintf('Panel "%s" is not available for token "%s".', $panel, $token)); 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( return Response::create(
'token' => $token, $this->twig->render($this->getTemplateManager()->getName($profile, $panel), array(
'profile' => $profile, 'token' => $token,
'collector' => $profile->getCollector($panel), 'profile' => $profile,
'panel' => $panel, 'collector' => $profile->getCollector($panel),
'page' => $page, 'panel' => $panel,
'request' => $request, 'page' => $page,
'templates' => $this->getTemplateManager()->getTemplates($profile), 'request' => $request,
'is_ajax' => $request->isXmlHttpRequest(), 'templates' => $this->getTemplateManager()->getTemplates($profile),
)), 200, array('Content-Type' => 'text/html')); 'is_ajax' => $request->isXmlHttpRequest(),
)),
200,
array('Content-Type' => 'text/html')
)->setCharset('UTF-8');
} }
/** /**
@ -147,9 +151,13 @@ class ProfilerController
$this->profiler->disable(); $this->profiler->disable();
return new Response($this->twig->render('@WebProfiler/Profiler/info.html.twig', array( return Response::create(
'about' => $about, $this->twig->render('@WebProfiler/Profiler/info.html.twig', array(
)), 200, array('Content-Type' => 'text/html')); 'about' => $about,
)),
200,
array('Content-Type' => 'text/html')
)->setCharset('UTF-8');
} }
/** /**
@ -197,13 +205,17 @@ class ProfilerController
// the profiler is not enabled // the profiler is not enabled
} }
return new Response($this->twig->render('@WebProfiler/Profiler/toolbar.html.twig', array( return Response::create(
'position' => $position, $this->twig->render('@WebProfiler/Profiler/toolbar.html.twig', array(
'profile' => $profile, 'position' => $position,
'templates' => $this->getTemplateManager()->getTemplates($profile), 'profile' => $profile,
'profiler_url' => $url, 'templates' => $this->getTemplateManager()->getTemplates($profile),
'token' => $token, 'profiler_url' => $url,
)), 200, array('Content-Type' => 'text/html')); 'token' => $token,
)),
200,
array('Content-Type' => 'text/html')
)->setCharset('UTF-8');
} }
/** /**
@ -241,16 +253,20 @@ class ProfilerController
$token = $session->get('_profiler_search_token'); $token = $session->get('_profiler_search_token');
} }
return new Response($this->twig->render('@WebProfiler/Profiler/search.html.twig', array( return Response::create(
'token' => $token, $this->twig->render('@WebProfiler/Profiler/search.html.twig', array(
'ip' => $ip, 'token' => $token,
'method' => $method, 'ip' => $ip,
'url' => $url, 'method' => $method,
'start' => $start, 'url' => $url,
'end' => $end, 'start' => $start,
'limit' => $limit, 'end' => $end,
'request' => $request, 'limit' => $limit,
)), 200, array('Content-Type' => 'text/html')); 'request' => $request,
)),
200,
array('Content-Type' => 'text/html')
)->setCharset('UTF-8');
} }
/** /**
@ -280,18 +296,22 @@ class ProfilerController
$end = $request->query->get('end', null); $end = $request->query->get('end', null);
$limit = $request->query->get('limit'); $limit = $request->query->get('limit');
return new Response($this->twig->render('@WebProfiler/Profiler/results.html.twig', array( return Response::create(
'token' => $token, $this->twig->render('@WebProfiler/Profiler/results.html.twig', array(
'profile' => $profile, 'token' => $token,
'tokens' => $this->profiler->find($ip, $url, $limit, $method, $start, $end), 'profile' => $profile,
'ip' => $ip, 'tokens' => $this->profiler->find($ip, $url, $limit, $method, $start, $end),
'method' => $method, 'ip' => $ip,
'url' => $url, 'method' => $method,
'start' => $start, 'url' => $url,
'end' => $end, 'start' => $start,
'limit' => $limit, 'end' => $end,
'panel' => null, 'limit' => $limit,
)), 200, array('Content-Type' => 'text/html')); 'panel' => null,
)),
200,
array('Content-Type' => 'text/html')
)->setCharset('UTF-8');
} }
/** /**
@ -365,7 +385,7 @@ class ProfilerController
phpinfo(); phpinfo();
$phpinfo = ob_get_clean(); $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');
} }
/** /**

View File

@ -68,10 +68,14 @@ class RouterController
$request = $profile->getCollector('request'); $request = $profile->getCollector('request');
return new Response($this->twig->render('@WebProfiler/Router/panel.html.twig', array( return Response::create(
'request' => $request, $this->twig->render('@WebProfiler/Router/panel.html.twig', array(
'router' => $profile->getCollector('router'), 'request' => $request,
'traces' => $matcher->getTraces($request->getPathInfo()), 'router' => $profile->getCollector('router'),
)), 200, array('Content-Type' => 'text/html')); 'traces' => $matcher->getTraces($request->getPathInfo()),
)),
200,
array('Content-Type' => 'text/html')
)->setCharset('UTF-8');
} }
} }

View File

@ -173,7 +173,8 @@
var addEventListener; var addEventListener;
if (document.attachEvent) { var el = document.createElement('div');
if (!'addEventListener' in el) {
addEventListener = function (element, eventName, callback) { addEventListener = function (element, eventName, callback) {
element.attachEvent('on' + eventName, callback); element.attachEvent('on' + eventName, callback);
}; };
@ -184,40 +185,42 @@
} }
{% if excluded_ajax_paths is defined %} {% 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) { XMLHttpRequest.prototype.open = function(method, url, async, user, pass) {
var self = this; var self = this;
/* prevent logging AJAX calls to static and inline files, like templates */ /* prevent logging AJAX calls to static and inline files, like templates */
if (url.substr(0, 1) === '/' && !url.match(new RegExp("{{ excluded_ajax_paths }}"))) { if (url.substr(0, 1) === '/' && !url.match(new RegExp("{{ excluded_ajax_paths }}"))) {
var stackElement = { var stackElement = {
loading: true, loading: true,
error: false, error: false,
url: url, url: url,
method: method, method: method,
start: new Date() start: new Date()
}; };
requestStack.push(stackElement); requestStack.push(stackElement);
addEventListener(this, 'readystatechange', function() { this.addEventListener('readystatechange', function() {
if (self.readyState == 4) { if (self.readyState == 4) {
stackElement.duration = new Date() - stackElement.start; stackElement.duration = new Date() - stackElement.start;
stackElement.loading = false; stackElement.loading = false;
stackElement.error = self.status < 200 || self.status >= 400; stackElement.error = self.status < 200 || self.status >= 400;
stackElement.profile = self.getResponseHeader("X-Debug-Token"); stackElement.profile = self.getResponseHeader("X-Debug-Token");
stackElement.profilerUrl = self.getResponseHeader("X-Debug-Token-Link"); 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 %} {% endif %}
return { return {

View File

@ -69,6 +69,7 @@ class ProfilerControllerTest extends \PHPUnit_Framework_TestCase
$response = $controller->toolbarAction(Request::create('/_wdt/found'), 'found'); $response = $controller->toolbarAction(Request::create('/_wdt/found'), 'found');
$this->assertEquals(200, $response->getStatusCode()); $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'); $response = $controller->toolbarAction(Request::create('/_wdt/notFound'), 'notFound');
$this->assertEquals(404, $response->getStatusCode()); $this->assertEquals(404, $response->getStatusCode());

View File

@ -257,7 +257,7 @@ class ArgvInputTest extends \PHPUnit_Framework_TestCase
public function testGetFirstArgument() public function testGetFirstArgument()
{ {
$input = new ArgvInput(array('cli.php', '-fbbar')); $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')); $input = new ArgvInput(array('cli.php', '-fbbar', 'foo'));
$this->assertEquals('foo', $input->getFirstArgument(), '->getFirstArgument() returns the first argument from the raw input'); $this->assertEquals('foo', $input->getFirstArgument(), '->getFirstArgument() returns the first argument from the raw input');

View File

@ -107,7 +107,7 @@ class Client extends BaseClient
$code = <<<EOF $code = <<<EOF
<?php <?php
error_reporting($errorReporting); error_reporting($errorReporting & ~E_USER_DEPRECATED);
require_once '$requirePath'; require_once '$requirePath';

View File

@ -26,8 +26,6 @@ use Symfony\Component\Process\Exception\RuntimeException;
*/ */
class PhpProcess extends Process class PhpProcess extends Process
{ {
private $executableFinder;
/** /**
* Constructor. * Constructor.
* *
@ -41,9 +39,12 @@ class PhpProcess extends Process
*/ */
public function __construct($script, $cwd = null, array $env = array(), $timeout = 60, array $options = array()) public function __construct($script, $cwd = null, array $env = array(), $timeout = 60, array $options = array())
{ {
parent::__construct(null, $cwd, $env, $script, $timeout, $options); $executableFinder = new PhpExecutableFinder();
if (false === $php = $executableFinder->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) public function start($callback = null)
{ {
if (null === $this->getCommandLine()) { if (null === $this->getCommandLine()) {
if (false === $php = $this->executableFinder->find()) { throw new RuntimeException('Unable to find the PHP executable.');
throw new RuntimeException('Unable to find the PHP executable.');
}
$this->setCommandLine($php);
} }
parent::start($callback); parent::start($callback);

View File

@ -949,6 +949,9 @@ class Process
if ('\\' === DIRECTORY_SEPARATOR && $tty) { if ('\\' === DIRECTORY_SEPARATOR && $tty) {
throw new RuntimeException('TTY mode is not supported on Windows platform.'); 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; $this->tty = (bool) $tty;

View File

@ -11,6 +11,7 @@
namespace Symfony\Component\Process\Tests; namespace Symfony\Component\Process\Tests;
use Symfony\Component\Process\PhpExecutableFinder;
use Symfony\Component\Process\PhpProcess; use Symfony\Component\Process\PhpProcess;
class PhpProcessTest extends \PHPUnit_Framework_TestCase class PhpProcessTest extends \PHPUnit_Framework_TestCase
@ -26,4 +27,23 @@ PHP
$process->wait(); $process->wait();
$this->assertEquals($expected, $process->getOutput()); $this->assertEquals($expected, $process->getOutput());
} }
public function testCommandLine()
{
$process = new PhpProcess(<<<PHP
<?php echo 'foobar';
PHP
);
$f = new PhpExecutableFinder();
$commandLine = $f->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');
}
} }

View File

@ -200,8 +200,9 @@ class PropertyAccessor implements PropertyAccessorInterface
if (!is_array($objectOrArray)) { if (!is_array($objectOrArray)) {
if (!$objectOrArray instanceof \Traversable) { if (!$objectOrArray instanceof \Traversable) {
throw new NoSuchIndexException(sprintf( throw new NoSuchIndexException(sprintf(
'Cannot read property "%s".', 'Cannot read index "%s" while trying to traverse path "%s".',
$property $property,
(string) $propertyPath
)); ));
} }
@ -209,8 +210,9 @@ class PropertyAccessor implements PropertyAccessorInterface
} }
throw new NoSuchIndexException(sprintf( 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, $property,
(string) $propertyPath,
print_r(array_keys($objectOrArray), true) print_r(array_keys($objectOrArray), true)
)); ));
} }
@ -250,7 +252,7 @@ class PropertyAccessor implements PropertyAccessorInterface
private function &readIndex(&$array, $index) private function &readIndex(&$array, $index)
{ {
if (!$array instanceof \ArrayAccess && !is_array($array)) { 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 // 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)) { 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); $camelized = $this->camelize($property);
@ -364,7 +366,7 @@ class PropertyAccessor implements PropertyAccessorInterface
private function writeIndex(&$array, $index, $value) private function writeIndex(&$array, $index, $value)
{ {
if (!$array instanceof \ArrayAccess && !is_array($array)) { 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; $array[$index] = $value;

View File

@ -12,7 +12,7 @@
namespace Symfony\Component\PropertyAccess; namespace Symfony\Component\PropertyAccess;
/** /**
* A configurable builder for PropertyAccessorInterface objects. * A configurable builder to create a PropertyAccessor.
* *
* @author Jérémie Augustin <jeremie.augustin@pixel-cookers.com> * @author Jérémie Augustin <jeremie.augustin@pixel-cookers.com>
*/ */
@ -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() 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 * @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 * @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() 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() public function getPropertyAccessor()
{ {