Skip to content

Commit a3b31bb

Browse files
authored
add zend service proxy (#7)
This will allow to inject any zend defined service into a symfony defined service.
1 parent 9f2962e commit a3b31bb

File tree

8 files changed

+160
-8
lines changed

8 files changed

+160
-8
lines changed

README.md

Lines changed: 35 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -52,21 +52,52 @@ return [
5252

5353
# Usage
5454

55-
Any existing service will directly be available through the Service Manager of Zend:
55+
Refer to the documentation of the [Symfony DI Component](https://symfony.com/doc/3.4/components/dependency_injection.html) for information on how to use the DI container.
56+
57+
#### Obtain a symfony defined service
58+
59+
Any existing symfony service will directly be available through the Service Manager of Zend:
5660

5761
```php
5862
<?php
5963

6064
$service = $this->getServiceLocator()->get(\My\Public\Service::class);
6165
```
6266

63-
But you can also retrieve the symfony container:
67+
#### Build a symfony defined service with a Zend service dependency
68+
69+
It will happen that you have to use a dependency which is already loaded into the Zend Service Manager. For example, if you are using the Doctrine Module and you
70+
need to have the instance of the Entity Manager, you can leverage the ZendServiceProxyFactory class:
71+
72+
```yaml
73+
services:
74+
75+
_defaults:
76+
77+
autowire: true # Automatically injects dependencies in your services.
78+
autoconfigure: true # Automatically registers your services as commands, event subscribers, etc.
79+
public: false # Allows optimizing the container by removing unused services; this also means
80+
# fetching services directly from the container via $container->get() won't work.
81+
# The best practice is to be explicit about your dependencies anyway.
82+
83+
#
84+
# Define service that needs to be retrieved via the Zend Service Manager
85+
#
86+
87+
Doctrine\ORM\EntityManagerInterface:
88+
factory: ['Adlogix\ZfSymfonyContainer\Service\Factory\ZendServiceProxyFactory', getService]
89+
arguments: ['@zend.container', 'doctrine.entitymanager.orm_default']
90+
class: Doctrine\ORM\EntityManagerInterface
91+
92+
```
93+
94+
With this configuration, and service defined with the symfony container requiring an instance of Doctrine\ORM\EntityManagerInterface will receive this from
95+
the Zend Service Manager.
6496

97+
#### Obtain the symfony container instance
6598

6699
```php
67100
<?php
68101

69102
$container = $this->getServiceLocator()->get('zf_symfony_container');
70103
```
71-
72-
Refer to the documentation of the [Symfony DI Component](https://symfony.com/doc/3.4/components/dependency_injection.html) for more information on how to use the container.

src/Service/Factory/SymfonyContainerAbstractFactory.php

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,10 @@
1616
use Zend\ServiceManager\ServiceLocatorInterface;
1717

1818
/**
19+
* Abstract Zend factory which will delegate service lookup in the symfony container when available.
20+
*
21+
* This allows to load symfony services transparently via the traditional $serviceLocator->get() method.
22+
*
1923
* @author Toni Van de Voorde <[email protected]>
2024
*/
2125
final class SymfonyContainerAbstractFactory implements AbstractFactoryInterface

src/Service/Factory/SymfonyContainerFactory.php

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -37,10 +37,10 @@ public function createService(ServiceLocatorInterface $serviceLocator)
3737
/**
3838
* {@inheritdoc}
3939
*/
40-
public function __invoke(ContainerInterface $container, $requestedName, array $options = null)
40+
public function __invoke(ContainerInterface $zfContainer, $requestedName, array $options = null)
4141
{
4242
/** @var Configuration $configuration */
43-
$configuration = $container->get('zf_symfony_container_config');
43+
$configuration = $zfContainer->get('zf_symfony_container_config');
4444

4545
$cachedFilePath = $configuration->getCacheDir() . DIRECTORY_SEPARATOR . $configuration->getCacheFilename();
4646

@@ -50,6 +50,13 @@ public function __invoke(ContainerInterface $container, $requestedName, array $o
5050
$containerBuilder = new ContainerBuilder();
5151
$loader = new YamlFileLoader($containerBuilder, new FileLocator([$configuration->getConfigDir()]));
5252
$loader->load('services.yaml');
53+
54+
// Register a synthetic service placement. This is where we are going to inject the zend service manager.
55+
// This is important so we can make use of the ZendServiceProxyFactory
56+
$containerBuilder
57+
->register('zend.container')
58+
->setSynthetic(true);
59+
5360
$containerBuilder->compile();
5461

5562
$dumper = new PhpDumper($containerBuilder);
@@ -64,6 +71,9 @@ public function __invoke(ContainerInterface $container, $requestedName, array $o
6471

6572
require_once $cachedFilePath;
6673

67-
return new \Adlogix\ZfSymfonyContainer\DependencyInjection\CachedContainer();
74+
$cachedContainer = new \Adlogix\ZfSymfonyContainer\DependencyInjection\CachedContainer();
75+
$cachedContainer->set('zend.container', $zfContainer);
76+
77+
return $cachedContainer;
6878
}
6979
}
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
<?php
2+
/*
3+
* This file is part of the Adlogix package.
4+
*
5+
* (c) Allan Segebarth <[email protected]>
6+
* (c) Jean-Jacques Courtens <[email protected]>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
namespace Adlogix\ZfSymfonyContainer\Service\Factory;
13+
14+
use Interop\Container\ContainerInterface;
15+
16+
/**
17+
* A symfony container factory, allowing the load zend specific services. This is crucial when requiring to load
18+
* services that have been injected in the Zend service manager through e.g. third party modules.
19+
*
20+
* @author Toni Van de Voorde <[email protected]>
21+
*/
22+
final class ZendServiceProxyFactory
23+
{
24+
/**
25+
* @param ContainerInterface $container
26+
* @param string $service
27+
*
28+
* @return mixed
29+
*/
30+
public static function getService(ContainerInterface $container, $service)
31+
{
32+
return $container->get($service);
33+
}
34+
}

tests/Fixtures/Zend/DummyThree.php

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
<?php
2+
/*
3+
* This file is part of the Adlogix package.
4+
*
5+
* (c) Allan Segebarth <[email protected]>
6+
* (c) Jean-Jacques Courtens <[email protected]>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
namespace Adlogix\ZfSymfonyContainer\Test\Fixtures\Zend;
13+
14+
class DummyThree
15+
{
16+
}
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
<?php
2+
/*
3+
* This file is part of the Adlogix package.
4+
*
5+
* (c) Allan Segebarth <[email protected]>
6+
* (c) Jean-Jacques Courtens <[email protected]>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
namespace Adlogix\ZfSymfonyContainer\Test\Service\Factory;
13+
14+
use Adlogix\ZfSymfonyContainer\Test\Fixtures\Zend\DummyThree;
15+
use Adlogix\ZfSymfonyContainer\Test\Util\ServiceManagerFactory;
16+
use PHPUnit\Framework\TestCase;
17+
use Symfony\Component\DependencyInjection\ContainerInterface;
18+
19+
/**
20+
* @author Toni Van de Voorde <[email protected]>
21+
*/
22+
final class ZendServiceProxyFactoryTest extends TestCase
23+
{
24+
/**
25+
* @test
26+
*/
27+
public function getService_givenAnExistingZendService_shouldReturnTheService()
28+
{
29+
/** @var ContainerInterface $container */
30+
$container = ServiceManagerFactory::getServiceManager()
31+
->get('zf_symfony_container');
32+
33+
$dummy = $container->get(DummyThree::class);
34+
35+
$this->assertInstanceOf(DummyThree::class, $dummy);
36+
}
37+
}

tests/sandbox/config/services.yaml

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,5 +4,15 @@ services:
44

55
autowire: true # Automatically injects dependencies in your services.
66

7+
#
8+
# Define service that needs to be retrieved via the Zend Service Manager
9+
#
10+
11+
Adlogix\ZfSymfonyContainer\Test\Fixtures\Zend\DummyThree:
12+
factory: ['Adlogix\ZfSymfonyContainer\Service\Factory\ZendServiceProxyFactory', getService]
13+
arguments: ['@zend.container', 'Adlogix\ZfSymfonyContainer\Test\Fixtures\Zend\DummyThree']
14+
class: Adlogix\ZfSymfonyContainer\Test\Fixtures\Zend\DummyThree
15+
716
Adlogix\ZfSymfonyContainer\Test\Fixtures\:
8-
resource: '../../Fixtures/*'
17+
resource: '../../Fixtures/*'
18+
exclude: '../../Fixtures/Zend/*'

tests/testing.config.php

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@
99
* file that was distributed with this source code.
1010
*/
1111

12+
use Adlogix\ZfSymfonyContainer\Test\Fixtures\Zend\DummyThree;
13+
1214
return [
1315

1416
'zf_symfony_container' => [
@@ -27,4 +29,12 @@
2729

2830
],
2931
],
32+
33+
'service_manager' => [
34+
35+
'invokables' => [
36+
DummyThree::class => DummyThree::class
37+
]
38+
39+
]
3040
];

0 commit comments

Comments
 (0)