Completed
Pull Request — master (#50)
by Jonathan
04:13 queued 02:03
created

FileDriver::setLocator()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

Changes 0
Metric Value
eloc 1
dl 0
loc 3
rs 10
c 0
b 0
f 0
ccs 0
cts 2
cp 0
cc 1
nc 1
nop 1
crap 2
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 is_file;
12
use function is_string;
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 11
    public function __construct($locator, ?string $fileExtension = null)
42
    {
43 11
        if ($locator instanceof FileLocator) {
44 8
            $this->locator = $locator;
45
        } else {
46 3
            $paths = is_string($locator) ? [$locator] : $locator;
47
48 3
            $this->locator = new DefaultFileLocator($paths, $fileExtension);
49
        }
50 11
    }
51
52
    /**
53
     * Sets the global basename.
54
     */
55 5
    public function setGlobalBasename(string $file) : void
56
    {
57 5
        $this->globalBasename = $file;
58 5
    }
59
60
    /**
61
     * Retrieves the global basename.
62
     */
63 1
    public function getGlobalBasename() : string
64
    {
65 1
        return $this->globalBasename;
66
    }
67
68
    /**
69
     * Gets the element of schema meta data for the class from the mapping file.
70
     * This will lazily load the mapping file if it is not loaded yet.
71
     *
72
     * @return ClassMetadata The element of schema meta data.
73
     *
74
     * @throws MappingException
75
     */
76 3
    public function getElement(string $className) : ClassMetadata
77
    {
78 3
        if ($this->classCache === null) {
79 3
            $this->initialize();
80
        }
81
82 3
        if (isset($this->classCache[$className])) {
83 2
            return $this->classCache[$className];
84
        }
85
86 2
        $result = $this->loadMappingFile($this->locator->findMappingFile($className));
87
88 2
        if (! isset($result[$className])) {
89
            throw MappingException::invalidMappingFile(
90
                $className,
91
                str_replace('\\', '.', $className) . $this->locator->getFileExtension()
92
            );
93
        }
94
95 2
        $this->classCache[$className] = $result[$className];
96
97 2
        return $result[$className];
98
    }
99
100
    /**
101
     * {@inheritDoc}
102
     */
103 3
    public function isTransient(string $className) : bool
104
    {
105 3
        if ($this->classCache === null) {
106 3
            $this->initialize();
107
        }
108
109 3
        if (isset($this->classCache[$className])) {
110 1
            return false;
111
        }
112
113 3
        return ! $this->locator->fileExists($className);
114
    }
115
116
    /**
117
     * {@inheritDoc}
118
     */
119 3
    public function getAllClassNames() : array
120
    {
121 3
        if ($this->classCache === null) {
122 3
            $this->initialize();
123
        }
124
125 3
        if ($this->classCache === []) {
126 1
            return $this->locator->getAllClassNames($this->globalBasename);
127
        }
128
129
        /** @var ClassMetadata[] $classCache */
130 2
        $classCache = $this->classCache;
131
132
        /** @var string[] $keys */
133 2
        $keys = array_keys($classCache);
134
135
        /** @var string[] $merged */
136 2
        $merged = array_merge(
137 2
            $keys,
138 2
            $this->locator->getAllClassNames($this->globalBasename)
139
        );
140
141 2
        return $merged;
142
    }
143
144
    /**
145
     * Loads a mapping file with the given name and returns a map
146
     * from class/entity names to their corresponding file driver elements.
147
     *
148
     * @param string $file The mapping file to load.
149
     *
150
     * @return ClassMetadata[]
151
     */
152
    abstract protected function loadMappingFile(string $file) : array;
153
154
    /**
155
     * Initializes the class cache from all the global files.
156
     *
157
     * Using this feature adds a substantial performance hit to file drivers as
158
     * more metadata has to be loaded into memory than might actually be
159
     * necessary. This may not be relevant to scenarios where caching of
160
     * metadata is in place, however hits very hard in scenarios where no
161
     * caching is used.
162
     */
163 9
    protected function initialize() : void
164
    {
165 9
        $this->classCache = [];
166 9
        if ($this->globalBasename === null) {
167
            return;
168
        }
169
170 9
        foreach ($this->locator->getPaths() as $path) {
171 9
            $file = $path . '/' . $this->globalBasename . $this->locator->getFileExtension();
172 9
            if (! is_file($file)) {
173 5
                continue;
174
            }
175
176 4
            $this->classCache = array_merge(
177 4
                $this->classCache,
178 4
                $this->loadMappingFile($file)
179
            );
180
        }
181 9
    }
182
183
    /**
184
     * Retrieves the locator used to discover mapping files by className.
185
     */
186
    public function getLocator() : FileLocator
187
    {
188
        return $this->locator;
189
    }
190
191
    /**
192
     * Sets the locator used to discover mapping files by className.
193
     */
194
    public function setLocator(FileLocator $locator) : void
195
    {
196
        $this->locator = $locator;
197
    }
198
}
199