126 lines
4.3 KiB
PHP
126 lines
4.3 KiB
PHP
<?php
|
|
|
|
/*
|
|
* This file is part of the Symfony package.
|
|
*
|
|
* (c) Fabien Potencier <fabien@symfony.com>
|
|
*
|
|
* For the full copyright and license information, please view the LICENSE
|
|
* file that was distributed with this source code.
|
|
*/
|
|
|
|
namespace Sensio\Bundle\FrameworkExtraBundle\Templating;
|
|
|
|
use Doctrine\Common\Persistence\Proxy;
|
|
use Symfony\Component\HttpKernel\Bundle\Bundle;
|
|
use Symfony\Component\HttpKernel\KernelInterface;
|
|
use Symfony\Component\HttpFoundation\Request;
|
|
|
|
/**
|
|
* The TemplateGuesser class handles the guessing of template name based on controller.
|
|
*
|
|
* @author Fabien Potencier <fabien@symfony.com>
|
|
*/
|
|
class TemplateGuesser
|
|
{
|
|
/**
|
|
* @var KernelInterface
|
|
*/
|
|
private $kernel;
|
|
|
|
/**
|
|
* @var string[]
|
|
*/
|
|
private $controllerPatterns;
|
|
|
|
/**
|
|
* @param string[] $controllerPatterns Regexps extracting the controller name from its FQN
|
|
*/
|
|
public function __construct(KernelInterface $kernel, array $controllerPatterns = [])
|
|
{
|
|
$controllerPatterns[] = '/Controller\\\(.+)Controller$/';
|
|
|
|
$this->kernel = $kernel;
|
|
$this->controllerPatterns = $controllerPatterns;
|
|
}
|
|
|
|
/**
|
|
* Guesses and returns the template name to render based on the controller
|
|
* and action names.
|
|
*
|
|
* @param callable $controller An array storing the controller object and action method
|
|
*
|
|
* @return string The template name
|
|
*
|
|
* @throws \InvalidArgumentException
|
|
*/
|
|
public function guessTemplateName($controller, Request $request)
|
|
{
|
|
if (\is_object($controller) && method_exists($controller, '__invoke')) {
|
|
$controller = [$controller, '__invoke'];
|
|
} elseif (!\is_array($controller)) {
|
|
throw new \InvalidArgumentException(sprintf('First argument of %s must be an array callable or an object defining the magic method __invoke. "%s" given.', __METHOD__, \gettype($controller)));
|
|
}
|
|
|
|
$className = $this->getRealClass(\get_class($controller[0]));
|
|
|
|
$matchController = null;
|
|
foreach ($this->controllerPatterns as $pattern) {
|
|
if (preg_match($pattern, $className, $tempMatch)) {
|
|
$matchController = str_replace('\\', '/', strtolower(preg_replace('/([a-z\d])([A-Z])/', '\\1_\\2', $tempMatch[1])));
|
|
break;
|
|
}
|
|
}
|
|
if (null === $matchController) {
|
|
throw new \InvalidArgumentException(sprintf('The "%s" class does not look like a controller class (its FQN must match one of the following regexps: "%s")', \get_class($controller[0]), implode('", "', $this->controllerPatterns)));
|
|
}
|
|
|
|
if ('__invoke' === $controller[1]) {
|
|
$matchAction = $matchController;
|
|
$matchController = null;
|
|
} else {
|
|
$matchAction = preg_replace('/Action$/', '', $controller[1]);
|
|
}
|
|
|
|
$matchAction = strtolower(preg_replace('/([a-z\d])([A-Z])/', '\\1_\\2', $matchAction));
|
|
$bundleName = $this->getBundleForClass($className);
|
|
|
|
return sprintf(($bundleName ? '@'.$bundleName.'/' : '').$matchController.($matchController ? '/' : '').$matchAction.'.'.$request->getRequestFormat().'.twig');
|
|
}
|
|
|
|
/**
|
|
* Returns the bundle name in which the given class name is located.
|
|
*
|
|
* @param string $class A fully qualified controller class name
|
|
*
|
|
* @return string|null $bundle A bundle name
|
|
*/
|
|
private function getBundleForClass($class)
|
|
{
|
|
$reflectionClass = new \ReflectionClass($class);
|
|
$bundles = $this->kernel->getBundles();
|
|
|
|
do {
|
|
$namespace = $reflectionClass->getNamespaceName();
|
|
foreach ($bundles as $bundle) {
|
|
if ('Symfony\Bundle\FrameworkBundle' === $bundle->getNamespace()) {
|
|
continue;
|
|
}
|
|
if (0 === strpos($namespace, $bundle->getNamespace())) {
|
|
return preg_replace('/Bundle$/', '', $bundle->getName());
|
|
}
|
|
}
|
|
$reflectionClass = $reflectionClass->getParentClass();
|
|
} while ($reflectionClass);
|
|
}
|
|
|
|
private static function getRealClass(string $class): string
|
|
{
|
|
if (false === $pos = strrpos($class, '\\'.Proxy::MARKER.'\\')) {
|
|
return $class;
|
|
}
|
|
|
|
return substr($class, $pos + Proxy::MARKER_LENGTH + 2);
|
|
}
|
|
}
|