SimpleDI::resetStored()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 3
CRAP Score 1

Importance

Changes 0
Metric Value
dl 0
loc 4
ccs 3
cts 3
cp 1
rs 10
c 0
b 0
f 0
cc 1
eloc 2
nc 1
nop 0
crap 1
1
<?php namespace SimpleDI;
2
3
use SimpleDI\Exception\SimpleDIException;
4
use SimpleHash\Hash;
5
use Closure;
6
7
/**
8
 * This is the main application
9
 *
10
 * @package    SimpleDI
11
 * @author     Kai Hempel <[email protected]>
12
 * @copyright  2015 Kai Hempel <[email protected]>
13
 * @license    http://www.opensource.org/licenses/BSD-3-Clause  The BSD 3-Clause License
14
 * @link       https://www.kuweh.de/
15
 * @since      Class available since Release 1.0.0
16
 */
17
class SimpleDI
18
{
19
    /**
20
     * Closure array
21
     *
22
     * @var array
23
     */
24
    protected $closures = array();
25
26
    /**
27
     * Getter list
28
     *
29
     * @var array
30
     */
31
    protected $getterList = array();
32
33
    /**
34
     * Object storage
35
     *
36
     * @var array
37
     */
38
    protected $objectList = array();
39
40
    /**
41
     * Processflag to store the dependency objects
42
     *
43
     * @var boolean
44
     */
45
    protected $getStored = false;
46
47
    /**
48
     * Constructor
49
     */
50 9
    public function __construct()
51
    {
52 9
    }
53
54
    /**
55
     * Sets the closure and the getter mapping
56
     *
57
     * @param   string          $name           Class name
58
     * @param   Closure         $closure        Closure function: Code to create
59
     *                                          the object instance.
60
     * @return  SimpleDI
61
     */
62 7
    public function add($name, Closure $closure)
63
    {
64 7
        if (isset($this->closures[$name])) {
65 1
            throw SimpleDIException::make('"' . $name . '" already exists!');
66
        }
67
68 7
        $this->addGetter($name);
69 7
        $this->closures[$name] = $closure;
70
71 7
        return $this;
72
    }
73
74
    /**
75
     * Removes the closure and getter mapping.
76
     *
77
     * @param   string          $name           Class name
78
     * @return  SimpleDI
79
     */
80 3
    public function remove($name)
81
    {
82 3
        $this->removeGetter($name);
83
84 3
        if ($this->exists($name)) {
85 3
            unset($this->closures[$name]);
86 3
        }
87
88 3
        return $this;
89
    }
90
91
    /**
92
     * Checks if one entry exists
93
     *
94
     * @param   string          $name           Class name
95
     * @return  boolean
96
     */
97 5
    public function exists($name)
98
    {
99 5
        return isset($this->closures[$name]);
100
    }
101
102
    /**
103
     * Checks if the current container is empty
104
     *
105
     * @return  boolean
106
     */
107 1
    public function isEmpty()
108
    {
109 1
        return empty($this->closures);
110
    }
111
112
    /**
113
     * Sets the getStored flag to true.
114
     * The next closure call will first check the local object list.
115
     * If no object is stored the result will be saved in the object list.
116
     *
117
     * @return  SimpleDI
118
     */
119 2
    public function getStored()
120
    {
121 2
        $this->getStored = true;
122
123 2
        return $this;
124
    }
125
126
    /**
127
     * Calls the container __call method.
128
     * This methods is the central closure call.
129
     *
130
     * @param   string          $name           Getter function name
131
     * @param   array           $args           Construction arguments
132
     * @return  false|mixed
133
     * @throws  SimpleDIException
134
     */
135 5
    public function __call($name, $args = array())
136
    {
137 5
        if (substr($name, 0, 3) != 'get') {
138 1
            throw SimpleDIException::make('Undefined method called!');
139
        }
140
141 4
        $name = $this->dispatchGetter($name);
142
143 4
        return $this->callClosure($name, $args);
144
    }
145
146
    /**
147
     * Executes the stored closure from the container. The method returns the
148
     * closure result or false in the closure execution fails.
149
     * If the "getStored" flag is set, the method checks the object list for a
150
     * exsisting instance. Otherwise the created instance will be stored for
151
     * further use.
152
     *
153
     * @param   string          $name           Class name
154
     * @param   array           $args           Construction arguments
155
     * @return  boolean|mixed
156
     */
157 4
    private function callClosure($name, $args)
158
    {
159
        // Check if the current object is stored
160
161 4
        $hash = $this->generateStorageHash($name, $args);
162
163 4
        if ($this->getStored === true && $this->isStored($hash)) {
164 1
            $this->resetStored();
165 1
            return $this->objectList[$hash];
166
        }
167
168
        // Call the closure and store the object
169
170 4
        $result = call_user_func_array($this->closures[$name], $args);
171
172
        // Store the instance in current object list
173
174 4
        if (is_object($result) && $this->getStored === true) {
175 2
            $this->resetStored();
176 2
            $this->objectList[$hash] = $result;
177 2
        }
178
179
        // Return the closure result
180
181 4
        return $result;
182
    }
183
184
    /**
185
     * Generates a hash to store the specific object
186
     *
187
     * @param   string          $name           Class name
188
     * @param   array           $args           Arguments
189
     * @return  string
190
     */
191 4
    private function generateStorageHash($name, $args) {
192
193 4
        $hash = Hash::Sha1($name . '_' . serialize($args));
194 4
        return $hash->getHashString();
195
    }
196
197
    /**
198
     * Checks if the current requested object is stored in the object list.
199
     *
200
     * @param   string          $hash           Class name
201
     * @return  mixed
202
     */
203 2
    private function isStored($hash)
204
    {
205 2
        if (empty($hash)) {
206
            return false;
207
        }
208
209 2
        return isset($this->objectList[$hash]);
210
    }
211
212
    /**
213
     * Resets the stored flag.
214
     * This should only enabled for the next operation!
215
     *
216
     * @return void
217
     */
218 2
    private function resetStored()
219
    {
220 2
        $this->getStored = false;
221 2
    }
222
223
    /**
224
     * Returns the getter name
225
     *
226
     * @param   string          $name           Class name
227
     * @return  string
228
     */
229 7
    private function buildGetterName($name)
230
    {
231 7
        return 'get' . ucfirst($name);
232
    }
233
234
    /**
235
     * Adds the getter function mapping to the getter list.
236
     *
237
     * @param   string          $name           Class name
238
     * @return  void
239
     */
240 7
    private function addGetter($name)
241
    {
242 7
        $this->getterList[$this->buildGetterName($name)] = $name;
243 7
    }
244
245
    /**
246
     * Removes the getter from the mapping list.
247
     *
248
     * @param   string          $name           Class name
249
     * @return  void
250
     */
251 3
    private function removeGetter($name)
252
    {
253 3
        $getter = $this->buildGetterName($name);
254
255 3
        if (isset($this->getterList[$getter])) {
256 3
            unset($this->getterList[$getter]);
257 3
        }
258 3
    }
259
260
    /**
261
     * Returns the mapped container method name.
262
     *
263
     * @param   string          $getter         Getter function name
264
     * @return  string
265
     * @throws  SimpleDIException
266
     */
267 4
    private function dispatchGetter($getter)
268
    {
269 4
        if (! isset($this->getterList[$getter])) {
270 2
            throw SimpleDIException::make('Undefined dependency "' . $getter . '"!');
271
        }
272
273 4
        return $this->getterList[$getter];
274
    }
275
}
276