Completed
Push — master ( c527ef...e35e63 )
by Rafał
02:22
created

Context::getConfigurationForValue()   B

Complexity

Conditions 5
Paths 5

Size

Total Lines 21
Code Lines 11

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 21
rs 8.7624
c 0
b 0
f 0
cc 5
eloc 11
nc 5
nop 1
1
<?php
2
3
/*
4
 * This file is part of the Superdesk Web Publisher Templates System.
5
 *
6
 * Copyright 2015 Sourcefabric z.ú. and contributors.
7
 *
8
 * For the full copyright and license information, please see the
9
 * AUTHORS and LICENSE files distributed with this source code.
10
 *
11
 * @copyright 2015 Sourcefabric z.ú
12
 * @license http://www.superdesk.org/license
13
 */
14
15
namespace SWP\Component\TemplatesSystem\Gimme\Context;
16
17
use Doctrine\Common\Cache\Cache;
18
use SWP\Component\TemplatesSystem\Gimme\Meta\Meta;
19
use Symfony\Component\Finder\Finder;
20
use Symfony\Component\Yaml\Parser;
21
22
class Context implements \ArrayAccess
23
{
24
    /**
25
     * Array with current page information's.
26
     *
27
     * @var Meta
28
     */
29
    protected $currentPage;
30
31
    /**
32
     * Array will all registered meta types.
33
     *
34
     * @var Meta[]
35
     */
36
    protected $registeredMeta = [];
37
38
    /**
39
     * Array with available meta configs.
40
     *
41
     * @var array
42
     */
43
    protected $availableConfigs = [];
44
45
    /**
46
     * @var Cache
47
     */
48
    protected $metadataCache;
49
50
    /**
51
     * @var string
52
     */
53
    protected $configsPath;
54
55
    /**
56
     * @var array
57
     */
58
    private $temporaryMeta = [];
59
60
    /**
61
     * @var bool
62
     */
63
    private $previewMode = false;
64
65
    /**
66
     * @var array
67
     */
68
    private $supportedCache = [];
69
70
    /**
71
     * @var array
72
     */
73
    private $configurationCache = [];
74
75
    /**
76
     * Context constructor.
77
     *
78
     * @param Cache  $metadataCache
79
     * @param string $configsPath
80
     */
81
    public function __construct(Cache $metadataCache, $configsPath = null)
82
    {
83
        $this->metadataCache = $metadataCache;
84
        $this->configsPath = $configsPath;
85
    }
86
87
    /**
88
     * @return array
89
     */
90
    public function getAvailableConfigs()
91
    {
92
        if (0 === count($this->availableConfigs)) {
93
            $this->loadConfigsFromPath($this->configsPath);
94
        }
95
96
        return $this->availableConfigs;
97
    }
98
99
    /**
100
     * @param array $configuration
101
     *
102
     * @return bool
103
     */
104
    public function addAvailableConfig(array $configuration)
105
    {
106
        if (isset($configuration['class']) && !isset($this->availableConfigs[$configuration['class']])) {
107
            $this->availableConfigs[$configuration['class']] = $configuration;
108
109
            return true;
110
        }
111
112
        return false;
113
    }
114
115
    /**
116
     * @param array $availableConfigs
117
     *
118
     * @return Context
119
     */
120
    public function setAvailableConfigs(array $availableConfigs)
121
    {
122
        $this->availableConfigs = $availableConfigs;
123
124
        return $this;
125
    }
126
127
    /**
128
     * @param string $configsPath
129
     */
130
    public function loadConfigsFromPath($configsPath)
131
    {
132
        if (file_exists($configsPath)) {
133
            if (!$this->metadataCache->contains('metadata_config_files')) {
134
                $finder = new Finder();
135
                $finder->in($configsPath)->files()->name('*.yml');
136
                $files = [];
137
                foreach ($finder as $file) {
138
                    $files[] = $file->getRealPath();
139
                    $this->addNewConfig($file->getRealPath());
140
                }
141
                $this->metadataCache->save('metadata_config_files', $files);
142
            } else {
143
                foreach ($this->metadataCache->fetch('metadata_config_files') as $file) {
144
                    $this->addNewConfig($file);
145
                }
146
            }
147
        }
148
    }
149
150
    /**
151
     * @param mixed $value
152
     *
153
     * @return array
154
     *
155
     * @throws \Exception
156
     */
157
    public function getConfigurationForValue($value)
158
    {
159
        if (false === is_object($value)) {
160
            throw new \Exception('Context supports configuration loading only for objects');
161
        }
162
163
        $objectClassName = get_class($value);
164
        if (array_key_exists($objectClassName, $this->configurationCache)) {
165
            return $this->configurationCache[$objectClassName];
166
        }
167
168
        foreach ($this->getAvailableConfigs() as $class => $configuration) {
169
            if ($value instanceof $class) {
170
                $this->configurationCache[$objectClassName] = $configuration;
171
172
                return $configuration;
173
            }
174
        }
175
176
        return [];
177
    }
178
179
    /**
180
     * @param mixed $value
181
     *
182
     * @return Meta
183
     */
184
    public function getMetaForValue($value)
185
    {
186
        return new Meta($this, $value, $this->getConfigurationForValue($value));
187
    }
188
189
    /**
190
     * @param mixed $value
191
     *
192
     * @return bool
193
     */
194
    public function isSupported($value)
195
    {
196
        if (!is_object($value)) {
197
            return false;
198
        }
199
200
        $objectClassName = get_class($value);
201
        if (array_key_exists($objectClassName, $this->supportedCache)) {
202
            return $this->supportedCache[$objectClassName];
203
        }
204
205
        $result = count($this->getConfigurationForValue($value)) > 0 ? true : false;
206
        $this->supportedCache[$objectClassName] = $result;
207
208
        return $result;
209
    }
210
211
    /**
212
     * @param string $filePath
213
     *
214
     * @return $this
215
     */
216
    public function addNewConfig($filePath)
217
    {
218
        $cacheKey = md5($filePath);
219
        if (!$this->metadataCache->contains($cacheKey)) {
220
            if (!is_readable($filePath)) {
221
                throw new \InvalidArgumentException('Configuration file is not readable for parser');
222
            }
223
            $parser = new Parser();
224
            $configuration = $parser->parse(file_get_contents($filePath));
225
            $this->metadataCache->save($cacheKey, $configuration);
226
        } else {
227
            $configuration = $this->metadataCache->fetch($cacheKey);
228
        }
229
230
        $this->addAvailableConfig($configuration);
231
        $this->supportedCache = [];
232
233
        return $configuration;
234
    }
235
236
    /**
237
     * Set current context page information's.
238
     *
239
     * @param Meta $currentPage
240
     *
241
     * @return self
242
     */
243
    public function setCurrentPage(Meta $currentPage)
244
    {
245
        $this->currentPage = $currentPage;
246
247
        return $this;
248
    }
249
250
    /**
251
     * Get current context page information's.
252
     *
253
     * @return Meta
254
     */
255
    public function getCurrentPage()
256
    {
257
        return $this->currentPage;
258
    }
259
260
    /**
261
     * Register new meta type, registration is required before setting new value for meta.
262
     *
263
     * @param Meta|null $meta Meta object
264
     *
265
     * @throws \Exception if already registered
266
     *
267
     * @return bool if registered successfully
268
     */
269
    public function registerMeta(Meta $meta = null)
270
    {
271
        $configuration = $meta->getConfiguration();
0 ignored issues
show
Bug introduced by
It seems like $meta is not always an object, but can also be of type null. Maybe add an additional type check?

If a variable is not always an object, we recommend to add an additional type check to ensure your method call is safe:

function someFunction(A $objectMaybe = null)
{
    if ($objectMaybe instanceof A) {
        $objectMaybe->doSomething();
    }
}
Loading history...
272
        $name = $configuration['name'];
273
        if (!array_key_exists($name, $this->registeredMeta)) {
274
            $this->registeredMeta[$name] = $configuration;
275
            if (null !== $meta) {
276
                $this[$name] = $meta;
277
            }
278
279
            return true;
280
        }
281
282
        return false;
283
    }
284
285
    /**
286
     * @return Meta[]
287
     */
288
    public function getRegisteredMeta()
289
    {
290
        return $this->registeredMeta;
291
    }
292
293
    /**
294
     * @return bool
295
     */
296
    public function isPreviewMode(): bool
297
    {
298
        return $this->previewMode;
299
    }
300
301
    /**
302
     * @param bool $previewMode
303
     */
304
    public function setPreviewMode(bool $previewMode)
305
    {
306
        $this->previewMode = $previewMode;
307
    }
308
309
    /**
310
     * {@inheritdoc}
311
     */
312
    public function offsetSet($name, $meta)
313
    {
314
        if (array_key_exists($name, $this->registeredMeta)) {
315
            $this->$name = $meta;
316
        }
317
318
        return true;
319
    }
320
321
    /**
322
     * {@inheritdoc}
323
     */
324
    public function offsetExists($name)
325
    {
326
        return isset($this->$name);
327
    }
328
329
    /**
330
     * {@inheritdoc}
331
     */
332
    public function offsetUnset($name)
333
    {
334
        unset($this->$name);
335
336
        return true;
337
    }
338
339
    /**
340
     * {@inheritdoc}
341
     */
342
    public function offsetGet($name)
343
    {
344
        if (array_key_exists($name, $this->registeredMeta) && isset($this->$name)) {
345
            return $this->$name;
346
        }
347
348
        return false;
349
    }
350
351
    /**
352
     * @param array $keys
353
     *
354
     * @return string
355
     */
356
    public function temporaryUnset(array $keys)
357
    {
358
        $metas = [];
359
        $keysId = md5(serialize($keys));
360
361
        if (0 === count($keys)) {
362
            foreach ($this->registeredMeta as $key => $configuration) {
363
                if (isset($this[$key])) {
364
                    $metas[$key] = $this[$key];
365
                    unset($this[$key]);
366
                }
367
            }
368
        }
369
370
        foreach ($keys as $key) {
371
            if (array_key_exists($key, $this->registeredMeta)) {
372
                $metas[$key] = $this[$key];
373
                unset($this[$key]);
374
            }
375
        }
376
        $this->temporaryMeta[$keysId] = $metas;
377
378
        return $keysId;
379
    }
380
381
    /**
382
     * @param string $id
383
     *
384
     * @return null|true
385
     */
386
    public function restoreTemporaryUnset($id)
387
    {
388
        $metas = $this->temporaryMeta[$id];
389
        if (!is_array($metas)) {
390
            return;
391
        }
392
393
        foreach ($metas as $key => $value) {
394
            $this[$key] = $value;
395
        }
396
397
        return true;
398
    }
399
400
    /**
401
     *  Resets context data.
402
     */
403
    public function reset()
404
    {
405
        $this->currentPage = null;
406
        $this->registeredMeta = [];
407
        $this->availableConfigs = [];
408
        $this->previewMode = false;
409
    }
410
}
411