Issues (39)

src/Metadata/MetadataFactory.php (1 issue)

1
<?php
2
3
namespace Bdf\Serializer\Metadata;
4
5
use Bdf\Serializer\Metadata\Driver\DriverInterface;
6
use Bdf\Serializer\Exception\UnexpectedValueException;
7
use Psr\SimpleCache\CacheInterface;
8
use ReflectionException;
9
10
/**
11
 * MetadataFactory
12
 */
13
class MetadataFactory implements MetadataFactoryInterface
14
{
15
    /**
16
     * Metadata already resolve
17
     *
18
     * @var ClassMetadata[]
19
     * @psalm-var class-string-map<T, ClassMetadata<T>>
20
     */
21
    private $metadata = [];
22
23
    /**
24
     * The cache for metadata
25
     *
26
     * @var CacheInterface|null
27
     */
28
    private $cache;
29
30
    /**
31
     * The cache id prefix
32
     *
33
     * @var string
34
     */
35
    private $cacheId;
36
37
    /**
38
     * Driver for loading metadata
39
     *
40
     * @var DriverInterface[]
41
     */
42
    private $drivers;
43
44
    /**
45
     * MetadataFactory constructor.
46
     *
47
     * @param array      $drivers
48
     * @param CacheInterface|null $cache
49
     * @param string     $cacheId
50
     */
51 182
    public function __construct(array $drivers, CacheInterface $cache = null, $cacheId = 'serializer-metadata-')
52
    {
53 182
        $this->drivers = $drivers;
54 182
        $this->cache = $cache;
55 182
        $this->cacheId = $cacheId;
56
    }
57
58
    /**
59
     * {@inheritdoc}
60
     *
61
     * @psalm-suppress InvalidReturnType
62
     */
63 158
    public function getMetadata($className): ClassMetadata
64
    {
65 158
        if (is_object($className)) {
66 152
            $className = get_class($className);
67
        }
68
69
        // find from memory
70 158
        if (isset($this->metadata[$className])) {
71 24
            return $this->metadata[$className];
72
        }
73
74
        // Load metadata from drivers
75
        /** @psalm-suppress InvalidReturnStatement */
76 158
        return $this->metadata[$className] = $this->loadMetadata($className);
77
    }
78
79
    /**
80
     * Create a class metadata for this object
81
     *
82
     * @param class-string<T> $className
0 ignored issues
show
Documentation Bug introduced by
The doc comment class-string<T> at position 0 could not be parsed: Unknown type name 'class-string' at position 0 in class-string<T>.
Loading history...
83
     *
84
     * @return ClassMetadata<T>
85
     *
86
     * @template T as object
87
     *
88
     * @throws UnexpectedValueException  if the class name has no metadata
89
     */
90 158
    private function loadMetadata($className): ClassMetadata
91
    {
92 158
        if ($this->cache !== null) {
93
            $cacheId = $this->getCacheKey($className);
94
95
            if ($metadata = $this->cache->get($cacheId)) {
96
                return $metadata;
97
            }
98
        }
99
100
        try {
101 158
            $reflection = new \ReflectionClass($className);
102 2
        } catch (ReflectionException $e) {
103 2
            throw new UnexpectedValueException('Cannot find normalizer for the class "'.$className.'"');
104
        }
105
106 156
        foreach ($this->drivers as $driver) {
107 156
            if ($metadata = $driver->getMetadataForClass($reflection)) {
108 154
                if ($this->cache !== null) {
109
                    /** @psalm-suppress PossiblyUndefinedVariable */
110
                    $this->cache->set($cacheId, $metadata);
111
                }
112 154
                return $metadata;
113
            }
114
        }
115
116 2
        throw new UnexpectedValueException('Cannot find normalizer for the class "'.$className.'"');
117
    }
118
119
    /**
120
     * Get the drivers
121
     *
122
     * @return DriverInterface[]
123
     */
124 2
    public function getDrivers()
125
    {
126 2
        return $this->drivers;
127
    }
128
129
    /**
130
     * Get the cache
131
     *
132
     * @return CacheInterface
133
     */
134 4
    public function getCache(): ?CacheInterface
135
    {
136 4
        return $this->cache;
137
    }
138
139
    /**
140
     * Create the valid cache key from class name
141
     *
142
     * @param string $className
143
     *
144
     * @return string
145
     */
146
    private function getCacheKey(string $className): string
147
    {
148
        return $this->cacheId.str_replace('\\', '.', $className);
149
    }
150
}
151