Test Failed
Push — master ( 9fdf3e...42dea4 )
by Mikael
01:22
created

CDI::load()   B

Complexity

Conditions 6
Paths 10

Size

Total Lines 30
Code Lines 20

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 30
rs 8.439
c 0
b 0
f 0
cc 6
eloc 20
nc 10
nop 1
1
<?php
2
3
namespace Anax\DI;
4
5
/**
6
 * Anax base class implementing Dependency Injection / Service Locator of the services used by the
7
 * framework, using lazy loading.
8
 *
9
 */
10
class CDI implements IDI
11
{
12
13
    /**
14
     * Properties
15
     *
16
     */
17
    public $loaded = [];  // Store all lazy loaded services, ready to be instantiated
18
    public $active = [];  // A service is instantiated into this array, once its accessed
19
20
21
22
    /**
23
     * Construct.
24
     *
25
     */
26
    public function __construct()
27
    {
28
        ;
29
    }
30
31
32
33
    /**
34
     * Return an arry with all loaded services names.
35
     *
36
     * @return void
37
     */
38
    public function getServices()
39
    {
40
        return array_keys($this->loaded);
41
    }
42
43
44
45
    /**
46
     * Return an array with all loaded services that are controllers.
47
     *
48
     * @return void
49
     */
50
    public function getControllers()
51
    {
52
        return array_filter(
53
            array_keys($this->loaded),
54
            function ($val) {
55
                return strpos($val, "Controller") !== false;
56
            }
57
        );
58
    }
59
60
61
62
    /**
63
     * Return an arry with all active services names.
64
     *
65
     * @return void
66
     */
67
    public function getActiveServices()
68
    {
69
        return array_keys($this->active);
70
    }
71
72
73
74
    /**
75
     * Set a service and connect it to a task which creates the object (lazy loading).
76
     *
77
     * @param string  $service   as a service label, naming this service.
78
     * @param mixed   $loader    contains a pre-defined object, a string with classname or an
79
     *      callable which returns an instance of the service object. Its the way to
80
     *      actually load, insantiate, the serviceobject.
81
     * @param boolean $singleton set if service is to act as singleton or not, default is false.
82
     *
83
     * @return nothing.
0 ignored issues
show
Documentation introduced by
The doc-type nothing. could not be parsed: Unknown type name "nothing." at position 0. (view supported doc-types)

This check marks PHPDoc comments that could not be parsed by our parser. To see which comment annotations we can parse, please refer to our documentation on supported doc-types.

Loading history...
84
     */
85
    public function set($service, $loader, $singleton = false)
86
    {
87
        $this->loaded[$service]['loader'] = $loader;
88
        $this->loaded[$service]['singleton'] = $singleton;
89
    }
90
91
92
93
    /**
94
     * Set a singleton service and connect it to a task which creates the object (lazy loading).
95
     *
96
     * @param string $service as a service label, naming this service.
97
     * @param mixed  $loader  contains a pre-defined object, a string with
98
     *                        classname or an callable which returns an
99
     *                        instance of the service object. Its the way
100
     *                        to actually load, insantiate, the serviceobject.
101
     *
102
     * @return nothing.
0 ignored issues
show
Documentation introduced by
The doc-type nothing. could not be parsed: Unknown type name "nothing." at position 0. (view supported doc-types)

This check marks PHPDoc comments that could not be parsed by our parser. To see which comment annotations we can parse, please refer to our documentation on supported doc-types.

Loading history...
103
     */
104
    public function setShared($service, $loader)
105
    {
106
        $this->set($service, $loader, true);
107
    }
108
109
110
111
    /**
112
     * Get an instance of the service object, managing singletons.
113
     *
114
     * @param string $service as a service label, naming this service.
115
     *
116
     * @return object as instance of the service object.
117
     * @throws Exception when service accessed is not loaded.
118
     */
119
    public function get($service)
120
    {
121
        // Is the service active?
122
        if (isset($this->active[$service])) {
123
            if ($this->loaded[$service]['singleton']) {
124
                return $this->active[$service];
125
            } else {
126
                return $this->load($service);
127
            }
128
        } elseif (isset($this->loaded[$service])) {
129
            // Is the service loaded?
130
            return $this->load($service);
131
        }
132
133
        $message  = "CDI the service accessed '$service' is not loaded in the DI-container.";
134
        $services = $this->getServices();
135
        natcasesort($services);
136
        $services = implode("\n", $services);
137
        $message .= " Loaded services are: <pre>$services</pre>";
138
        
139
        throw new \Exception($message);
140
    }
141
142
143
144
    /**
145
     * Magic method to get and create services.
146
     * When created it is also stored as a parameter of this object.
147
     *
148
     * @param string $service name of class property not existing.
149
     *
150
     * @return class as the service requested.
151
     */
152
    public function __get($service)
153
    {
154
        return $this->get($service);
155
    }
156
157
158
159
    /**
160
     * Check if service exists by name.
161
     *
162
     * @param string $service as a service label, naming this service.
163
     *
164
     * @return boolean true if the service exists, otherwise false.
165
     */
166
    public function has($service)
167
    {
168
        return isset($this->loaded[$service])
169
            ? true
170
            : false;
171
    }
172
173
174
175
    /**
176
     * Magic method to get and create services.
177
     * When created it is also stored as a parameter of this object.
178
     *
179
     * @param string $service   name of class property not existing.
180
     * @param array  $arguments currently NOT USED.
181
     *
182
     * @return class as the service requested.
183
     */
184
    public function __call($service, $arguments = [])
185
    {
186
        return $this->get($service);
187
    }
188
189
190
191
    /**
192
     * Lazy load a service object and create an instance of it.
193
     *
194
     * @param string $service as a service label, naming this service.
195
     *
196
     * @return object as instance of the service object.
197
     * @throws Exception when service could not be loaded.
198
     */
199
    protected function load($service)
200
    {
201
        $sol = isset($this->loaded[$service]['loader'])
202
            ? $this->loaded[$service]['loader']
203
            : null;
204
205
        // Load by calling a function
206
        if (is_callable($sol)) {
207
            try {
208
                $this->active[$service] = $sol();
209
            } catch (\Exception $e) {
210
                throw new \Exception(
211
                    "CDI could not load service '$service'."
212
                    . "Failed in the callback that instantiates the service. "
213
                    . $e->getMessage()
214
                );
215
            }
216
        } elseif (is_object($sol)) {
217
            // Load by pre-instantiated object
218
            $this->active[$service] = $sol;
219
        } elseif (is_string($sol)) {
220
            // Load by creating a new object from class-string
221
            $this->active[$service] = new $sol();
222
        } else {
223
            throw new Exception("CDI could not load service '$service'. It is unknown how to load it.");
224
        }
225
226
        $this->$service = $this->active[$service];
227
        return $this->active[$service];
228
    }
229
}
230