2

编辑:在我发布这个问题几周后,Evan Coury 写了一篇关于 ZF2 ServiceManager 主题的优秀博客文章,这是我找到问题的最佳答案的地方:http ://blog.evan.pro/introduction-to -the-zend-framework-2-servicemanager

--

我正在使用 ZendFramework 2.0.0beta4 开发一个项目,并且在使用 Zend\ServiceManager 处理依赖项时遇到了麻烦。这是当前的ZF2 ServiceManager 文档

它列出了在使用 ServiceManager 注册类以在我们的模块中使用时使用的 6 个子键:abstract_factoriesaliasesfactoryinvokablesservicesshared。如果我只想注册一个模型类,我将在控制器中使用它从数据库中提取数据,那么哪个最好?我特别尝试将下面显示的ZF2 Skeleton Application中的示例改编为我自己的应用程序(DashboardTable 是一个模型),并且此示例使用工厂方式。

public function getServiceConfiguration()
{
    return array(
        'factories' => array(
            'album-table' => function($sm) {
                $dbAdapter = $sm->get('db-adapter');
                $table = new DashboardTable($dbAdapter);
                return $table;
            },
            'test-model' => Dashboard\Model\TestModel(),
        ),
    );
}

但是,我不知道“db-adapter”是如何在来自 SkeletonApplication 的单独工作示例中进入 ServiceManager ($sm) - 它与自动加载的 global.php 配置文件中的一个条目有关db' 包含数据库信息的条目。因为我不确切知道如何从配置文件到 ServiceManager,所以我在下面创建了一个简单的条目,以将问题减少到它的基本组件 - “test-model”。当我注释掉“仪表板表”条目并从控制器中的 TestModel 调用一个函数时,它只输出一些文本。下面是我的 Module.php 中的 ServiceManager 配置

<?php

namespace Dashboard\Model;

class TestModel {

public function testMethod()
{
    $testResult = "Hello";
    return $testResult;
}

}

然后从我的控制器传递到视图:

<?php

namespace Dashboard\Controller;

use Zend\Mvc\Controller\ActionController;
use Zend\View\Model\ViewModel;
use Dashboard\Model\AlbumTable;
use Dashboard\Model\TestModel;
use Dashboard\Model\Dashboard;

class DashboardController extends ActionController
{
    public function indexAction()
    {   
        return new ViewModel(array(
            'users' => $this->getTestModel()->testMethod(),
        ));
    }

    public function getAlbumTable()
    {
        if (!$this->albumTable) {
            $sm = $this->getServiceLocator();
            $this->albumTable = $sm->get('album-table');
        }
        return $this->albumTable;
    }

    public function getTestModel()
    {
        if (!$this->testModel) {
            $sm = $this->getServiceLocator();
            $this->testModel = $sm->get('test-model');
        }
        return $this->testModel;
    }

}

这段代码给了我一个完全空白的页面,没有错误。当我从 Module.php 中注释掉 ServiceManager 配置并只渲染一个新的 ViewModel 而没有在我的 DashboardController.php 文件中传递任何参数时,页面会正常渲染 - 加载 layout.phtml 和 index.phtml。

我相信我误解了如何使用 ServiceManager 或可能的 ZF2 的基本部分,并且非常感谢任何人可以提供的任何见解。这也是我在 StackOverflow 上的第一个问题,所以我欢迎任何关于格式化我的问题的建议。谢谢。

4

3 回答 3

3

从服务经理那里获得工厂有两个不错的选择。一种是创建工厂类,这在 Zend 框架代码本身中发生的大部分时间。第二个是使用闭包,就像你正在做的那样。

确保您不键入以下内容:

'test-model' => Dashboard\Model\TestModel(),

但是像你的第一个这样的真正的闭包就是一个很好的例子。其次,当您尝试获取无法实例化的服务时,服务管理器总是会给出异常。请注意,此异常不包括消息原因:可能找不到类或在实例化期间引发异常(例如,因为服务管理器无法实例化您尝试获取的服务的依赖项)。

最后一点是您不需要use在您尝试获取的位置使用语句导入 FQCN(完全限定的类名) 。但是当您尝试实例化时需要导入 FQCN 。

所以这有效:

<?php

class MyClass
{
  protected $sm;

  public function setServiceManager($sm)
  {
    $this->sm = $sm;
  }

  public function doSomething()
  {
    $this->sm->get('some-special-key');
  }
}

这也是:

<?php

use Foo\Bar\Baz;

$serviceConfig = array(
  'factories' => array(
    'some-special-key' => function($sm) {
      return new Baz;
    }
  ),
);

但这不是(如果您尝试获得 a Foo\Bar\Baz):

<?php

$serviceConfig = array(
  'factories' => array(
    'some-special-key' => function($sm) {
      return new Baz;
    }
  ),
);

您可能想查看我的SlmCmfKernel存储库。在我的Module.php 中,我包含了一个服务配置文件,它被放在一个单独的位置。在代码的另一部分,我从经理那里得到了服务。

于 2012-06-24T07:57:09.893 回答
2

只是为了澄清:

public function getServiceConfiguration()
{
    return array(
        'factories' => array(
            'test-model' => function($sm){
                return new Model\TestModel;
            },
        ),
    );
}

也可以写成可调用的:

public function getServiceConfiguration()
{
    return array(
        'invokables' => array(
            'test-model' => 'Model\TestModel',
        ),
    );
}

在这种情况下,您可能需要考虑在配置文件而不是 Module.php 中定义它,因为您可以利用配置缓存,因为它只是一个标量数组。

于 2012-07-21T01:14:11.380 回答
1

我最终通过更多调试找到了我自己问题的答案(我以前没有 ini_set('display_errors', '1'); set - 傻我)。

将类添加到 ZF2 ServiceManager(在您的 Module.php 中)的正确语法似乎是:

public function getServiceConfiguration()
{
    return array(
        'factories' => array(
            'album-table' => function($sm) {
                $dbAdapter = $sm->get('db-adapter');
                $table = new AlbumTable($dbAdapter);
                return $table;
            },
            'test-model' => function($sm){
                return new Model\TestModel;
            },
        ),
    );
}

为了完整起见,为了从您包含的类中调用方法,只要您扩展 ActionController 类,您就可以在控制器文件(在我的情况下为 DashboardController.php)中使用它:

class DashboardController extends ActionController
{
    public function indexAction()
    {   
        return new ViewModel(array(
            'users' => $this->getTestModel()->testMethod(),
        ));
    }

    public function getTestModel()
    {
        if (!$this->testModel) {
            $sm = $this->getServiceLocator();
            $this->testModel = $sm->get('test-model');
        }
        return $this->testModel;
    }

}

其中 testMethod() 是 TestModel 类中的一个方法。对于 Zend 或命名空间的新手来说,这里有一些注意事项 - 我的一个问题是,当我将文件顶部的命名空间设置为 Dashboard 时,我使用的是完整的类名引用 (Dashboard\Model\TestModel),所以第一个 Dashboard 是不必要的,并导致 PHP 查找 Dashboard\Dashboard\Model\TestModel。此外,在撰写本文时,ZF2 模块示例很少——我建议查看 EvanDotPro 的 ZfcUser 之类的示例,以获取有关此类事物的示例。

我最初对用于向 ServiceManager 添加类的各种子键的困惑仍然存在,因此,如果您对此有任何见解,我将继续监视这个问题,并将您的答案标记为“该”答案,如果您解决了那一点, 谢谢你 :)。

于 2012-06-23T21:33:27.753 回答