我的所有控制器都在命名空间MyApp\Controllers
下,因此,正如文档推荐的那样,我已将默认命名空间设置为:
$dispatcher->setDefaultNamespace('MyApp\Controllers');
但是现在我不仅需要在文件夹中组织我的控制器,还要命名它们并拥有友好的URL,如:/features/featureX/
和/wizards/featureX/
。所以从这个例子我得到了MyApp\Controllers\Features\FeaturesX
和MyApp\Controllers\Wizards\FeaturesX
。
我认为他们不应该被视为模块吗?它们只是一些自定义路由,但是从路由文档中我无法告诉如何:
$router->add("/:namespace", ["namespace" => 1]);
)LoginController
应保留在MyApp\Controllers
命名空间中。也许我可以通过为每个路由器或调度程序使用一个路由器或调度程序来实现这一点。任何经验丰富的Phalcon开发人员都可以在这里给我一个亮点吗?!
答案 0 :(得分:14)
好吧,经过一段时间使用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似乎更多地瞄准简单/琐碎的项目,但这非常合理,即使使用所有这些样板代码来使您的应用程序更加花哨,框架的其余部分本身也使得以后的所有工作都值得上。
与此同时,我希望下一版本包含更多名称空间友好的功能。