Skip to content
This repository was archived by the owner on Jan 29, 2020. It is now read-only.

Commit 5ba7039

Browse files
committed
Reinstate factory logic, but raise exceptions for zend-servicemanager v3 usage
This patch reinstates the code removed in 2.7.9, and updates the docblocks to remove narrative indicating that they extend counterparts in zend-servicemanager-di. Additionally, the DiAbstractServiceFactoryFactory and DiServiceInitializerFactory were updated to raise exceptions if they detect that the relevant `Zend\ServiceManager\Di` artifacts are not present.
1 parent be1656d commit 5ba7039

7 files changed

+372
-28
lines changed

src/Service/DiAbstractServiceFactoryFactory.php

Lines changed: 50 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -9,17 +9,60 @@
99

1010
namespace Zend\Mvc\Service;
1111

12-
use Zend\ServiceManager\Di\DiAbstractServiceFactoryFactory as OriginalFactory;
12+
use Interop\Container\ContainerInterface;
13+
use Zend\Mvc\Exception;
14+
use Zend\ServiceManager\Di\DiAbstractServiceFactory;
15+
use Zend\ServiceManager\FactoryInterface;
16+
use Zend\ServiceManager\ServiceLocatorInterface;
17+
use Zend\ServiceManager\ServiceManager;
1318

1419
/**
15-
* Since 2.7.9, this class now extends the version defined in zend-servicemanager-di,
16-
* ensuring backwards compatibility with zend-servicemanger v2 and forwards
17-
* compatibility with zend-servicemanager v3.
18-
*
1920
* @deprecated Since 2.7.9. The factory is now defined in zend-servicemanager-di,
2021
* and removed in 3.0.0. Use Zend\ServiceManager\Di\DiAbstractServiceFactoryFactory
21-
* from zend-servicemanager-di instead if you rely on this feature.
22+
* from zend-servicemanager-di if you are using zend-servicemanager v3, and/or when
23+
* ready to migrate to zend-mvc 3.0.
2224
*/
23-
class DiAbstractServiceFactoryFactory extends OriginalFactory
25+
class DiAbstractServiceFactoryFactory implements FactoryInterface
2426
{
27+
/**
28+
* Class responsible for instantiating a DiAbstractServiceFactory
29+
*
30+
* @param ContainerInterface $container
31+
* @param string $name
32+
* @param null|array $options
33+
* @return DiAbstractServiceFactory
34+
* @throws Exception\RuntimeException if zend-servicemanager v3 is in use.
35+
*/
36+
public function __invoke(ContainerInterface $container, $name, array $options = null)
37+
{
38+
if (! class_exists(DiAbstractServiceFactory::class)) {
39+
throw new Exception\RuntimeException(sprintf(
40+
"%s is not compatible with zend-servicemanager v3, which you are currently using. \n"
41+
. "Please run 'composer require zendframework/zend-servicemanager-di', and then update\n"
42+
. "your configuration to use Zend\ServiceManager\Di\DiAbstractServiceFactoryFactory instead.",
43+
__CLASS__
44+
));
45+
}
46+
47+
$factory = new DiAbstractServiceFactory($container->get('Di'), DiAbstractServiceFactory::USE_SL_BEFORE_DI);
48+
49+
if ($container instanceof ServiceManager) {
50+
$container->addAbstractFactory($factory, false);
51+
}
52+
53+
return $factory;
54+
}
55+
56+
/**
57+
* Create and return DiAbstractServiceFactory instance
58+
*
59+
* For use with zend-servicemanager v2; proxies to __invoke().
60+
*
61+
* @param ServiceLocatorInterface $container
62+
* @return DiAbstractServiceFactory
63+
*/
64+
public function createService(ServiceLocatorInterface $container)
65+
{
66+
return $this($container, DiAbstractServiceFactory::class);
67+
}
2568
}

src/Service/DiFactory.php

Lines changed: 47 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -9,17 +9,57 @@
99

1010
namespace Zend\Mvc\Service;
1111

12-
use Zend\ServiceManager\Di\DiFactory as OriginalFactory;
12+
use Interop\Container\ContainerInterface;
13+
use Zend\Di\Config;
14+
use Zend\Di\Di;
15+
use Zend\ServiceManager\FactoryInterface;
16+
use Zend\ServiceManager\ServiceLocatorInterface;
1317

1418
/**
15-
* Since 2.7.9, this class now extends the version defined in zend-servicemanager-di,
16-
* ensuring backwards compatibility with zend-servicemanger v2 and forwards
17-
* compatibility with zend-servicemanager v3.
18-
*
1919
* @deprecated Since 2.7.9. The factory is now defined in zend-servicemanager-di,
2020
* and removed in 3.0.0. Use Zend\ServiceManager\Di\DiFactory from
21-
* zend-servicemanager-di instead if you rely on this feature.
21+
* from zend-servicemanager-di if you are using zend-servicemanager v3, and/or when
22+
* ready to migrate to zend-mvc 3.0.
2223
*/
23-
class DiFactory extends OriginalFactory
24+
class DiFactory implements FactoryInterface
2425
{
26+
/**
27+
* Create and return abstract factory seeded by dependency injector
28+
*
29+
* Creates and returns an abstract factory seeded by the dependency
30+
* injector. If the "di" key of the configuration service is set, that
31+
* sub-array is passed to a DiConfig object and used to configure
32+
* the DI instance. The DI instance is then used to seed the
33+
* DiAbstractServiceFactory, which is then registered with the service
34+
* manager.
35+
*
36+
* @param ContainerInterface $container
37+
* @param string $name
38+
* @param null|array $options
39+
* @return Di
40+
*/
41+
public function __invoke(ContainerInterface $container, $name, array $options = null)
42+
{
43+
$di = new Di();
44+
$config = $container->has('config') ? $container->get('config') : [];
45+
46+
if (isset($config['di'])) {
47+
(new Config($config['di']))->configure($di);
48+
}
49+
50+
return $di;
51+
}
52+
53+
/**
54+
* Create and return Di instance
55+
*
56+
* For use with zend-servicemanager v2; proxies to __invoke().
57+
*
58+
* @param ServiceLocatorInterface $container
59+
* @return Di
60+
*/
61+
public function createService(ServiceLocatorInterface $container)
62+
{
63+
return $this($container, Di::class);
64+
}
2565
}

src/Service/DiServiceInitializerFactory.php

Lines changed: 43 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -9,17 +9,53 @@
99

1010
namespace Zend\Mvc\Service;
1111

12-
use Zend\ServiceManager\Di\DiServiceInitializerFactory as OriginalFactory;
12+
use Interop\Container\ContainerInterface;
13+
use Zend\Mvc\Exception;
14+
use Zend\ServiceManager\Di\DiServiceInitializer;
15+
use Zend\ServiceManager\FactoryInterface;
16+
use Zend\ServiceManager\ServiceLocatorInterface;
17+
use Zend\ServiceManager\ServiceManager;
1318

1419
/**
15-
* Since 2.7.9, this class now extends the version defined in zend-servicemanager-di,
16-
* ensuring backwards compatibility with zend-servicemanger v2 and forwards
17-
* compatibility with zend-servicemanager v3.
18-
*
1920
* @deprecated Since 2.7.9. The factory is now defined in zend-servicemanager-di,
2021
* and removed in 3.0.0. Use Zend\ServiceManager\Di\DiServiceInitializerFactory
21-
* from zend-servicemanager-di instead if you rely on this feature.
22+
* from zend-servicemanager-di if you are using zend-servicemanager v3, and/or when
23+
* ready to migrate to zend-mvc 3.0.
2224
*/
23-
class DiServiceInitializerFactory extends OriginalFactory
25+
class DiServiceInitializerFactory implements FactoryInterface
2426
{
27+
/**
28+
* Class responsible for instantiating a DiServiceInitializer
29+
*
30+
* @param ContainerInterface $container
31+
* @param string $name
32+
* @param null|array $options
33+
* @return DiServiceInitializer
34+
*/
35+
public function __invoke(ContainerInterface $container, $requestedName, array $options = null)
36+
{
37+
if (! class_exists(DiServiceInitializer::class)) {
38+
throw new Exception\RuntimeException(sprintf(
39+
"%s is not compatible with zend-servicemanager v3, which you are currently using. \n"
40+
. "Please run 'composer require zendframework/zend-servicemanager-di', and then update\n"
41+
. "your configuration to use Zend\ServiceManager\Di\DiServiceInitializerFactory instead.",
42+
__CLASS__
43+
));
44+
}
45+
46+
return new DiServiceInitializer($container->get('Di'), $container);
47+
}
48+
49+
/**
50+
* Create and return DiServiceInitializer instance
51+
*
52+
* For use with zend-servicemanager v2; proxies to __invoke().
53+
*
54+
* @param ServiceLocatorInterface $container
55+
* @return DiServiceInitializer
56+
*/
57+
public function createService(ServiceLocatorInterface $container)
58+
{
59+
return $this($container, DiServiceInitializer::class);
60+
}
2561
}

src/Service/DiStrictAbstractServiceFactory.php

Lines changed: 172 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -9,17 +9,183 @@
99

1010
namespace Zend\Mvc\Service;
1111

12-
use Zend\ServiceManager\Di\DiStrictAbstractServiceFactory as OriginalFactory;
12+
use Interop\Container\ContainerInterface;
13+
use Zend\Di\Di;
14+
use Zend\Di\Exception\ClassNotFoundException;
15+
use Zend\ServiceManager\AbstractFactoryInterface;
16+
use Zend\ServiceManager\AbstractPluginManager;
17+
use Zend\ServiceManager\Exception;
18+
use Zend\ServiceManager\ServiceLocatorInterface;
1319

1420
/**
15-
* Since 2.7.9, this class now extends the version defined in zend-servicemanager-di,
16-
* ensuring backwards compatibility with zend-servicemanger v2 and forwards
17-
* compatibility with zend-servicemanager v3.
21+
* Create and return instances from a DI container and/or the parent container.
22+
*
23+
* This abstract factory can be mapped to arbitrary class names, and used to
24+
* pull them from the composed Di instance, using the following behaviors:
25+
*
26+
* - If USE_SL_BEFORE_DI is passed as the second argument to the constructor,
27+
* the factory will attempt to fetch the service from the passed container
28+
* first, and fall back to the composed DI container only on failure.
29+
* - If USE_SL_AFTER_DI is passed as the second argument to the constructor,
30+
* the factory will attempt to fetch the service from the composed DI
31+
* container first, and fall back to the passed container only on failure.
32+
* - If USE_SL_NONE is passed as the second argument to the constructor (or no
33+
* argument is passed), then the factory will only fetch from the composed
34+
* DI container.
35+
*
36+
* Unlike DiAbstractServiceFactory and DiServiceFactory, this abstract factory
37+
* requires that classes requested are in a provided whitelist; if the requested
38+
* service is not, an exception is raised. This is useful to provide a scoped
39+
* container, e.g., to limit to known controller classes, etc.
1840
*
1941
* @deprecated Since 2.7.9. The factory is now defined in zend-servicemanager-di,
2042
* and removed in 3.0.0. Use Zend\ServiceManager\Di\DiStrictAbstractServiceFactory
21-
* from zend-servicemanager-di instead if you rely on this feature.
43+
* from zend-servicemanager-di if you are using zend-servicemanager v3, and/or when
44+
* ready to migrate to zend-mvc 3.0.
2245
*/
23-
class DiStrictAbstractServiceFactory extends OriginalFactory
46+
class DiStrictAbstractServiceFactory extends Di implements AbstractFactoryInterface
2447
{
48+
/**@#+
49+
* constants
50+
*/
51+
const USE_SL_BEFORE_DI = 'before';
52+
const USE_SL_AFTER_DI = 'after';
53+
const USE_SL_NONE = 'none';
54+
/**@#-*/
55+
56+
/**
57+
* @var Di
58+
*/
59+
protected $di = null;
60+
61+
/**
62+
* @var string
63+
*/
64+
protected $useContainer = self::USE_SL_AFTER_DI;
65+
66+
/**
67+
* @var ContainerInterface
68+
*/
69+
protected $container = null;
70+
71+
/**
72+
* @var array an array of whitelisted service names (keys are the service names)
73+
*/
74+
protected $allowedServiceNames = [];
75+
76+
/**
77+
* @param Di $di
78+
* @param string $useContainer
79+
*/
80+
public function __construct(Di $di, $useContainer = self::USE_SL_NONE)
81+
{
82+
$this->useContainer = $useContainer;
83+
84+
// Since we are using this in a proxy-fashion, localize state
85+
$this->di = $di;
86+
$this->definitions = $this->di->definitions;
87+
$this->instanceManager = $this->di->instanceManager;
88+
}
89+
90+
/**
91+
* @param array $allowedServiceNames
92+
*/
93+
public function setAllowedServiceNames(array $allowedServiceNames)
94+
{
95+
$this->allowedServiceNames = array_flip(array_values($allowedServiceNames));
96+
}
97+
98+
/**
99+
* @return array
100+
*/
101+
public function getAllowedServiceNames()
102+
{
103+
return array_keys($this->allowedServiceNames);
104+
}
105+
106+
/**
107+
* {@inheritDoc}
108+
*
109+
* Allows creation of services only when in a whitelist
110+
*/
111+
public function __invoke(ContainerInterface $container, $name, array $options = null)
112+
{
113+
if (! isset($this->allowedServiceNames[$name])) {
114+
throw new Exception\InvalidServiceException(sprintf(
115+
'Service "%s" is not whitelisted',
116+
$name
117+
));
118+
}
119+
120+
$this->container = ($container instanceof AbstractPluginManager)
121+
? $container->getServiceLocator()
122+
: $container;
123+
124+
return parent::get($name);
125+
}
126+
127+
/**
128+
* {@inheritDoc}
129+
*
130+
* For use with zend-servicemanager v2; proxies to __invoke().
131+
*/
132+
public function createServiceWithName(ServiceLocatorInterface $container, $serviceName, $requestedName)
133+
{
134+
return $this($container, $requestedName);
135+
}
136+
137+
/**
138+
* Overrides Zend\Di to allow the given container's services to be reused by Di itself
139+
*
140+
* {@inheritDoc}
141+
*
142+
* @throws Exception\InvalidServiceNameException
143+
*/
144+
public function get($name, array $params = [])
145+
{
146+
if (null === $this->container) {
147+
throw new Exception\DomainException(
148+
'No ServiceLocator defined, use `createServiceWithName` instead of `get`'
149+
);
150+
}
151+
152+
if (self::USE_SL_BEFORE_DI === $this->useContainer && $this->container->has($name)) {
153+
return $this->container->get($name);
154+
}
155+
156+
try {
157+
return parent::get($name, $params);
158+
} catch (ClassNotFoundException $e) {
159+
if (self::USE_SL_AFTER_DI === $this->useContainer && $this->container->has($name)) {
160+
return $this->container->get($name);
161+
}
162+
163+
throw new Exception\ServiceNotFoundException(
164+
sprintf('Service %s was not found in this DI instance', $name),
165+
null,
166+
$e
167+
);
168+
}
169+
}
170+
171+
/**
172+
* {@inheritDoc}
173+
*
174+
* Allows creation of services only when in a whitelist.
175+
*/
176+
public function canCreate(ContainerInterface $container, $requestedName)
177+
{
178+
// won't check if the service exists, we are trusting the user's whitelist
179+
return isset($this->allowedServiceNames[$requestedName]);
180+
}
181+
182+
/**
183+
* {@inheritDoc}
184+
*
185+
* For use with zend-servicemanager v2; proxies to canCreate().
186+
*/
187+
public function canCreateServiceWithName(ServiceLocatorInterface $container, $name, $requestedName)
188+
{
189+
return $this->canCreate($container, $requestedName);
190+
}
25191
}

src/Service/DiStrictAbstractServiceFactoryFactory.php

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,8 @@
1616
/**
1717
* @deprecated Since 2.7.9. The factory is now defined in zend-servicemanager-di,
1818
* and removed in 3.0.0. Use Zend\ServiceManager\Di\DiStrictAbstractServiceFactoryFactory
19-
* from zend-servicemanager-di instead if you rely on this feature.
19+
* from zend-servicemanager-di if you are using zend-servicemanager v3, and/or when
20+
* ready to migrate to zend-mvc 3.0.
2021
*/
2122
class DiStrictAbstractServiceFactoryFactory implements FactoryInterface
2223
{

0 commit comments

Comments
 (0)