<?php
/**
* Elements DeMI
*
* This source file is available under the elements DeMI license version 1
*
* @copyright Copyright (c) elements.at New Media Solutions GmbH (https://www.elements.at/)
* @license elements DeMI Lizenz Version 1 (https://www.elements.at/de/demi-lizenz)
*/
namespace Elements\Bundle\DemiFrontendBundle\EventListener;
use Doctrine\Common\Persistence\Proxy;
use JetBrains\PhpStorm\ArrayShape;
use Pimcore\Tool\DeviceDetector;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Template;
use Symfony\Bundle\FrameworkBundle\Templating\TemplateReference;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Symfony\Component\HttpKernel\Event\GetResponseForControllerResultEvent;
use Symfony\Component\HttpKernel\Event\ViewEvent;
use Symfony\Component\HttpKernel\KernelEvents;
use Symfony\Component\HttpKernel\KernelInterface;
class DeviceDependentTemplateListener implements EventSubscriberInterface
{
public function __construct(protected KernelInterface $kernel)
{
}
/**
* @inheritDoc
*/
#[ArrayShape([KernelEvents::VIEW => "array"])] public static function getSubscribedEvents()
{
return [
KernelEvents::VIEW => ['onKernelView', 20]
];
}
public static function getTemplateName($path, $templateName, $view, $forceTemplateType = '')
{
if (empty($forceTemplateType)) {
$deviceType = 'desktop';
if (DeviceDetector::getInstance()->isPhone()) {
$deviceType = 'mobile';
}
} else {
$deviceType = $forceTemplateType;
}
if ($view->exists($path . $templateName .'.'. $deviceType .'.html.php')) {
return $path . $templateName .'.'. $deviceType . '.html.php';
}
return $path . $templateName . '.html.php';
}
public function onKernelView(ViewEvent $event)
{
$request = $event->getRequest();
if (!$request->get('_demi_frontend_request')) {
return;
}
if ($request->attributes->has('_template')) {
$deviceType = 'desktop';
if (DeviceDetector::getInstance()->isPhone()) {
$deviceType = 'mobile';
}
$template = $request->attributes->get('_template');
$className = self::getRealClass(\get_class($template->getOwner()[0]));
$matchController = $matchAction = null;
if (preg_match('/Controller\\\(.+)Controller$/', $className, $tempMatch)) {
$matchController = $tempMatch;
}
if ($template->getOwner()[1] === '__invoke') {
$matchAction = $matchController;
$matchController = null;
} elseif (!preg_match('/^(.+)Action$/', $template->getOwner()[1], $matchAction)) {
$matchAction = [null, $template->getOwner()[1]];
}
$bundle = $this->getBundleForClass($className);
if ($bundle) {
while ($bundleName = $bundle->getName()) {
if (!method_exists($bundle, 'getParent') || (null === $parentBundleName = $bundle->getParent())) {
$bundleName = $bundle->getName();
break;
}
$bundles = $this->kernel->getBundle($parentBundleName, false);
$bundle = array_pop($bundles);
}
} else {
$bundleName = null;
}
$deviceTemplateReference = new TemplateReference($bundleName, $matchController[1], $matchAction[1] . '.' . $deviceType, $request->getRequestFormat(), 'php');
try {
$this->kernel->locateResource($deviceTemplateReference->getPath());
$template->setTemplate($deviceTemplateReference);
} catch (\Exception $e) {
// do nothing
}
}
}
private static function getRealClass(string $class): string
{
if (false === $pos = strrpos($class, '\\'.Proxy::MARKER.'\\')) {
return $class;
}
return substr($class, $pos + Proxy::MARKER_LENGTH + 2);
}
protected function getBundleForClass($class): mixed
{
$reflectionClass = new \ReflectionClass($class);
$returnBundle = null;
$bundles = $this->kernel->getBundles();
do {
$namespace = $reflectionClass->getNamespaceName();
foreach ($bundles as $bundle) {
if (str_starts_with($namespace, $bundle->getNamespace())) {
$returnBundle = $bundle;
break;
}
}
$reflectionClass = $reflectionClass->getParentClass();
} while ($reflectionClass);
return $returnBundle;
}
}