ZF2服务定位器

时间:2013-01-05 18:37:40

标签: zend-framework2

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

$this->getServiceLocator();

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

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

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

感谢。

4 个答案:

答案 0 :(得分:7)

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
}

答案 1 :(得分: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;
    }
}

答案 2 :(得分:0)

在Zend Framework中工作时,我们经常需要自定义帮助程序,这使我们的工作变得简单,在zf1中从帮助程序访问数据库模型很容易,但我不知道如何访问Custom View Helper中的任何表的数据库模型,但是因为我需要它我在视图中通过creatina新数据库适配器对象以不专业的方式解决问题,这从来都不是好方法,但最近我通过非常有趣的方式来了解访问视图助手中的数据库适配器和在那里我必须对任何表执行任何查询,它可能不是那么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-&gt; tableGateway-&gt; 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;
    }

在视图中我将'adapter'对象传递给这样的自定义视图..

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

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

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

谢谢

答案 3 :(得分:-1)

$this->getView()->getHelperPluginManager()->getServiceLocator();