Completed
Branch master (f77b3e)
by
unknown
05:55
created

Container::getProviderMappings()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 1

Importance

Changes 1
Bugs 0 Features 0
Metric Value
c 1
b 0
f 0
dl 0
loc 4
ccs 2
cts 2
cp 1
rs 10
cc 1
eloc 2
nc 1
nop 0
crap 1
1
<?php namespace Neomerx\JsonApi\Schema;
2
3
/**
4
 * Copyright 2015 [email protected] (www.neomerx.com)
5
 *
6
 * Licensed under the Apache License, Version 2.0 (the "License");
7
 * you may not use this file except in compliance with the License.
8
 * You may obtain a copy of the License at
9
 *
10
 * http://www.apache.org/licenses/LICENSE-2.0
11
 *
12
 * Unless required by applicable law or agreed to in writing, software
13
 * distributed under the License is distributed on an "AS IS" BASIS,
14
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15
 * See the License for the specific language governing permissions and
16
 * limitations under the License.
17
 */
18
19
use \Closure;
20
use \InvalidArgumentException;
21
use \Psr\Log\LoggerAwareTrait;
22
use \Psr\Log\LoggerAwareInterface;
23
use \Neomerx\JsonApi\Factories\Exceptions;
24
use \Neomerx\JsonApi\I18n\Translator as T;
25
use \Neomerx\JsonApi\Contracts\Schema\ContainerInterface;
26
use \Neomerx\JsonApi\Contracts\Schema\SchemaFactoryInterface;
27
use \Neomerx\JsonApi\Contracts\Schema\SchemaProviderInterface;
28
29
/**
30
 * @package Neomerx\JsonApi
31
 */
32
class Container implements ContainerInterface, LoggerAwareInterface
33
{
34
    use LoggerAwareTrait;
35
36
    /**
37
     * @var array
38
     */
39
    private $providerMapping = [];
40
41
    /**
42
     * @var SchemaProviderInterface[]
43
     */
44
    private $createdProviders = [];
45
46
    /**
47
     * @var array
48
     */
49
    private $resType2JsonType = [];
50
51
    /**
52
     * @var SchemaFactoryInterface
53
     */
54
    private $factory;
55
56
    /**
57
     * @param SchemaFactoryInterface $factory
58
     * @param array                  $schemas
59
     */
60 79
    public function __construct(SchemaFactoryInterface $factory, array $schemas = [])
61
    {
62 79
        $this->factory = $factory;
63 79
        $this->registerArray($schemas);
64 77
    }
65
66
    /**
67
     * Register provider for resource type.
68
     *
69
     * @param string         $type
70
     * @param string|Closure $schema
71
     *
72
     * @return void
73
     */
74 71
    public function register($type, $schema)
75
    {
76
        // Type must be non-empty string
77 71
        $isOk = (is_string($type) === true && empty($type) === false);
78 71
        if ($isOk === false) {
79 1
            throw new InvalidArgumentException(T::t('Type must be non-empty string.'));
80
        }
81
82 70
        $isOk = ((is_string($schema) === true && empty($schema) === false) || $schema instanceof Closure);
83 70
        if ($isOk === false) {
84 1
            throw new InvalidArgumentException(T::t(
85 1
                'Schema for type \'%s\' must be non-empty string or Closure.',
86 1
                [$type]
87 1
            ));
88
        }
89
90 69 View Code Duplication
        if ($this->hasProviderMapping($type) === true) {
91 1
            throw new InvalidArgumentException(T::t(
92 1
                'Type should not be used more than once to register a schema (\'%s\').',
93 1
                [$type]
94 2
            ));
95
        }
96
97 69
        $this->setProviderMapping($type, $schema);
98 69
    }
99
100
    /**
101
     * Register providers for resource types.
102
     *
103
     * @param array $schemas
104
     *
105
     * @return void
106
     */
107 79
    public function registerArray(array $schemas)
108
    {
109 79
        foreach ($schemas as $type => $schema) {
110 70
            $this->register($type, $schema);
111 77
        }
112 77
    }
113
114
    /**
115
     * @inheritdoc
116
     */
117 60
    public function getSchema($resource)
118
    {
119 60
        $resourceType = $this->getResourceType($resource);
120
121 60
        return $this->getSchemaByType($resourceType);
122
    }
123
124
    /**
125
     * @inheritdoc
126
     */
127 62
    public function getSchemaByType($type)
128
    {
129 62
        is_string($type) === true ?: Exceptions::throwInvalidArgument('type', $type);
130
131 62
        if ($this->hasCreatedProvider($type) === true) {
132 54
            return $this->getCreatedProvider($type);
133
        }
134
135 62 View Code Duplication
        if ($this->hasProviderMapping($type) === false) {
136 2
            throw new InvalidArgumentException(T::t('Schema is not registered for type \'%s\'.', [$type]));
137
        }
138
139 62
        $classNameOrClosure = $this->getProviderMapping($type);
140 62
        if ($classNameOrClosure instanceof Closure) {
141 29
            $schema = $this->createSchemaFromClosure($classNameOrClosure);
142 29
        } else {
143 43
            $schema = $this->createSchemaFromClassName($classNameOrClosure);
144
        }
145 62
        $this->setCreatedProvider($type, $schema);
146
147
        /** @var SchemaProviderInterface $schema */
148
149 62
        $this->setResourceToJsonTypeMapping($schema->getResourceType(), $type);
150
151 62
        return $schema;
152
    }
153
154
    /**
155
     * @inheritdoc
156
     */
157 45
    public function getSchemaByResourceType($resourceType)
158
    {
159
        // Schema is not found among instantiated schemas for resource type $resourceType
160 45
        $isOk = (is_string($resourceType) === true && $this->hasResourceToJsonTypeMapping($resourceType) === true);
161
162
        // Schema might not be found if it hasn't been searched by type (not resource type) before.
163
        // We instantiate all schemas and then find one.
164 45
        if ($isOk === false) {
165 1
            foreach ($this->getProviderMappings() as $type => $schema) {
166 1
                if ($this->hasCreatedProvider($type) === false) {
167
                    // it will instantiate the schema
168 1
                    $this->getSchemaByType($type);
169 1
                }
170 1
            }
171 1
        }
172
173
        // search one more time
174 45
        $isOk = (is_string($resourceType) === true && $this->hasResourceToJsonTypeMapping($resourceType) === true);
175
176 45
        if ($isOk === false) {
177 1
            throw new InvalidArgumentException(T::t(
178 1
                'Schema is not registered for resource type \'%s\'.',
179 1
                [$resourceType]
180 1
            ));
181
        }
182
183 45
        return $this->getSchemaByType($this->getJsonType($resourceType));
184
    }
185
186
    /**
187
     * @return SchemaFactoryInterface
188
     */
189 62
    protected function getFactory()
190
    {
191 62
        return $this->factory;
192
    }
193
194
    /**
195
     * @return array
196
     */
197 1
    protected function getProviderMappings()
198
    {
199 1
        return $this->providerMapping;
200
    }
201
202
    /**
203
     * @param string $type
204
     *
205
     * @return bool
206
     */
207 69
    protected function hasProviderMapping($type)
208
    {
209 69
        return array_key_exists($type, $this->providerMapping);
210
    }
211
212
    /**
213
     * @param string $type
214
     *
215
     * @return mixed
216
     */
217 62
    protected function getProviderMapping($type)
218
    {
219 62
        return $this->providerMapping[$type];
220
    }
221
222
    /**
223
     * @param string         $type
224
     * @param string|Closure $schema
225
     *
226
     * @return void
227
     */
228 69
    protected function setProviderMapping($type, $schema)
229
    {
230 69
        $this->providerMapping[$type] = $schema;
231 69
    }
232
233
    /**
234
     * @param string $type
235
     *
236
     * @return bool
237
     */
238 62
    protected function hasCreatedProvider($type)
239
    {
240 62
        return array_key_exists($type, $this->createdProviders);
241
    }
242
243
    /**
244
     * @param string $type
245
     *
246
     * @return SchemaProviderInterface
247
     */
248 54
    protected function getCreatedProvider($type)
249
    {
250 54
        return $this->createdProviders[$type];
251
    }
252
253
    /**
254
     * @param string                  $type
255
     * @param SchemaProviderInterface $provider
256
     *
257
     * @return void
258
     */
259 62
    protected function setCreatedProvider($type, SchemaProviderInterface $provider)
260
    {
261 62
        $this->createdProviders[$type] = $provider;
262 62
    }
263
264
    /**
265
     * @param string $resourceType
266
     *
267
     * @return bool
268
     */
269 45
    protected function hasResourceToJsonTypeMapping($resourceType)
270
    {
271 45
        return array_key_exists($resourceType, $this->resType2JsonType);
272
    }
273
274
    /**
275
     * @param string $resourceType
276
     *
277
     * @return string
278
     */
279 45
    protected function getJsonType($resourceType)
280
    {
281 45
        return $this->resType2JsonType[$resourceType];
282
    }
283
284
    /**
285
     * @param string $resourceType
286
     * @param string $jsonType
287
     *
288
     * @return void
289
     */
290 62
    protected function setResourceToJsonTypeMapping($resourceType, $jsonType)
291
    {
292 62
        $this->resType2JsonType[$resourceType] = $jsonType;
293 62
    }
294
295
    /**
296
     * @param object $resource
297
     *
298
     * @return string
299
     */
300 60
    protected function getResourceType($resource)
301
    {
302 60
        return get_class($resource);
303
    }
304
305
    /**
306
     * @param Closure $closure
307
     *
308
     * @return SchemaProviderInterface
309
     */
310 28
    protected function createSchemaFromClosure(Closure $closure)
311
    {
312 28
        $schema = $closure($this->getFactory());
313
314 28
        return $schema;
315
    }
316
317
    /**
318
     * @param string $className
319
     *
320
     * @return SchemaProviderInterface
321
     */
322 42
    protected function createSchemaFromClassName($className)
323
    {
324 42
        $schema = new $className($this->getFactory());
325
326 42
        return $schema;
327
    }
328
}
329