Skip to content

Commit 12f32b4

Browse files
committed
feature: throw exception if header/footer and partials used at same time
closes #288
1 parent f6839a9 commit 12f32b4

File tree

5 files changed

+72
-3
lines changed

5 files changed

+72
-3
lines changed

src/Dispatch/Dispatcher.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -403,6 +403,7 @@ public function processResponse(
403403

404404
$componentList = $this->viewModelProcessor?->processPartialContent(
405405
$this->viewModel,
406+
$this->viewAssembly,
406407
);
407408

408409
// TODO: CSRF handling - needs to be done on any POST request.

src/Logic/HTMLDocumentProcessor.php

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
use GT\DomTemplate\PartialExpander;
99
use GT\Routing\Assembly;
1010
use GT\Routing\Path\DynamicPath;
11+
use GT\WebEngine\View\HeaderFooterPartialConflictException;
1112

1213
class HTMLDocumentProcessor extends ViewModelProcessor {
1314
function processDynamicPath(
@@ -30,7 +31,16 @@ function processDynamicPath(
3031

3132
function processPartialContent(
3233
HTMLDocument $model,
34+
?Assembly $viewAssembly = null,
3335
):LogicAssemblyComponentList {
36+
if($viewAssembly
37+
&& $this->containsPartialExtends($model)
38+
&& $this->containsHeaderOrFooterView($viewAssembly)) {
39+
throw new HeaderFooterPartialConflictException(
40+
"Header/footer view files cannot be combined with partial views."
41+
);
42+
}
43+
3444
$componentList = new LogicAssemblyComponentList();
3545

3646
try {
@@ -81,4 +91,54 @@ function processPartialContent(
8191

8292
return $componentList;
8393
}
94+
95+
private function containsHeaderOrFooterView(Assembly $viewAssembly):bool {
96+
foreach($viewAssembly as $viewFile) {
97+
$fileName = pathinfo($viewFile, PATHINFO_FILENAME);
98+
if($fileName === "_header" || $fileName === "_footer") {
99+
return true;
100+
}
101+
}
102+
103+
return false;
104+
}
105+
106+
private function containsPartialExtends(HTMLDocument $model):bool {
107+
return $this->containsPartialExtendsInNode($model->documentElement);
108+
}
109+
110+
/** @return ?array<string, array<string, string>|string> */
111+
private function parseCommentIni(string $data):?array {
112+
set_error_handler(
113+
static fn() => true
114+
);
115+
116+
try {
117+
$parsed = parse_ini_string($data, true);
118+
}
119+
finally {
120+
restore_error_handler();
121+
}
122+
123+
return is_array($parsed)
124+
? $parsed
125+
: null;
126+
}
127+
128+
private function containsPartialExtendsInNode(\DOMNode $node):bool {
129+
if($node->nodeType === XML_COMMENT_NODE) {
130+
$parsed = $this->parseCommentIni(trim($node->textContent));
131+
if(isset($parsed["extends"])) {
132+
return true;
133+
}
134+
}
135+
136+
foreach($node->childNodes as $childNode) {
137+
if($this->containsPartialExtendsInNode($childNode)) {
138+
return true;
139+
}
140+
}
141+
142+
return false;
143+
}
84144
}

src/Logic/ViewModelProcessor.php

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
<?php
22
namespace GT\WebEngine\Logic;
33

4-
use Generator;
54
use GT\Dom\HTMLDocument;
5+
use GT\Routing\Assembly;
66
use GT\Routing\Path\DynamicPath;
77

88
abstract class ViewModelProcessor {
@@ -18,5 +18,6 @@ abstract function processDynamicPath(
1818

1919
abstract function processPartialContent(
2020
HTMLDocument $model,
21+
?Assembly $viewAssembly = null,
2122
):LogicAssemblyComponentList;
2223
}
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
<?php
2+
namespace GT\WebEngine\View;
3+
4+
use GT\WebEngine\WebEngineException;
5+
6+
class HeaderFooterPartialConflictException extends WebEngineException {}

test/phpunit/DefaultRouterTest.php

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
use GT\Routing\RouterConfig;
1414
use GT\WebEngine\DefaultRouter;
1515
use Gt\ServiceContainer\Container;
16+
use GT\WebEngine\View\HeaderFooterPartialConflictException;
1617
use GT\WebEngine\View\HTMLView;
1718
use PHPUnit\Framework\TestCase;
1819

@@ -109,11 +110,11 @@ class_exists(PartialExpander::class);
109110
$viewModel = $view->createViewModel();
110111

111112
$processor = new HTMLDocumentProcessor("components", "page/_partial");
112-
$this->expectException(\LogicException::class);
113+
$this->expectException(HeaderFooterPartialConflictException::class);
113114
$this->expectExceptionMessage(
114115
"Header/footer view files cannot be combined with partial views."
115116
);
116-
$processor->processPartialContent($viewModel);
117+
$processor->processPartialContent($viewModel, $sut->getViewAssembly());
117118
}
118119

119120
private function removeDirectory(string $dir):void {

0 commit comments

Comments
 (0)