Completed
Push — master ( 2c9a51...3752f9 )
by Oscar
02:47
created

App::addFactory()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 7
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 7
rs 9.4285
c 0
b 0
f 0
cc 1
eloc 4
nc 1
nop 2
1
<?php
2
3
namespace Fol;
4
5
use Fol\NotFoundException;
6
use Fol\ContainerException;
7
use Psr\Container\ContainerInterface;
8
use Interop\Container\ServiceProviderInterface;
9
use Psr\Http\Message\UriInterface;
10
use Throwable;
11
12
/**
13
 * Manages an app.
14
 */
15
class App implements ContainerInterface
16
{
17
    private $services = [];
18
    private $items = [];
19
    private $path;
20
    private $uri;
21
22
    /**
23
     * Constructor. Set the base path and uri
24
     *
25
     * @param string $path
26
     * @param UriInterface $uri
27
     */
28
    public function __construct(string $path, UriInterface $uri)
29
    {
30
        $this->path = rtrim($path, '/') ?: '/';
31
        $this->uri = $uri;
32
    }
33
34
    /**
35
     * Add a new service provider.
36
     *
37
     * @param ServiceProviderInterface $provider
38
     *
39
     * @return self
40
     */
41
    public function addServiceProvider(ServiceProviderInterface $provider): self
42
    {
43
        foreach ($provider->getFactories() as $id => $factory) {
44
            $this->addFactory($id, $factory);
45
        }
46
47
        foreach ($provider->getExtensions() as $id => $extension) {
48
            $this->addExtension($id, $extension);
49
        }
50
51
        return $this;
52
    }
53
54
    /**
55
     * Add a new factory.
56
     *
57
     * @param string|int $id
58
     * @param callable   $factory
59
     *
60
     * @return self
61
     */
62
    public function addFactory($id, callable $factory): self
63
    {
64
        $this->createServiceIfNotExists($id);
65
        $this->services[$id][0] = $factory;
66
67
        return $this;
68
    }
69
70
    /**
71
     * Add a new extension.
72
     *
73
     * @param string|int $id
74
     * @param callable   $extension
75
     *
76
     * @return self
77
     */
78
    public function addExtension($id, callable $extension): self
79
    {
80
        $this->createServiceIfNotExists($id);
81
        $this->services[$id][] = $extension;
82
83
        return $this;
84
    }
85
86
    /**
87
     * Add a new factory.
88
     *
89
     * @param string|int $id
90
     * @param callable   $service
0 ignored issues
show
Bug introduced by
There is no parameter named $service. Was it maybe removed?

This check looks for PHPDoc comments describing methods or function parameters that do not exist on the corresponding method or function.

Consider the following example. The parameter $italy is not defined by the method finale(...).

/**
 * @param array $germany
 * @param array $island
 * @param array $italy
 */
function finale($germany, $island) {
    return "2:1";
}

The most likely cause is that the parameter was removed, but the annotation was not.

Loading history...
91
     */
92
    private function createServiceIfNotExists($id)
93
    {
94
        if (empty($this->services[$id])) {
95
            $this->services[$id] = [null];
96
        }
97
    }
98
99
    /**
100
     * @see ContainerInterface
101
     *
102
     * {@inheritdoc}
103
     */
104
    public function has($id)
105
    {
106
        if (isset($this->items[$id])) {
107
            return true;
108
        }
109
110
        if (isset($this->services[$id][0])) {
111
            return true;
112
        }
113
114
        return false;
115
    }
116
117
    /**
118
     * @see ContainerInterface
119
     *
120
     * {@inheritdoc}
121
     */
122
    public function get($id)
123
    {
124
        if (isset($this->items[$id])) {
125
            return $this->items[$id];
126
        }
127
128
        if (isset($this->services[$id][0])) {
129
            try {
130
                return $this->items[$id] = array_reduce(
131
                    $this->services[$id],
132
                    function ($item, $callback) {
133
                        return $callback($this, $item);
134
                    }
135
                );
136
            } catch (Throwable $exception) {
137
                throw new ContainerException("Error retrieving {$id}", 0, $exception);
138
            }
139
        }
140
141
        throw new NotFoundException("Identifier {$id} is not found");
142
    }
143
144
    /**
145
     * Set a variable.
146
     *
147
     * @param string|int $id
148
     * @param mixed  $value
149
     *
150
     * @return self
151
     */
152
    public function set($id, $value): self
153
    {
154
        $this->items[$id] = $value;
155
156
        return $this;
157
    }
158
159
    /**
160
     * Returns the absolute path of the app.
161
     *
162
     * @param string ...$dirs
163
     *
164
     * @return string
165
     */
166
    public function getPath(string ...$dirs): string
167
    {
168
        if (empty($dirs)) {
169
            return $this->path;
170
        }
171
172
        return self::canonicalize($this->path, $dirs);
173
    }
174
175
    /*
176
     * Returns the base uri of the app.
177
     *
178
     * @param string ...$dirs
179
     *
180
     * @return UriInterface
181
     */
182
    public function getUri(string ...$dirs): UriInterface
183
    {
184
        if (empty($dirs)) {
185
            return $this->uri;
186
        }
187
188
        return $this->uri->withPath(self::canonicalize($this->uri->getPath(), $dirs));
189
    }
190
191
    /**
192
     * helper function to fix paths '//' or '/./' or '/foo/../' in a path.
193
     *
194
     * @param string   $base
195
     * @param string[] $dirs
196
     *
197
     * @return string
198
     */
199
    private static function canonicalize(string $base, array $dirs): string
200
    {
201
        $path = $base.'/'.implode('/', $dirs);
202
        $replace = ['#(/\.?/)#', '#/(?!\.\.)[^/]+/\.\./#'];
203
204
        do {
205
            $path = preg_replace($replace, '/', $path, -1, $n);
206
        } while ($n > 0);
207
208
        return $path;
209
    }
210
}
211