Zend Framework 2-应用程序/模块/服务经理-天哪



作为Zend Framework 1的长期开发人员,我刚刚开始学习Zend Framework 2。我很难理解新术语。

回到ZF1中,如果我想创建一个对应用程序全局的记录器,我会将配置添加到application.ini文件中,引导程序会将其初始化为资源(我希望我说得对)。因此,从我的任何模块控制器,我都可以通过引导程序资源访问记录器。

输入ZF2,模块有点不同,它们是自包含的,但我对它们如何与应用程序交互有点困惑。在我看来,这就是ServiceManager发挥作用的地方。我的目标是,让我的模块(不是控制器,而是模块本身)检查应用程序是否定义了记录器,如果定义了,则在整个模块中使用该记录器。如果应用程序没有定义记录器,我希望模块定义用于模块范围日志记录的记录器。

这个问题也与数据库有关,比如说,我希望应用程序定义数据库连接的逻辑,而我希望模块定义它所需的表的逻辑。我该如何配置它,以及如何/在哪里判断应用程序中是否已经定义了数据库资源。

注意:我已经浏览了Rob Allen的Quickstart(相当多的信息,也是我发现的唯一一个缺乏模糊性的资源)和ZF2(readthedocs),并且已经在谷歌上搜索了很多。我发现,当涉及到拼图的某些部分的"去向"时,信息通常非常模糊。

您从Zend Framework 1.x中了解到的是一个"应用程序资源"。

"应用程序资源"的概念在Zend Framework 2中被所谓的"服务"(此处介绍)所取代

另一个变化是模块本身。在ZF1中,模块主要是应用程序中处理一些请求的子部分。ZF2中不再是这样:如果您的模块定义了一个服务或控制器,那么现在所有应用程序都可以访问该服务或控制器。Gary Hockin介绍了ZF1和ZF2之间的一些差异。

但无论如何,模块都是自包含的。它们应该在隔离环境中开发,并且具有尽可能小的依赖性,但它们提供了影响所有应用程序的交叉关注功能。

对于记录器的特定情况,我建议您的模块始终定义记录器并使用它。可以做些什么来有条件地定义记录器如下:

class MyModule
{
    public function onBootstrap($e)
    {
        // $e->getTarget() is the ZendMvcApplication
        $sm = $e->getTarget()->getServiceManager();
        if (!$sm->has('some-logger-name')) {
            $sm->setFactory('some-logger-name', function ($sl) {
                return new MyLogger($sl->get('some-db'));
            });
        }
    }
}

然后,您就可以在所有应用程序中使用您的"某个记录器名称"。

另一种方法是只定义记录器服务,然后让其他模块或配置稍后覆盖它:

class MyModule
{
    public function getConfig()
    {
        return array(
            'service_manager' => array(
                'factories' => array(
                    'some-logger-name' => 'MyLoggerFactoryClassName'
                ),
            ),
        );
    }
}

getServiceConfig也实现了这一点,它的灵活性较低,不能缓存,但比getConfig具有更高的优先级(允许重写),还可以将服务工厂定义为闭包:

class MyModule
{
    public function getServiceConfig()
    {
        return array(
            'factories' => array(
                'some-logger-name' => function ($sl) {
                    return new MyLogger($sl->get('some-db'));
                },
            ),
        );
    }
}

然后,您甚至可以定义一个配置密钥,该密钥必须用于决定使用哪个记录器(服务名称)。

模块和配置的概念是"最后一个模块获胜",因此您可以在您的模块或之前加载的任何模块中定义服务'some-logger-name'

同样的概念也适用于您的数据库连接。

正如你所看到的,转向服务业已经给了你一定程度的自由。

请记住,并不是"应用程序"为您定义了一些东西:模块定义了您的服务/配置/事件等。运行的应用程序就是所有这些东西的组合。

我认为,特别是在日志记录的情况下,有一种可能比使用ServiceManager更好、当然更封装的方法。ZF2本质上是一个事件驱动的框架,实现这种事件驱动架构的功能可以对我们有利。日志记录就是一个很好的例子。您不需要定义工厂,只需要附加一个记录器事件,该事件可以从应用程序中的任何位置触发。

Module.php:中附加一个log事件侦听器

public function onBootstrap(MvcEvent $e)
{
    //setup some $logger
    $sharedManager = $e->getApplication()->getEventManager()->getSharedManager();
    $sharedManager->attach('*', 'log', function($e) use ($logger) {
        /** @var $e MvcEvent */
        $target   = get_class($e->getTarget());
        $message  = $e->getParam('message', 'No message provided');
        $priority = $e->getParam('priority', Logger::INFO);
        $message  = sprintf('%s: %s', $target, $message);
        $logger->log($priority, $message);
    });
}

然后从应用程序中的任何位置触发它,例如控制器:

$this->getEventManager()->trigger('log', $this, array(
    'priority' => ZendLogLogger::INFO, 
    'message' => 'just some info to be logged'
));

最新更新