21
21
use Zend \ServiceManager \Exception \ServiceNotCreatedException ;
22
22
use Zend \ServiceManager \Exception \ServiceNotFoundException ;
23
23
24
- use function array_intersect_key ;
25
24
use function array_keys ;
26
25
use function array_merge ;
27
26
use function array_merge_recursive ;
@@ -333,6 +332,8 @@ public function getAllowOverride()
333
332
*/
334
333
public function configure (array $ config )
335
334
{
335
+ // This is a bulk update/initial configuration
336
+ // So we check all definitions
336
337
$ this ->validateConfig ($ config );
337
338
338
339
if (isset ($ config ['services ' ])) {
@@ -344,6 +345,7 @@ public function configure(array $config)
344
345
$ factories = $ this ->createFactoriesForInvokables ($ config ['invokables ' ]);
345
346
346
347
if (! empty ($ aliases )) {
348
+ // @todo: This is wrong! These aliases are 'resolved' already
347
349
$ config ['aliases ' ] = (isset ($ config ['aliases ' ]))
348
350
? \array_merge ($ config ['aliases ' ], $ aliases )
349
351
: $ aliases ;
@@ -366,10 +368,16 @@ public function configure(array $config)
366
368
$ this ->shared = $ config ['shared ' ] + $ this ->shared ;
367
369
}
368
370
371
+ $ aliases = [];
369
372
if (isset ($ config ['aliases ' ])) {
370
- $ this -> configureAliases ( $ config ['aliases ' ]) ;
373
+ $ aliases = $ config ['aliases ' ];
371
374
} elseif (! $ this ->configured && ! empty ($ this ->aliases )) {
372
- $ this ->resolveAliases ($ this ->aliases );
375
+ $ aliases = $ this ->aliases ;
376
+ }
377
+ if (! empty ($ aliases )) {
378
+ foreach ($ aliases as $ alias => $ target ) {
379
+ $ this ->doSetAlias ($ alias , $ target );
380
+ }
373
381
}
374
382
375
383
if (isset ($ config ['shared_by_default ' ])) {
@@ -386,7 +394,11 @@ public function configure(array $config)
386
394
// For abstract factories and initializers, we always directly
387
395
// instantiate them to avoid checks during service construction.
388
396
if (isset ($ config ['abstract_factories ' ])) {
389
- $ this ->resolveAbstractFactories ($ config ['abstract_factories ' ]);
397
+ $ abstractFactories = $ config ['abstract_factories ' ];
398
+ // $key not needed, but foreach faster
399
+ foreach ($ abstractFactories as $ key => $ abstractFactory ) {
400
+ $ this ->doAddAbstractFactory ($ abstractFactory );
401
+ }
390
402
}
391
403
392
404
if (isset ($ config ['initializers ' ])) {
@@ -398,35 +410,6 @@ public function configure(array $config)
398
410
return $ this ;
399
411
}
400
412
401
- /**
402
- * @param string[] $aliases
403
- *
404
- * @return void
405
- */
406
- private function configureAliases (array $ aliases )
407
- {
408
- if (! $ this ->configured ) {
409
- $ this ->aliases = $ aliases + $ this ->aliases ;
410
-
411
- $ this ->resolveAliases ($ this ->aliases );
412
-
413
- return ;
414
- }
415
-
416
- // Performance optimization. If there are no collisions, then we don't need to recompute loops
417
- $ intersecting = $ this ->aliases && array_intersect_key ($ this ->aliases , $ aliases );
418
- $ this ->aliases = $ this ->aliases ? array_merge ($ this ->aliases , $ aliases ) : $ aliases ;
419
-
420
- if ($ intersecting ) {
421
- $ this ->resolveAliases ($ this ->aliases );
422
-
423
- return ;
424
- }
425
-
426
- $ this ->resolveAliases ($ aliases );
427
- $ this ->resolveNewAliasesWithPreviouslyResolvedAliases ($ aliases );
428
- }
429
-
430
413
/**
431
414
* Add an alias.
432
415
*
@@ -436,16 +419,8 @@ private function configureAliases(array $aliases)
436
419
public function setAlias ($ alias , $ target )
437
420
{
438
421
$ this ->validate ($ alias );
439
- $ this ->aliases [ $ alias] = $ target ;
422
+ $ this ->doSetAlias ( $ alias, $ target) ;
440
423
441
- $ this ->resolvedAliases [$ alias ] =
442
- isset ($ this ->resolvedAliases [$ target ]) ? $ this ->resolvedAliases [$ target ] : $ target ;
443
- if (in_array ($ alias , $ this ->resolvedAliases )) {
444
- $ r = array_intersect ($ this ->resolvedAliases , [ $ alias ]);
445
- foreach ($ r as $ name => $ service ) {
446
- $ this ->resolvedAliases [$ name ] = $ target ;
447
- }
448
- }
449
424
}
450
425
451
426
/**
@@ -492,7 +467,7 @@ public function mapLazyService($name, $class = null)
492
467
*/
493
468
public function addAbstractFactory ($ factory )
494
469
{
495
- $ this ->resolveAbstractFactory ($ factory );
470
+ $ this ->doAddAbstractFactory ($ factory );
496
471
}
497
472
498
473
/**
@@ -541,63 +516,6 @@ public function setShared($name, $flag)
541
516
$ this ->shared [$ name ] = (bool ) $ flag ;
542
517
}
543
518
544
- private function resolveAbstractFactory ($ abstractFactory )
545
- {
546
- if (\is_string ($ abstractFactory ) && \class_exists ($ abstractFactory )) {
547
- //Cached string
548
- if (! isset ($ this ->cachedAbstractFactories [$ abstractFactory ])) {
549
- $ this ->cachedAbstractFactories [$ abstractFactory ] = new $ abstractFactory ();
550
- }
551
-
552
- $ abstractFactory = $ this ->cachedAbstractFactories [$ abstractFactory ];
553
- }
554
-
555
- if ($ abstractFactory instanceof Factory \AbstractFactoryInterface) {
556
- $ abstractFactoryObjHash = \spl_object_hash ($ abstractFactory );
557
- $ this ->abstractFactories [$ abstractFactoryObjHash ] = $ abstractFactory ;
558
- return ;
559
- }
560
-
561
- // Error condition; let's find out why.
562
-
563
- // If we still have a string, we have a class name that does not resolve
564
- if (\is_string ($ abstractFactory )) {
565
- throw new InvalidArgumentException (
566
- sprintf (
567
- 'An invalid abstract factory was registered; resolved to class "%s" ' .
568
- 'which does not exist; please provide a valid class name resolving ' .
569
- 'to an implementation of %s ' ,
570
- $ abstractFactory ,
571
- AbstractFactoryInterface::class
572
- )
573
- );
574
- }
575
-
576
- // Otherwise, we have an invalid type.
577
- throw new InvalidArgumentException (
578
- sprintf (
579
- 'An invalid abstract factory was registered. Expected an instance of "%s", ' .
580
- 'but "%s" was received ' ,
581
- AbstractFactoryInterface::class,
582
- (is_object ($ abstractFactory ) ? get_class ($ abstractFactory ) : gettype ($ abstractFactory ))
583
- )
584
- );
585
- }
586
-
587
- /**
588
- * Instantiate abstract factories for to avoid checks during service construction.
589
- *
590
- * @param string[]|Factory\AbstractFactoryInterface[] $abstractFactories
591
- *
592
- * @return void
593
- */
594
- private function resolveAbstractFactories (array $ abstractFactories )
595
- {
596
- foreach ($ abstractFactories as $ abstractFactory ) {
597
- $ this ->resolveAbstractFactory ($ abstractFactory );
598
- }
599
- }
600
-
601
519
/**
602
520
* Instantiate initializers for to avoid checks during service construction.
603
521
*
@@ -656,49 +574,6 @@ private function resolveInitializers(array $initializers)
656
574
}
657
575
}
658
576
659
- /**
660
- * Resolve aliases to their canonical service names.
661
- *
662
- * @param string[] $aliases
663
- *
664
- * @returns void
665
- */
666
- private function resolveAliases (array $ aliases )
667
- {
668
- foreach ($ aliases as $ alias => $ service ) {
669
- $ visited = [];
670
- $ name = $ alias ;
671
-
672
- while (isset ($ this ->aliases [$ name ])) {
673
- if (isset ($ visited [$ name ])) {
674
- throw CyclicAliasException::fromAliasesMap ($ aliases );
675
- }
676
-
677
- $ visited [$ name ] = true ;
678
- $ name = $ this ->aliases [$ name ];
679
- }
680
-
681
- $ this ->resolvedAliases [$ alias ] = $ name ;
682
- }
683
- }
684
-
685
- /**
686
- * Rewrites the map of aliases by resolving the given $aliases with the existing resolved ones.
687
- * This is mostly done for performance reasons.
688
- *
689
- * @param string[] $aliases
690
- *
691
- * @return void
692
- */
693
- private function resolveNewAliasesWithPreviouslyResolvedAliases (array $ aliases )
694
- {
695
- foreach ($ this ->resolvedAliases as $ name => $ target ) {
696
- if (isset ($ aliases [$ target ])) {
697
- $ this ->resolvedAliases [$ name ] = $ this ->resolvedAliases [$ target ];
698
- }
699
- }
700
- }
701
-
702
577
/**
703
578
* Get a factory for the given service name
704
579
*
@@ -1021,4 +896,85 @@ private function validateConfig(array $config)
1021
896
$ this ->validateArray ($ config ['lazy_services ' ]['class_map ' ]);
1022
897
}
1023
898
}
899
+
900
+ /**
901
+ * Assuming that the alias name is valid (see above) resolve/add it.
902
+ *
903
+ * @param string $alias
904
+ * @param string $target
905
+ */
906
+ private function doSetAlias ($ alias , $ target )
907
+ {
908
+ $ this ->aliases [$ alias ] = $ target ;
909
+ $ this ->resolvedAliases [$ alias ] =
910
+ isset ($ this ->resolvedAliases [$ target ]) ? $ this ->resolvedAliases [$ target ] : $ target ;
911
+
912
+ if ($ alias === $ this ->resolvedAliases [$ alias ]) {
913
+ throw CyclicAliasException::fromAliasesMap ([$ alias ]);
914
+ }
915
+
916
+ if (in_array ($ alias , $ this ->resolvedAliases )) {
917
+ $ r = array_intersect ($ this ->resolvedAliases , [ $ alias ]);
918
+ foreach ($ r as $ name => $ service ) {
919
+ $ this ->resolvedAliases [$ name ] = $ target ;
920
+ }
921
+ }
922
+ }
923
+
924
+ /**
925
+ * Instantiate abstract factories for to avoid checks during service construction.
926
+ *
927
+ * @todo: To construct to avoid is not really an optimization, it's lazyness
928
+ * AbstractFactories are shared services. Make sure that has() is guarded against
929
+ * numerical parameters. Handle AbstractFactories as any other shared services.
930
+ *
931
+ * @todo: Implement a has() and get() logic which unifies the several arrays
932
+ * It is not necessary to isset(blah) several times on a request.
933
+ *
934
+ * @param string[]|Factory\AbstractFactoryInterface[] $abstractFactories
935
+ *
936
+ * @return void
937
+ */
938
+ private function doAddAbstractFactory ($ abstractFactory )
939
+ {
940
+ if (\is_string ($ abstractFactory ) && \class_exists ($ abstractFactory )) {
941
+ //Cached string
942
+ if (! isset ($ this ->cachedAbstractFactories [$ abstractFactory ])) {
943
+ $ this ->cachedAbstractFactories [$ abstractFactory ] = new $ abstractFactory ();
944
+ }
945
+
946
+ $ abstractFactory = $ this ->cachedAbstractFactories [$ abstractFactory ];
947
+ }
948
+
949
+ if ($ abstractFactory instanceof Factory \AbstractFactoryInterface) {
950
+ $ abstractFactoryObjHash = \spl_object_hash ($ abstractFactory );
951
+ $ this ->abstractFactories [$ abstractFactoryObjHash ] = $ abstractFactory ;
952
+ return ;
953
+ }
954
+
955
+ // Error condition; let's find out why.
956
+
957
+ // If we still have a string, we have a class name that does not resolve
958
+ if (\is_string ($ abstractFactory )) {
959
+ throw new InvalidArgumentException (
960
+ sprintf (
961
+ 'An invalid abstract factory was registered; resolved to class "%s" ' .
962
+ 'which does not exist; please provide a valid class name resolving ' .
963
+ 'to an implementation of %s ' ,
964
+ $ abstractFactory ,
965
+ AbstractFactoryInterface::class
966
+ )
967
+ );
968
+ }
969
+
970
+ // Otherwise, we have an invalid type.
971
+ throw new InvalidArgumentException (
972
+ sprintf (
973
+ 'An invalid abstract factory was registered. Expected an instance of "%s", ' .
974
+ 'but "%s" was received ' ,
975
+ AbstractFactoryInterface::class,
976
+ (is_object ($ abstractFactory ) ? get_class ($ abstractFactory ) : gettype ($ abstractFactory ))
977
+ )
978
+ );
979
+ }
1024
980
}
0 commit comments