Skip to content

Commit 703601b

Browse files
committed
Wip on fixing no-layout issues
1 parent 10d3f53 commit 703601b

File tree

3 files changed

+100
-9
lines changed

3 files changed

+100
-9
lines changed

EventListener/LayoutsListener.php

Lines changed: 32 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,9 @@
1111

1212
namespace Orbitale\Bundle\CmsBundle\EventListener;
1313

14+
use Orbitale\Bundle\CmsBundle\Controller\CategoryController;
15+
use Orbitale\Bundle\CmsBundle\Controller\PageController;
16+
use Orbitale\Bundle\CmsBundle\Controller\PostsController;
1417
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
1518
use Symfony\Component\HttpKernel\Event\RequestEvent;
1619
use Symfony\Component\HttpKernel\KernelEvents;
@@ -82,21 +85,45 @@ public function setRequestLayout(RequestEvent $event): void
8285
$layouts = $this->layouts;
8386
do {
8487
$finalLayout = array_shift($layouts);
88+
if (!$finalLayout) {
89+
continue;
90+
}
8591
if ($finalLayout['host'] || $finalLayout['pattern']) {
8692
$finalLayout = null;
8793
}
8894
} while (null === $finalLayout && count($layouts));
8995
}
9096

91-
if (null === $finalLayout || !$this->twig->getLoader()->exists($finalLayout['resource'])) {
92-
$source = new Source('', $finalLayout['resource']);
97+
if (null === $finalLayout) {
98+
// Means that there is no fall-back to "default layout".
99+
100+
$controller = $request->attributes->get('_controller');
101+
102+
if (
103+
!is_a($controller, PageController::class, true)
104+
&& !is_a($controller, CategoryController::class, true)
105+
&& !is_a($controller, PostsController::class, true)
106+
) {
107+
// Don't do anything if there's no layout and the controller isn't supposed to use it.
108+
// If the user still wants to use a layout "outside" the built-in controllers,
109+
// they will have to add a layout config for it anyway.
110+
return;
111+
}
112+
113+
throw new \RuntimeException(sprintf(
114+
'Unable to find layout for url "%s://%s%s". Did you forget to add a layout configuration for this path?',
115+
$request->getScheme(), $host, $path
116+
));
117+
}
93118

94-
throw new LoaderError(sprintf(
119+
if (!$this->twig->getLoader()->exists($finalLayout['resource'])) {
120+
throw new \RuntimeException(sprintf(
95121
'Unable to find template %s for layout %s. The "layout" parameter must be a valid twig view to be used as a layout.',
96-
$finalLayout['resource'], $finalLayout['name']
97-
), 0, $source);
122+
$finalLayout['resource'] ?? '', $finalLayout['name'] ?? ''
123+
));
98124
}
99125

126+
100127
$event->getRequest()->attributes->set('_orbitale_cms_layout', $finalLayout);
101128
}
102129
}

Tests/EventListener/LayoutsListenerTest.php

Lines changed: 66 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,14 @@
1212
namespace Orbitale\Bundle\CmsBundle\Tests\EventListener;
1313

1414
use Doctrine\ORM\EntityManagerInterface;
15+
use Orbitale\Bundle\CmsBundle\Controller\CategoryController;
16+
use Orbitale\Bundle\CmsBundle\Controller\PageController;
17+
use Orbitale\Bundle\CmsBundle\Controller\PostsController;
18+
use Orbitale\Bundle\CmsBundle\EventListener\LayoutsListener;
1519
use Orbitale\Bundle\CmsBundle\Tests\AbstractTestCase;
1620
use Orbitale\Bundle\CmsBundle\Tests\Fixtures\TestBundle\Entity\Page;
21+
use Symfony\Component\HttpFoundation\Request;
22+
use Symfony\Component\HttpKernel\Event\RequestEvent;
1723
use Twig\Environment;
1824
use Twig\Error\LoaderError;
1925

@@ -44,11 +50,64 @@ public function testHostLayout(): void
4450

4551
public function testLayoutWrong(): void
4652
{
47-
$this->expectException(LoaderError::class);
48-
$this->expectExceptionMessage('Unable to find template this_layout_does_not_exist.html.twig for layout front. The "layout" parameter must be a valid twig view to be used as a layout in "this_layout_does_not_exist.html.twig".');
53+
$this->expectException(\RuntimeException::class);
54+
$this->expectExceptionMessage('Unable to find template this_layout_does_not_exist.html.twig for layout front. The "layout" parameter must be a valid twig view to be used as a layout.');
4955
static::createClient(['environment' => 'layout_wrong'])->request('GET', '/page/');
5056
}
5157

58+
public function testNoLayoutsDoesNotSetRequestAttribute()
59+
{
60+
$kernel = static::bootKernel();
61+
$request = Request::create('/');
62+
$listener = new LayoutsListener([], $this->getTwig());
63+
$listener->setRequestLayout(new RequestEvent($kernel, $request, $kernel::MASTER_REQUEST));
64+
static::assertFalse($request->attributes->has('_orbitale_cms_layout'));
65+
}
66+
67+
public function testNoMatchingLayoutDoesNotSetRequestAttribute()
68+
{
69+
$kernel = static::bootKernel();
70+
71+
$listener = new LayoutsListener([
72+
[
73+
'pattern' => '/noop',
74+
'host' => '',
75+
'resource' => '.',
76+
],
77+
], $this->getTwig());
78+
$request = Request::create('/');
79+
$listener->setRequestLayout(new RequestEvent($kernel, $request, $kernel::MASTER_REQUEST));
80+
81+
static::assertFalse($request->attributes->has('_orbitale_cms_layout'));
82+
}
83+
84+
/** @dataProvider provideBundleControllerClasses */
85+
public function testNoMatchingLayoutWithBundleControllerThrowsException(string $controller)
86+
{
87+
$kernel = static::bootKernel();
88+
89+
$listener = new LayoutsListener([
90+
[
91+
'pattern' => '/noop',
92+
'host' => '',
93+
'resource' => '.',
94+
],
95+
], $this->getTwig());
96+
$request = Request::create('/no-way');
97+
$request->attributes->set('_controller', $controller);
98+
99+
$this->expectException(\RuntimeException::class);
100+
$this->expectExceptionMessage('Unable to find layout for url "http://localhost/no-way". Did you forget to add a layout configuration for this path?');
101+
$listener->setRequestLayout(new RequestEvent($kernel, $request, $kernel::MASTER_REQUEST));
102+
}
103+
104+
public function provideBundleControllerClasses(): \Generator
105+
{
106+
yield [PageController::class];
107+
yield [CategoryController::class];
108+
yield [PostsController::class];
109+
}
110+
52111
/**
53112
* {@inheritdoc}
54113
*/
@@ -71,4 +130,9 @@ protected static function createClient(array $options = [], array $server = [])
71130

72131
return $client;
73132
}
133+
134+
private function getTwig(): Environment
135+
{
136+
return $this->createMock(Environment::class);
137+
}
74138
}

Tests/bootstrap.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -49,8 +49,8 @@
4949

5050
$application = new Application($kernel);
5151
$application->setAutoExit(false);
52-
$application->run(new ArrayInput(['command' => 'doctrine:database:create']));
53-
$application->run(new ArrayInput(['command' => 'doctrine:schema:create']));
52+
$application->run(new ArrayInput(['command' => 'doctrine:database:create']), new NullOutput());
53+
$application->run(new ArrayInput(['command' => 'doctrine:schema:create']), new NullOutput());
5454

5555
$kernel->shutdown();
5656
})();

0 commit comments

Comments
 (0)