8000 Merge branch '2.7' into 2.8 · symfony/symfony@791b143 · GitHub
[go: up one dir, main page]

Skip to content

Commit 791b143

Browse files
committed
Merge branch '2.7' into 2.8
* 2.7: always check for all fields to be mapped clarify exception when no args are configured [PropertyAccess] Handle interfaces in the invalid argument exception [Debug] Workaround "null" $context [Debug] Remove $context arg from handleError(), preparing for PHP 7.2 [Routing] Fix BC break in AnnotationClassLoader defaults attributes handling Fix tests with ICU 57.1 Fix the condition checking the minimum ICU version
2 parents 21f1be1 + bc391c1 commit 791b143

File tree

18 files changed

+229
-27
lines changed

18 files changed

+229
-27
lines changed

composer.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -90,7 +90,8 @@
9090
"phpdocumentor/reflection": "^1.0.7"
9191
},
9292
"conflict": {
93-
"phpdocumentor/reflection": "<1.0.7"
93+
"phpdocumentor/reflection": "<1.0.7",
94+
"sensio/framework-extra-bundle": "^3.0.2"
9495
},
9596
"autoload": {
9697
"psr-4": {

src/Symfony/Bridge/Doctrine/Tests/Validator/Constraints/UniqueEntityValidatorTest.php

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -247,6 +247,23 @@ public function testValidateUniquenessWithIgnoreNull()
247247
->assertRaised();
248248
}
249249

250+
/**
251+
* @expectedException \Symfony\Component\Validator\Exception\ConstraintDefinitionException
252+
*/
253+
public function testAllConfiguredFieldsAreCheckedOfBeingMappedByDoctrineWithIgnoreNullEnabled()
254+
{
255+
$constraint = new UniqueEntity(array(
256+
'message' => 'myMessage',
257+
'fields' => array('name', 'name2'),
258+
'em' => self::EM_NAME,
259+
'ignoreNull' => true,
260+
));
261+
262+
$entity1 = new SingleIntIdEntity(1, null);
263+
264+
$this->validator->validate($entity1, $constraint);
265+
}
266+
250267
public function testValidateUniquenessWithValidCustomErrorPath()
251268
{
252269
$constraint = new UniqueEntity(array(

src/Symfony/Bridge/Doctrine/Validator/Constraints/UniqueEntityValidator.php

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -85,12 +85,14 @@ public function validate($entity, Constraint $constraint)
8585
throw new ConstraintDefinitionException(sprintf('The field "%s" is not mapped by Doctrine, so it cannot be validated for uniqueness.', $fieldName));
8686
}
8787

88-
$criteria[$fieldName] = $class->reflFields[$fieldName]->getValue($entity);
88+
$fieldValue = $class->reflFields[$fieldName]->getValue($entity);
8989

90-
if ($constraint->ignoreNull && null === $criteria[$fieldName]) {
91-
return;
90+
if ($constraint->ignoreNull && null === $fieldValue) {
91+
continue;
9292
}
9393

94+
$criteria[$fieldName] = $fieldValue;
95+
9496
if (null !== $criteria[$fieldName] && $class->hasAssociation($fieldName)) {
9597
/* Ensure the Proxy is initialized before using reflection to
9698
* read its identifiers. This is necessary because the wrapped
@@ -100,6 +102,12 @@ public function validate($entity, Constraint $constraint)
100102
}
101103
}
102104

105+
// skip validation if there are no criteria (this can happen when the
106+
// "ignoreNull" option is enabled and fields to be checked are null
107+
if (empty($criteria)) {
108+
return;
109+
}
110+
103111
$repository = $em->getRepository(get_class($entity));
104112
$result = $repository->{$constraint->repositoryMethod}($criteria);
105113

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <fabien@symfony.com>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
namespace Symfony\Bundle\FrameworkBundle\Tests\Functional;
13+
14+
class AnnotatedControllerTest extends WebTestCase
15+
{
16+
/**
17+
* @dataProvider getRoutes
18+
*/
19+
public function testAnnotatedController($path, $expectedValue)
20+
{
21+
$client = $this->createClient(array('test_case' => 'AnnotatedController', 'root_config' => 'config.yml'));
22+
$client->request('GET', '/annotated'.$path);
23+
24+
$this->assertSame(200, $client->getResponse()->getStatusCode());
25+
$this->assertSame($expectedValue, $client->getResponse()->getContent());
26+
}
27+
28+
public function getRoutes()
29+
{
30+
return array(
31+
array('/null_request', 'Symfony\Component\HttpFoundation\Request'),
32+
array('/null_argument', ''),
33+
array('/null_argument_with_route_param', ''),
34+
array('/null_argument_with_route_param/value', 'value'),
35+
array('/argument_with_route_param_and_default', 'value'),
36+
array('/argument_with_route_param_and_default/custom', 'custom'),
37+
);
38+
}
39+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <fabien@symfony.com>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
namespace Symfony\Bundle\FrameworkBundle\Tests\Functional\Bundle\TestBundle\Controller;
13+
14+
use Symfony\Component\HttpFoundation\Request;
15+
use Symfony\Component\HttpFoundation\Response;
16+
use Symfony\Component\Routing\Annotation\Route;
17+
18+
class AnnotatedController
19+
{
20+
/**
21+
* @Route("/null_request", name="null_request")
22+
*/
23+
public function requestDefaultNullAction(Request $request = null)
24+
{
25+
return new Response($request ? get_class($request) : null);
26+
}
27+
28+
/**
29+
* @Route("/null_argument", name="null_argument")
30+
*/
31+
public function argumentDefaultNullWithoutRouteParamAction($value = null)
32+
{
33+
return new Response($value);
34+
}
35+
36+
/**
37+
* @Route("/null_argument_with_route_param/{value}", name="null_argument_with_route_param")
38+
*/
39+
public function argumentDefaultNullWithRouteParamAction($value = null)
40+
{
41+
return new Response($value);
42+
}
43+
44+
/**
45+
* @Route("/argument_with_route_param_and_default/{value}", defaults={"value": "value"}, name="argument_with_route_param_and_default")
46+
*/
47+
public function argumentWithoutDefaultWithRouteParamAndDefaultAction($value)
48+
{
49+
return new Response($value);
50+
}
51+
}
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <fabien@symfony.com>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
use Symfony\Bundle\FrameworkBundle\Tests\Functional\Bundle\TestBundle\TestBundle;
13+
use Symfony\Bundle\FrameworkBundle\FrameworkBundle;
14+
use Sensio\Bundle\FrameworkExtraBundle\SensioFrameworkExtraBundle;
15+
16+
return array(
17+
new FrameworkBundle(),
18+
new TestBundle(),
19+
new SensioFrameworkExtraBundle(),
20+
);
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
imports:
2+
- { resource: ../config/default.yml }
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
annotated_controller:
2+
prefix: /annotated
3+
resource: "@TestBundle/Controller/AnnotatedController.php"
4+
type: annotation

src/Symfony/Bundle/FrameworkBundle/composer.json

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@
2727
"symfony/http-kernel": "~2.8.16",
2828
"symfony/polyfill-mbstring": "~1.0",
2929
"symfony/filesystem": "~2.3|~3.0.0",
30-
"symfony/routing": "~2.8|~3.0.0",
30+
"symfony/routing": "~2.8.17",
3131
"symfony/security-core": "~2.6.13|~2.7.9|~2.8|~3.0.0",
3232
"symfony/security-csrf": "~2.6|~3.0.0",
3333
"symfony/stopwatch": "~2.3|~3.0.0",
@@ -50,7 +50,8 @@
5050
"symfony/yaml": "~2.0,>=2.0.5|~3.0.0",
5151
"symfony/property-info": "~2.8|~3.0.0",
5252
"phpdocumentor/reflection": "^1.0.7",
53-
"twig/twig": "~1.23|~2.0"
53+
"twig/twig": "~1.23|~2.0",
54+
"sensio/framework-extra-bundle": "^3.0.2"
5455
},
5556
"suggest": {
5657
"symfony/console": "For using the console commands",

src/Symfony/Component/Debug/ErrorHandler.php

Lines changed: 14 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -375,20 +375,18 @@ private function reRegister($prev)
375375
/**
376376
* Handles errors by filtering then logging them according to the configured bit fields.
377377
*
378-
* @param int $type One of the E_* constants
378+
* @param int $type One of the E_* constants
379379
* @param string $message
380380
* @param string $file
381381
* @param int $line
382-
* @param array $context
383-
* @param array $backtrace
384382
*
385383
* @return bool Returns false when no handling happens so that the PHP engine can handle the error itself
386384
*
387385
* @throws \ErrorException When $this->thrownErrors requests so
388386
*
389387
* @internal
390388
*/
391-
public function handleError($type, $message, $file, $line, array $context, array $backtrace = null)
389+
public function handleError($type, $message, $file, $line)
392390
{
393391
$level = error_reporting() | E_RECOVERABLE_ERROR | E_USER_ERROR | E_DEPRECATED | E_USER_DEPRECATED;
394392
$log = $this->loggedErrors & $type;
@@ -398,8 +396,17 @@ public function handleError($type, $message, $file, $line, array $context, array
398396
if (!$type || (!$log && !$throw)) {
399397
return $type && $log;
400398
}
399+
$scope = $this->scopedErrors & $type;
401400

402-
if (isset($context['GLOBALS']) && ($this->scopedErrors & $type)) {
401+
if (4 < $numArgs = func_num_args()) {
402+
$context = $scope ? (func_get_arg(4) ?: array()) : array();
403+
$backtrace = 5 < $numArgs ? func_get_arg(5) : null; // defined on HHVM
404+
} else {
405+
$context = array();
406+
$backtrace = null;
407+
}
408+
409+
if (isset($context['GLOBALS']) && $scope) {
403410
$e = $context; // Whatever the signature of the method,
404411
unset($e['GLOBALS'], $context); // $context is always a reference in 5.3
405412
$context = $e;
@@ -418,7 +425,7 @@ public function handleError($type, $message, $file, $line, array $context, array
418425
if (null !== self::$toStringException) {
419426
$throw = self::$toStringException;
420427
self::$toStringException = null;
421-
} elseif (($this->scopedErrors & $type) && class_exists('Symfony\Component\Debug\Exception\ContextErrorException')) {
428+
} elseif ($scope && class_exists('Symfony\Component\Debug\Exception\ContextErrorException')) {
422429
// Checking for class exis 10000 tence is a work around for https://bugs.php.net/42098
423430
$throw = new ContextErrorException($this->levels[$type].': '.$message, 0, $type, $file, $line, $context);
424431
} else {
@@ -490,7 +497,7 @@ public function handleError($type, $message, $file, $line, array $context, array
490497
$e = compact('type', 'file', 'line', 'level');
491498

492499
if ($type & $level) {
493-
if ($this->scopedErrors & $type) {
500+
if ($scope) {
494501
$e['scope_vars'] = $context;
495502
if ($trace) {
496503
$e['stack'] = $backtrace ?: debug_backtrace(DEBUG_BACKTRACE_PROVIDE_OBJECT);

src/Symfony/Component/DependencyInjection/Definition.php

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -308,6 +308,10 @@ public function addArgument($argument)
308308
*/
309309
public function replaceArgument($index, $argument)
310310
{
311+
if (0 === count($this->arguments)) {
312+
throw new OutOfBoundsException('Cannot replace arguments if none have been configured yet.');
313+
}
314+
311315
if ($index < 0 || $index > count($this->arguments) - 1) {
312316
throw new OutOfBoundsException(sprintf('The index "%d" is not in the range [0, %d].', $index, count($this->arguments) - 1));
313317
}

src/Symfony/Component/DependencyInjection/Tests/DefinitionTest.php

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -292,6 +292,7 @@ public function testGetArgumentShouldCheckBounds()
292292

293293
/**
294294
* @expectedException \OutOfBoundsException
295+
* @expectedExceptionMessage The index "1" is not in the range [0, 0].
295296
*/
296297
public function testReplaceArgumentShouldCheckBounds()
297298
{
@@ -301,6 +302,16 @@ public function testReplaceArgumentShouldCheckBounds()
301302
$def->replaceArgument(1, 'bar');
302303
}
303304

305+
/**
306+
* @expectedException \OutOfBoundsException
307+
* @expectedExceptionMessage Cannot replace arguments if none have been configured yet.
308+
*/
309+
public function testReplaceArgumentWithoutExistingArgumentsShouldCheckBounds()
310+
{
311+
$def = new Definition('stdClass');
312+
$def->replaceArgument(0, 'bar');
313+
}
314+
304315
public function testSetGetProperties()
305316
{
306317
$def = new Definition('stdClass');

src/Symfony/Component/Form/Tests/Extension/Core/Type/DateTypeTest.php

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -79,10 +79,10 @@ public function testSubmitFromSingleTextDateTimeWithDefaultFormat()
7979

8080
public function testSubmitFromSingleTextDateTime()
8181
{
82-
// we test against "de_AT", so we need the full implementation
82+
// we test against "de_DE", so we need the full implementation
8383
IntlTestHelper::requireFullIntl($this, false);
8484

85-
\Locale::setDefault('de_AT');
85+
\Locale::setDefault('de_DE');
8686

8787
$form = $this->factory->create('Symfony\Component\Form\Extension\Core\Type\DateType', null, array(
8888
'format' => \IntlDateFormatter::MEDIUM,
@@ -100,10 +100,10 @@ public function testSubmitFromSingleTextDateTime()
100100

101101
public function testSubmitFromSingleTextString()
102102
{
103-
// we test against "de_AT", so we need the full implementation
103+
// we test against "de_DE", so we need the full implementation
104104
IntlTestHelper::requireFullIntl($this, false);
105105

106-
\Locale::setDefault('de_AT');
106+
\Locale::setDefault('de_DE');
107107

108108
$form = $this->factory->create('Symfony\Component\Form\Extension\Core\Type\DateType', null, array(
109109
'format' => \IntlDateFormatter::MEDIUM,
@@ -121,10 +121,10 @@ public function testSubmitFromSingleTextString()
121121

122122
public function testSubmitFromSingleTextTimestamp()
123123
{
124-
// we test against "de_AT", so we need the full implementation
124+
// we test against "de_DE", so we need the full implementation
125125
IntlTestHelper::requireFullIntl($this, false);
126126

127-
\Locale::setDefault('de_AT');
127+
\Locale::setDefault('de_DE');
128128

129129
$form = $this->factory->create('Symfony\Component\Form\Extension\Core\Type\DateType', null, array(
130130
'format' => \IntlDateFormatter::MEDIUM,
@@ -144,10 +144,10 @@ public function testSubmitFromSingleTextTimestamp()
144144

145145
public function testSubmitFromSingleTextRaw()
146146
{
147-
// we test against "de_AT", so we need the full implementation
147+
// we test against "de_DE", so we need the full implementation
148148
IntlTestHelper::requireFullIntl($this, false);
149149

150-
\Locale::setDefault('de_AT');
150+
\Locale::setDefault('de_DE');
151151

152152
$form = $this->factory->create('Symfony\Component\Form\Extension\Core\Type\DateType', null, array(
153153
'format' => \IntlDateFormatter::MEDIUM,
@@ -408,10 +408,10 @@ public function testThrowExceptionIfDaysIsInvalid()
408408

409409
public function testSetDataWithNegativeTimezoneOffsetStringInput()
410410
{
411-
// we test against "de_AT", so we need the full implementation
411+
// we test against "de_DE", so we need the full implementation
412412
IntlTestHelper::requireFullIntl($this, false);
413413

414-
\Locale::setDefault('de_AT');
414+
\Locale::setDefault('de_DE');
415415

416416
$form = $this->factory->create('Symfony\Component\Form\Extension\Core\Type\DateType', null, array(
417417
'format' => \IntlDateFormatter::MEDIUM,
@@ -430,10 +430,10 @@ public function testSetDataWithNegativeTimezoneOffsetStringInput()
430430

431431
public function testSetDataWithNegativeTimezoneOffsetDateTimeInput()
432432
{
433-
// we test against "de_AT", so we need the full implementation
433+
// we test against "de_DE", so we need the full implementation
434434
IntlTestHelper::requireFullIntl($this, false);
435435

< FECB /code>
436-
\Locale::setDefault('de_AT');
436+
\Locale::setDefault('de_DE');
437437

438438
$form = $this->factory->create('Symfony\Component\Form\Extension\Core\Type\DateType', null, array(
439439
'format' => \IntlDateFormatter::MEDIUM,

src/Symfony/Component/Intl/Util/IntlTestHelper.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ public static function requireIntl(\PHPUnit_Framework_TestCase $testCase, $minim
4141
// * the intl extension is loaded with version Intl::getIcuStubVersion()
4242
// * the intl extension is not loaded
4343

44-
if (($minimumIcuVersion || defined('HHVM_VERSION_ID')) && IcuVersion::compare(Intl::getIcuVersion(), $minimumIcuVersion, '!=', 1)) {
44+
if (($minimumIcuVersion || defined('HHVM_VERSION_ID')) && IcuVersion::compare(Intl::getIcuVersion(), $minimumIcuVersion, '<', 1)) {
4545
$testCase->markTestSkipped('ICU version '.$minimumIcuVersion.' is required.');
4646
}
4747

src/Symfony/Component/PropertyAccess/PropertyAccessor.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -246,7 +246,7 @@ public static function handleError($type, $message, $file, $line, $context)
246246
private static function throwInvalidArgumentException($message, $trace, $i)
247247
{
248248
if (isset($trace[$i]['file']) && __FILE__ === $trace[$i]['file']) {
249-
$pos = strpos($message, $delim = 'must be of the type ') ?: strpos($message, $delim = 'must be an instance of ');
249+
$pos = strpos($message, $delim = 'must be of the type ') ?: (strpos($message, $delim = 'must be an instance of ') ?: strpos($message, $delim = 'must implement interface '));
250250
$pos += strlen($delim);
251251
$type = $trace[$i]['args'][0];
252252
$type = is_object($type) ? get_class($type) : gettype($type);

0 commit comments

Comments
 (0)
0