Skip to content

Commit e097ab3

Browse files
committed
Show welcome message if no routing configuration could be found
1 parent 5e2f869 commit e097ab3

File tree

14 files changed

+228
-2
lines changed

14 files changed

+228
-2
lines changed

src/Symfony/Bundle/FrameworkBundle/Resources/config/routing.xml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -109,6 +109,8 @@
109109
<argument type="service" id="request_stack" />
110110
<argument type="service" id="router.request_context" on-invalid="ignore" />
111111
<argument type="service" id="logger" on-invalid="ignore" />
112+
<argument>%kernel.project_dir%</argument>
113+
<argument>%kernel.debug%</argument>
112114
</service>
113115
</services>
114116
</container>

src/Symfony/Component/HttpKernel/EventListener/RouterListener.php

Lines changed: 29 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,13 +12,16 @@
1212
namespace Symfony\Component\HttpKernel\EventListener;
1313

1414
use Psr\Log\LoggerInterface;
15+
use Symfony\Component\HttpFoundation\Response;
1516
use Symfony\Component\HttpKernel\Event\GetResponseEvent;
1617
use Symfony\Component\HttpKernel\Event\FinishRequestEvent;
18+
use Symfony\Component\HttpKernel\Kernel;
1719
use Symfony\Component\HttpKernel\KernelEvents;
1820
use Symfony\Component\HttpKernel\Exception\MethodNotAllowedHttpException;
1921
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
2022
use Symfony\Component\HttpFoundation\RequestStack;
2123
use Symfony\Component\Routing\Exception\MethodNotAllowedException;
24+
use Symfony\Component\Routing\Exception\NoConfigurationException;
2225
use Symfony\Component\Routing\Exception\ResourceNotFoundException;
2326
use Symfony\Component\Routing\Matcher\UrlMatcherInterface;
2427
use Symfony\Component\Routing\Matcher\RequestMatcherInterface;
@@ -31,23 +34,28 @@
3134
* Initializes the context from the request and sets request attributes based on a matching route.
3235
*
3336
* @author Fabien Potencier <fabien@symfony.com>
37+
* @author Yonel Ceruto <yonelceruto@gmail.com>
3438
*/
3539
class RouterListener implements EventSubscriberInterface
3640
{
3741
private $matcher;
3842
private $context;
3943
private $logger;
4044
private $requestStack;
45+
private $projectDir;
46+
private $debug;
4147

4248
/**
4349
* @param UrlMatcherInterface|RequestMatcherInterface $matcher The Url or Request matcher
4450
* @param RequestStack $requestStack A RequestStack instance
4551
* @param RequestContext|null $context The RequestContext (can be null when $matcher implements RequestContextAwareInterface)
4652
* @param LoggerInterface|null $logger The logger
53+
* @param string $projectDir
54+
* @param bool $debug
4755
*
4856
* @throws \InvalidArgumentException
4957
*/
50-
public function __construct($matcher, RequestStack $requestStack, RequestContext $context = null, LoggerInterface $logger = null)
58+
public function __construct($matcher, RequestStack $requestStack, RequestContext $context = null, LoggerInterface $logger = null, $projectDir = null, $debug = true)
5159
{
5260
if (!$matcher instanceof UrlMatcherInterface && !$matcher instanceof RequestMatcherInterface) {
5361
throw new \InvalidArgumentException('Matcher must either implement UrlMatcherInterface or RequestMatcherInterface.');
@@ -61,6 +69,8 @@ public function __construct($matcher, RequestStack $requestStack, RequestContext
6169
$this->context = $context ?: $matcher->getContext();
6270
$this->requestStack = $requestStack;
6371
$this->logger = $logger;
72+
$this->projectDir = $projectDir;
73+
$this->debug = $debug;
6474
}
6575

6676
private function setCurrentRequest(Request $request = null)
@@ -114,6 +124,12 @@ public function onKernelRequest(GetResponseEvent $event)
114124
unset($parameters['_route'], $parameters['_controller']);
115125
$request->attributes->set('_route_params', $parameters);
116126
} catch (ResourceNotFoundException $e) {
127+
if ($this->debug && $e instanceof NoConfigurationException) {
128+
$event->setResponse($this->createWelcomeResponse());
129+
130+
return;
131+
}
132+
117133
$message = sprintf('No route found for "%s %s"', $request->getMethod(), $request->getPathInfo());
118134

119135
if ($referer = $request->headers->get('referer')) {
@@ -135,4 +151,16 @@ public static function getSubscribedEvents()
135151
KernelEvents::FINISH_REQUEST => array(array('onKernelFinishRequest', 0)),
136152
);
137153
}
154+
155+
private function createWelcomeResponse()
156+
{
157+
$version = Kernel::VERSION;
158+
$baseDir = realpath($this->projectDir).DIRECTORY_SEPARATOR;
159+
$docVersion = substr(Kernel::VERSION, 0, 3);
160+
161+
ob_start();
162+
include __DIR__.'/../Resources/welcome.html.php';
163+
164+
return new Response(ob_get_clean(), Response::HTTP_NOT_FOUND);
165+
}
138166
}
Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
<!DOCTYPE html>
2+
<html>
3+
<head>
4+
<meta charset="UTF-8" />
5+
<title>Welcome!</title>
6+
<style>
7+
body { background: #F5F5F5; font: 18px/1.5 sans-serif; }
8+
h1, h2 { line-height: 1.2; margin: 0 0 .5em; }
9+
h1 { font-size: 36px; }
10+
h2 { font-size: 21px; margin-bottom: 1em; }
11+
p { margin: 0 0 1em 0; }
12+
a { color: #0000F0; }
13+
a:hover { text-decoration: none; }
14+
code { background: #F5F5F5; max-width: 100px; padding: 2px 6px; word-wrap: break-word; }
15+
#wrapper { background: #FFF; margin: 1em auto; max-width: 800px; width: 95%; }
16+
#container { padding: 2em; }
17+
#welcome, #status { margin-bottom: 2em; }
18+
#welcome h1 span { display: block; font-size: 75%; }
19+
#comment { font-size: 14px; text-align: center; color: #777777; background: #FEFFEA; padding: 10px; }
20+
#comment p { margin-bottom: 0; }
21+
#icon-status, #icon-book { float: left; height: 64px; margin-right: 1em; margin-top: -4px; width: 64px; }
22+
#icon-book { display: none; }
23+
24+
@media (min-width: 768px) {
25+
#wrapper { width: 80%; margin: 2em auto; }
26+
#icon-book { display: inline-block; }
27+
#status a, #next a { display: block; }
28+
29+
@-webkit-keyframes fade-in { 0% { opacity: 0; } 100% { opacity: 1; } }
30+
@keyframes fade-in { 0% { opacity: 0; } 100% { opacity: 1; } }
31+
.sf-toolbar { opacity: 0; -webkit-animation: fade-in 1s .2s forwards; animation: fade-in 1s .2s forwards;}
32+
}
33+
</style>
34+
</head>
35+
<body>
36+
<div id="wrapper">
37+
<div id="container">
38+
<div id="welcome">
39+
<h1><span>Welcome to</span> Symfony <?php echo $version; ?></h1>
40+
</div>
41+
42+
<div id="status">
43+
<p>
44+
<svg id="icon-status" width="1792" height="1792" viewBox="0 0 1792 1792" xmlns="http://www.w3.org/2000/svg"><path d="M1671 566q0 40-28 68l-724 724-136 136q-28 28-68 28t-68-28l-136-136-362-362q-28-28-28-68t28-68l136-136q28-28 68-28t68 28l294 295 656-657q28-28 68-28t68 28l136 136q28 28 28 68z" fill="#759E1A"/></svg>
45+
46+
Your application is now ready. You can start working on it at:<br>
47+
<code><?php echo $baseDir; ?></code>
48+
</p>
49+
</div>
50+
51+
<div id="next">
52+
<h2>What's next?</h2>
53+
<p>
54+
<svg id="icon-book" version="1.1" xmlns="http://www.w3.org/2000/svg" x="0px" y="0px" viewBox="-12.5 9 64 64" enable-background="new -12.5 9 64 64" xml:space="preserve">
55+
<path fill="#AAA" d="M6.8,40.8c2.4,0.8,4.5-0.7,4.9-2.5c0.2-1.2-0.3-2.1-1.3-3.2l-0.8-0.8c-0.4-0.5-0.6-1.3-0.2-1.9
56+
c0.4-0.5,0.9-0.8,1.8-0.5c1.3,0.4,1.9,1.3,2.9,2.2c-0.4,1.4-0.7,2.9-0.9,4.2l-0.2,1c-0.7,4-1.3,6.2-2.7,7.5
57+
c-0.3,0.3-0.7,0.5-1.3,0.6c-0.3,0-0.4-0.3-0.4-0.3c0-0.3,0.2-0.3,0.3-0.4c0.2-0.1,0.5-0.3,0.4-0.8c0-0.7-0.6-1.3-1.3-1.3
58+
c-0.6,0-1.4,0.6-1.4,1.7s1,1.9,2.4,1.8c0.8,0,2.5-0.3,4.2-2.5c2-2.5,2.5-5.4,2.9-7.4l0.5-2.8c0.3,0,0.5,0.1,0.8,0.1
59+
c2.4,0.1,3.7-1.3,3.7-2.3c0-0.6-0.3-1.2-0.9-1.2c-0.4,0-0.8,0.3-1,0.8c-0.1,0.6,0.8,1.1,0.1,1.5c-0.5,0.3-1.4,0.6-2.7,0.4l0.3-1.3
60+
c0.5-2.6,1-5.7,3.2-5.8c0.2,0,0.8,0,0.8,0.4c0,0.2,0,0.2-0.2,0.5c-0.2,0.3-0.3,0.4-0.2,0.7c0,0.7,0.5,1.1,1.2,1.1
61+
c0.9,0,1.2-1,1.2-1.4c0-1.2-1.2-1.8-2.6-1.8c-1.5,0.1-2.8,0.9-3.7,2.1c-1.1,1.3-1.8,2.9-2.3,4.5c-0.9-0.8-1.6-1.8-3.1-2.3
62+
c-1.1-0.7-2.3-0.5-3.4,0.3c-0.5,0.4-0.8,1-1,1.6c-0.4,1.5,0.4,2.9,0.8,3.4l0.9,1c0.2,0.2,0.6,0.8,0.4,1.5c-0.3,0.8-1.2,1.3-2.1,1
63+
c-0.4-0.2-1-0.5-0.9-0.9c0.1-0.2,0.2-0.3,0.3-0.5s0.1-0.3,0.1-0.3c0.2-0.6-0.1-1.4-0.7-1.6c-0.6-0.2-1.2,0-1.3,0.8
64+
C4.3,38.4,4.7,40,6.8,40.8z M46.1,20.9c0-4.2-3.2-7.5-7.1-7.5h-3.8C34.8,10.8,32.7,9,30.2,9L-2.3,9.1c-2.8,0.1-4.9,2.4-4.9,5.4
65+
L-7,58.6c0,4.8,8.1,13.9,11.6,14.1l34.7-0.1c3.9,0,7-3.4,7-7.6L46.1,20.9z M-0.3,36.4c0-8.6,6.5-15.6,14.5-15.6
66+
c8,0,14.5,7,14.5,15.6S22.1,52,14.2,52C6.1,52-0.3,45-0.3,36.4z M42.1,65.1c0,1.8-1.5,3.1-3.1,3.1H4.6c-0.7,0-3-1.8-4.5-4.4h30.4
67+
c2.8,0,5-2.4,5-5.4V17.9h3.7c1.6,0,2.9,1.4,2.9,3.1V65.1L42.1,65.1z"/>
68+
</svg>
69+
70+
Read the documentation to learn
71+
<a href="https://symfony.com/doc/<?php echo $docVersion; ?>/page_creation.html">
72+
How to create your first page in Symfony
73+
</a>
74+
</p>
75+
</div>
76+
</div>
77+
<div id="comment">
78+
<p>
79+
You're seeing this message because you have debug mode enabled and you haven't configured any URLs.
80+
</p>
81+
</div>
82+
</div>
83+
</body>
84+
</html>

src/Symfony/Component/HttpKernel/Tests/EventListener/RouterListenerTest.php

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
use Symfony\Component\HttpKernel\HttpKernelInterface;
2525
use Symfony\Component\HttpKernel\HttpKernel;
2626
use Symfony\Component\HttpKernel\Event\GetResponseEvent;
27+
use Symfony\Component\Routing\Exception\NoConfigurationException;
2728
use Symfony\Component\Routing\RequestContext;
2829

2930
class RouterListenerTest extends TestCase
@@ -185,4 +186,26 @@ public function testWithBadRequest()
185186
$response = $kernel->handle($request);
186187
$this->assertSame(400, $response->getStatusCode());
187188
}
189+
190+
public function testNoRoutingConfigurationResponse()
191+
{
192+
$requestStack = new RequestStack();
193+
194+
$requestMatcher = $this->getMockBuilder('Symfony\Component\Routing\Matcher\RequestMatcherInterface')->getMock();
195+
$requestMatcher
196+
->expects($this->once())
197+
->method('matchRequest')
198+
->willThrowException(new NoConfigurationException())
199+
;
200+
201+
$dispatcher = new EventDispatcher();
202+
$dispatcher->addSubscriber(new RouterListener($requestMatcher, $requestStack, new RequestContext()));
203+
204+
$kernel = new HttpKernel($dispatcher, new ControllerResolver(), $requestStack, new ArgumentResolver());
205+
206+
$request = Request::create('http://localhost/');
207+
$response = $kernel->handle($request);
208+
$this->assertSame(404, $response->getStatusCode());
209+
$this->assertContains('Welcome', $response->getContent());
210+
}
188211
}

src/Symfony/Component/HttpKernel/composer.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@
3333
"symfony/expression-language": "~2.8|~3.0|~4.0",
3434
"symfony/finder": "~2.8|~3.0|~4.0",
3535
"symfony/process": "~2.8|~3.0|~4.0",
36-
"symfony/routing": "~2.8|~3.0|~4.0",
36+
"symfony/routing": "~3.4|~4.0",
3737
"symfony/stopwatch": "~2.8|~3.0|~4.0",
3838
"symfony/templating": "~2.8|~3.0|~4.0",
3939
"symfony/translation": "~2.8|~3.0|~4.0",

src/Symfony/Component/Routing/CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ CHANGELOG
44
3.4.0
55
-----
66

7+
* Added `NoConfigurationException`.
78
* Added the possibility to define a prefix for all routes of a controller via @Route(name="prefix_")
89
* Added support for prioritized routing loaders.
910
* Add matched and default parameters to redirect responses
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
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\Component\Routing\Exception;
13+
14+
/**
15+
* Exception thrown when no routes are configured.
16+
*
17+
* @author Yonel Ceruto <yonelceruto@gmail.com>
18+
*/
19+
class NoConfigurationException extends ResourceNotFoundException
20+
{
21+
}

src/Symfony/Component/Routing/Matcher/Dumper/PhpMatcherDumper.php

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -155,6 +155,12 @@ private function compileRoutes(RouteCollection $routes, $supportsRedirections)
155155
}
156156
}
157157

158+
if ('' === $code) {
159+
$code .= " if ('/' === \$pathinfo) {\n";
160+
$code .= " throw new Symfony\Component\Routing\Exception\NoConfigurationException();\n";
161+
$code .= " }\n";
162+
}
163+
158164
return $code;
159165
}
160166

src/Symfony/Component/Routing/Matcher/RequestMatcherInterface.php

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
namespace Symfony\Component\Routing\Matcher;
1313

1414
use Symfony\Component\HttpFoundation\Request;
15+
use Symfony\Component\Routing\Exception\NoConfigurationException;
1516
use Symfony\Component\Routing\Exception\ResourceNotFoundException;
1617
use Symfony\Component\Routing\Exception\MethodNotAllowedException;
1718

@@ -32,6 +33,7 @@ interface RequestMatcherInterface
3233
*
3334
* @return array An array of parameters
3435
*
36+
* @throws NoConfigurationException If no routing configuration could be found
3537
* @throws ResourceNotFoundException If no matching resource could be found
3638
* @throws MethodNotAllowedException If a matching resource was found but the request method is not allowed
3739
*/

src/Symfony/Component/Routing/Matcher/UrlMatcher.php

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
namespace Symfony\Component\Routing\Matcher;
1313

1414
use Symfony\Component\Routing\Exception\MethodNotAllowedException;
15+
use Symfony\Component\Routing\Exception\NoConfigurationException;
1516
use Symfony\Component\Routing\Exception\ResourceNotFoundException;
1617
use Symfony\Component\Routing\RouteCollection;
1718
use Symfony\Component\Routing\RequestContext;
@@ -91,6 +92,10 @@ public function match($pathinfo)
9192
return $ret;
9293
}
9394

95+
if (0 === count($this->routes) && '/' === $pathinfo) {
96+
throw new NoConfigurationException();
97+
}
98+
9499
throw 0 < count($this->allow)
95100
? new MethodNotAllowedException(array_unique($this->allow))
96101
: new ResourceNotFoundException(sprintf('No routes found for "%s".', $pathinfo));
@@ -123,6 +128,7 @@ public function addExpressionLanguageProvider(ExpressionFunctionProviderInterfac
123128
*
124129
* @return array An array of parameters
125130
*
131+
* @throws NoConfigurationException If no routing configuration could be found
126132
* @throws ResourceNotFoundException If the resource could not be found
127133
* @throws MethodNotAllowedException If the resource was found but the request method is not allowed
128134
*/

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy