6

作为一名长期的 Zend Framework 1 开发人员,我刚刚开始学习 Zend Framework 2。我在理解新术语时遇到了一些麻烦。

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

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

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

注意:我已经浏览了 Rob Allen 的快速入门(相当多的信息,也是迄今为止我发现的唯一一个不为人知的资源),以及 ZF2(阅读文档),并且已经用谷歌搜索了很多。我发现,当涉及到拼图的某些部分“去哪里”时,信息通常非常模糊。

4

2 回答 2

6

您从 Zend Framework 1.x 了解到的是“应用程序资源”。

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

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

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

对于您的记录器的具体情况,我建议您的模块始终定义一个记录器并使用它。有条件地定义记录器的方法如下:

class MyModule
{
    public function onBootstrap($e)
    {
        // $e->getTarget() is the \Zend\Mvc\Application
        $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' => 'My\Logger\Factory\ClassName'
                ),
            ),
        );
    }
}

使用 实现相同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'在模块中或在它之前加载的任何模块中定义服务。

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

如您所见,转向服务已经为您提供了一定程度的自由。

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

于 2013-02-15T10:05:48.857 回答
3

我认为,尤其是在日志记录的情况下,可能有一种比使用ServiceManager. ZF2 本质上是一个事件驱动框架,支持这种事件驱动架构的功能可以为我们所用。日志记录就是一个很好的例子。您只需附加一个可以从应用程序中的任何位置触发的记录器事件,而不是定义工厂。

log您的Module.php

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' => \Zend\Log\Logger::INFO, 
    'message' => 'just some info to be logged'
));
于 2013-02-15T22:54:48.617 回答