<?php
namespace App\Component\ViewLayer\ViewHandlers;
use App\Component\Dom\Nodes\RawNode;
use App\Component\ViewLayer\AbstractView;
use App\Component\ViewLayer\AbstractViewHandler;
use App\Component\ViewLayer\Views\AbstractHtmlView;
use Symfony\Component\Serializer\NameConverter\CamelCaseToSnakeCaseNameConverter;
use Twig\Environment;
/**
* Class HtmlViewHandler
* @package App\Component\ViewLayer\ViewHandlers
*/
final class HtmlViewHandler extends AbstractViewHandler
{
/**
* @var Environment
*/
protected Environment $twig;
/**
* @param Environment $twig
*/
public function __construct(
Environment $twig
)
{
$this->twig = $twig;
$this->snakecaser = new CamelCaseToSnakeCaseNameConverter();
}
/**
* {@inheritDoc}
*/
public function supports(AbstractView $view): bool
{
return ($view instanceof AbstractHtmlView);
}
/**
* {@inheritDoc}
* @param AbstractHtmlView $view
*/
public function prepare(AbstractView $view): void
{
// see if we don't have a template given; if not generate a default one
if (empty($view->getTemplate())) {
// get the routing information
$route = $view->getRequest()->attributes->get('_route');
// determine the controller
$controller = $view->getRequest()->attributes->get('_controller');
$controller = substr($controller, 0, strpos($controller, '::'));
// determine the alias
if (str_starts_with($controller, 'App\\')) {
$alias = 'App';
} else {
$alias = preg_replace('/^([^\\\\]+?)\\\\(.+?)Bundle\\\\.*$/', '$1$2', $controller);
}
// get the parts that make up the route; currently ignoring the first two
// TODO: need to make this a bit more flexible as the naming convention might not be consistent?
$paths = array_slice(explode('.', $route), 2);
// need to rip the last one off as that is the file
$file = array_pop($paths);
// set the template path
$view->setTemplate(call_user_func_array(
'sprintf',
array_merge(
[
'@%s/%s/%s.html.twig',
$alias,
],
[implode('/', $paths)],
[$file]
)
));
}
}
/**
* {@inheritDoc}
* @param AbstractHtmlView $view
*/
public function handle(AbstractView $view): string
{
// render the main content area and set it into the dom
$content = $this->twig->render(
$view->getTemplate(),
array_merge(
$view->getParameters(),
[]
)
);
// generate the final content
return $this->twig->render(
sprintf(
'@App/view_layer/%s.html.twig',
strtolower(preg_replace(
'/^.+\\\\(.+?)HtmlView$/',
'$1',
get_class($view)
))
),
array_merge(
$view->getDom()->toArray(),
[
'content' => (new RawNode())->setContent($content),
]
)
);
}
}