Failed Conditions
Push — master ( cadc22...fc953e )
by Marco
33s
created

FileDriver::getAllClassNames()   A

Complexity

Conditions 3
Paths 4

Size

Total Lines 19
Code Lines 9

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 10
CRAP Score 3

Importance

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