【问题标题】:Namespaces with Phalcon使用 Phalcon 的命名空间
【发布时间】:2014-04-30 18:04:59
【问题描述】:

我所有的控制器都在命名空间 MyApp\Controllers 下,因此,按照文档的建议,我已将默认命名空间设置为它:

$dispatcher->setDefaultNamespace('MyApp\Controllers');

但现在我不仅需要在文件夹中组织我的控制器,还需要为它们命名空间并拥有友好的 URL,例如:/features/featureX//wizards/featureX/。所以从那个例子中我得到了MyApp\Controllers\Features\FeaturesXMyApp\Controllers\Wizards\FeaturesX

我认为它们不应该被视为模块,对吧?它们只是一些自定义路由,但从路由文档中我不知道如何:

  • 声明一个只定义命名空间的路由(例如$router->add("/:namespace", ["namespace" => 1]);
  • 使上述路由策略仅用于某些控制器。例如,LoginController 应保留在 MyApp\Controllers 命名空间中。

也许我可以通过为每个路由器使用一个路由器或调度程序来实现这一点。任何有经验的 Phalcon 开发者都可以在这里给我指点一下吗?!

【问题讨论】:

  • 很高兴能在这个问题上得到答案。卡在同一个问题上。 Phalcon 社区很穷,从不回答......感觉没有人能理解这个框架,人们只是试图触及它的冰山顶部 :(
  • @Fratyr 我为此实施了一个解决方案,但现在我有大量工作要做。今晚我将在这里发布我的解决方案,也许它会帮助你:) 现在我可以给你一个兄弟提示,它是使用自动方式为每个命名空间添加多个路由的方式“解决”的。
  • 我不知道如何为命名空间添加路由 ^_^ 我尝试路由硬编码控制器名称 /users/:controller/:action/:params 但它不起作用.....当您发布您的解决方案时,请尽可能附上您的 services.php 和 loader.php 配置,我想看看您如何注册命名空间和服务。:)
  • @Fratyr 在这里...
  • @Fratyr 哎呀我忘了最重要的部分。查看我在“路由器和控制器”部分添加的最后一个链接。

标签: phalcon


【解决方案1】:

好吧,在使用 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 的目标更多是简单/琐碎的项目,但这是完全合理的,即使使用所有这些样板代码让您的应用程序更加花哨,框架的其余部分本身也值得以后的工作。

同时我只是希望下一个版本包含更多对命名空间友好的功能。

【讨论】:

  • 我有一堆错误使用你的要点。你的 phalcon 版本是多少?
  • @Fratyr 顺便说一句,我有一些好消息,如果您在项目中使用PSR-0 方法,Phalcon 自动加载器会更加实用。我会尽快更新我的答案,同时阅读 PSR 规范:)
  • @Fratyr 除了好消息之外,仍然需要自定义路由器来处理命名空间。我已经更新了要点并添加了关于如何使用它的评论。
  • 我设法让它工作,但没有自定义路由器,因此我的 router.php 现在有点乱,但其余部分似乎按预期工作。我会检查新的要点。非常感谢。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2015-01-04
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-11-14
  • 1970-01-01
相关资源
最近更新 更多