12
12
namespace Symfony \Bundle \FrameworkBundle \Routing ;
13
13
14
14
use Symfony \Bundle \FrameworkBundle \Controller \ControllerNameParser ;
15
+ use Symfony \Component \Config \Exception \FileLoaderLoadException ;
15
16
use Symfony \Component \Config \Loader \DelegatingLoader as BaseDelegatingLoader ;
16
17
use Symfony \Component \Config \Loader \LoaderResolverInterface ;
17
18
use Psr \Log \LoggerInterface ;
18
- use Symfony \Component \Routing \RouteCollection ;
19
19
20
20
/**
21
21
* DelegatingLoader delegates route loading to other loaders using a loader resolver.
@@ -29,6 +29,7 @@ class DelegatingLoader extends BaseDelegatingLoader
29
29
{
30
30
protected $ parser ;
31
31
protected $ logger ;
32
+ private $ loading = false ;
32
33
33
34
/**
34
35
* Constructor.
@@ -46,16 +47,39 @@ public function __construct(ControllerNameParser $parser, LoggerInterface $logge
46
47
}
47
48
48
49
/**
49
- * Loads a resource.
50
- *
51
- * @param mixed $resource A resource
52
- * @param string $type The resource type
53
- *
54
- * @return RouteCollection A RouteCollection instance
50
+ * {@inheritdoc}
55
51
*/
56
52
public function load ($ resource , $ type = null )
57
53
{
58
- $ collection = parent ::load ($ resource , $ type );
54
+ if ($ this ->loading ) {
55
+ // This can happen if a fatal error occurs in parent::load().
56
+ // Here is the scenario:
57
+ // - while routes are being loaded by parent::load() below, a fatal error
58
+ // occurs (e.g. parse error in a controller while loading annotations);
59
+ // - PHP abruptly empties the stack trace, bypassing all catch blocks;
60
+ // it then calls the registered shutdown functions;
61
+ // - the ErrorHandler catches the fatal error and re-injects it for rendering
62
+ // thanks to HttpKernel->terminateWithException() (that calls handleException());
63
+ // - at this stage, if we try to load the routes again, we must prevent
64
+ // the fatal error from occurring a second time,
65
+ // otherwise the PHP process would be killed immediately;
66
+ // - while rendering the exception page, the router can be required
67
+ // (by e.g. the web profiler that needs to generate an URL);
68
+ // - this handles the case and prevents the second fatal error
69
+ // by triggering an exception beforehand.
70
+
71
+ throw new FileLoaderLoadException ($ resource );
72
+ }
73
+ $ this ->loading = true ;
74
+
75
+ try {
76
+ $ collection = parent ::load ($ resource , $ type );
77
+ } catch (\Exception $ e ) {
78
+ $ this ->loading = false ;
79
+ throw $ e ;
80
+ }
81
+
82
+ $ this ->loading = false ;
59
83
60
84
foreach ($ collection ->all () as $ route ) {
61
85
if ($ controller = $ route ->getDefault ('_controller ' )) {
0 commit comments