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-2015 Zend Technologies USA Inc. (http://www.zend.com) 7 * @license http://framework.zend.com/license/new-bsd New BSD License 8 */ 9 10namespace Zend\Di; 11 12use SplDoublyLinkedList; 13use Zend\Di\Definition\RuntimeDefinition; 14 15/** 16 * Class definition based on multiple definitions 17 */ 18class DefinitionList extends SplDoublyLinkedList implements Definition\DefinitionInterface 19{ 20 protected $classes = array(); 21 protected $runtimeDefinitions; 22 23 /** 24 * @param Definition\DefinitionInterface|Definition\DefinitionInterface[] $definitions 25 */ 26 public function __construct($definitions) 27 { 28 $this->runtimeDefinitions = new SplDoublyLinkedList(); 29 if (!is_array($definitions)) { 30 $definitions = array($definitions); 31 } 32 foreach ($definitions as $definition) { 33 $this->addDefinition($definition, true); 34 } 35 } 36 37 /** 38 * Add definitions 39 * 40 * @param Definition\DefinitionInterface $definition 41 * @param bool $addToBackOfList 42 * @return void 43 */ 44 public function addDefinition(Definition\DefinitionInterface $definition, $addToBackOfList = true) 45 { 46 if ($addToBackOfList) { 47 $this->push($definition); 48 } else { 49 $this->unshift($definition); 50 } 51 } 52 53 protected function getDefinitionClassMap(Definition\DefinitionInterface $definition) 54 { 55 $definitionClasses = $definition->getClasses(); 56 if (empty($definitionClasses)) { 57 return array(); 58 } 59 return array_combine(array_values($definitionClasses), array_fill(0, count($definitionClasses), $definition)); 60 } 61 62 public function unshift($definition) 63 { 64 $result = parent::unshift($definition); 65 if ($definition instanceof RuntimeDefinition) { 66 $this->runtimeDefinitions->unshift($definition); 67 } 68 $this->classes = array_merge($this->classes, $this->getDefinitionClassMap($definition)); 69 return $result; 70 } 71 72 public function push($definition) 73 { 74 $result = parent::push($definition); 75 if ($definition instanceof RuntimeDefinition) { 76 $this->runtimeDefinitions->push($definition); 77 } 78 $this->classes = array_merge($this->getDefinitionClassMap($definition), $this->classes); 79 return $result; 80 } 81 82 /** 83 * @param string $type 84 * @return Definition\DefinitionInterface[] 85 */ 86 public function getDefinitionsByType($type) 87 { 88 $definitions = array(); 89 foreach ($this as $definition) { 90 if ($definition instanceof $type) { 91 $definitions[] = $definition; 92 } 93 } 94 95 return $definitions; 96 } 97 98 /** 99 * Get definition by type 100 * 101 * @param string $type 102 * @return Definition\DefinitionInterface 103 */ 104 public function getDefinitionByType($type) 105 { 106 foreach ($this as $definition) { 107 if ($definition instanceof $type) { 108 return $definition; 109 } 110 } 111 112 return false; 113 } 114 115 /** 116 * @param string $class 117 * @return bool|Definition\DefinitionInterface 118 */ 119 public function getDefinitionForClass($class) 120 { 121 if (array_key_exists($class, $this->classes)) { 122 return $this->classes[$class]; 123 } 124 /** @var $definition Definition\DefinitionInterface */ 125 foreach ($this->runtimeDefinitions as $definition) { 126 if ($definition->hasClass($class)) { 127 return $definition; 128 } 129 } 130 131 return false; 132 } 133 134 /** 135 * @param string $class 136 * @return bool|Definition\DefinitionInterface 137 */ 138 public function forClass($class) 139 { 140 return $this->getDefinitionForClass($class); 141 } 142 143 /** 144 * {@inheritDoc} 145 */ 146 public function getClasses() 147 { 148 return array_keys($this->classes); 149 } 150 151 /** 152 * {@inheritDoc} 153 */ 154 public function hasClass($class) 155 { 156 if (array_key_exists($class, $this->classes)) { 157 return true; 158 } 159 /** @var $definition Definition\DefinitionInterface */ 160 foreach ($this->runtimeDefinitions as $definition) { 161 if ($definition->hasClass($class)) { 162 return true; 163 } 164 } 165 166 return false; 167 } 168 169 /** 170 * {@inheritDoc} 171 */ 172 public function getClassSupertypes($class) 173 { 174 if (false === ($classDefinition = $this->getDefinitionForClass($class))) { 175 return array(); 176 } 177 $supertypes = $classDefinition->getClassSupertypes($class); 178 if (! $classDefinition instanceof Definition\PartialMarker) { 179 return $supertypes; 180 } 181 /** @var $definition Definition\DefinitionInterface */ 182 foreach ($this as $definition) { 183 if ($definition === $classDefinition) { 184 continue; 185 } 186 if ($definition->hasClass($class)) { 187 $supertypes = array_merge($supertypes, $definition->getClassSupertypes($class)); 188 if ($definition instanceof Definition\PartialMarker) { 189 continue; 190 } 191 192 return $supertypes; 193 } 194 } 195 return $supertypes; 196 } 197 198 /** 199 * {@inheritDoc} 200 */ 201 public function getInstantiator($class) 202 { 203 if (! $classDefinition = $this->getDefinitionForClass($class)) { 204 return false; 205 } 206 $value = $classDefinition->getInstantiator($class); 207 if (!is_null($value)) { 208 return $value; 209 } 210 if (! $classDefinition instanceof Definition\PartialMarker) { 211 return false; 212 } 213 /** @var $definition Definition\DefinitionInterface */ 214 foreach ($this as $definition) { 215 if ($definition === $classDefinition) { 216 continue; 217 } 218 if ($definition->hasClass($class)) { 219 $value = $definition->getInstantiator($class); 220 if ($value === null && $definition instanceof Definition\PartialMarker) { 221 continue; 222 } 223 224 return $value; 225 } 226 } 227 228 return false; 229 } 230 231 /** 232 * {@inheritDoc} 233 */ 234 public function hasMethods($class) 235 { 236 if (! $classDefinition = $this->getDefinitionForClass($class)) { 237 return false; 238 } 239 if (false !== ($methods = $classDefinition->hasMethods($class))) { 240 return $methods; 241 } 242 if (! $classDefinition instanceof Definition\PartialMarker) { 243 return false; 244 } 245 /** @var $definition Definition\DefinitionInterface */ 246 foreach ($this as $definition) { 247 if ($definition === $classDefinition) { 248 continue; 249 } 250 if ($definition->hasClass($class)) { 251 if ($definition->hasMethods($class) === false && $definition instanceof Definition\PartialMarker) { 252 continue; 253 } 254 255 return $definition->hasMethods($class); 256 } 257 } 258 259 return false; 260 } 261 262 /** 263 * {@inheritDoc} 264 */ 265 public function hasMethod($class, $method) 266 { 267 if (!$this->hasMethods($class)) { 268 return false; 269 } 270 $classDefinition = $this->getDefinitionForClass($class); 271 if ($classDefinition->hasMethod($class, $method)) { 272 return true; 273 } 274 /** @var $definition Definition\DefinitionInterface */ 275 foreach ($this->runtimeDefinitions as $definition) { 276 if ($definition === $classDefinition) { 277 continue; 278 } 279 if ($definition->hasClass($class) && $definition->hasMethod($class, $method)) { 280 return true; 281 } 282 } 283 284 return false; 285 } 286 287 /** 288 * {@inheritDoc} 289 */ 290 public function getMethods($class) 291 { 292 if (false === ($classDefinition = $this->getDefinitionForClass($class))) { 293 return array(); 294 } 295 $methods = $classDefinition->getMethods($class); 296 if (! $classDefinition instanceof Definition\PartialMarker) { 297 return $methods; 298 } 299 /** @var $definition Definition\DefinitionInterface */ 300 foreach ($this as $definition) { 301 if ($definition === $classDefinition) { 302 continue; 303 } 304 if ($definition->hasClass($class)) { 305 if (!$definition instanceof Definition\PartialMarker) { 306 return array_merge($definition->getMethods($class), $methods); 307 } 308 309 $methods = array_merge($definition->getMethods($class), $methods); 310 } 311 } 312 313 return $methods; 314 } 315 316 /** 317 * {@inheritDoc} 318 */ 319 public function hasMethodParameters($class, $method) 320 { 321 $methodParameters = $this->getMethodParameters($class, $method); 322 323 return ($methodParameters !== array()); 324 } 325 326 /** 327 * {@inheritDoc} 328 */ 329 public function getMethodParameters($class, $method) 330 { 331 if (false === ($classDefinition = $this->getDefinitionForClass($class))) { 332 return array(); 333 } 334 if ($classDefinition->hasMethod($class, $method) && $classDefinition->hasMethodParameters($class, $method)) { 335 return $classDefinition->getMethodParameters($class, $method); 336 } 337 /** @var $definition Definition\DefinitionInterface */ 338 foreach ($this as $definition) { 339 if ($definition === $classDefinition) { 340 continue; 341 } 342 if ($definition->hasClass($class) 343 && $definition->hasMethod($class, $method) 344 && $definition->hasMethodParameters($class, $method) 345 ) { 346 return $definition->getMethodParameters($class, $method); 347 } 348 } 349 350 return array(); 351 } 352} 353