|
29 | 29 | use function call_user_func_array;
|
30 | 30 | use function restore_error_handler;
|
31 | 31 | use function set_error_handler;
|
| 32 | +use ZendTest\ServiceManager\TestAsset\SampleFactory; |
| 33 | +use ZendTest\ServiceManager\TestAsset\AbstractFactoryFoo; |
| 34 | +use ZendTest\ServiceManager\TestAsset\PassthroughDelegatorFactory; |
32 | 35 |
|
33 | 36 | trait CommonServiceLocatorBehaviorsTrait
|
34 | 37 | {
|
@@ -879,4 +882,154 @@ public function testCoverageDepthFirstTaggingOnRecursiveAliasDefinitions()
|
879 | 882 | $this->assertSame($sm->get('alias1'), $sm->get('alias2'));
|
880 | 883 | $this->assertSame($sm->get(stdClass::class), $sm->get('alias1'));
|
881 | 884 | }
|
| 885 | + |
| 886 | + /** |
| 887 | + * The ServiceManager can change internal state on calls to get, |
| 888 | + * build or has, latter not currently. Possible state changes |
| 889 | + * are caching a factory, registering a service produced by |
| 890 | + * a factory, ... |
| 891 | + * |
| 892 | + * This tests performs three consecutive calls to build/get for |
| 893 | + * each registered service to push the service manager through |
| 894 | + * all internal states, thereby verifying that build/get/has |
| 895 | + * remain stable through the internal states. |
| 896 | + * |
| 897 | + * @dataProvider provideConsistencyOverInternalStatesTests |
| 898 | + * |
| 899 | + * @param ContainerInterface $smTemplate |
| 900 | + * @param string $name |
| 901 | + * @param array[] string $test |
| 902 | + */ |
| 903 | + public function testConsistencyOverInternalStates($smTemplate, $name, $test, $shared) |
| 904 | + { |
| 905 | + $sm = clone $smTemplate; |
| 906 | + $object['get'] = []; |
| 907 | + $object['build'] = []; |
| 908 | + |
| 909 | + // call get()/build() and store the retrieved |
| 910 | + // objects in $object['get'] or $object['build'] |
| 911 | + // respectively |
| 912 | + foreach ($test as $method) { |
| 913 | + $obj = $sm->$method($name); |
| 914 | + $object[$shared ? $method : 'build'][] = $obj; |
| 915 | + $this->assertNotNull($obj); |
| 916 | + $this->assertTrue($sm->has($name)); |
| 917 | + } |
| 918 | + |
| 919 | + // compares the first to the first also, but ok |
| 920 | + foreach ($object['get'] as $sharedObj) { |
| 921 | + $this->assertSame($object['get'][0], $sharedObj); |
| 922 | + } |
| 923 | + // objects from object['build'] have to be different |
| 924 | + // from all other objects |
| 925 | + foreach ($object['build'] as $idx1 => $nonSharedObj1) { |
| 926 | + $this->assertNotContains($nonSharedObj1, $object['get']); |
| 927 | + foreach ($object['build'] as $idx2 => $nonSharedObj2) { |
| 928 | + if ($idx1 !== $idx2) { |
| 929 | + $this->assertNotSame($nonSharedObj1, $nonSharedObj2); |
| 930 | + } |
| 931 | + } |
| 932 | + } |
| 933 | + } |
| 934 | + |
| 935 | + /** |
| 936 | + * Data provider |
| 937 | + * |
| 938 | + * @see testConsistencyOverInternalStates above |
| 939 | + * |
| 940 | + * @param ContainerInterface $smTemplate |
| 941 | + * @param string $name |
| 942 | + * @param string[] $test |
| 943 | + */ |
| 944 | + public function provideConsistencyOverInternalStatesTests() |
| 945 | + { |
| 946 | + $config1 = [ |
| 947 | + 'factories' => [ |
| 948 | + // to allow build('service') |
| 949 | + 'service' => function ($container, $requestedName, array $options = null) { |
| 950 | + return new stdClass(); |
| 951 | + }, |
| 952 | + 'factory' => SampleFactory::class, |
| 953 | + 'delegator' => SampleFactory::class, |
| 954 | + ], |
| 955 | + 'delegators' => [ |
| 956 | + 'delegator' => [ |
| 957 | + PassthroughDelegatorFactory::class |
| 958 | + ], |
| 959 | + ], |
| 960 | + 'invokables' => [ |
| 961 | + 'invokable' => InvokableObject::class, |
| 962 | + ], |
| 963 | + 'services' => [ |
| 964 | + 'service' => new stdClass(), |
| 965 | + ], |
| 966 | + 'aliases' => [ |
| 967 | + 'serviceAlias' => 'service', |
| 968 | + 'invokableAlias' => 'invokable', |
| 969 | + 'factoryAlias' => 'factory', |
| 970 | + 'abstractFactoryAlias' => 'foo', |
| 971 | + 'delegatorAlias' => 'delegator', |
| 972 | + ], |
| 973 | + 'abstract_factories' => [ |
| 974 | + AbstractFactoryFoo::class |
| 975 | + ] |
| 976 | + ]; |
| 977 | + $config2 = $config1; |
| 978 | + $config2['shared_by_default'] = false; |
| 979 | + |
| 980 | + $configs = [ $config1, $config2 ]; |
| 981 | + |
| 982 | + foreach ($configs as $config) { |
| 983 | + $smTemplates[] = $this->createContainer($config); |
| 984 | + } |
| 985 | + |
| 986 | + // produce all 3-tuples of 'build' and 'get', i.e. |
| 987 | + // |
| 988 | + // [['get', 'get', 'get'], ['get', 'get', 'build'], ... |
| 989 | + // ['build', 'build', 'build']] |
| 990 | + // |
| 991 | + $methods = ['get', 'build']; |
| 992 | + foreach ($methods as $method1) { |
| 993 | + foreach ($methods as $method2) { |
| 994 | + foreach ($methods as $method3) { |
| 995 | + $callSequences[] = [$method1, $method2, $method3]; |
| 996 | + } |
| 997 | + } |
| 998 | + } |
| 999 | + |
| 1000 | + foreach ($configs as $config) { |
| 1001 | + $smTemplate = $this->createContainer($config); |
| 1002 | + |
| 1003 | + // setup sharing, services are always shared |
| 1004 | + $names = array_fill_keys(array_keys($config['services']), true); |
| 1005 | + |
| 1006 | + // initialize the other keys with shared_by_default |
| 1007 | + // and merge them |
| 1008 | + $names = array_merge(array_fill_keys(array_keys(array_merge( |
| 1009 | + $config['factories'], |
| 1010 | + $config['invokables'], |
| 1011 | + $config['aliases'], |
| 1012 | + $config['delegators'] |
| 1013 | + )), $config['shared_by_default'] ?? true), $names); |
| 1014 | + |
| 1015 | + // add the key resolved by the abstract factory |
| 1016 | + $names['foo'] = $config['shared_by_default'] ?? true; |
| 1017 | + |
| 1018 | + // adjust shared setting for individual keys from |
| 1019 | + // $shared array if present |
| 1020 | + if (! empty($config['shared'])) { |
| 1021 | + foreach ($config['shared'] as $name => $shared) { |
| 1022 | + $names[$name] = $shared; |
| 1023 | + } |
| 1024 | + } |
| 1025 | + |
| 1026 | + foreach ($names as $name => $shared) { |
| 1027 | + foreach ($callSequences as $callSequence) { |
| 1028 | + $sm = clone $smTemplate; |
| 1029 | + $tests[] = [$smTemplate, $name, $callSequence, $shared]; |
| 1030 | + } |
| 1031 | + } |
| 1032 | + } |
| 1033 | + return $tests; |
| 1034 | + } |
882 | 1035 | }
|
0 commit comments