Passed
Push — types ( 98b391...18970e )
by Jonathan
01:55
created

FileDriver::getElement()   A

Complexity

Conditions 4
Paths 6

Size

Total Lines 22
Code Lines 11

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 9
CRAP Score 4.25

Importance

Changes 0
Metric Value
eloc 11
dl 0
loc 22
ccs 9
cts 12
cp 0.75
rs 9.9
c 0
b 0
f 0
cc 4
nc 6
nop 1
crap 4.25
1
<?php
2
3
namespace Doctrine\Persistence\Mapping\Driver;
4
5
use Doctrine\Persistence\Mapping\ClassMetadata;
6
use Doctrine\Persistence\Mapping\MappingException;
7
use function array_keys;
8
use function array_merge;
9
use function is_file;
10
use function str_replace;
11
12
/**
13
 * Base driver for file-based metadata drivers.
14
 *
15
 * A file driver operates in a mode where it loads the mapping files of individual
16
 * classes on demand. This requires the user to adhere to the convention of 1 mapping
17
 * file per class and the file names of the mapping files must correspond to the full
18
 * class name, including namespace, with the namespace delimiters '\', replaced by dots '.'.
19
 */
20
abstract class FileDriver implements MappingDriver
21
{
22
    /** @var FileLocator */
23
    protected $locator;
24
25
    /** @var ClassMetadata[]|null */
26
    protected $classCache;
27
28
    /** @var string|null */
29
    protected $globalBasename;
30
31
    /**
32
     * Initializes a new FileDriver that looks in the given path(s) for mapping
33
     * documents and operates in the specified operating mode.
34
     *
35
     * @param string|string[]|FileLocator $locator A FileLocator or one/multiple paths
36
     *                                          where mapping documents can be found.
37
     */
38 11
    public function __construct($locator, ?string $fileExtension = null)
39
    {
40 11
        if ($locator instanceof FileLocator) {
41 8
            $this->locator = $locator;
42
        } else {
43 3
            $this->locator = new DefaultFileLocator((array) $locator, $fileExtension);
44
        }
45 11
    }
46
47
    /**
48
     * Sets the global basename.
49
     */
50 5
    public function setGlobalBasename(string $file) : void
51
    {
52 5
        $this->globalBasename = $file;
53 5
    }
54
55
    /**
56
     * Retrieves the global basename.
57
     */
58 1
    public function getGlobalBasename() : ?string
59
    {
60 1
        return $this->globalBasename;
61
    }
62
63
    /**
64
     * Gets the element of schema meta data for the class from the mapping file.
65
     * This will lazily load the mapping file if it is not loaded yet.
66
     *
67
     * @return ClassMetadata The element of schema meta data.
68
     *
69
     * @throws MappingException
70
     */
71 3
    public function getElement(string $className) : ClassMetadata
72
    {
73 3
        if ($this->classCache === null) {
74 3
            $this->initialize();
75
        }
76
77 3
        if (isset($this->classCache[$className])) {
78 2
            return $this->classCache[$className];
79
        }
80
81 2
        $result = $this->loadMappingFile($this->locator->findMappingFile($className));
82
83 2
        if (! isset($result[$className])) {
84
            throw MappingException::invalidMappingFile(
85
                $className,
86
                str_replace('\\', '.', $className) . $this->locator->getFileExtension()
87
            );
88
        }
89
90 2
        $this->classCache[$className] = $result[$className];
91
92 2
        return $result[$className];
93
    }
94
95
    /**
96
     * {@inheritDoc}
97
     */
98 3
    public function isTransient(string $className) : bool
99
    {
100 3
        if ($this->classCache === null) {
101 3
            $this->initialize();
102
        }
103
104 3
        if (isset($this->classCache[$className])) {
105 1
            return false;
106
        }
107
108 3
        return ! $this->locator->fileExists($className);
109
    }
110
111
    /**
112
     * {@inheritDoc}
113
     */
114 3
    public function getAllClassNames() : array
115
    {
116 3
        if ($this->classCache === null) {
117 3
            $this->initialize();
118
        }
119
120 3
        if (! $this->classCache) {
121 1
            return (array) $this->locator->getAllClassNames($this->globalBasename);
122
        }
123
124
        /** @var string[] $keys */
125 2
        $keys = array_keys($this->classCache);
126
127
        /** @var string[] $merged */
128 2
        $merged = array_merge(
129 2
            $keys,
130 2
            (array) $this->locator->getAllClassNames($this->globalBasename)
131
        );
132
133 2
        return $merged;
134
    }
135
136
    /**
137
     * Loads a mapping file with the given name and returns a map
138
     * from class/entity names to their corresponding file driver elements.
139
     *
140
     * @param string $file The mapping file to load.
141
     *
142
     * @return ClassMetadata[]
143
     */
144
    abstract protected function loadMappingFile(string $file) : array;
145
146
    /**
147
     * Initializes the class cache from all the global files.
148
     *
149
     * Using this feature adds a substantial performance hit to file drivers as
150
     * more metadata has to be loaded into memory than might actually be
151
     * necessary. This may not be relevant to scenarios where caching of
152
     * metadata is in place, however hits very hard in scenarios where no
153
     * caching is used.
154
     */
155 9
    protected function initialize() : void
156
    {
157 9
        $this->classCache = [];
158 9
        if ($this->globalBasename === null) {
159 5
            return;
160
        }
161
162 4
        foreach ($this->locator->getPaths() as $path) {
163 4
            $file = $path . '/' . $this->globalBasename . $this->locator->getFileExtension();
164 4
            if (! is_file($file)) {
165
                continue;
166
            }
167
168 4
            $this->classCache = array_merge(
169 4
                $this->classCache,
170 4
                $this->loadMappingFile($file)
171
            );
172
        }
173 4
    }
174
175
    /**
176
     * Retrieves the locator used to discover mapping files by className.
177
     */
178
    public function getLocator() : FileLocator
179
    {
180
        return $this->locator;
181
    }
182
183
    /**
184
     * Sets the locator used to discover mapping files by className.
185
     */
186
    public function setLocator(FileLocator $locator) : void
187
    {
188
        $this->locator = $locator;
189
    }
190
}
191