【发布时间】:2014-12-31 01:34:45
【问题描述】:
我正在构建一个托管 CMS,它使用平台的核心文件,但允许我们在必要时为客户端创建自定义文件,而不是核心文件。所以我的核心 Symfony 兼容代码位于这样的目录中:
// root directory
/var/www/core/cms/
// symfony app directory
/var/www/core/cms/app
// my cms bundle
/var/www/core/cms/src/Gutensite/CmsBundle
// web root
/var/www/core/web
etc.
这些遵循标准的命名约定和文件位置,因此 symfony 会在我需要时自动加载类。 Symfony 结构允许我根据需要覆盖供应商捆绑包,方法是将供应商捆绑包文件夹和文件放在我的 /app 或 /src/ 目录中。 See Docs.
"Bundle inheritance allows you to override any existing bundle in order to customize its
controllers, templates, or any of its files."
但我的客户端文件夹将存在于不同的 vhost id 目录中,例如:
// the root of the client vhost directory
/var/www/vhosts/999/
// will reflect the same structure as the core app
/var/www/vhosts/999/src/
所以如果我有一个核心控制器叫做:
/var/www/core/cms/src/Gutensite/MenuBundle/Controller/MenuPrimaryController.php
我想为客户制作一个自定义版本,我会把它放在这里:
/var/www/vhosts/999/src/Gutensite/MenuBundle/Controller/MenuPrimaryController.php
我的主应用有一个 InitController,通常会像这样加载控制器:
$namespaceController = 'Gutensite\MenuBundle\Controller\MenuPrimaryController';
$contentController = new $namespaceController();
所以我想将该控制器的路径更改为不同的命名空间并让 Symfony 加载它,例如
// I think namespace can't have parts that start with numbers
$namespaceController = 'vhost999\src\Gutensite\MenuBundle\Controller\MenuPrimaryController';
现在,我的代码通过检查文件是否存在,然后要求该文件来手动执行此操作。然后new 命令加载正确的控制器。但如果可能的话,我想使用 symfony 的自动加载功能(并获得专家建议以最佳方式完成此操作)。
我想更好地了解如何自定义 symfony 查找的 ORDER 和 LOCATION 以覆盖捆绑包等。这样我就可以按以下顺序在以下位置查找:
1. Custom Directory (/var/www/vhosts/999/src/Gutensite/MenuBundle)
2. Template Directory (/var/www/core/cms/src/Gutensite/TemplateBundle/Controller/MyDesign/Gutensite/MenuBundle
3. Core Vendor Directory (/var/www/core/cms/src/Gutensite/MenuBundle)
更新--大部分已解决:
Cerad 的建议回答了这个问题的大部分内容,即当 Symfony 尝试加载控制器时,如何确定优先级。按照他的示例,我为所有以Gutensite 开头的命名空间注册了一个替代文件位置,方法是将其添加到app/autoload.php
$loader->add('Gutensite', '/var/www/vhosts/1/src', true);
然后在我的控制器中,我通过打印确认它已注册:
print_r(ClassMapGenerator::createMap('/var/www/vhosts/1'));
返回:
Array
(
[Gutensite\MenuBundle\Controller\MenuPrimaryController] => /var/www/vhosts/1/src/Gutensite/MenuBundle/Controller/MenuPrimaryController.php
)
这是正确的路径,并且确实加载了我的自定义控制器,而不是默认控制器。这正是我所需要的。
特定视图记录的替代命名空间
我还有一个稍微不同的用例需要解决。有时我会想为一个内容类型的所有实例创建一个自定义控制器(如上)。其他时候,我需要为特定页面创建一个特定实例(例如,查看 ID 35160)。
我尝试了很多不同的方法来组织它,以便我可以在命名空间或对象和文件名中包含 ID,但显然在如何使用数字、下划线和破折号方面存在很多限制 (见文末注释)。所以这是最终起作用的命名约定:
把自定义文件和通用控制器放在同一个文件夹下,文件名里放具体的视图ID号,不带下划线或破折号:
/var/www/vhosts/1/src/Gutensite/MenuBundle/Controller/MenuPrimaryController35160.php
namespace Gutensite\MenuBundle\Controller;
class MenuPrimaryController35160
{
public function indexAction()
{
echo "\n custom MenuPrimaryController for View ID 35160 in /var/www/vhosts/1/src";
}
}
重要的命名约定说明:
我的尝试多次失败,因为我尝试使用数字、破折号和下划线作为命名空间路径、对象名称或文件名的一部分,但它们都以不同的方式失败。
根据comments on php.net,命名空间不能包含仅是数字的部分,例如foo/1/bar/ 会失败,但 foo/bar1 会工作。
自动加载中使用的下划线PSR-0 specs 将被转换为目录分隔符,例如foo/bar/class_1 将映射到 foo/bar/class/1 而不是名为 class_1 的文件。
对象名称不应包含“-”等特殊字符。
剩下的问题:修改控制器中的自动加载
我能否稍后在控制器中修改自动加载位置(而不是在上面使用的app/autoload.php 方法中)。我需要为 Gutensite 命名空间注册另一个路径以获取替代文件位置,并且它需要指向正确的模板文件夹,但是直到我在主控制器中加载站点信息之后,我才知道它们使用的是哪个模板.
【问题讨论】:
标签: symfony