Skip to content

Commit 9a7fc9a

Browse files
committed
Removed processData(), processFile() and getComponentFileContent() methods.
Added the ability to create and process components directly in the process() method.
1 parent 34c55a3 commit 9a7fc9a

File tree

3 files changed

+120
-139
lines changed

3 files changed

+120
-139
lines changed

src/HTMLServerComponent.php

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -135,4 +135,19 @@ public function __unset($name)
135135
$this->removeAttribute($name);
136136
}
137137

138+
/**
139+
* Returns a HTML representation of the component
140+
*/
141+
public function __toString()
142+
{
143+
$html = '<component';
144+
foreach ($this->attributes as $name => $value) {
145+
$html .= ' ' . $name . '="' . htmlspecialchars($value) . '"';
146+
}
147+
$html .= '>';
148+
$html .= $this->innerHTML;
149+
$html .= '</component>';
150+
return $html;
151+
}
152+
138153
}

src/HTMLServerComponentsCompiler.php

Lines changed: 79 additions & 137 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ class HTMLServerComponentsCompiler
1818
/**
1919
* Library version
2020
*/
21-
const VERSION = '0.4.3';
21+
const VERSION = '0.5.0';
2222

2323
/**
2424
* Stores the added aliases
@@ -49,136 +49,110 @@ public function addAlias($alias, $original)
4949
/**
5050
* Converts components code (if any) into HTML code
5151
*
52-
* @param string $content The content to be processed
52+
* @param string|\IvoPetkov\HTMLServerComponent $content The content to be processed
5353
* @param array $options Compiler options
5454
* @throws \InvalidArgumentException
5555
* @return string The result HTML code
5656
*/
5757
public function process($content, $options = [])
5858
{
59-
if (!is_string($content)) {
59+
if (!is_string($content) && !($content instanceof \IvoPetkov\HTMLServerComponent)) {
6060
throw new \InvalidArgumentException('');
6161
}
6262
if (!is_array($options)) {
6363
throw new \InvalidArgumentException('');
6464
}
65+
if (is_string($content) && strpos($content, '<component') === false) {
66+
return $content;
67+
}
6568
if (isset($options['_internal_process_components']) && $options['_internal_process_components'] === false) {
6669
return $content;
6770
}
68-
$domDocument = new \IvoPetkov\HTML5DOMDocument();
69-
$domDocument->loadHTML($content);
70-
$componentElements = $domDocument->getElementsByTagName('component');
71-
$componentElementsCount = $componentElements->length;
72-
if ($componentElementsCount > 0) {
73-
for ($i = 0; $i < $componentElementsCount; $i++) {
74-
$component = $componentElements->item(0);
75-
$attributes = $component->getAttributes();
76-
if (isset($attributes['src'])) {
77-
$srcAttributeValue = $attributes['src'];
78-
if (isset($this->aliases[$srcAttributeValue])) {
79-
$sourceParts = explode(':', $this->aliases[$srcAttributeValue], 2);
80-
} else {
81-
$sourceParts = explode(':', $srcAttributeValue, 2);
71+
72+
$getComponentFileContent = function($file, $component, $variables) {
73+
if (is_file($file)) {
74+
$__componentFile = $file;
75+
unset($file);
76+
if (!empty($variables)) {
77+
extract($variables, EXTR_SKIP);
78+
}
79+
unset($variables);
80+
ob_start();
81+
include $__componentFile;
82+
$content = ob_get_clean();
83+
return $content;
84+
} else {
85+
throw new \Exception('Component file cannot be found (' . $file . ')');
86+
}
87+
};
88+
89+
$getComponentResultHTML = function($component) use (&$getComponentFileContent, $options) {
90+
if (isset($component->attributes['src'])) {
91+
// todo check alias of alias
92+
$srcAttributeValue = $component->attributes['src'];
93+
if (isset($this->aliases[$srcAttributeValue])) {
94+
$sourceParts = explode(':', $this->aliases[$srcAttributeValue], 2);
95+
} else {
96+
$sourceParts = explode(':', $srcAttributeValue, 2);
97+
}
98+
if (sizeof($sourceParts) === 2) {
99+
$scheme = $sourceParts[0];
100+
if (isset($options['recursive']) && $options['recursive'] === false) {
101+
$componentOptions = array_merge($options, ['_internal_process_components' => false]);
82102
}
83-
if (sizeof($sourceParts) === 2) {
84-
$scheme = $sourceParts[0];
85-
if (isset($options['recursive']) && $options['recursive'] === false && ($scheme === 'data' || $scheme === 'file')) {
86-
$componentOptions = array_values($options);
87-
$componentOptions['_internal_process_components'] = false;
103+
if ($scheme === 'data') {
104+
if (substr($sourceParts[1], 0, 7) === 'base64,') {
105+
return $this->process(base64_decode(substr($sourceParts[1], 7)), isset($componentOptions) ? $componentOptions : $options);
88106
}
89-
if ($scheme === 'data') {
90-
$componentHTML = $this->processData($sourceParts[1], isset($componentOptions) ? $componentOptions : $options);
91-
} elseif ($scheme === 'file') {
92-
$componentHTML = $this->processFile(urldecode($sourceParts[1]), $attributes, $component->innerHTML, [], isset($componentOptions) ? $componentOptions : $options);
93-
} else {
94-
throw new \Exception('URI scheme not valid!' . $domDocument->saveHTML($component));
95-
}
96-
} else {
97-
throw new \Exception('URI scheme not found!' . $domDocument->saveHTML($component));
107+
throw new \Exception('Data URI scheme only supports base64!' . (string) $component);
108+
} elseif ($scheme === 'file') {
109+
return $this->process($getComponentFileContent(urldecode($sourceParts[1]), $component, isset($options['variables']) && is_array($options['variables']) ? $options['variables'] : []), isset($componentOptions) ? $componentOptions : $options);
98110
}
99-
} else {
100-
throw new \Exception('Component src attribute missing! ' . $domDocument->saveHTML($component));
111+
throw new \Exception('URI scheme not valid!' . (string) $component);
101112
}
113+
throw new \Exception('URI scheme not found!' . (string) $component);
114+
}
115+
throw new \Exception('Component src attribute missing! ' . (string) $component);
116+
};
102117

103-
$isInBodyTag = false;
104-
$parentNode = $component->parentNode;
105-
while ($parentNode !== null && isset($parentNode->tagName)) {
106-
if ($parentNode->tagName === 'body') {
107-
$isInBodyTag = true;
108-
break;
118+
$domDocument = new \IvoPetkov\HTML5DOMDocument();
119+
if ($content instanceof \IvoPetkov\HTMLServerComponent) {
120+
$domDocument->loadHTML($getComponentResultHTML($content));
121+
} else {
122+
$domDocument->loadHTML($content);
123+
$componentElements = $domDocument->getElementsByTagName('component');
124+
$componentElementsCount = $componentElements->length;
125+
if ($componentElementsCount > 0) {
126+
for ($i = 0; $i < $componentElementsCount; $i++) {
127+
$componentElement = $componentElements->item(0);
128+
$component = $this->constructComponent($componentElement->getAttributes(), $componentElement->innerHTML);
129+
$componentResultHTML = $getComponentResultHTML($component);
130+
131+
$isInBodyTag = false;
132+
$parentNode = $componentElement->parentNode;
133+
while ($parentNode !== null && isset($parentNode->tagName)) {
134+
if ($parentNode->tagName === 'body') {
135+
$isInBodyTag = true;
136+
break;
137+
}
138+
$parentNode = $parentNode->parentNode;
139+
}
140+
if ($isInBodyTag) {
141+
$insertTargetName = 'html-server-components-compiler-target-' . uniqid();
142+
$componentElement->parentNode->insertBefore($domDocument->createInsertTarget($insertTargetName), $componentElement);
143+
$domDocument->insertHTML($componentResultHTML, $insertTargetName);
144+
} else {
145+
$domDocument->insertHTML($componentResultHTML);
109146
}
110-
$parentNode = $parentNode->parentNode;
111-
}
112-
if ($isInBodyTag) {
113-
$insertTargetName = 'html-server-components-compiler-target-' . uniqid();
114-
$component->parentNode->insertBefore($domDocument->createInsertTarget($insertTargetName), $component);
115-
$domDocument->insertHTML($componentHTML, $insertTargetName);
116-
} else {
117-
$domDocument->insertHTML($componentHTML);
118-
}
119147

120-
$component->parentNode->removeChild($component);
148+
$componentElement->parentNode->removeChild($componentElement);
149+
}
121150
}
122151
}
123152

124153
return $domDocument->saveHTML();
125154
}
126155

127-
/**
128-
* Creates a component from the data specified and processes the content
129-
*
130-
* @param string $data The data to be used as component content. Currently only base64 encoded data is allowed.
131-
* @param array $options Compiler options
132-
* @return string The result HTML code
133-
* @throws \InvalidArgumentException
134-
*/
135-
public function processData($data, $options = [])
136-
{
137-
if (!is_string($data)) {
138-
throw new \InvalidArgumentException('');
139-
}
140-
if (!is_array($options)) {
141-
throw new \InvalidArgumentException('');
142-
}
143-
$content = $data;
144-
if (substr($data, 0, 7) === 'base64,') {
145-
$content = base64_decode(substr($data, 7));
146-
}
147-
return $this->process($content, $options);
148-
}
149-
150-
/**
151-
* Creates a component from the file specified and processes the content
152-
*
153-
* @param string $file The file to be run as component
154-
* @param array $attributes Component object attributes
155-
* @param string $innerHTML Component object innerHTML
156-
* @param array $variables List of variables that will be passes to the file. They will be available in the file scope.
157-
* @param array $options Compiler options
158-
* @return string The result HTML code
159-
* @throws \InvalidArgumentException
160-
*/
161-
public function processFile($file, $attributes = [], $innerHTML = '', $variables = [], $options = [])
162-
{
163-
if (!is_string($file)) {
164-
throw new \InvalidArgumentException('');
165-
}
166-
if (!is_array($attributes)) {
167-
throw new \InvalidArgumentException('');
168-
}
169-
if (!is_string($innerHTML)) {
170-
throw new \InvalidArgumentException('');
171-
}
172-
if (!is_array($variables)) {
173-
throw new \InvalidArgumentException('');
174-
}
175-
if (!is_array($options)) {
176-
throw new \InvalidArgumentException('');
177-
}
178-
$component = $this->constructComponent($attributes, $innerHTML);
179-
return $this->process($this->getComponentFileContent($file, array_merge($variables, ['component' => $component])), $options);
180-
}
181-
182156
/**
183157
* Constructs a component object
184158
*
@@ -187,7 +161,7 @@ public function processFile($file, $attributes = [], $innerHTML = '', $variables
187161
* @return \IvoPetkov\HTMLServerComponent A component object
188162
* @throws \InvalidArgumentException
189163
*/
190-
protected function constructComponent($attributes = [], $innerHTML = '')
164+
public function constructComponent($attributes = [], $innerHTML = '')
191165
{
192166
if (!is_array($attributes)) {
193167
throw new \InvalidArgumentException('');
@@ -201,36 +175,4 @@ protected function constructComponent($attributes = [], $innerHTML = '')
201175
return $component;
202176
}
203177

204-
/**
205-
* Includes a component file and returns its content
206-
*
207-
* @param string $file The filename
208-
* @param array $variables List of variables that will be passes to the file. They will be available in the file scope.
209-
* @return string The content of the file
210-
* @throws \InvalidArgumentException
211-
* @throws \Exception
212-
*/
213-
protected function getComponentFileContent($file, $variables)
214-
{
215-
if (!is_string($file)) {
216-
throw new \InvalidArgumentException('');
217-
}
218-
if (!is_array($variables)) {
219-
throw new \InvalidArgumentException('');
220-
}
221-
if (is_file($file)) {
222-
$__componentFile = $file;
223-
unset($file);
224-
if (!empty($variables)) {
225-
extract($variables, EXTR_SKIP);
226-
}
227-
ob_start();
228-
include $__componentFile;
229-
$content = ob_get_clean();
230-
return $content;
231-
} else {
232-
throw new \Exception('Component file cannot be found (' . $file . ')');
233-
}
234-
}
235-
236178
}

tests/Test.php

Lines changed: 26 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,20 @@ public function testAlias()
5858
$this->assertTrue($result === $expectedResult);
5959
}
6060

61+
/**
62+
*
63+
*/
64+
public function testCreateComponent()
65+
{
66+
$fullFilename = $this->createFile('component1.php', '<html><body>text1</body></html>');
67+
68+
$compiler = new \IvoPetkov\HTMLServerComponentsCompiler();
69+
$component = $compiler->constructComponent(['var1' => '1'], 'hi');
70+
71+
$expectedResult = '<component var1="1">hi</component>';
72+
$this->assertTrue((string) $component === $expectedResult);
73+
}
74+
6175
/**
6276
*
6377
*/
@@ -66,7 +80,14 @@ public function testVariables()
6680
$fullFilename = $this->createFile('component1.php', '<html><body><?= $component->test1?><?= $test2?></body></html>');
6781

6882
$compiler = new \IvoPetkov\HTMLServerComponentsCompiler();
69-
$result = $compiler->processFile($fullFilename, ['test1' => '1'], '', ['test2' => 2]);
83+
$component = new \IvoPetkov\HTMLServerComponent();
84+
$component->src = 'file:' . $fullFilename;
85+
$component->test1 = '1';
86+
$result = $compiler->process($component, [
87+
'variables' => [
88+
'test2' => 2
89+
]
90+
]);
7091
$expectedResult = '<!DOCTYPE html><html><body>12</body></html>';
7192
$this->assertTrue($result === $expectedResult);
7293
}
@@ -118,7 +139,10 @@ public function testComponentAttribute()
118139
. '?></body></html>');
119140

120141
$compiler = new \IvoPetkov\HTMLServerComponentsCompiler();
121-
$result = $compiler->processFile($fullFilename, ['test1' => '1']);
142+
$component = new \IvoPetkov\HTMLServerComponent();
143+
$component->src = 'file:' . $fullFilename;
144+
$component->test1 = '1';
145+
$result = $compiler->process($component);
122146
$expectedResult = '<!DOCTYPE html><html><body>1210</body></html>';
123147
$this->assertTrue($result === $expectedResult);
124148
}

0 commit comments

Comments
 (0)