FactoryListContainer::offsetUnset()   A
last analyzed

Complexity

Conditions 2
Paths 2

Size

Total Lines 14
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Importance

Changes 2
Bugs 0 Features 1
Metric Value
c 2
b 0
f 1
dl 0
loc 14
rs 9.4285
cc 2
eloc 5
nc 2
nop 1
1
<?php
2
3
/**
4
 * Copyright (c) 2016-present Ganbaro Digital Ltd
5
 * All rights reserved.
6
 *
7
 * Redistribution and use in source and binary forms, with or without
8
 * modification, are permitted provided that the following conditions
9
 * are met:
10
 *
11
 *   * Redistributions of source code must retain the above copyright
12
 *     notice, this list of conditions and the following disclaimer.
13
 *
14
 *   * Redistributions in binary form must reproduce the above copyright
15
 *     notice, this list of conditions and the following disclaimer in
16
 *     the documentation and/or other materials provided with the
17
 *     distribution.
18
 *
19
 *   * Neither the names of the copyright holders nor the names of his
20
 *     contributors may be used to endorse or promote products derived
21
 *     from this software without specific prior written permission.
22
 *
23
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
24
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
25
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
26
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
27
 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
28
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
29
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
30
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
31
 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
33
 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
34
 * POSSIBILITY OF SUCH DAMAGE.
35
 *
36
 * @category  Libraries
37
 * @package   DIContainers/V1/FactoryList
38
 * @author    Stuart Herbert <[email protected]>
39
 * @copyright 2016-present Ganbaro Digital Ltd www.ganbarodigital.com
40
 * @license   http://www.opensource.org/licenses/bsd-license.php  BSD License
41
 * @link      http://ganbarodigital.github.io/php-mv-di-containers
42
 */
43
44
namespace GanbaroDigital\DIContainers\V1\FactoryList\Containers;
45
46
use GanbaroDigital\DIContainers\V1\Exceptions\DIContainersExceptions;
47
use GanbaroDigital\DIContainers\V1\Exceptions\NoSuchFactory;
48
use GanbaroDigital\DIContainers\V1\Exceptions\NotAFactory;
49
use GanbaroDigital\DIContainers\V1\Exceptions\NotAListOfFactories;
50
use GanbaroDigital\DIContainers\V1\Exceptions\NotAFactoryList;
51
use GanbaroDigital\DIContainers\V1\Interfaces\EntityContainer;
52
use GanbaroDigital\DIContainers\V1\Interfaces\FactoryList;
53
use GanbaroDigital\DIContainers\V1\Requirements\RequireWriteableContainer;
54
use GanbaroDigital\MissingBits\Entities\WriteProtectTab;
55
56
/**
57
 * An entity which holds a list of registered factories. Can be
58
 * accessed as an array.
59
 */
60
class FactoryListContainer
61
  implements FactoryList
0 ignored issues
show
Coding Style introduced by
The implements keyword must be on the same line as the class name
Loading history...
62
{
63
    // satisfies WriteProtectedEntity interface
64
    use WriteProtectTab;
65
66
    // the file that we are declared in
67
    const file = __FILE__;
0 ignored issues
show
Coding Style introduced by
This class constant is not uppercase (expected FILE).
Loading history...
68
69
    /**
70
     * the list of factories
71
     *
72
     * the 'key' is the alias for the instance. We recommend using either the
73
     * fully-qualified class name, or the class name with no namespace
74
     *
75
     * the 'value' is a callable that returns something. We recommend that this
76
     * always returns an object of some kind, but we deliberately do not
77
     * enforce that, in case you find new and novel ways to use this provider
78
     *
79
     * @var array
80
     */
81
    private $factories = [];
82
83
    /**
84
     * the list of exceptions to throw
85
     *
86
     * @var FactoryList
87
     */
88
    private $exceptions;
89
90
    /**
91
     * create a managed list of factories
92
     *
93
     * the array has the following format:
94
     * - 'key' is the name or alias for your factor
95
     * - 'value' is a callable that will return something
96
     *
97
     * examples of keys include:
98
     *
99
     * - 'NotAFactoryList::newFromVar'
100
     * - 'NotAFactory::newFromNonCallable'
101
     *
102
     * the only requirements on 'value' are that
103
     * - it is a callable
104
     *
105
     * @param array $factories
106
     *        the list of factories to define
107
     * @param FactoryList $exceptions
0 ignored issues
show
Documentation introduced by
Should the type for parameter $exceptions not be null|FactoryList?

This check looks for @param annotations where the type inferred by our type inference engine differs from the declared type.

It makes a suggestion as to what type it considers more descriptive.

Most often this is a case of a parameter that can be null in addition to its declared types.

Loading history...
108
     *        the list of exceptions to throw
109
     */
110
    public function __construct($factories = [], FactoryList $exceptions = null)
111
    {
112
        // make sure we have some exceptions
113
        if ($exceptions === null) {
114
            $exceptions = new DIContainersExceptions;
115
        }
116
117
        // normally, we would not cache the exceptions in an object
118
        // but in this case, some of our public methods need to throw exceptions,
119
        // and cannot accept an exceptions list as a parameter
120
        $this->exceptions = $exceptions;
121
122
        // robustness!
123
        if (!is_array($factories)) {
124
            throw $exceptions['NotAListOfFactories::newFromInputParameter']($factories, '$factories');
125
        }
126
        foreach ($factories as $name => $factory) {
127
            if (!is_callable($factory)) {
128
                throw $exceptions['NotAFactory::newFromInputParameter']($factory, '$factories["' . $name . '"]');
129
            }
130
        }
131
132
        // remember the factories we've been given
133
        $this->factories = $factories;
134
135
        // put ourselves into read-only mode
136
        $this->setReadOnly();
137
    }
138
139
    /**
140
     * get a factory for you to call
141
     *
142
     * @param  string $factoryName
143
     *         a valid key into the list of factories stored in this entity
144
     * @return callable
145
     *
146
     * @throws NoSuchFactory
147
     *         if we can't find a factory for $factoryName
148
     */
149
    public function offsetGet($factoryName)
150
    {
151
        // do we have a factory for this?
152
        if (isset($this->factories[$factoryName])) {
153
            return $this->factories[$factoryName];
154
        }
155
156
        // if we get here, then we do not have a factory by that name
157
        throw $this->exceptions['NoSuchFactory::newFromInputParameter']($factoryName, '$factoryName');
158
    }
159
160
    /**
161
     * do we have a factory for a given instance alias?
162
     *
163
     * @param string $factoryName
164
     *        the factory to look for
165
     */
166
    public function offsetExists($factoryName)
167
    {
168
        if (isset($this->factories[$factoryName])) {
169
            return true;
170
        }
171
172
        return false;
173
    }
174
175
    /**
176
     * set a factory for a given instance alias
177
     *
178
     * @param string $factoryName
179
     *        the name or alias to give to $factory
180
     * @param callable $factory
181
     *        the factory to add to our container
182
     *
183
     * @throws NotAFactory
184
     *         if $factory isn't callable
185
     */
186
    public function offsetSet($factoryName, $factory)
187
    {
188
        // are we allowed to edit this container?
189
        RequireWriteableContainer::apply(null, [RequireWriteableContainer::class])->to($this, '$this');
190
191
        // do we have an acceptable factory?
192
        if (!is_callable($factory)) {
193
            throw $this->exceptions['NotAFactory::newFromInputParameter']($factory, $factoryName);
194
        }
195
196
        // if we get here, all is good
197
        $this->factories[$factoryName] = $factory;
198
    }
199
200
    /**
201
     * forget a factory
202
     *
203
     * @param string $factoryName
204
     *        the factory that we want to forget
205
     */
206
    public function offsetUnset($factoryName)
207
    {
208
        // are we allowed to edit this container?
209
        RequireWriteableContainer::apply(null, [RequireWriteableContainer::class])->to($this, '$this');
210
211
        // it's PHP convention that attempting to unset() something that is
212
        // already unset() is not considered an error
213
        if (!isset($this->factories[$factoryName])) {
214
            return;
215
        }
216
217
        // forget the factory
218
        unset($this->factories[$factoryName]);
219
    }
220
221
    /**
222
     * return the full list of factories as a real PHP array
223
     *
224
     * @return array
225
     */
226
    public function getList()
227
    {
228
        return $this->factories;
229
    }
230
}
231