我想创建一个动态模板定位器。 基本上,我希望在满足某些全局条件时优先考虑某些包中的模板。类似于bundle继承的工作方式,但是运行时动态。
它应该像这样工作: 我有类别'并且每个类别都有自己的捆绑。当要呈现模板时,我会检查当前设置的类别,并在此类别的包中搜索此模板。如果没有找到,则回退到内置机制。
我虽然重写Symfony\Bundle\FrameworkBundle\Templating\Loader\TemplateLocator
,但这看起来有些过时。如果可能的话,我想模仿bundle继承,但我找不到它的实现位置。
你会怎么做? TemplateLocator
是注入逻辑的最佳位置吗?
答案 0 :(得分:0)
这可能不是最漂亮的解决方案,但它就像一个魅力。
我将TemplateLocator
服务分包并重载:
class CategoryAwareTemplateLocator extends TemplateLocator
{
/**
* @var string
*/
protected $categoryBundle = null;
/**
* @var string
*/
protected $defaultBundle = null;
/**
* {@inheritDoc}
*/
public function __construct(FileLocatorInterface $locator, $cacheDir = null)
{
parent::__construct($locator, $cacheDir);
}
/**
* {@inheritDoc}
*/
public function locate($template, $currentPath = null, $first = true)
{
if(!$template instanceof TemplateReferenceInterface) {
throw new \InvalidArgumentException('The template must be an instance of TemplateReferenceInterface.');
}
$templateParameters = $template->all();
$templateBundle = array_key_exists('bundle', $templateParameters) ? $templateParameters['bundle'] : null;
if(
null !== $this->categoryBundle &&
$templateBundle === $this->defaultBundle /* Override only defaultBundle templates */
) {
/* Try our category bundle first */
$categoryTemplate = clone $template;
$categoryTemplate->set('bundle', $this->categoryBundle);
try {
return parent::locate($categoryTemplate, $currentPath, $first);
} catch(\InvalidArgumentException $exception) {
/* Just fall through to default mechanism */
}
}
return parent::locate($template, $currentPath, $first);
}
/**
* @param string $defaultBundle
* @param string $categoryBundle
*/
public function setCategoryBundle($defaultBundle, $categoryBundle)
{
$this->categoryBundle = $categoryBundle;
$this->defaultBundle = $defaultBundle;
}
}
在运行时通过setter注入所需的包名称(它在编译时'中未知)。这也有点难看。
最棒的是,这适用于所有树枝标记(include
,use
,...)。唯一的问题是您无法访问'默认'模板你压倒一切。如果您尝试从覆盖它的模板执行此操作,您将获得嵌套级别(无限递归)错误。
这不是一件大事,因为你可以巧妙地继承'使用组合从基础模板(将模板拆分成较小的模板)。