Issues (2)

src/Provider/ConfigServiceProvider.php (1 issue)

Labels
Severity
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Arp\Container\Provider;
6
7
use Arp\Container\ContainerInterface;
8
use Arp\Container\Exception\ContainerException;
9
use Arp\Container\Provider\Exception\ServiceProviderException;
10
11
/**
12
 * @author  Alex Patterson <[email protected]>
13
 * @package Arp\Container\Provider
14
 */
15
final class ConfigServiceProvider implements ServiceProviderInterface
16
{
17
    public const ALIASES = 'aliases';
18
    public const FACTORIES = 'factories';
19
    public const SERVICES = 'services';
20
21
    /**
22
     * @var array
23
     */
24
    private array $config;
25
26
    /**
27
     * @param array $config
28
     */
29
    public function __construct(array $config)
30
    {
31
        $this->config = $config;
32
    }
33
34
    /**
35
     * @param ContainerInterface $container
36
     *
37
     * @throws ServiceProviderException
38
     */
39
    public function registerServices(ContainerInterface $container): void
40
    {
41
        if (isset($this->config[self::SERVICES]) && is_array($this->config[self::SERVICES])) {
42
            foreach ($this->config[self::SERVICES] as $name => $service) {
43
                $container->set($name, $service);
44
            }
45
        }
46
47
        if (isset($this->config[self::FACTORIES]) && is_array($this->config[self::FACTORIES])) {
48
            $this->registerFactories($container, $this->config[self::FACTORIES]);
49
        }
50
51
        if (isset($this->config[self::ALIASES]) && is_array($this->config[self::ALIASES])) {
52
            $this->registerAliases($container, $this->config[self::ALIASES]);
53
        }
54
    }
55
56
    /**
57
     * @param ContainerInterface $container
58
     * @param array              $factories
59
     *
60
     * @throws ServiceProviderException
61
     */
62
    private function registerFactories(ContainerInterface $container, array $factories): void
63
    {
64
        foreach ($factories as $name => $factory) {
65
            if (is_array($factory)) {
66
                $this->registerArrayFactory($container, $name, $factory);
67
                continue;
68
            }
69
70
            if (is_string($factory)) {
71
                $container->setFactoryClass($name, $factory);
72
                continue;
73
            }
74
75
            $this->registerFactory($container, $name, $factory);
76
        }
77
    }
78
79
    /**
80
     * Register a factory that was provided as a configuration array. Using the array format of [$factory, $methodName]
81
     *
82
     * @param ContainerInterface $container
83
     * @param string             $serviceName
84
     * @param array              $factoryConfig
85
     *
86
     * @throws ServiceProviderException
87
     */
88
    private function registerArrayFactory(
89
        ContainerInterface $container,
90
        string $serviceName,
91
        array $factoryConfig
92
    ): void {
93
        $factory = $factoryConfig[0] ?? null;
94
        if (null !== $factory) {
95
            $methodName = $factoryConfig[1] ?? null;
96
97
            if (is_string($factory)) {
98
                $container->setFactoryClass($serviceName, $factory, $methodName);
99
                return;
100
            }
101
102
            if (is_object($factory) || is_callable($factory)) {
103
                $this->registerFactory($container, $serviceName, $factory, $methodName);
104
                return;
105
            }
106
        }
107
108
        throw new ServiceProviderException(
109
            sprintf('Failed to register service \'%s\': The provided array configuration is invalid', $serviceName)
110
        );
111
    }
112
113
    /**
114
     * @param ContainerInterface     $container
115
     * @param string                 $serviceName
116
     * @param object|callable|string $factory
117
     * @param string|null            $methodName
118
     *
119
     * @throws ServiceProviderException
120
     */
121
    private function registerFactory(
122
        ContainerInterface $container,
123
        string $serviceName,
124
        $factory,
125
        string $methodName = null
126
    ): void {
127
        $methodName = $methodName ?? '__invoke';
128
129
        if (!is_callable($factory) && !$factory instanceof \Closure) {
130
            $factory = [$factory, $methodName];
131
        }
132
133
        if (!is_callable($factory)) {
134
            throw new ServiceProviderException(
135
                sprintf('Failed to register service \'%s\': The factory provided is not callable', $serviceName),
136
            );
137
        }
138
139
        try {
140
            $container->setFactory($serviceName, $factory);
0 ignored issues
show
It seems like $factory can also be of type object; however, parameter $factory of Arp\Container\ContainerInterface::setFactory() does only seem to accept callable|string, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

140
            $container->setFactory($serviceName, /** @scrutinizer ignore-type */ $factory);
Loading history...
141
        } catch (ContainerException $e) {
142
            throw new ServiceProviderException(
143
                sprintf('Failed to set factory for service \'%s\': %s', $serviceName, $e->getMessage()),
144
                $e->getCode(),
145
                $e
146
            );
147
        }
148
    }
149
150
    /**
151
     * @param ContainerInterface $container
152
     * @param array              $aliases
153
     *
154
     * @throws ServiceProviderException
155
     */
156
    private function registerAliases(ContainerInterface $container, array $aliases): void
157
    {
158
        foreach ($aliases as $aliasName => $serviceName) {
159
            try {
160
                $container->setAlias($aliasName, $serviceName);
161
            } catch (ContainerException $e) {
162
                throw new ServiceProviderException(
163
                    sprintf(
164
                        'Failed to register alias \'%s\' for service \'%s\': %s',
165
                        $aliasName,
166
                        $serviceName,
167
                        $e->getMessage()
168
                    ),
169
                    $e->getCode(),
170
                    $e
171
                );
172
            }
173
        }
174
    }
175
}
176