Merge branch '2.7'

* 2.7:
  Minor hot fix
  [PROCESS] make sure /dev/tty is readable
  [PhpUnitBridge] Allow PHP 5.3.3 to use with Symfony 2.3
  [2.3] require-dev PHPUnit bridge
  [FrameworkBundle] Fixed Shell logo
  [2.3] Update CONTRIBUTING.md
  [2.3][Process] Fixed PhpProcess::getCommandLine() result
  [Debug] Deprecations exception for Symfony internals
  [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/PhpUnit/composer.json
This commit is contained in:
Nicolas Grekas 2015-02-24 13:15:02 +01:00
commit a01fd1b673
19 changed files with 220 additions and 133 deletions

View File

@ -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;

View File

@ -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

View File

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

View File

@ -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');
}
/**

View File

@ -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()

View File

@ -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()

View File

@ -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');
}
/**

View File

@ -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');
}
}

View File

@ -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 {

View File

@ -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());

View File

@ -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');

View File

@ -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);
}
}

View File

@ -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) {

View File

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

View File

@ -26,8 +26,6 @@ use Symfony\Component\Process\Exception\RuntimeException;
*/
class PhpProcess extends Process
{
private $executableFinder;
/**
* Constructor.
*
@ -41,9 +39,12 @@ class PhpProcess extends Process
*/
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)
{
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);

View File

@ -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;

View File

@ -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(<<<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 (!$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;

View File

@ -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 <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()
{
@ -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()
{