【问题标题】:ZF2 Service LocatorZF2 服务定位器
【发布时间】:2013-01-05 18:37:39
【问题描述】:

我对 zf2 很陌生,我正在试验它。我有一个视图助手,我需要它来访问一个表对象。在我的控制器中我可以运行:

$this->getServiceLocator();

但理想情况下,我会在我的视图助手中运行它。不幸的是,我似乎无法从我的视图助手中访问它。我尝试通过构造函数传递它,在 module.config.php 中配置工厂方法,但是当我尝试这样做时,Zend 将不再将 tablegateway 对象传递给我从模块模块中的服务工厂方法创建的模型对象之一。 .php 文件。这似乎是因为它不再调用工厂方法,而是选择在没有任何参数的情况下运行实例化。

我不确定我是否理解为什么视图工厂方法会影响具有不同名称的一组不同的工厂方法。

谁能告诉我我在做什么有什么问题?我可以提供更多细节,但在不提供整个代码库的情况下,我不清楚哪些细节实际上很重要。

谢谢。

【问题讨论】:

标签: zend-framework2


【解决方案1】:

Crisp 确实为您的问题提供了有效答案,但我建议您更进一步。服务定位器的注入使您的视图助手与框架和服务定位器模式紧密耦合并且容易受到攻击,因为应用程序中的每段代码都可以修改服务定位器中的每个服务。

are reasons to inject your dependency directly,所以你只依赖于你的依赖项,你不再实现这个反模式。假设您的视图助手依赖于MyModule\Model\MyTable,那么您的视图助手的构造函数将如下所示:

namespace MyModule;

use MyModule\Model\MyTable;
use Zend\View\Helper\AbstractHelper;

class MyViewHelper extends AbstractHelper
{
  protected $table;

  public function __construct(MyTable $table)
  {
    $this->table = $table;
  }
}

正如您所指出的,您现在只需注入您的MyTable

namespace MyModule;

class Module
{
  public function getViewHelperConfig()
  {
    return array(
      'factories' => array(
        'MyViewHelper' => function($sm) {
          $sm = $sm->getServiceLocator(); // $sm was the view helper's locator
          $table = $sm->get('MyModule_MyTable');

          $helper = new MyModule\View\Helper\MyHelper($table);
          return $helper;
        }
      )
    );
  }
}

请注意,在视图助手工厂中,您的服务管理器是视图助手的服务管理器,而不是注册表的“主要”服务管理器(另请参阅blog post of I wrote earlier)。 $sm->getServiceLocator() 为您解决这个问题。

我不确定我是否理解为什么视图工厂方法会影响具有不同名称的一组不同的工厂方法。

并非如此,因此您的代码中可能存在错误。如果上述方法不起作用,请提供有关您的服务管理器配置的更多详细信息,以便我更新答案。

上述方法的一大优点是您可以让视图助手的单元测试变得非常容易。您可以模拟表网关并专注于视图助手的完整行为。

use MyModule\View\Helper\MyHelper;

public function testHelperusesTable
{
  $mock   = $this->getMock('MyModule\Model\MyTable');
  $helper = new MyHelper($mock);

  // Test your $helper now
}

【讨论】:

  • 问题原来是我应该使用服务定位器时使用了服务管理器。我没有检查对象类型,因为我常用的方法(print_r、debug_backtrace 等)会导致大量内存短缺。此外,它们似乎都有一个“get”方法,似乎可以理解工厂方法的路径,但似乎只有一个方法实际运行了该方法。
【解决方案2】:

您可以从 Module.php 中的视图助手配置中将服务定位器注入到您的视图助手中

// Application/Module.php

public function getViewHelperConfig()
{
    return array(
        'factories' => array(
            'myViewHelper' => function ($serviceManager) {
                // Get the service locator 
                $serviceLocator = $serviceManager->getServiceLocator();
                // pass it to your helper 
                return new \Application\View\Helper\MyViewHelper($serviceLocator);
            }
        )
    );
}

在你看来是帮手

<?php
namespace Application\View\Helper;

use Zend\View\Helper\AbstractHelper,
    Zend\ServiceManager\ServiceLocatorInterface as ServiceLocator;

class MyViewHelper extends AbstractHelper
{
    protected $serviceLocator;

    public function __construct(ServiceLocator $serviceLocator)
    {
        $this->serviceLocator = $serviceLocator;
    }
}

【讨论】:

  • 这似乎导致不再使用服务工厂方法创建我想要的表对象的相同问题。也许它只是不喜欢有服务工厂方法和查看辅助方法,虽然我不知道为什么它不会。我只会将服务管理器或其他一些对象传递到视图中,直到我更好地理解这一点,就像这样做对我来说似乎一样混乱。
  • 看起来很奇怪,在工厂方法中使用插件、帮助程序或服务时,我没有遇到任何问题,无论是作为具体类还是像我上面给出的示例一样作为闭包。也许您可以稍微扩展一下表对象的问题,我假设它只是使用 dbadapter 和表名来实例化 TableGateway,但也许您还有更多的事情要做?
  • 为了创建表对象,我基本上是按照framework.zend.com/manual/2.0/en/user-guide/…的zf2教程进行的。工厂创建一个对象并像您说的那样传入 TableGateway。事实证明,问题在于我使用的是 ServiceManager 而不是 ServiceLocator。它们似乎都有一个“获取”功能,在每种情况下都做类似的事情,但并不完全相同。然后,猜测一下,ServiceManager::get 将通过不带参数的构造函数为 get 路径运行已知类。感谢您的帮助:)
【解决方案3】:

在 Zend Framework 中工作时,我们经常需要自定义帮助器,这使我们的工作变得容易,在 zf1 中,从帮助器访问数据库模型很容易,但我遇到了如何访问自定义视图帮助器中任何表的数据库模型的问题,但是当我需要它时,我通过在视图中创建新的数据库适配器对象以不专业的方式解决了这个问题,这从来都不是好方法,但最近我通过非常有趣的方式了解了在视图助手中访问数据库适配器和我必须对任何表执行任何查询,它可能不是 Zend F2 方式,而是解决问题的非常简单和简短的方法。

这是我的模型示例...

<?php

namespace Application\Model;

use Zend\Db\TableGateway\TableGateway;

class SlideImageSubTable {

    protected $tableGateway;
    public $adapter;

    public function __construct(TableGateway $tableGateway) {
        $this->tableGateway = $tableGateway;
        $this->adapter = $this->tableGateway->getAdapter();
    }

    public function fetchAll() {
        $resultSet = $this->tableGateway->select();
        return $resultSet;
    }

    public function getSlideImageSub($id) {
        $id = (int) $id;
        $rowset = $this->tableGateway->select(array('id' => $id));
        $row = $rowset->current();
        if (!$row) {
            throw new \Exception("Could not find row $id");
        }
        return $row;
    }

    public function getImageMenu($id) {
        $id = (int) $id;
        $rowset = $this->tableGateway->select(array('slide_image_id' => $id));
        $rows = array_values(iterator_to_array($rowset));
        if (!$rows) {
            throw new \Exception("Could not find row $id");
        }
        return $rows;
    }

    public function saveSlideImageSub(SlideImageSub $slideImageSub) {
        $data = array(
            'slide_image_id' => $slideImageSub->slide_image_id,
            'title' => $slideImageSub->title,
            'description' => $slideImageSub->description
        );

        $id = (int) $slideImageSub->id;
        if ($id == 0) {
            $this->tableGateway->insert($data);
        } else {
            if ($this->getSlideImageSub($id)) {
                $this->tableGateway->update($data, array('id' => $id));
            } else {
                throw new \Exception('Form id does not exist');
            }
        }
    }

    public function deleteSlideImageSub($id) {
        $this->tableGateway->delete(array('id' => $id));
    }

}

看看'public $adapter'公共变量。在构造函数中,我将通过调用 $this->tableGateway->getAdapter(); 来初始化它。方法,getAdapter() 通过网关对象可用。

然后在我的控制器操作视图中,我必须将它分配给任何变量并将该变量传递给查看页面。像这样..

public function equitiesAction() {
        $image_id = $this->params('id');
        $result = $this->getTable('SlideImageSub')->getImageMenu($image_id);
        $adapter = $this->table->adapter;
        $view = new ViewModel(array(
                    'result' => $result,
                    'adapter' => $adapter,
                ));
        return $view;
    }

在视图中,我将“适配器”对象传递给这样的自定义视图..

<?php echo $this->GetMenuProducts( $this->adapter); ?>

现在在自定义视图中,我可以使用此数据库适配器对象并在任何表上创建选择查询。

希望这会对某人有所帮助,我四处寻找在自定义视图助手中使用数据库访问,但提供的配置方法对我不起作用。

谢谢

【讨论】:

    【解决方案4】:
    $this->getView()->getHelperPluginManager()->getServiceLocator();
    

    【讨论】:

    • 这个答案是一年多后添加的,显然没有增加任何价值。请编辑您的答案以澄清我是否错了。
    猜你喜欢
    • 1970-01-01
    • 2013-01-21
    • 2013-05-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-07-03
    • 2018-10-27
    • 2010-11-28
    相关资源
    最近更新 更多