好吧,在使用 Phalcon 一段时间后,我可以说,有时当您决定使用与我们在项目文档中找到的方法不同的方法时,它并不那么灵活。命名空间的使用就是其中一种情况。
框架不能很好地处理多个命名空间级别,但它仍然设计良好且可扩展。您几乎可以覆盖任何东西,并且通过一些自定义,您可以实现任何您想要的行为。
以下是我在文件夹/命名空间中组织我的所有内容并仍然使用整个框架的操作。
其中一些信息可能对您的上下文有用,所以这里是我迄今为止的传奇旅程的报告......
Phalcon 与命名空间
好的,所以如果您决定将 PHP 源代码组织在文件夹和命名空间中,请准备好调整几乎所有主要功能,并在您的实现中更加明确(即使用到处都是完整的类路径)。
基本上,您将丢弃框架必须提供的一些最酷的自动化,因为它们是基于约定的,而这些约定似乎是在没有考虑命名空间的情况下定义的。
但是,尽管前面有这么多额外的工作,我还是决定保留这个设计决定;毕竟,我们选择 MVC 框架是有原因的,对吧?!我们想让事情井井有条。特别是在大型项目中,将源代码稀释在多个命名空间/文件中以提高可维护性非常重要。
目录结构
首先,您应该了解我选择的目录结构,以了解我在下面所说的内容。相信我,我花了 小时 天来调整这个结构并阅读其他 MVC 框架推荐的结构,毕竟我个人的建议很简单:选择问题较少的一个!一般来说,这意味着更加解耦/碎片化的一个。
这是我目前使用的结构,它为我服务了将近两年,并且适合我需要向它抛出的任何类型的代码:
清楚地了解您的目录/命名空间结构可以在实现新内容时消除大量猜测,并帮助您在不知不觉中编写解耦代码。如果您在一开始就“浪费”一些时间来关心这个问题,这意味着您将来可以减少痛苦的重构。
类加载器
您是否注意到source/ 文件夹及其内容或多或少符合PSR Standards 的要求?!
原因是Phalcon's Class Loader 符合 PSR-0 标准;
所以基本上我只需要将source/ 文件夹注册到加载器中:
$phLoader = new PhLoader();
// Considering the public folder as your current __DIR__
$phLoader->registerDirs(['../source/']);
$phLoader->register();
...瞧!您只需引用该类(在需要时使用完整路径),PHP 和 Phalcon 内部实现都会找到它。例如,在我的 DI 容器中注册我的组件之一:
// At the first time the service 'foo' is needed
// Phalcon will read the file at 'source/MyApp/Components/Foo.php'
// and then call Foo's constructor
$di->set('foo', 'MyApp\Components\Foo');
路由器和控制器
如果您的所有控制器都在同一个命名空间/文件夹中,您可以这样做:
$router->setDefaultNamespace('MyApp\Controllers');
不错!
但是如果你在MyApp\Controllers\Foo\BarController下有一个控制器呢?!
就像默认的加载器行为一样,路由器不会尝试将Foo 部分解释为另一个命名空间级别。
ATTOW 没有办法让路由器在“更深”的命名空间中找到控制器。到目前为止,我的解决方案是关闭default routing behavior 并为每个命名空间分支手动添加四种常见模式。
“四种常见模式”是指这些路线:
:namespace/index/index
仅定义命名空间时
:namespace/:controller/index/
仅定义命名空间和控制器名称时
:namespace/:controller/:action/
定义命名空间、控制器和动作名称时
:namespace/:controller/:action/:params
当一切都被定义并包含参数时
为了为所有命名空间启用这些路由,我将 :namespace 正则表达式占位符替换为另一个匹配所有可能命名空间的正则表达式,并实现了一个“转换器”,将路由转换为正确的命名空间(即“/foo/bar/ baz" --> ['namespace' => 'MyApp\Controllers\Foo', 'controller' => 'bar', 'action' => 'baz'])。
为了说明我在说什么,这里有一个我前段时间写的自定义路由器,它使用了这种技术:
https://gist.github.com/snolflake/9797835
型号
您必须遵循the docs say 的内容。这意味着,每当您在 PHQL(或关系定义)上引用模型时,您都需要始终使用完整的类路径。
观看次数
我所说的视图基本上是指模板文件。当然,它们不在命名空间下,但由于您的控制器在,因此自动视图拾取无法正常工作。所以应该手动选择您的视图:
namespace MyApp\Controllers\Foo;
class BarController
{
public function bazAction()
{
// The path is relative to the views dir you've set before
$this->view->pick('configurations/subscriptions/index.volt')
...
很高兴您可以利用事件beforeExecuteRoute 根据您自己的约定自动选择视图。
结论
看起来 Phalcon 的目标更多是简单/琐碎的项目,但这是完全合理的,即使使用所有这些样板代码让您的应用程序更加花哨,框架的其余部分本身也值得以后的工作。
同时我只是希望下一个版本包含更多对命名空间友好的功能。