Added the zend framework 2 library, the path is specified in line no.26 in zend_modul...
[openemr.git] / interface / modules / zend_modules / library / Zend / Di / ServiceLocator / Generator.php
bloba7182590db61641535ed21dcb139d869d3769f56
1 <?php
2 /**
3 * Zend Framework (http://framework.zend.com/)
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 */
10 namespace Zend\Di\ServiceLocator;
12 use Zend\Code\Generator\ClassGenerator;
13 use Zend\Code\Generator\FileGenerator;
14 use Zend\Code\Generator\MethodGenerator;
15 use Zend\Code\Generator\ParameterGenerator;
16 use Zend\Di\Di;
17 use Zend\Di\Exception;
19 /**
20 * Generator that creates the body of a service locator that can emulate the logic of the given Zend\Di\Di instance
21 * without class definitions
23 class Generator
25 protected $containerClass = 'ApplicationContext';
27 /** @var DependencyInjectorProxy */
28 protected $injector;
30 /**
31 * @var null|string
33 protected $namespace;
35 /**
36 * Constructor
38 * Requires a DependencyInjection manager on which to operate.
40 * @param Di $injector
42 public function __construct(Di $injector)
44 $this->injector = new DependencyInjectorProxy($injector);
47 /**
48 * Set the class name for the generated service locator container
50 * @param string $name
51 * @return Generator
53 public function setContainerClass($name)
55 $this->containerClass = $name;
57 return $this;
60 /**
61 * Set the namespace to use for the generated class file
63 * @param string $namespace
64 * @return Generator
66 public function setNamespace($namespace)
68 $this->namespace = $namespace;
70 return $this;
73 /**
74 * Construct, configure, and return a PHP class file code generation object
76 * Creates a Zend\Code\Generator\FileGenerator object that has
77 * created the specified class and service locator methods.
79 * @param null|string $filename
80 * @throws \Zend\Di\Exception\RuntimeException
81 * @return FileGenerator
83 public function getCodeGenerator($filename = null)
85 $injector = $this->injector;
86 $im = $injector->instanceManager();
87 $indent = ' ';
88 $aliases = $this->reduceAliases($im->getAliases());
89 $caseStatements = array();
90 $getters = array();
91 $definitions = $injector->definitions();
93 $fetched = array_unique(array_merge($definitions->getClasses(), $im->getAliases()));
95 foreach ($fetched as $name) {
96 $getter = $this->normalizeAlias($name);
97 $meta = $injector->get($name);
98 $params = $meta->getParams();
100 // Build parameter list for instantiation
101 foreach ($params as $key => $param) {
102 if (null === $param || is_scalar($param) || is_array($param)) {
103 $string = var_export($param, 1);
104 if (strstr($string, '::__set_state(')) {
105 throw new Exception\RuntimeException('Arguments in definitions may not contain objects');
107 $params[$key] = $string;
108 } elseif ($param instanceof GeneratorInstance) {
109 /* @var $param GeneratorInstance */
110 $params[$key] = sprintf('$this->%s()', $this->normalizeAlias($param->getName()));
111 } else {
112 $message = sprintf('Unable to use object arguments when building containers. Encountered with "%s", parameter of type "%s"', $name, get_class($param));
113 throw new Exception\RuntimeException($message);
117 // Strip null arguments from the end of the params list
118 $reverseParams = array_reverse($params, true);
119 foreach ($reverseParams as $key => $param) {
120 if ('NULL' === $param) {
121 unset($params[$key]);
122 continue;
124 break;
127 // Create instantiation code
128 $constructor = $meta->getConstructor();
129 if ('__construct' != $constructor) {
130 // Constructor callback
131 $callback = var_export($constructor, 1);
132 if (strstr($callback, '::__set_state(')) {
133 throw new Exception\RuntimeException('Unable to build containers that use callbacks requiring object instances');
135 if (count($params)) {
136 $creation = sprintf('$object = call_user_func(%s, %s);', $callback, implode(', ', $params));
137 } else {
138 $creation = sprintf('$object = call_user_func(%s);', $callback);
140 } else {
141 // Normal instantiation
142 $className = '\\' . ltrim($name, '\\');
143 $creation = sprintf('$object = new %s(%s);', $className, implode(', ', $params));
146 // Create method call code
147 $methods = '';
148 foreach ($meta->getMethods() as $methodData) {
149 if (!isset($methodData['name']) && !isset($methodData['method'])) {
150 continue;
152 $methodName = isset($methodData['name']) ? $methodData['name'] : $methodData['method'];
153 $methodParams = $methodData['params'];
155 // Create method parameter representation
156 foreach ($methodParams as $key => $param) {
157 if (null === $param || is_scalar($param) || is_array($param)) {
158 $string = var_export($param, 1);
159 if (strstr($string, '::__set_state(')) {
160 throw new Exception\RuntimeException('Arguments in definitions may not contain objects');
162 $methodParams[$key] = $string;
163 } elseif ($param instanceof GeneratorInstance) {
164 $methodParams[$key] = sprintf('$this->%s()', $this->normalizeAlias($param->getName()));
165 } else {
166 $message = sprintf('Unable to use object arguments when generating method calls. Encountered with class "%s", method "%s", parameter of type "%s"', $name, $methodName, get_class($param));
167 throw new Exception\RuntimeException($message);
171 // Strip null arguments from the end of the params list
172 $reverseParams = array_reverse($methodParams, true);
173 foreach ($reverseParams as $key => $param) {
174 if ('NULL' === $param) {
175 unset($methodParams[$key]);
176 continue;
178 break;
181 $methods .= sprintf("\$object->%s(%s);\n", $methodName, implode(', ', $methodParams));
184 // Generate caching statement
185 $storage = '';
186 if ($im->hasSharedInstance($name, $params)) {
187 $storage = sprintf("\$this->services['%s'] = \$object;\n", $name);
190 // Start creating getter
191 $getterBody = '';
193 // Create fetch of stored service
194 if ($im->hasSharedInstance($name, $params)) {
195 $getterBody .= sprintf("if (isset(\$this->services['%s'])) {\n", $name);
196 $getterBody .= sprintf("%sreturn \$this->services['%s'];\n}\n\n", $indent, $name);
199 // Creation and method calls
200 $getterBody .= sprintf("%s\n", $creation);
201 $getterBody .= $methods;
203 // Stored service
204 $getterBody .= $storage;
206 // End getter body
207 $getterBody .= "return \$object;\n";
209 $getterDef = new MethodGenerator();
210 $getterDef->setName($getter);
211 $getterDef->setBody($getterBody);
212 $getters[] = $getterDef;
214 // Get cases for case statements
215 $cases = array($name);
216 if (isset($aliases[$name])) {
217 $cases = array_merge($aliases[$name], $cases);
220 // Build case statement and store
221 $statement = '';
222 foreach ($cases as $value) {
223 $statement .= sprintf("%scase '%s':\n", $indent, $value);
225 $statement .= sprintf("%sreturn \$this->%s();\n", str_repeat($indent, 2), $getter);
227 $caseStatements[] = $statement;
230 // Build switch statement
231 $switch = sprintf("switch (%s) {\n%s\n", '$name', implode("\n", $caseStatements));
232 $switch .= sprintf("%sdefault:\n%sreturn parent::get(%s, %s);\n", $indent, str_repeat($indent, 2), '$name', '$params');
233 $switch .= "}\n\n";
235 // Build get() method
236 $nameParam = new ParameterGenerator();
237 $nameParam->setName('name');
238 $paramsParam = new ParameterGenerator();
239 $paramsParam->setName('params')
240 ->setType('array')
241 ->setDefaultValue(array());
243 $get = new MethodGenerator();
244 $get->setName('get');
245 $get->setParameters(array(
246 $nameParam,
247 $paramsParam,
249 $get->setBody($switch);
251 // Create getters for aliases
252 $aliasMethods = array();
253 foreach ($aliases as $class => $classAliases) {
254 foreach ($classAliases as $alias) {
255 $aliasMethods[] = $this->getCodeGenMethodFromAlias($alias, $class);
259 // Create class code generation object
260 $container = new ClassGenerator();
261 $container->setName($this->containerClass)
262 ->setExtendedClass('ServiceLocator')
263 ->addMethodFromGenerator($get)
264 ->addMethods($getters)
265 ->addMethods($aliasMethods);
267 // Create PHP file code generation object
268 $classFile = new FileGenerator();
269 $classFile->setUse('Zend\Di\ServiceLocator')
270 ->setClass($container);
272 if (null !== $this->namespace) {
273 $classFile->setNamespace($this->namespace);
276 if (null !== $filename) {
277 $classFile->setFilename($filename);
280 return $classFile;
284 * Reduces aliases
286 * Takes alias list and reduces it to a 2-dimensional array of
287 * class names pointing to an array of aliases that resolve to
288 * it.
290 * @param array $aliasList
291 * @return array
293 protected function reduceAliases(array $aliasList)
295 $reduced = array();
296 $aliases = array_keys($aliasList);
297 foreach ($aliasList as $alias => $service) {
298 if (in_array($service, $aliases)) {
299 do {
300 $service = $aliasList[$service];
301 } while (in_array($service, $aliases));
303 if (!isset($reduced[$service])) {
304 $reduced[$service] = array();
306 $reduced[$service][] = $alias;
309 return $reduced;
313 * Create a PhpMethod code generation object named after a given alias
315 * @param string $alias
316 * @param string $class Class to which alias refers
317 * @return MethodGenerator
319 protected function getCodeGenMethodFromAlias($alias, $class)
321 $alias = $this->normalizeAlias($alias);
322 $method = new MethodGenerator();
323 $method->setName($alias);
324 $method->setBody(sprintf('return $this->get(\'%s\');', $class));
326 return $method;
330 * Normalize an alias to a getter method name
332 * @param string $alias
333 * @return string
335 protected function normalizeAlias($alias)
337 $normalized = preg_replace('/[^a-zA-Z0-9]/', ' ', $alias);
338 $normalized = 'get' . str_replace(' ', '', ucwords($normalized));
340 return $normalized;