翻译进度
2
分块数量
1
参与人数

5.3. Zend Framework 1

这是一篇协同翻译的文章,你可以点击『我来翻译』按钮来参与翻译。


PHP-DI in Zend Framework 1

Set up

If you are using ZF1, PHP-DI provides easy and clean integration so that you don't have
to call the container (thus avoiding the Service Locator pattern).

First, install the bridge to ZF1:

composer require php-di/zf1-bridge

To use PHP-DI in your ZF1 application, you need to change the Dispatcher used by the Front Controller in the Bootstrap.

    protected function _initContainer()
    {
        $builder = new \DI\ContainerBuilder();
        $builder->useAnnotations(true);
        $container = $builder->build();

        $dispatcher = new \DI\Bridge\ZendFramework1\Dispatcher();
        $dispatcher->setContainer($container);

        Zend_Controller_Front::getInstance()->setDispatcher($dispatcher);
    }

That's it!

As you can see since PHP-DI 5 it's necessary to enable annotations because they are disabled by default.

Warning: if you use Zend's autoloader (and not Composer), you will need to configure it:

$autoloader->suppressNotFoundWarnings(true);

Usage

Now you can inject dependencies in your controllers!

For example, here is the GuestbookController of the quickstart:

class GuestbookController extends Zend_Controller_Action
{
    /**
     * This dependency will be injected by PHP-DI
     * @Inject
     * @var Application_Service_GuestbookService
     */
    private $guestbookService;

    public function indexAction()
    {
        $this->view->entries = $this->guestbookService->getAllEntries();
    }
}

Recommended layout

Here is a recommended layout for your configuration:

application/
    configs/
        application.ini          # ZF config
        config.php               # DI config
        config.development.php   # DI config for development
        config.production.php    # DI config for production
        parameters.php           # Local parameters (DB password, …) -> Don't commit this file
        parameters.php.default   # Template for parameters.php -> Commit this file
    Bootstrap.php

Here is an example of the full Bootstrap method:

    protected function _initContainer()
    {
        $configuration = new Zend_Config($this->getOptions());

        $builder = new ContainerBuilder();
        $builder->addDefinitions(APPLICATION_PATH . '/configs/config.php');
        $builder->addDefinitions(APPLICATION_PATH . '/configs/config.' . APPLICATION_ENV . '.php');
        $builder->addDefinitions(APPLICATION_PATH . '/configs/parameters.php');

        if (APPLICATION_ENV === 'production') {
            $cache = new MemcachedCache();
            $memcached = new Memcached();
            $memcached->addServer('localhost', 11211);
            $cache->setMemcached($memcached);
        } else {
            $cache = new ArrayCache();
        }
        $cache->setNamespace('MyApp');
        $builder->setDefinitionCache($cache);

        $this->container = $builder->build();

        $dispatcher = new \DI\Bridge\ZendFramework1\Dispatcher();
        $dispatcher->setContainer($this->container);
        Zend_Controller_Front::getInstance()->setDispatcher($dispatcher);
    }

You are not required to follow it of course.

Tests

Zend Framework 1 provides a base class to test controllers.
If you are using this base class, and you want to have full control on the dependencies that will be injected
inside the controller you are testing (for example to inject mocks), here is a recommended approach:

class UserControllerTest extends Zend_Test_PHPUnit_ControllerTestCase
{
    private $container;

    public function setUp()
    {
        $this->bootstrap = array($this, 'appBootstrap');
        parent::setUp();
    }

    public function appBootstrap()
    {
        $builder = new ContainerBuilder();
        // Configure your container here
        $builder->addDefinitions(__DIR__ . '/../../application/config/config.php');
        $this->container = $builder->build();

        $dispatcher = new \DI\Bridge\ZendFramework1\Dispatcher();
        $dispatcher->setContainer($this->container);

        $this->frontController->setDispatcher($dispatcher);
    }

    public function testCallWithoutActionShouldPullFromIndexAction()
    {
        // Here I can override the dependencies that will be injected
        $fakeEntityManager = $this->getMock(...);
        $this->container->set('Doctrine\ORM\EntityManager', $fakeEntityManager);

        $this->dispatch('/user');
        $this->assertController('user');
        $this->assertAction('index');
    }
}

How it works: a new container is created for each test, which ensures that whatever you do
with the container in one test will not affect the others.

Obviously, the setUp() and appBootstrap() methods could go in a base abstract class.

More

Read more on the ZF1-Bridge project on GitHub.

(这段是本节的开头,原文并没有,无须翻译)

郁雁 翻译于 2年前

本文章首发在 LearnKu.com 网站上。

本文中的所有译文仅用于学习和交流目的,转载请务必注明文章译者、出处、和本文链接
我们的翻译工作遵照 CC 协议,如果我们的工作有侵犯到您的权益,请及时联系我们。

贡献者:1
讨论数量: 0
发起讨论 只看当前版本


暂无话题~