Skip to content

Commit 1385afd

Browse files
committed
Merge pull request #940 from FriendsOfSymfony/exception_fallback_format
make it possible to define a separate fallback format for exceptions
2 parents 185c829 + d1b0a30 commit 1385afd

File tree

8 files changed

+32
-5
lines changed

8 files changed

+32
-5
lines changed

Controller/ExceptionController.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -211,7 +211,7 @@ protected function getStatusCode($exception)
211211
protected function getFormat(Request $request, $format)
212212
{
213213
try {
214-
$formatNegotiator = $this->container->get('fos_rest.format_negotiator');
214+
$formatNegotiator = $this->container->get('fos_rest.exception_format_negotiator');
215215
$format = $formatNegotiator->getBestFormat($request) ?: $format;
216216
$request->attributes->set('_format', $format);
217217
} catch (StopFormatListenerException $e) {

DependencyInjection/Compiler/FormatListenerRulesPass.php

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ public function process(ContainerBuilder $container)
3939
'path' => "^/$path/",
4040
'priorities' => array('html', 'json'),
4141
'fallback_format' => 'html',
42+
'exception_fallback_format' => 'html',
4243
'prefer_extension' => true,
4344
);
4445

@@ -65,8 +66,14 @@ protected function addRule(array $rule, ContainerBuilder $container)
6566
$rule['prefer_extension'] = '2.0';
6667
}
6768

69+
$exceptionFallbackFormat = $rule['exception_fallback_format'];
70+
unset($rule['exception_fallback_format']);
6871
$container->getDefinition('fos_rest.format_negotiator')
6972
->addMethodCall('add', array($matcher, $rule));
73+
74+
$rule['fallback_format'] = $exceptionFallbackFormat;
75+
$container->getDefinition('fos_rest.exception_format_negotiator')
76+
->addMethodCall('add', array($matcher, $rule));
7077
}
7178

7279
protected function createRequestMatcher(ContainerBuilder $container, $path = null, $host = null, $methods = null)

DependencyInjection/Configuration.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -212,6 +212,7 @@ private function addFormatListenerSection(ArrayNodeDefinition $rootNode)
212212
->booleanNode('stop')->defaultFalse()->end()
213213
->booleanNode('prefer_extension')->defaultTrue()->end()
214214
->scalarNode('fallback_format')->defaultValue('html')->end()
215+
->scalarNode('exception_fallback_format')->defaultNull()->end()
215216
->arrayNode('priorities')
216217
->beforeNormalization()->ifString()->then(function ($v) { return preg_split('/\s*,\s*/', $v); })->end()
217218
->prototype('scalar')->end()

DependencyInjection/FOSRestExtension.php

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -163,6 +163,12 @@ public function load(array $configs, ContainerBuilder $container)
163163
if (!empty($config['format_listener']['rules'])) {
164164
$loader->load('format_listener.xml');
165165

166+
foreach ($config['format_listener']['rules'] as $key => $rule) {
167+
if (!isset($rule['exception_fallback_format'])) {
168+
$config['format_listener']['rules'][$key]['exception_fallback_format'] = $rule['fallback_format'];
169+
}
170+
}
171+
166172
$container->setParameter(
167173
$this->getAlias().'.format_listener.rules',
168174
$config['format_listener']['rules']

Resources/config/util.xml

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

1414
<services>
1515
<service id="fos_rest.format_negotiator" class="%fos_rest.format_negotiator.class%" />
16+
<service id="fos_rest.exception_format_negotiator" class="%fos_rest.format_negotiator.class%" />
1617
<service id="fos_rest.inflector.doctrine" class="%fos_rest.inflector.class%" />
1718
<service id="fos_rest.request_matcher" class="%fos_rest.request_matcher.class%" public="false" />
1819
<service id="fos_rest.violation_formatter" class="%fos_rest.violation_formatter.class%" />

Resources/doc/3-listener-support.rst

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -396,6 +396,9 @@ Setting ``priorities`` to a non empty array enables Accept header negotiations.
396396
- { path: '^/image', priorities: ['jpeg', 'gif'], fallback_format: false, prefer_extension: true }
397397
# setting fallback_format to null means that in case of a priority mismatch the next rule will be considered
398398
- { path: '^/admin', methods: [ 'GET', 'POST'], priorities: [ 'xml', 'html'], fallback_format: ~, prefer_extension: false }
399+
# setting fallback_format to null, while setting exception_fallback_format to xml, will mean that in case of an exception, xml will be used
400+
- { path: '^/api', priorities: [ 'xml', 'json'], fallback_format: ~, exception_fallback_format: xml, prefer_extension: false }
401+
# setting a priority to */* basically means any format will be matched
399402
- { path: '^/', priorities: [ 'text/html', '*/*'], fallback_format: html, prefer_extension: true }
400403
401404
For example using the above configuration and the following Accept header:

Resources/doc/configuration-reference.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,7 @@ Full default configuration
9090
methods: null
9191
prefer_extension: true
9292
fallback_format: html
93+
exception_fallback_format: ~
9394
priorities: []
9495
media_type:
9596
version_regex: '/(v|version)=(?P<version>[0-9\.]+)/'

Tests/DependencyInjection/Compiler/FormatListenerRulesPassTest.php

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -46,14 +46,18 @@ public function testRulesAreAddedWhenFormatListenerAndProfilerToolbarAreEnabled(
4646
'path' => '^/',
4747
'priorities' => array('html', 'json'),
4848
'fallback_format' => 'html',
49+
'exception_fallback_format' => 'html',
4950
'prefer_extension' => true,
5051
),
5152
) )
5253
);
5354

54-
$container->expects($this->exactly(2))
55+
$container->expects($this->exactly(4))
5556
->method('getDefinition')
56-
->with('fos_rest.format_negotiator')
57+
->with($this->logicalOr(
58+
$this->equalTo('fos_rest.format_negotiator'),
59+
$this->equalTo('fos_rest.exception_format_negotiator')
60+
))
5761
->will($this->returnValue($definition));
5862

5963
$compiler = new FormatListenerRulesPass();
@@ -88,14 +92,18 @@ public function testNoRulesAreAddedWhenProfilerToolbarAreDisabled()
8892
'path' => '^/',
8993
'priorities' => array('html', 'json'),
9094
'fallback_format' => 'html',
95+
'exception_fallback_format' => 'html',
9196
'prefer_extension' => true,
9297
),
9398
) )
9499
);
95100

96-
$container->expects($this->exactly(1))
101+
$container->expects($this->exactly(2))
97102
->method('getDefinition')
98-
->with('fos_rest.format_negotiator')
103+
->with($this->logicalOr(
104+
$this->equalTo('fos_rest.format_negotiator'),
105+
$this->equalTo('fos_rest.exception_format_negotiator')
106+
))
99107
->will($this->returnValue($definition));
100108

101109
$compiler = new FormatListenerRulesPass();

0 commit comments

Comments
 (0)