Subversion Repositories PHPX

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
39 PointedEar 1
<?php
2
/**
3
 * Zend Framework (http://framework.zend.com/)
4
 *
5
 * @link      http://github.com/zendframework/zf2 for the canonical source repository
6
 * @copyright Copyright (c) 2005-2013 Zend Technologies USA Inc. (http://www.zend.com)
7
 * @license   http://framework.zend.com/license/new-bsd New BSD License
8
 */
9
 
10
namespace Zend\ServiceManager;
11
 
12
/**
13
 * ServiceManager implementation for managing plugins
14
 *
15
 * Automatically registers an initializer which should be used to verify that
16
 * a plugin instance is of a valid type. Additionally, allows plugins to accept
17
 * an array of options for the constructor, which can be used to configure
18
 * the plugin when retrieved. Finally, enables the allowOverride property by
19
 * default to allow registering factories, aliases, and invokables to take
20
 * the place of those provided by the implementing class.
21
 */
22
abstract class AbstractPluginManager extends ServiceManager implements ServiceLocatorAwareInterface
23
{
24
    /**
25
     * Allow overriding by default
26
     *
27
     * @var bool
28
     */
29
    protected $allowOverride = true;
30
 
31
    /**
32
     * Whether or not to auto-add a class as an invokable class if it exists
33
     *
34
     * @var bool
35
     */
36
    protected $autoAddInvokableClass = true;
37
 
38
    /**
39
     * Options to use when creating an instance
40
     *
41
     * @var mixed
42
     */
43
    protected $creationOptions = null;
44
 
45
    /**
46
     * The main service locator
47
     *
48
     * @var ServiceLocatorInterface
49
     */
50
    protected $serviceLocator;
51
 
52
    /**
53
     * Constructor
54
     *
55
     * Add a default initializer to ensure the plugin is valid after instance
56
     * creation.
57
     *
58
     * @param  null|ConfigInterface $configuration
59
     */
60
    public function __construct(ConfigInterface $configuration = null)
61
    {
62
        parent::__construct($configuration);
63
        $self = $this;
64
        $this->addInitializer(function ($instance) use ($self) {
65
            if ($instance instanceof ServiceLocatorAwareInterface) {
66
                $instance->setServiceLocator($self);
67
            }
68
        });
69
    }
70
 
71
    /**
72
     * Validate the plugin
73
     *
74
     * Checks that the filter loaded is either a valid callback or an instance
75
     * of FilterInterface.
76
     *
77
     * @param  mixed $plugin
78
     * @return void
79
     * @throws Exception\RuntimeException if invalid
80
     */
81
    abstract public function validatePlugin($plugin);
82
 
83
    /**
84
     * Retrieve a service from the manager by name
85
     *
86
     * Allows passing an array of options to use when creating the instance.
87
     * createFromInvokable() will use these and pass them to the instance
88
     * constructor if not null and a non-empty array.
89
     *
90
     * @param  string $name
91
     * @param  array $options
92
     * @param  bool $usePeeringServiceManagers
93
     * @return object
94
     */
95
    public function get($name, $options = array(), $usePeeringServiceManagers = true)
96
    {
97
        // Allow specifying a class name directly; registers as an invokable class
98
        if (!$this->has($name) && $this->autoAddInvokableClass && class_exists($name)) {
99
            $this->setInvokableClass($name, $name);
100
        }
101
 
102
        $this->creationOptions = $options;
103
        $instance = parent::get($name, $usePeeringServiceManagers);
104
        $this->creationOptions = null;
105
        $this->validatePlugin($instance);
106
        return $instance;
107
    }
108
 
109
    /**
110
     * Register a service with the locator.
111
     *
112
     * Validates that the service object via validatePlugin() prior to
113
     * attempting to register it.
114
     *
115
     * @param  string $name
116
     * @param  mixed $service
117
     * @param  bool $shared
118
     * @return AbstractPluginManager
119
     * @throws Exception\InvalidServiceNameException
120
     */
121
    public function setService($name, $service, $shared = true)
122
    {
123
        if ($service) {
124
            $this->validatePlugin($service);
125
        }
126
        parent::setService($name, $service, $shared);
127
        return $this;
128
    }
129
 
130
    /**
131
     * Set the main service locator so factories can have access to it to pull deps
132
     *
133
     * @param ServiceLocatorInterface $serviceLocator
134
     * @return AbstractPluginManager
135
     */
136
    public function setServiceLocator(ServiceLocatorInterface $serviceLocator)
137
    {
138
        $this->serviceLocator = $serviceLocator;
139
        return $this;
140
    }
141
 
142
    /**
143
     * Get the main plugin manager. Useful for fetching dependencies from within factories.
144
     *
145
     * @return mixed
146
     */
147
    public function getServiceLocator()
148
    {
149
        return $this->serviceLocator;
150
    }
151
 
152
    /**
153
     * Attempt to create an instance via an invokable class
154
     *
155
     * Overrides parent implementation by passing $creationOptions to the
156
     * constructor, if non-null.
157
     *
158
     * @param  string $canonicalName
159
     * @param  string $requestedName
160
     * @return null|\stdClass
161
     * @throws Exception\ServiceNotCreatedException If resolved class does not exist
162
     */
163
    protected function createFromInvokable($canonicalName, $requestedName)
164
    {
165
        $invokable = $this->invokableClasses[$canonicalName];
166
 
167
        if (null === $this->creationOptions
168
            || (is_array($this->creationOptions) && empty($this->creationOptions))
169
        ) {
170
            $instance = new $invokable();
171
        } else {
172
            $instance = new $invokable($this->creationOptions);
173
        }
174
 
175
        return $instance;
176
    }
177
 
178
    /**
179
     * Attempt to create an instance via a factory class
180
     *
181
     * Overrides parent implementation by passing $creationOptions to the
182
     * constructor, if non-null.
183
     *
184
     * @param  string $canonicalName
185
     * @param  string $requestedName
186
     * @return mixed
187
     * @throws Exception\ServiceNotCreatedException If factory is not callable
188
     */
189
    protected function createFromFactory($canonicalName, $requestedName)
190
    {
191
        $factory = $this->factories[$canonicalName];
192
        if (is_string($factory) && class_exists($factory, true)) {
193
            if (null === $this->creationOptions || (is_array($this->creationOptions) && empty($this->creationOptions))) {
194
                $factory = new $factory();
195
            } else {
196
                $factory = new $factory($this->creationOptions);
197
            }
198
 
199
            $this->factories[$canonicalName] = $factory;
200
        }
201
 
202
        if ($factory instanceof FactoryInterface) {
203
            $instance = $this->createServiceViaCallback(array($factory, 'createService'), $canonicalName, $requestedName);
204
        } elseif (is_callable($factory)) {
205
            $instance = $this->createServiceViaCallback($factory, $canonicalName, $requestedName);
206
        } else {
207
            throw new Exception\ServiceNotCreatedException(sprintf(
208
                'While attempting to create %s%s an invalid factory was registered for this instance type.', $canonicalName, ($requestedName ? '(alias: ' . $requestedName . ')' : '')
209
            ));
210
        }
211
 
212
        return $instance;
213
    }
214
}