diff --git a/src/HtmlParser.php b/src/HtmlParser.php
index acd9e89..1c6ec76 100644
--- a/src/HtmlParser.php
+++ b/src/HtmlParser.php
@@ -6,6 +6,7 @@
use DOMDocument;
use DOMElement;
+use DOMXPath;
use Exception;
use LibXMLError;
@@ -14,6 +15,12 @@
*/
class HtmlParser {
+ private array $components;
+
+ public function __construct( array $components = [] ) {
+ $this->components = $components;
+ }
+
/**
* Parse the given HTML string into a DOM document.
*/
@@ -46,9 +53,24 @@ public function parseHtml( string $html ): DOMDocument {
//TODO Throw an exception
}
+ $this->substituteComponents( $document );
+
return $document;
}
+ private function substituteComponents( DOMDocument $document ) {
+ $xpath = new DOMXPath( $document );
+ foreach ( $this->components as $componentName => $template ) {
+ $entries = $xpath->query( '//' . $componentName );
+ foreach ( $entries as $entry ) {
+ $templateRoot = $this->getBodyElement( $this->parseHtml( $template ) )->firstChild;
+ $templateNode = $document->importNode( $templateRoot, true );
+ $entry->parentNode->append( $templateNode );
+ $entry->remove();
+ }
+ }
+ }
+
/**
* Get the root node of the template represented by the given document.
*/
diff --git a/src/Templating.php b/src/Templating.php
index a7d3deb..e64858e 100644
--- a/src/Templating.php
+++ b/src/Templating.php
@@ -4,6 +4,12 @@
class Templating {
+ private array $components;
+
+ public function __construct( array $componentTemplates = [] ) {
+ $this->components = $componentTemplates;
+ }
+
/**
* @param string $template
* @param array $data
@@ -12,7 +18,7 @@ class Templating {
* @return string
*/
public function render( $template, array $data, array $methods = [] ) {
- $htmlParser = new HtmlParser();
+ $htmlParser = new HtmlParser( $this->components );
$document = $htmlParser->parseHtml( $template );
$rootNode = $htmlParser->getRootNode( $document );
$component = new Component( $rootNode, $methods );
diff --git a/tests/integration/FixtureTest.php b/tests/integration/FixtureTest.php
index b61b6af..bb4d336 100644
--- a/tests/integration/FixtureTest.php
+++ b/tests/integration/FixtureTest.php
@@ -18,7 +18,8 @@ class FixtureTest extends TestCase {
* @dataProvider provideFixtures
*/
public function testPhpRenderingEqualsVueJsRendering( $template, array $data, $expectedResult ) {
- $templating = new Templating();
+ $components = $this->loadFixtureComponents();
+ $templating = new Templating( $components );
$methods = [
'message' => 'strval',
'directionality' => function () {
@@ -31,6 +32,31 @@ public function testPhpRenderingEqualsVueJsRendering( $template, array $data, $e
$this->assertEqualHtml( $expectedResult, $result );
}
+ public function loadFixtureComponents() {
+ $componentDir = __DIR__ . '/fixture/components';
+
+ $components = [];
+ /** @var DirectoryIterator $fileInfo */
+ foreach ( new DirectoryIterator( $componentDir ) as $fileInfo ) {
+ if ( $fileInfo->isDot() || $fileInfo->isDir() ) {
+ continue;
+ }
+
+ $document = new DOMDocument();
+ // Ignore all warnings issued by DOMDocument when parsing
+ // as soon as VueJs template is not actually a "valid" HTML
+ /** @noinspection UsageOfSilenceOperatorInspection */
+ // @codingStandardsIgnoreLine
+ @$document->loadHTMLFile( $fileInfo->getPathname() );
+
+ $componentName = $this->getAttribute( $document, 'template', 'component-name' );
+ $template = $this->getContents( $document, 'template' );
+
+ $components[$componentName] = $template;
+ }
+ return $components;
+ }
+
public function provideFixtures() {
$fixtureDir = __DIR__ . '/fixture';
@@ -38,7 +64,7 @@ public function provideFixtures() {
/** @var DirectoryIterator $fileInfo */
foreach ( new DirectoryIterator( $fixtureDir ) as $fileInfo ) {
- if ( $fileInfo->isDot() ) {
+ if ( $fileInfo->isDot() || $fileInfo->isDir() ) {
continue;
}
@@ -67,6 +93,10 @@ public function provideFixtures() {
return $cases;
}
+ private function getAttribute( DOMDocument $document, $elementId, $attributeId ) {
+ return $document->getElementById( $elementId )->getAttribute( $attributeId );
+ }
+
/**
* @param DOMDocument $document
* @param string $elementId
diff --git a/tests/integration/fixture/components/subcomponent.vue b/tests/integration/fixture/components/subcomponent.vue
new file mode 100644
index 0000000..a133632
--- /dev/null
+++ b/tests/integration/fixture/components/subcomponent.vue
@@ -0,0 +1,15 @@
+
+ Subcomponent! Surrounding HTML
Surrounding HTML
Subcomponent!