Skip to content

Commit 90dcd92

Browse files
committed
Merge branch '2.8' into 3.0
* 2.8: [Yaml] fix exception contexts People - person singularization [Yaml] properly handle unindented collections [Serializer] Add test for ignored attributes during denormalization chomp newlines only at the end of YAML documents Fixed server status command when port has been omitted Update UPGRADE FROM 2.x to 3.0 fix removed commands wording in upgrade file Catch \Throwable Catch \Throwable Use levenshtein level for better Bundle matching [WebProfilerBundle] Fix CORS ajax security issues [DX][DI] Make Autowiring exceptions more future friendly
2 parents 7bdd50c + 5cb0ad3 commit 90dcd92

File tree

14 files changed

+143
-47
lines changed

14 files changed

+143
-47
lines changed

UPGRADE-3.0.md

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -398,8 +398,11 @@ UPGRADE FROM 2.x to 3.0
398398
</service>
399399
```
400400

401-
* The `ChoiceToBooleanArrayTransformer`, `ChoicesToBooleanArrayTransformer`,
402-
`FixRadioInputListener`, and `FixCheckboxInputListener` classes were removed.
401+
* The `max_length` option was removed. Use the `attr` option instead by setting it to
402+
an `array` with a `maxlength` key.
403+
404+
* The `ChoiceToBooleanArrayTransformer`, `ChoicesToBooleanArrayTransformer`,
405+
`FixRadioInputListener`, and `FixCheckboxInputListener` classes were removed.
403406

404407
* The `choice_list` option of `ChoiceType` was removed.
405408

@@ -1742,8 +1745,7 @@ UPGRADE FROM 2.x to 3.0
17421745

17431746
### WebProfiler
17441747

1745-
* The `profiler:import` and `profiler:export` commands have been deprecated and
1746-
will be removed in 3.0.
1748+
* The `profiler:import` and `profiler:export` commands have been removed.
17471749

17481750
* All the profiler storages different than `FileProfilerStorage` have been
17491751
removed. The removed classes are:

src/Symfony/Bundle/FrameworkBundle/Command/ServerStatusCommand.php

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313

1414
use Symfony\Component\Console\Input\InputArgument;
1515
use Symfony\Component\Console\Input\InputInterface;
16+
use Symfony\Component\Console\Input\InputOption;
1617
use Symfony\Component\Console\Output\OutputInterface;
1718
use Symfony\Component\Console\Style\SymfonyStyle;
1819

@@ -32,6 +33,7 @@ protected function configure()
3233
$this
3334
->setDefinition(array(
3435
new InputArgument('address', InputArgument::OPTIONAL, 'Address:port', '127.0.0.1:8000'),
36+
new InputOption('port', 'p', InputOption::VALUE_REQUIRED, 'Address port number', '8000'),
3537
))
3638
->setName('server:status')
3739
->setDescription('Outputs the status of the built-in web server for the given address')
@@ -46,6 +48,10 @@ protected function execute(InputInterface $input, OutputInterface $output)
4648
$io = new SymfonyStyle($input, $output);
4749
$address = $input->getArgument('address');
4850

51+
if (false === strpos($address, ':')) {
52+
$address = $address.':'.$input->getOption('port');
53+
}
54+
4955
// remove an orphaned lock file
5056
if (file_exists($this->getLockFile($address)) && !$this->isServerRunning($address)) {
5157
unlink($this->getLockFile($address));

src/Symfony/Bundle/FrameworkBundle/Controller/ControllerNameParser.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -142,6 +142,7 @@ private function findAlternative($nonExistentBundleName)
142142
$lev = levenshtein($nonExistentBundleName, $bundleName);
143143
if ($lev <= strlen($nonExistentBundleName) / 3 && ($alternative === null || $lev < $shortest)) {
144144
$alternative = $bundleName;
145+
$shortest = $lev;
145146
}
146147
}
147148

src/Symfony/Bundle/FrameworkBundle/Tests/Controller/ControllerNameParserTest.php

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -59,8 +59,8 @@ public function testBuild()
5959
{
6060
$parser = $this->createParser();
6161

62-
$this->assertEquals('FooBundle:Default:index', $parser->build('TestBundle\FooBundle\Controller\DefaultController::indexAction'), '->parse() converts a class::method string to a short a:b:c notation string');
63-
$this->assertEquals('FooBundle:Sub\Default:index', $parser->build('TestBundle\FooBundle\Controller\Sub\DefaultController::indexAction'), '->parse() converts a class::method string to a short a:b:c notation string');
62+
$this->assertEquals('FoooooBundle:Default:index', $parser->build('TestBundle\FooBundle\Controller\DefaultController::indexAction'), '->parse() converts a class::method string to a short a:b:c notation string');
63+
$this->assertEquals('FoooooBundle:Sub\Default:index', $parser->build('TestBundle\FooBundle\Controller\Sub\DefaultController::indexAction'), '->parse() converts a class::method string to a short a:b:c notation string');
6464

6565
try {
6666
$parser->build('TestBundle\FooBundle\Controller\DefaultController::index');
@@ -132,8 +132,9 @@ public function testInvalidBundleName($bundleName, $suggestedBundleName)
132132
public function getInvalidBundleNameTests()
133133
{
134134
return array(
135-
array('FoodBundle:Default:index', 'FooBundle:Default:index'),
136-
array('CrazyBundle:Default:index', false),
135+
'Alternative will be found using levenshtein' => array('FoodBundle:Default:index', 'FooBundle:Default:index'),
136+
'Alternative will be found using partial match' => array('FabpotFooBund:Default:index', 'FabpotFooBundle:Default:index'),
137+
'Bundle does not exist at all' => array('CrazyBundle:Default:index', false),
137138
);
138139
}
139140

@@ -162,6 +163,7 @@ private function createParser()
162163
$bundles = array(
163164
'SensioFooBundle' => $this->getBundle('TestBundle\Fabpot\FooBundle', 'FabpotFooBundle'),
164165
'SensioCmsFooBundle' => $this->getBundle('TestBundle\Sensio\Cms\FooBundle', 'SensioCmsFooBundle'),
166+
'FoooooBundle' => $this->getBundle('TestBundle\FooBundle', 'FoooooBundle'),
165167
'FooBundle' => $this->getBundle('TestBundle\FooBundle', 'FooBundle'),
166168
'FabpotFooBundle' => $this->getBundle('TestBundle\Fabpot\FooBundle', 'FabpotFooBundle'),
167169
);

src/Symfony/Bundle/WebProfilerBundle/Resources/views/Profiler/base_js.html.twig

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,20 @@
8282
8383
requestStack = [],
8484
85+
extractHeaders = function(xhr, stackElement) {
86+
// Here we avoid to call xhr.getResponseHeader in order to
87+
// prevent polluting the console with CORS security errors
88+
var allHeaders = xhr.getAllResponseHeaders();
89+
var ret;
90+
91+
if (ret = allHeaders.match(/^x-debug-token:\s+(.*)$/im)) {
92+
stackElement.profile = ret[1];
93+
}
94+
if (ret = allHeaders.match(/^x-debug-token-link:\s+(.*)$/im)) {
95+
stackElement.profilerUrl = ret[1];
96+
}
97+
},
98+
8599
renderAjaxRequests = function() {
86100
var requestCounter = document.querySelectorAll('.sf-toolbar-ajax-requests');
87101
if (!requestCounter.length) {
@@ -241,8 +255,8 @@
241255
stackElement.duration = new Date() - stackElement.start;
242256
stackElement.loading = false;
243257
stackElement.error = self.status < 200 || self.status >= 400;
244-
stackElement.profile = self.getResponseHeader("X-Debug-Token");
245-
stackElement.profilerUrl = self.getResponseHeader("X-Debug-Token-Link");
258+
259+
extractHeaders(self, stackElement);
246260
247261
Sfjs.renderAjaxRequests();
248262
}

src/Symfony/Component/Debug/ErrorHandler.php

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -580,6 +580,8 @@ public static function handleFatalError(array $error = null)
580580
}
581581
} catch (\Exception $exception) {
582582
// Handled below
583+
} catch (\Throwable $exception) {
584+
// Handled below
583585
}
584586

585587
if ($error && $error['type'] &= E_PARSE | E_ERROR | E_CORE_ERROR | E_COMPILE_ERROR) {

src/Symfony/Component/DependencyInjection/Compiler/AutowirePass.php

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -44,8 +44,8 @@ public function process(ContainerBuilder $container)
4444
$this->completeDefinition($id, $definition);
4545
}
4646
}
47-
} catch (\Error $e) {
4847
} catch (\Exception $e) {
48+
} catch (\Throwable $e) {
4949
}
5050

5151
spl_autoload_unregister($throwingAutoloader);
@@ -225,13 +225,16 @@ private function set($type, $id)
225225
private function createAutowiredDefinition(\ReflectionClass $typeHint, $id)
226226
{
227227
if (isset($this->notGuessableTypes[$typeHint->name])) {
228-
throw new RuntimeException(sprintf('Unable to autowire argument of type "%s" for the service "%s". Several services implementing this type have been declared: "%s".', $typeHint->name, $id, implode('", "', $this->types[$typeHint->name])));
229-
}
228+
$classOrInterface = $typeHint->isInterface() ? 'interface' : 'class';
229+
$matchingServices = implode(', ', $this->types[$typeHint->name]);
230+
231+
throw new RuntimeException(sprintf('Unable to autowire argument of type "%s" for the service "%s". Multiple services exist for this %s (%s).', $typeHint->name, $id, $classOrInterface, $matchingServices));
230232

231-
$noAvailableDefinitionMessage = sprintf('Unable to autowire argument of type "%s" for the service "%s". This type cannot be instantiated automatically and no service implementing this type is declared.', $typeHint->name, $id);
233+
}
232234

233235
if (!$typeHint->isInstantiable()) {
234-
throw new RuntimeException($noAvailableDefinitionMessage);
236+
$classOrInterface = $typeHint->isInterface() ? 'interface' : 'class';
237+
throw new RuntimeException(sprintf('Unable to autowire argument of type "%s" for the service "%s". No services were found matching this %s and it cannot be auto-registered.', $typeHint->name, $id, $classOrInterface));
235238
}
236239

237240
$argumentId = sprintf('autowired.%s', $typeHint->name);
@@ -244,7 +247,9 @@ private function createAutowiredDefinition(\ReflectionClass $typeHint, $id)
244247
try {
245248
$this->completeDefinition($argumentId, $argumentDefinition);
246249
} catch (RuntimeException $e) {
247-
throw new RuntimeException($noAvailableDefinitionMessage, 0, $e);
250+
$classOrInterface = $typeHint->isInterface() ? 'interface' : 'class';
251+
$message = sprintf('Unable to autowire argument of type "%s" for the service "%s". No services were found matching this %s and it cannot be auto-registered.', $typeHint->name, $id, $classOrInterface);
252+
throw new RuntimeException($message, 0, $e);
248253
}
249254

250255
return new Reference($argumentId);

src/Symfony/Component/DependencyInjection/Tests/Compiler/AutowirePassTest.php

Lines changed: 19 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -103,14 +103,15 @@ public function testCompleteExistingDefinitionWithNotDefinedArguments()
103103

104104
/**
105105
* @expectedException \Symfony\Component\DependencyInjection\Exception\RuntimeException
106-
* @expectedExceptionMessage Unable to autowire argument of type "Symfony\Component\DependencyInjection\Tests\Compiler\CollisionInterface" for the service "a". Several services implementing this type have been declared: "c1", "c2".
106+
* @expectedExceptionMessage Unable to autowire argument of type "Symfony\Component\DependencyInjection\Tests\Compiler\CollisionInterface" for the service "a". Multiple services exist for this interface (c1, c2, c3).
107107
*/
108108
public function testTypeCollision()
109109
{
110110
$container = new ContainerBuilder();
111111

112112
$container->register('c1', __NAMESPACE__.'\CollisionA');
113113
$container->register('c2', __NAMESPACE__.'\CollisionB');
114+
$container->register('c3', __NAMESPACE__.'\CollisionB');
114115
$aDefinition = $container->register('a', __NAMESPACE__.'\CannotBeAutowired');
115116
$aDefinition->setAutowired(true);
116117

@@ -120,7 +121,7 @@ public function testTypeCollision()
120121

121122
/**
122123
* @expectedException \Symfony\Component\DependencyInjection\Exception\RuntimeException
123-
* @expectedExceptionMessage Unable to autowire argument of type "Symfony\Component\DependencyInjection\Tests\Compiler\Foo" for the service "a". Several services implementing this type have been declared: "a1", "a2".
124+
* @expectedExceptionMessage Unable to autowire argument of type "Symfony\Component\DependencyInjection\Tests\Compiler\Foo" for the service "a". Multiple services exist for this class (a1, a2).
124125
*/
125126
public function testTypeNotGuessable()
126127
{
@@ -137,7 +138,7 @@ public function testTypeNotGuessable()
137138

138139
/**
139140
* @expectedException \Symfony\Component\DependencyInjection\Exception\RuntimeException
140-
* @expectedExceptionMessage Unable to autowire argument of type "Symfony\Component\DependencyInjection\Tests\Compiler\A" for the service "a". Several services implementing this type have been declared: "a1", "a2".
141+
* @expectedExceptionMessage Unable to autowire argument of type "Symfony\Component\DependencyInjection\Tests\Compiler\A" for the service "a". Multiple services exist for this class (a1, a2).
141142
*/
142143
public function testTypeNotGuessableWithSubclass()
143144
{
@@ -152,6 +153,21 @@ public function testTypeNotGuessableWithSubclass()
152153
$pass->process($container);
153154
}
154155

156+
/**
157+
* @expectedException \Symfony\Component\DependencyInjection\Exception\RuntimeException
158+
* @expectedExceptionMessage Unable to autowire argument of type "Symfony\Component\DependencyInjection\Tests\Compiler\CollisionInterface" for the service "a". No services were found matching this interface and it cannot be auto-registered.
159+
*/
160+
public function testTypeNotGuessableNoServicesFound()
161+
{
162+
$container = new ContainerBuilder();
163+
164+
$aDefinition = $container->register('a', __NAMESPACE__.'\CannotBeAutowired');
165+
$aDefinition->setAutowired(true);
166+
167+
$pass = new AutowirePass();
168+
$pass->process($container);
169+
}
170+
155171
public function testTypeNotGuessableWithTypeSet()
156172
{
157173
$container = new ContainerBuilder();
@@ -207,21 +223,6 @@ public function testCreateDefinition()
207223
$this->assertEquals(__NAMESPACE__.'\Lille', $lilleDefinition->getClass());
208224
}
209225

210-
/**
211-
* @expectedException \Symfony\Component\DependencyInjection\Exception\RuntimeException
212-
* @expectedExceptionMessage Unable to autowire argument of type "Symfony\Component\DependencyInjection\Tests\Compiler\CollisionInterface" for the service "a". This type cannot be instantiated automatically and no service implementing this type is declared.
213-
*/
214-
public function testCreateNonInstanciable()
215-
{
216-
$container = new ContainerBuilder();
217-
218-
$aDefinition = $container->register('a', __NAMESPACE__.'\CannotBeAutowired');
219-
$aDefinition->setAutowired(true);
220-
221-
$pass = new AutowirePass();
222-
$pass->process($container);
223-
}
224-
225226
public function testResolveParameter()
226227
{
227228
$container = new ContainerBuilder();

src/Symfony/Component/PropertyAccess/StringUtil.php

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -124,6 +124,9 @@ class StringUtil
124124

125125
// chateaux (chateau)
126126
array('xuae', 4, false, true, 'eau'),
127+
128+
// people (person)
129+
array('elpoep', 6, true, true, 'person'),
127130
);
128131

129132
/**

src/Symfony/Component/PropertyAccess/Tests/StringUtilTest.php

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,8 @@ public function singularifyProvider()
107107
array('objectives', 'objective'),
108108
array('oxen', 'ox'),
109109
array('parties', 'party'),
110+
array('people', 'person'),
111+
array('persons', 'person'),
110112
array('phenomena', array('phenomenon', 'phenomenum')),
111113
array('photos', 'photo'),
112114
array('pianos', 'piano'),

0 commit comments

Comments
 (0)