@ -29,6 +29,11 @@ class View
private string $componentPrefix;
private string $componentPrefix;
private string $componentsPath;
private string $componentsPath;
private int $fetchDepth = 0;
/** @var array< string , bool > */
private array $styles = [];
/** @var array< string , bool > */
private array $scripts = [];
/**
/**
* @param string $path Path to templates directory
* @param string $path Path to templates directory
@ -119,110 +124,118 @@ class View
*/
*/
public function fetch(string $file, ?array $data = null): string
public function fetch(string $file, ?array $data = null): string
{
{
$template = $this->getTemplate($file);
if ($this->fetchDepth === 0) {
$this->styles = [];
if (!$this->exists($file)) {
$this->scripts = [];
throw new Exception("Template file not found: $template.");
}
}
extract($this->vars) ;
$this->fetchDepth++ ;
if (is_array($data)) {
try {
extract($data );
$template = $this->getTemplate($file );
if ($this->preserveVars ) {
if (!$this->exists($file) ) {
$this->vars += $data ;
throw new Exception("Template file not found: $template.") ;
}
}
}
ob_start();
$component = include $template;
switch (true) {
case is_callable($component):
$view = $component();
ob_end_clean();
break;
case $component instanceof Component:
$view = $component->html();
$css = $component->css();
$js = $component->js();
static $styles = [];
extract($this->vars);
static $scripts = [];
if ($css & & !array_key_exists($template, $styles)) {
if (is_array($data)) {
$view .= < < < html
extract($data);
< style >
$css
< / style >
html;
$styles[$template] = true;
if ($this->preserveVars) {
$this->vars += $data;
}
}
}
if ($js & & !array_key_exists($template, $scripts)) {
ob_start();
$view .= < < < html
$component = include $template;
< script >
$js
switch (true) {
< / script >
case is_callable($component):
html;
$view = $component();
ob_end_clean();
$scripts[$template] = true;
}
break;
case $component instanceof Component:
$view = $component->html();
$css = $component->css();
$js = $component->js();
if ($css & & !array_key_exists($template, $this->styles)) {
$view .= < < < html
< style >
$css
< / style >
html;
$this->styles[$template] = true;
}
if ($js & & !array_key_exists($template, $this->scripts)) {
$view .= < < < html
< script >
$js
< / script >
html;
$this->scripts[$template] = true;
}
ob_end_clean();
break;
default:
$view = ob_get_clean();
}
ob_end_clean();
preg_match_all(
"/< $this->componentPrefix-(?< component > [a-z-]+)\s*(?< props > ([a-z]+=\"[^\"]+\"\s*)*)?\s*\/>/",
$view,
$tagsMatches,
);
break;
$tagsMatches = array_filter($tagsMatches);
default:
$view = ob_get_clean();
}
preg_match_all(
foreach ($tagsMatches[0] ?? [] as $tagIndex => $match) {
"/< $this->componentPrefix-(?< component > [a-z-]+)\s*(?< props > ([a-z]+=\"[^\"]+\"\s*)*)?\s*\/>/",
$tag = $match;
$view,
$component = $tagsMatches['component'][$tagIndex];
$tagsMatches,
$props = $tagsMatches['props'][$tagIndex] ?? '';
);
$tagsMatches = array_filter($tagsMatches);
preg_match_all(
'/(?< name > [a-z]+)="(?< value > [^"]+)"/',
$props,
$propsMatches,
);
foreach ($tagsMatches[0] ?? [] as $tagIndex => $match) {
$propsMatches = array_filter($propsMatches);
$tag = $match;
$component = $tagsMatches['component'][$tagIndex];
$props = $tagsMatches['props'][$tagIndex] ?? '';
preg_match_all(
if ($propsMatches) {
'/(?< name > [a-z]+)="(?< value > [^"]+)"/',
$props = [];
$props,
$propsMatches,
);
$propsMatches = array_filter($propsMatches);
foreach (array_keys($propsMatches[0]) as $propIndex) {
$name = $propsMatches['name'][$propIndex];
$value = $propsMatches['value'][$propIndex];
$props[$name] = $value;
}
} else {
$props = [];
}
if ($propsMatches) {
$component = $this->fetch("$this->componentsPath/$component", $props);
$props = [];
$tagPosition = strpos($view, $tag) ;
foreach (array_keys($propsMatches[0]) as $propIndex) {
if ($tagPosition === false) {
$name = $propsMatches['name'][$propIndex];
continue;
$value = $propsMatches['value'][$propIndex];
$props[$name] = $value;
}
}
} else {
$props = [];
}
$component = $this->fetch("$this->componentsPath/$component", $props);
$view = substr_replace($view, $component, $tagPosition, strlen($tag));
$tagPosition = strpos($view, $tag);
if ($tagPosition === false) {
continue;
}
}
$view = substr_replace($view, $component, $tagPosition, strlen($tag));
return $view;
} finally {
$this->fetchDepth--;
}
}
return $view;
}
}
/**
/**