Passed
Push — types ( 30d5cd )
by Jonathan
04:47
created

FileDriver::initialize()   A

Complexity

Conditions 4
Paths 4

Size

Total Lines 16
Code Lines 10

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 10
CRAP Score 4.0119

Importance

Changes 0
Metric Value
eloc 10
dl 0
loc 16
rs 9.9332
c 0
b 0
f 0
ccs 10
cts 11
cp 0.9091
cc 4
nc 4
nop 0
crap 4.0119
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 2
        if (! isset($result[$className])) {
83
            throw MappingException::invalidMappingFile($className, str_replace('\\', '.', $className) . $this->locator->getFileExtension());
84
        }
85
86 2
        $this->classCache[$className] = $result[$className];
87
88 2
        return $result[$className];
89
    }
90
91
    /**
92
     * {@inheritDoc}
93
     */
94 3
    public function isTransient(string $className) : bool
95
    {
96 3
        if ($this->classCache === null) {
97 3
            $this->initialize();
98
        }
99
100 3
        if (isset($this->classCache[$className])) {
101 1
            return false;
102
        }
103
104 3
        return ! $this->locator->fileExists($className);
105
    }
106
107
    /**
108
     * {@inheritDoc}
109
     */
110 3
    public function getAllClassNames() : array
111
    {
112 3
        if ($this->classCache === null) {
113 3
            $this->initialize();
114
        }
115
116 3
        if (! $this->classCache) {
117 1
            return (array) $this->locator->getAllClassNames($this->globalBasename);
118
        }
119
120
        /** @var string[] $keys */
121 2
        $keys = array_keys($this->classCache);
122
123
        /** @var string[] $merged */
124 2
        $merged = array_merge(
125 2
            $keys,
126 2
            (array) $this->locator->getAllClassNames($this->globalBasename)
127
        );
128
129 2
        return $merged;
130
    }
131
132
    /**
133
     * Loads a mapping file with the given name and returns a map
134
     * from class/entity names to their corresponding file driver elements.
135
     *
136
     * @param string $file The mapping file to load.
137
     *
138
     * @return ClassMetadata[]
139
     */
140
    abstract protected function loadMappingFile(string $file) : array;
141
142
    /**
143
     * Initializes the class cache from all the global files.
144
     *
145
     * Using this feature adds a substantial performance hit to file drivers as
146
     * more metadata has to be loaded into memory than might actually be
147
     * necessary. This may not be relevant to scenarios where caching of
148
     * metadata is in place, however hits very hard in scenarios where no
149
     * caching is used.
150
     */
151 9
    protected function initialize() : void
152
    {
153 9
        $this->classCache = [];
154 9
        if ($this->globalBasename === null) {
155 5
            return;
156
        }
157
158 4
        foreach ($this->locator->getPaths() as $path) {
159 4
            $file = $path . '/' . $this->globalBasename . $this->locator->getFileExtension();
160 4
            if (! is_file($file)) {
161
                continue;
162
            }
163
164 4
            $this->classCache = array_merge(
165 4
                $this->classCache,
166 4
                $this->loadMappingFile($file)
167
            );
168
        }
169 4
    }
170
171
    /**
172
     * Retrieves the locator used to discover mapping files by className.
173
     */
174
    public function getLocator() : FileLocator
175
    {
176
        return $this->locator;
177
    }
178
179
    /**
180
     * Sets the locator used to discover mapping files by className.
181
     */
182
    public function setLocator(FileLocator $locator) : void
183
    {
184
        $this->locator = $locator;
185
    }
186
}
187