These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more
1 | <?php declare(strict_types=1); |
||
2 | |||
3 | namespace ApiClients\Foundation; |
||
4 | |||
5 | use ApiClients\Foundation\Events\CommandLocatorEvent; |
||
6 | use ApiClients\Foundation\Events\ServiceLocatorEvent; |
||
7 | use ApiClients\Foundation\Hydrator\Factory as HydratorFactory; |
||
8 | use ApiClients\Foundation\Hydrator\Hydrator; |
||
9 | use ApiClients\Foundation\Transport\Client as TransportClient; |
||
10 | use ApiClients\Foundation\Transport\Factory as TransportFactory; |
||
11 | use ApiClients\Tools\CommandBus\CommandBus; |
||
12 | use Generator; |
||
13 | use Interop\Container\ContainerInterface; |
||
14 | use League\Container\Container; |
||
15 | use League\Container\ReflectionContainer; |
||
16 | use League\Event\Emitter; |
||
17 | use League\Event\EmitterInterface; |
||
18 | use League\Tactician\Container\ContainerLocator; |
||
19 | use League\Tactician\Handler\CommandHandlerMiddleware; |
||
20 | use League\Tactician\Handler\CommandNameExtractor\ClassNameExtractor; |
||
21 | use League\Tactician\Handler\MethodNameInflector\HandleInflector; |
||
22 | use React\EventLoop\LoopInterface; |
||
23 | |||
24 | final class Factory |
||
25 | { |
||
26 | public static function create( |
||
27 | LoopInterface $loop = null, |
||
28 | ContainerInterface $wrappedContainer = null, |
||
29 | array $options = [] |
||
30 | ): Client { |
||
31 | $container = self::createContainer($wrappedContainer); |
||
32 | |||
33 | $container->share(EmitterInterface::class, new Emitter()); |
||
34 | $container->share(TransportClient::class, self::createTransport($container, $loop, $options)); |
||
35 | $container->share(Hydrator::class, self::createHydrator($container, $options)); |
||
36 | $container->share(CommandBus::class, function () use ($container) { |
||
37 | return self::createCommandBus($container); |
||
38 | }); |
||
39 | array_map( |
||
40 | [$container, 'share'], |
||
41 | iterator_to_array( |
||
42 | self::locateServices($container->get(EmitterInterface::class)) |
||
43 | ) |
||
44 | ); |
||
45 | |||
46 | return new Client( |
||
47 | $container |
||
48 | ); |
||
49 | } |
||
50 | |||
51 | private static function createContainer(ContainerInterface $wrappedContainer = null): Container |
||
52 | { |
||
53 | $container = new Container(); |
||
54 | $container->delegate(new ReflectionContainer()); |
||
55 | |||
56 | if ($wrappedContainer instanceof ContainerInterface) { |
||
57 | $container->delegate($wrappedContainer); |
||
58 | } |
||
59 | |||
60 | return $container; |
||
61 | } |
||
62 | |||
63 | private static function createCommandBus(ContainerInterface $container): CommandBus |
||
64 | { |
||
65 | $commandToHandlerMap = self::mapCommandsToHandlers($container->get(EmitterInterface::class)); |
||
66 | |||
67 | $containerLocator = new ContainerLocator( |
||
68 | $container, |
||
69 | $commandToHandlerMap |
||
70 | ); |
||
71 | |||
72 | $commandHandlerMiddleware = new CommandHandlerMiddleware( |
||
73 | new ClassNameExtractor(), |
||
74 | $containerLocator, |
||
75 | new HandleInflector() |
||
76 | ); |
||
77 | |||
78 | return new CommandBus( |
||
79 | $container->get(LoopInterface::class), |
||
80 | $commandHandlerMiddleware |
||
81 | ); |
||
82 | } |
||
83 | |||
84 | private static function mapCommandsToHandlers(EmitterInterface $emitter): array |
||
85 | { |
||
86 | return $emitter->emit(CommandLocatorEvent::create())->getMap(); |
||
0 ignored issues
–
show
|
|||
87 | } |
||
88 | |||
89 | private static function locateServices(EmitterInterface $emitter): Generator |
||
90 | { |
||
91 | return $emitter->emit(ServiceLocatorEvent::create())->getMap(); |
||
0 ignored issues
–
show
It seems like you code against a concrete implementation and not the interface
League\Event\EventInterface as the method getMap() does only exist in the following implementations of said interface: ApiClients\Foundation\Events\CommandLocatorEvent , ApiClients\Foundation\Events\ServiceLocatorEvent .
Let’s take a look at an example: interface User
{
/** @return string */
public function getPassword();
}
class MyUser implements User
{
public function getPassword()
{
// return something
}
public function getDisplayName()
{
// return some name.
}
}
class AuthSystem
{
public function authenticate(User $user)
{
$this->logger->info(sprintf('Authenticating %s.', $user->getDisplayName()));
// do something.
}
}
In the above example, the authenticate() method works fine as long as you just pass instances of MyUser. However, if you now also want to pass a different implementation of User which does not have a getDisplayName() method, the code will break. Available Fixes
Note: PHP Analyzer uses reverse abstract interpretation to narrow down the types
inside the if block in such a case.
Loading history...
|
|||
92 | } |
||
93 | |||
94 | private static function createTransport( |
||
95 | ContainerInterface $container, |
||
96 | LoopInterface $loop = null, |
||
97 | array $options = [] |
||
98 | ): TransportClient { |
||
99 | return TransportFactory::create($container, $loop, $options[Options::TRANSPORT_OPTIONS]); |
||
100 | } |
||
101 | |||
102 | private static function createHydrator(ContainerInterface $container, array $options = []) |
||
103 | { |
||
104 | if (isset($options[Options::HYDRATOR]) && $options[Options::HYDRATOR] instanceof Hydrator) { |
||
105 | return $options[Options::HYDRATOR]; |
||
106 | } |
||
107 | |||
108 | if (!isset($options[Options::HYDRATOR_OPTIONS])) { |
||
109 | throw new \Exception('Missing Hydrator options'); |
||
110 | } |
||
111 | |||
112 | return HydratorFactory::create($container, $options[Options::HYDRATOR_OPTIONS]); |
||
113 | } |
||
114 | } |
||
115 |
Let’s take a look at an example:
In the above example, the authenticate() method works fine as long as you just pass instances of MyUser. However, if you now also want to pass a different implementation of User which does not have a getDisplayName() method, the code will break.
Available Fixes
Change the type-hint for the parameter:
Add an additional type-check:
Add the method to the interface: