ResourceMetadataFactory::getClass()   C
last analyzed

Complexity

Conditions 8
Paths 10

Size

Total Lines 27
Code Lines 14

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 27
rs 5.3846
c 0
b 0
f 0
cc 8
eloc 14
nc 10
nop 1
1
<?php
2
3
/*
4
 * This file is part of the "elao/api-resources-metadata" package.
5
 *
6
 * Copyright (C) 2016 Elao
7
 *
8
 * @author Elao <[email protected]>
9
 */
10
11
namespace Elao\ApiResourcesMetadata\Resource\Factory;
12
13
use Elao\ApiResourcesMetadata\Exception\InvalidArgumentException;
14
use Elao\ApiResourcesMetadata\Resource\Loader\LoaderInterface;
15
use Elao\ApiResourcesMetadata\Resource\ResourceIndex;
16
use Elao\ApiResourcesMetadata\Resource\ResourceMetadata;
17
use Psr\Cache\CacheItemPoolInterface;
18
19
final class ResourceMetadataFactory
20
{
21
    /**
22
     * @internal
23
     */
24
    const CACHE_PREFIX = 'elao.api_resources_metadata.metadata.';
25
26
    /** @var LoaderInterface[] */
27
    private $loaders;
28
29
    /**
30
     * Loaded metadata indexed by classname
31
     *
32
     * @var ResourceMetadata[]
33
     */
34
    private $loadedClasses;
35
36
    /** @var ResourceIndex */
37
    private $resourceIndex;
38
39
    /** @var CacheItemPoolInterface|null */
40
    private $cache;
41
42
    /**
43
     * @param ResourceIndex               $resourceIndex
44
     * @param LoaderInterface[]           $loaders
45
     * @param CacheItemPoolInterface|null $cache
46
     */
47
    public function __construct(ResourceIndex $resourceIndex, array $loaders, CacheItemPoolInterface $cache = null)
48
    {
49
        $this->loaders = $loaders;
50
        $this->resourceIndex = $resourceIndex;
51
        $this->loadedClasses = [];
52
        $this->cache = $cache;
53
    }
54
55
    /**
56
     * @param $value Resource class, instance, or short name
57
     *
58
     * @throws InvalidArgumentException When none of the loaders were able to guess information from
59
     *
60
     * @return ResourceMetadata
61
     */
62
    public function getMetadataFor($value): ResourceMetadata
63
    {
64
        $class = $this->getClass($value);
65
        $cacheKey = self::CACHE_PREFIX . str_replace('\\', '_', $class);
66
67
        if (null !== $this->cache && $this->cache->getItem($cacheKey)->isHit()) {
68
            return $this->cache->getItem($cacheKey)->get();
69
        }
70
71
        if (isset($this->loadedClasses[$class])) {
72
            return $this->loadedClasses[$class];
73
        }
74
75
        $metadata = new ResourceMetadata($class);
76
77
        $loaded = false;
78
        foreach ($this->loaders as $loader) {
79
            if ($loader->loadResourceMetadata($metadata)) {
80
                $loaded = true;
81
            }
82
        }
83
84
        if (!$loaded) {
85
            throw new InvalidArgumentException(sprintf(
86
                'Unable to load metadata for "%s". No supporting loader found.',
87
                $class
88
            ));
89
        }
90
91
        if (null !== $this->cache) {
92
            $item = $this->cache->getItem($cacheKey);
93
            $item->set($metadata);
94
            $this->cache->save($item);
95
        }
96
97
        return $this->loadedClasses[$class] = $metadata;
98
    }
99
100
    /**
101
     * Gets a class name for a given class, instance or resource short name.
102
     *
103
     * @param string|object $value
104
     *
105
     * @throws InvalidArgumentException If it isn't a resource
106
     *
107
     * @return string The resource class
108
     */
109
    private function getClass($value): string
110
    {
111
        if (!is_string($value) && !is_object($value)) {
112
            throw new InvalidArgumentException(sprintf(
113
                'Cannot create metadata for non-objects. Got: "%s"',
114
                gettype($value)
115
            ));
116
        }
117
118
        if (is_string($value)) {
119
            $value = ltrim($value, '\\');
120
            if (!class_exists($value) && !interface_exists($value)) {
121
                // Check for the resource short name
122
                return $this->resourceIndex->getResourceClass($value);
123
            }
124
        }
125
126
        if (is_object($value)) {
127
            $value = get_class($value);
128
        }
129
130
        if (!$this->resourceIndex->has($value)) {
131
            throw new InvalidArgumentException(sprintf('Class "%s" is not indexed as a resource.', $value));
132
        }
133
134
        return $value;
135
    }
136
}
137