5

是否可以在 Module.php 中创建变量甚至共享对象(如 DB 适配器)以用于所有视图控制器?(Zend 框架 2)

例如:

class Module 
{
    public function onBootstrap(MvcEvent $e)
    {

        $moduleConfig = $e->getServiceManager()->get('Config')
    }
}

在控制器中,以某种方式访问​​使用:

$this->moduleConfig['db']

在上面,我知道这只是 db 适配器的配置数组,但它是如何工作的呢?

我看到可以在控制器操作中执行此操作:

$config = $this->getServiceLocator()->get('Config')
$dba = new DbAdapter($config['db']);

我不想在我需要配置的每个地方都这样做。我怎样才能使它像: $this->config ?因此它可用于所有操作。更好的是,如何在整个模块中做到这一点?我知道这一切都错了,但在 ZF1 中,我们使用 Zend_Registry::get() 来处理类似这样的简单事情。我正在阅读文档和各种各样的 tuts,但总是有一些假设,我只是迷路了。所以我真正想要的是:A)全局可访问的配置项,B)全局可访问的数据库适配器

我只想在我的控制器中调用 $this->db 或 $this->config->item。这可能吗?我知道我错过了一些完全简单的东西。

我也尝试使用 $this->getServiceLocator()->get('Config'); 在我的 __construct 中设置 $this->config 但我知道在构建期间服务定位器尚不可用。我尝试通过在模块的 onBootstrap 中设置 preDispatch 来做类似的事情,但我似乎无法将这些项目放入我的控制器中。

仅供参考,我的 global.php 中确实有这个(不,它不会留在那里,只是示例):

'db' => array(
        'driver' => 'Pdo',
        'dsn'   => 'mysql:dbname=mydb;host=localhost;',
        'username' => 'root',
        'password' => '',
        'driver_options' => array(
            PDO::MYSQL_ATTR_INIT_COMMAND => 'SET NAMES \'UTF8\''
        ),

    ),

我可以使用 getServiceLocator() 在任何操作中访问该项目和其他项目。我希望这些项目可以作为我的控制器属性在 $this->config->item 中使用。

我很感激任何指导!谢谢!

4

1 回答 1

18

好的...多部分答案。

1.添加配置变量,站点范围。(以及如何在控制器中访问)

这很容易,一旦我看到它起作用。但取决于下面的 preDispatch。在您的应用程序根目录中,将文件放入 config/autoload. 调用它:things.config.local.php

在这个文件中,我们只返回一个带有配置项的数组。

<?php
return array(
    'things' => array(
        'avalue' => 'avalue1',
        'boolvalue' => true,
        ),

);

所以我想在我的控制器中访问它。假设您在控制器中创建了一个配置属性,您可以通过这种方式访问​​它。(您在下面的 preDispatch 中设置该属性以使其工作)在我的系统中,我希望像这样检索该值:

$this->config['things']['boolvalue'];

但是,您可以通过如下操作调用它:

$config = $this->getServiceLocator()->get('Config');
echo $config['things']['boolvalue'];

这实际上很容易。不知道如何使用 ini 文件来做到这一点,但在我的情况下,它不需要,而且我的 ini 文件直接移动到数组中并不是什么大问题。问题1为我解决了!

2.如何在控制器中获取preDispatch(因为__construct不会加载配置)

我的另一个问题是我可以在全局级别访问某些对象和/或值,并在初始化控制器和操作时加载它们。据我了解,无法在控制器的 __construct 中访问服务管理器配置。

$this->getServiceLocator()->get('Config');

以上是行不通的。我相信因为在控制器类的构造过程中 ServiceManager 还不可用。说得通。

不过,还有几个额外的步骤,我可以让 preDispatch 工作,类似于 ZF1。 然后配置的东西工作。以及访问全局对象,如数据库。

在控制器中添加以下方法:

protected function attachDefaultListeners()
{
    parent::attachDefaultListeners();
    $events = $this->getEventManager();
    $this->events->attach('dispatch', array($this, 'preDispatch'), 100);
    $this->events->attach('dispatch', array($this, 'postDispatch'), -100);
}

然后添加 pre 和 post 方法。

public function preDispatch (MvcEvent $e)
{
    // this is a db convenience class I setup in global.php
    // under the service_manager factories (will show below)
    $this->db = $this->getServiceLocator()->get('FBDb');
    // this is just standard config loaded from ServiceManager
    // set your property in your class for $config  (protected $config;)
    // then have access in entire controller
    $this->config = $this->getServiceLocator()->get('Config');
    // this comes from the things.config.local.php file
    echo "things boolvalue: " . $this->config['things']['boolvalue'];
}

public function postDispatch (MvcEvent $e)
{
    // Called after actions
}

问题2解决了!初始化控制器。

3.如何使用上面的ServiceManager来加载一个DB对象供Controller使用

好的,我想要的最后一件事是全局访问我的数据库。我希望它在控制器范围内,所以我可以在任何地方调用 $this->db->fetchAll。

在 global.php 中首先设置服务管理器。
另外,请记住,我不会像在我的 global.php 文件中那样完全保留它。但它现在有效。将这些数组添加到 global.php 中的返回数组中:

'db' => array(
    'driver' => 'Pdo',
    'dsn'   => 'mysql:dbname=mydb;host=localhost;',
    'username' => 'root',
    'password' => '',
    'driver_options' => array(
        PDO::MYSQL_ATTR_INIT_COMMAND => 'SET NAMES \'UTF8\''
    ),

),
'service_manager' => array(
    'factories' => array(
        'Zend\Db\Adapter\Adapter'
                => 'Zend\Db\Adapter\AdapterServiceFactory',
        'db-adapter' => function($sm) {
                $config = $sm->get('config');
                $config = $config['db'];
                $dbAdapter = new Zend\Db\Adapter\Adapter($config);
                return $dbAdapter;
             },
        'FBDb'  => function($sm) {
                $dba= $sm->get('db-adapter');
                $db = new FBDb\Db($dba);
                return $db;
             },

    ),
),

在上面,我设置了 db 配置,然后 service_manager 有一些工厂,这些工厂在应用程序的其余部分需要时可用。就我而言,我想要一些方便以向后兼容我的一些旧 ZF1 代码,所以我添加了一个名为 FBDb 的自定义模块。我发现了 Fabrizio Balliano 的一个很棒的 wrapper/bridge-to-zf1-style-db 类,叫做 ZFBridge。非常适合我的需求,您可以在这里找到: https ://github.com/fballiano/zfbridge

我接受了它,对其进行了一些修改,然后制作了一个模块。所以 FBDb 对象在我的控制器中作为我的数据库连接可用。如果我想在其他地方使用它,则与“db-adapter”相同。

无论如何,在我的控制器中,我设置了“受保护的 $db;” 在课程开始时,我可以使用该属性。然后如上面的#2 所示,我有 preDispatch 将 FBDb 数据库对象分配给 $this->db。

$this->db = $this->getServiceLocator()->get('FBDb');

然后在我的操作方法中,如果需要,我可以使用以下命令调用记录集或数据库值:

$sql = 'select * from customer where cust_nbr between ? and ?';
$rs = $this->db->fetchResults($sql, array('120400', '125250'));

或者,对于返回的数组:

$rs = $this->db->fetchAll($sql, array('120400', '125250'));

(我将 fetchResults 添加到 ZFBridge 以仅从 db 查询中返回 PDO\Results 对象,以便稍后在 foreach 中使用。)

我知道其中一些可能是糟糕的设计或“糟糕的 OOP”,但它对我有用,我喜欢它。我个人不喜欢使用纯基于对象的数据实体来处理所有事情,只是一些事情。很多时候,我只想放入一个结果集并完成它。:)

问题解决了。目前。如果你习惯了 ZF1,现在让 ZF2 变得更加友好。

于 2013-01-03T19:34:06.483 回答