File: zf1.md

package info (click to toggle)
php-di 7.1.1-1
  • links: PTS, VCS
  • area: main
  • in suites: sid
  • size: 2,932 kB
  • sloc: php: 10,572; makefile: 42; xml: 17; sh: 10; pascal: 5
file content (164 lines) | stat: -rw-r--r-- 4,892 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
---
layout: documentation
current_menu: zf1
---

# 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.

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

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

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

That's it!

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

```php
$autoloader->suppressNotFoundWarnings(true);
```

## Usage

Now you can inject dependencies in your controllers!

For example, here is the GuestbookController of the quickstart:

```php
class GuestbookController extends Zend_Controller_Action
{
    /**
     * This dependency will be injected by PHP-DI
     */
    #[Inject]
    private Application_Service_GuestbookService $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:

```php
    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](http://framework.zend.com/manual/1.12/en/zend.test.phpunit.html).
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:

```php
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](https://github.com/PHP-DI/ZF1-Bridge).