Skip to content

Commit 914957d

Browse files
author
Pia Sinzig
committed
Merge branch 'master' of https://github.com/Paneon/php-vue-to-twig into feature/SHODVES2-122
# Conflicts: # src/Compiler.php
2 parents 9088bf7 + 3c24d23 commit 914957d

File tree

7 files changed

+265
-45
lines changed

7 files changed

+265
-45
lines changed

src/Compiler.php

Lines changed: 97 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
use DOMText;
1010
use Exception;
1111
use Paneon\VueToTwig\Models\Replacements;
12+
use Paneon\VueToTwig\Utils\TwigBuilder;
1213
use Psr\Log\LoggerInterface;
1314

1415
class Compiler
@@ -26,16 +27,37 @@ class Compiler
2627
/** @var LoggerInterface */
2728
protected $logger;
2829

30+
/** @var string[] */
31+
protected $banner;
32+
/**
33+
* @var TwigBuilder
34+
*/
35+
protected $builder;
36+
2937
public function __construct(DOMDocument $document, LoggerInterface $logger)
3038
{
31-
$this->logger = $logger;
39+
$this->builder = new TwigBuilder();
3240
$this->document = $document;
41+
$this->logger = $logger;
3342
$this->lastCloseIf = null;
3443
$this->components = [];
44+
$this->banner = [];
3545

3646
$this->logger->debug("\n--------- New Compiler Instance ----------\n");
3747
}
3848

49+
/**
50+
* @param string|string[] $strings
51+
*/
52+
public function setBanner($strings): void
53+
{
54+
if (!is_array($strings)) {
55+
$strings = [$strings];
56+
}
57+
58+
$this->banner = $strings;
59+
}
60+
3961
/**
4062
* @throws Exception
4163
*/
@@ -53,22 +75,30 @@ public function convert(): string
5375

5476
$html = $this->replacePlaceholders($html);
5577

78+
if (!empty($this->banner)) {
79+
$html = $this->addBanner($html);
80+
}
81+
5682
return $html;
5783
}
5884

5985
public function convertNode(DOMNode $node): DOMNode
6086
{
61-
if ($node->nodeType === XML_TEXT_NODE) {
62-
return $node;
63-
}
64-
65-
if ($node->nodeType === XML_ELEMENT_NODE) {
66-
//echo "\nElement node found";
67-
/** @var DOMElement $node */
68-
$this->replaceShowWithIf($node);
69-
$this->handleIf($node);
70-
} elseif ($node->nodeType === XML_HTML_DOCUMENT_NODE) {
71-
$this->logger->warning("Document node found.");
87+
switch ($node->nodeType) {
88+
case XML_TEXT_NODE:
89+
$this->logger->debug('Text node found', ['name' => $node->nodeName]);
90+
// fall through to next case, because we don't need to handle either of these node-types
91+
case XML_COMMENT_NODE:
92+
$this->logger->debug('Comment node found', ['name' => $node->nodeName]);
93+
return $node;
94+
case XML_ELEMENT_NODE:
95+
/** @var DOMElement $node */
96+
$this->replaceShowWithIf($node);
97+
$this->handleIf($node);
98+
break;
99+
case XML_HTML_DOCUMENT_NODE:
100+
$this->logger->warning("Document node found.");
101+
break;
72102
}
73103

74104
if (in_array($node->nodeName, array_keys($this->components))) {
@@ -158,8 +188,8 @@ private function handleAttributeBinding(DOMElement $node)
158188
$this->logger->debug('- setAttribute "'.$name.'" with value');
159189
$node->setAttribute(
160190
$name,
161-
Replacements::getSanitizedConstant('DOUBLE_CURLY_OPEN') .
162-
$value .
191+
Replacements::getSanitizedConstant('DOUBLE_CURLY_OPEN').
192+
$value.
163193
Replacements::getSanitizedConstant('DOUBLE_CURLY_CLOSE')
164194
);
165195
}
@@ -184,6 +214,21 @@ private function handleAttributeBinding(DOMElement $node)
184214
}
185215
$node->setAttribute($name, implode(' ', $classes));
186216
}
217+
} /*
218+
* <div :class="`abc ${someDynamicClass}`">
219+
*/
220+
elseif (preg_match('/^`(?P<content>.+)`$/', $value, $matches)) {
221+
$templateStringContent = $matches['content'];
222+
223+
$templateStringContent = preg_replace(
224+
'/\$\{(.+)\}/',
225+
'{{ $1 }}',
226+
$templateStringContent
227+
);
228+
229+
$node->setAttribute($name, $templateStringContent);
230+
} else {
231+
$this->logger->warning('- No Handling for: '.$value);
187232
}
188233

189234
$this->logger->debug('=> remove original '.$attribute->name);
@@ -204,11 +249,11 @@ private function handleIf(DOMElement $node): void
204249
$condition = $this->sanitizeCondition($condition);
205250

206251
// Open with if
207-
$openIf = $this->document->createTextNode('{% if '.$condition.' %}');
252+
$openIf = $this->document->createTextNode($this->builder->createIf($condition));
208253
$node->parentNode->insertBefore($openIf, $node);
209254

210255
// Close with endif
211-
$closeIf = $this->document->createTextNode('{% endif %}');
256+
$closeIf = $this->document->createTextNode($this->builder->createEndIf());
212257
$node->parentNode->insertBefore($closeIf, $node->nextSibling);
213258

214259
$this->lastCloseIf = $closeIf;
@@ -219,20 +264,20 @@ private function handleIf(DOMElement $node): void
219264
$condition = $this->sanitizeCondition($condition);
220265

221266
// Replace old endif with else
222-
$this->lastCloseIf->textContent = '{% elseif '.$condition.' %}';
267+
$this->lastCloseIf->textContent = $this->builder->createElseIf($condition);
223268

224269
// Close with new endif
225-
$closeIf = $this->document->createTextNode('{% endif %}');
270+
$closeIf = $this->document->createTextNode($this->builder->createEndIf());
226271
$node->parentNode->insertBefore($closeIf, $node->nextSibling);
227272
$this->lastCloseIf = $closeIf;
228273

229274
$node->removeAttribute('v-else-if');
230275
} elseif ($node->hasAttribute('v-else')) {
231276
// Replace old endif with else
232-
$this->lastCloseIf->textContent = '{% else %}';
277+
$this->lastCloseIf->textContent = $this->builder->createElse();
233278

234279
// Close with new endif
235-
$closeIf = $this->document->createTextNode('{% endif %}');
280+
$closeIf = $this->document->createTextNode($this->builder->createEndIf());
236281
$node->parentNode->insertBefore($closeIf, $node->nextSibling);
237282
$this->lastCloseIf = $closeIf;
238283

@@ -263,7 +308,7 @@ private function handleFor(DOMElement $node)
263308
}
264309

265310
// (1)
266-
$forCommand = '{% for '.$forLeft.' in '.$listName.' %}';
311+
$forCommand = $this->builder->createForItemInList($forLeft, $listName);
267312

268313
if (strpos($forLeft, ',')) {
269314
$forLeft = str_replace('(', '', $forLeft);
@@ -276,19 +321,19 @@ private function handleFor(DOMElement $node)
276321
$forIndex = $forLeftArray[2] ?? null;
277322

278323
// (3)
279-
$forCommand = '{% for '.$forKey.', '.$forValue.' in '.$listName.' %}';
324+
$forCommand = $this->builder->createFor($listName, $forValue, $forKey);
280325

281326
if ($forIndex) {
282327
// (4)
283-
$forCommand .= ' {% set '.$forIndex.' = loop.index0 %}';
328+
$forCommand .= $this->builder->createVariable($forIndex, 'loop.index0');
284329
}
285330
}
286331

287332
$startFor = $this->document->createTextNode($forCommand);
288333
$node->parentNode->insertBefore($startFor, $node);
289334

290335
// End For
291-
$endFor = $this->document->createTextNode('{% endfor %}');
336+
$endFor = $this->document->createTextNode($this->builder->createEndFor());
292337
$node->parentNode->insertBefore($endFor, $node->nextSibling);
293338

294339
$node->removeAttribute('v-for');
@@ -315,10 +360,11 @@ private function getRootNode(DOMElement $element): \DOMNode
315360
$tagNodes = 0;
316361
$firstTagNode = null;
317362

363+
/** @var DOMNode $node */
318364
foreach ($nodes as $node) {
319365
if ($node->nodeType === XML_TEXT_NODE) {
320366
continue;
321-
} else if ($node->nodeName === 'script' || $node->nodeName === 'style') {
367+
} elseif (in_array($node->nodeName, ['script', 'style'])) {
322368
continue;
323369
} else {
324370
$tagNodes++;
@@ -338,7 +384,7 @@ protected function sanitizeCondition(string $condition)
338384
$condition = str_replace('&&', 'and', $condition);
339385
$condition = str_replace('||', 'or', $condition);
340386

341-
foreach(Replacements::getConstants() as $constant => $value) {
387+
foreach (Replacements::getConstants() as $constant => $value) {
342388
$condition = str_replace($value, Replacements::getSanitizedConstant($constant), $condition);
343389
}
344390

@@ -347,7 +393,7 @@ protected function sanitizeCondition(string $condition)
347393

348394
protected function replacePlaceholders(string $string)
349395
{
350-
foreach(Replacements::getConstants() as $constant => $value) {
396+
foreach (Replacements::getConstants() as $constant => $value) {
351397
$string = str_replace(Replacements::getSanitizedConstant($constant), $value, $string);
352398
}
353399

@@ -358,4 +404,28 @@ public function registerComponent(string $componentName, string $componentPath)
358404
{
359405
$this->components[strtolower($componentName)] = new Component($componentName, $componentPath);
360406
}
407+
408+
protected function addSingleLineBanner(string $html)
409+
{
410+
return $this->builder->createComment(implode('', $this->banner))."\n".$html;
411+
}
412+
413+
protected function addBanner(string $html)
414+
{
415+
if (count($this->banner) === 1) {
416+
return $this->addSingleLineBanner($html);
417+
}
418+
419+
$bannerLines = ['{#'];
420+
421+
foreach ($this->banner as $line) {
422+
$bannerLines[] = ' # '.$line;
423+
}
424+
425+
$bannerLines[] = ' #}';
426+
427+
$html = implode("\n", $bannerLines)."\n".$html;
428+
429+
return $html;
430+
}
361431
}

src/Utils/TwigBuilder.php

Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
<?php
2+
3+
namespace Paneon\VueToTwig\Utils;
4+
5+
class TwigBuilder
6+
{
7+
protected const OPEN = 0;
8+
protected const CLOSE = 1;
9+
10+
protected $options;
11+
12+
public function __construct(array $options = [])
13+
{
14+
$this->options = array_merge([
15+
'tag_comment' => ['{#', '#}'],
16+
'tag_block' => ['{%', '%}'],
17+
'tag_variable' => ['{{', '}}'],
18+
'whitespace_trim' => '-',
19+
'interpolation' => ['#{', '}'],
20+
], $options);
21+
}
22+
23+
public function createVariable($name, $assignment)
24+
{
25+
return $this->createBlock('set '.$name.' = '.$assignment);
26+
}
27+
28+
public function createIf(string $condition)
29+
{
30+
return $this->createBlock('if '.$condition);
31+
}
32+
33+
public function createElseIf(string $condition)
34+
{
35+
return $this->createBlock('elseif '.$condition);
36+
}
37+
38+
public function createElse()
39+
{
40+
return $this->createBlock('else');
41+
}
42+
43+
public function createEndIf()
44+
{
45+
return $this->createBlock('endif');
46+
}
47+
48+
public function createForItemInList(string $item, string $list)
49+
{
50+
return $this->createBlock('for '.$item.' in '.$list);
51+
}
52+
53+
public function createForKeyInList(string $key, string $list)
54+
{
55+
return $this->createBlock('for '.$key.' in '.$list);
56+
}
57+
58+
public function createFor(string $list, ?string $item = null, ?string $key = null)
59+
{
60+
if($item !== null && $key !== null) {
61+
return $this->createBlock( 'for '.$key.', '.$item.' in '.$list);
62+
}
63+
elseif($item !== null) {
64+
return $this->createForItemInList($item, $list);
65+
}
66+
elseif($key !== null) {
67+
return $this->createForKeyInList($key, $list);
68+
}
69+
70+
return null;
71+
}
72+
73+
public function createEndFor()
74+
{
75+
return $this->createBlock('endfor');
76+
}
77+
78+
public function createComment(string $comment)
79+
{
80+
return $this->options['tag_comment'][self::OPEN].' '.$comment.' '.$this->options['tag_comment'][self::CLOSE];
81+
}
82+
83+
public function createMultilineComment(array $comments)
84+
{
85+
return $this->options['tag_comment'][self::OPEN].' '.$comments.' '.$this->options['tag_comment'][self::CLOSE];
86+
}
87+
88+
public function createBlock($content)
89+
{
90+
return $this->options['tag_block'][self::OPEN].' '.$content.' '.$this->options['tag_block'][self::CLOSE];
91+
}
92+
}

0 commit comments

Comments
 (0)