Passed
Pull Request — 1.1 (#48)
by Patrick
03:58
created

FluentDriver::loadPaths()   C

Complexity

Conditions 11
Paths 20

Size

Total Lines 59
Code Lines 31

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 35
CRAP Score 11.0191

Importance

Changes 0
Metric Value
dl 0
loc 59
ccs 35
cts 37
cp 0.9459
rs 6.3545
c 0
b 0
f 0
cc 11
eloc 31
nc 20
nop 1
crap 11.0191

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
3
namespace LaravelDoctrine\Fluent;
4
5
use Doctrine\Common\Persistence\Mapping\ClassMetadata;
6
use Doctrine\Common\Persistence\Mapping\Driver\MappingDriver;
7
use Doctrine\ORM\Mapping\Builder\ClassMetadataBuilder;
8
use Doctrine\ORM\Mapping\MappingException;
9
use FilesystemIterator;
10
use InvalidArgumentException;
11
use LaravelDoctrine\Fluent\Builders\Builder;
12
use LaravelDoctrine\Fluent\Mappers\MapperSet;
13
use RecursiveDirectoryIterator;
14
use RecursiveIteratorIterator;
15
use RecursiveRegexIterator;
16
use ReflectionClass;
17
use RegexIterator;
18
19
class FluentDriver implements MappingDriver
20
{
21
    /**
22
     * @var MapperSet
23
     */
24
    protected $mappers;
25
26
    /**
27
     * @var callable
28
     */
29
    protected $fluentFactory;
30
31
    /**
32
     * The file extension of mapping documents.
33
     *
34
     * @var string
35
     */
36
    protected $fileExtension = '.php';
37
38
    /**
39
     * Initializes a new FileDriver that looks in the given path(s) for mapping
40
     * documents and operates in the specified operating mode.
41
     *
42
     * @param string[] $mappings
43
     * @param array    $paths
44
     *
45
     * @throws MappingException
46
     */
47
    public function __construct(array $mappings = [], array $paths = [])
48
    {
49 5
        $this->fluentFactory = function (ClassMetadata $metadata) {
50 5
            return new Builder(new ClassMetadataBuilder($metadata));
51
        };
52
53 95
        $this->mappers = new MapperSet();
54
55 95
        if (!empty($paths)) {
56 1
            $this->loadPaths($paths);
57 1
        }
58
59 95
        if (!empty($mappings)) {
60 79
            $this->addMappings($mappings);
61 79
        }
62 95
    }
63
64
    /**
65
     * Loads the metadata for the specified class into the provided container.
66
     *
67
     * @param string        $className
68
     * @param ClassMetadata $metadata
69
     */
70 7
    public function loadMetadataForClass($className, ClassMetadata $metadata)
71
    {
72 7
        $this->mappers->getMapperFor($className)->map(
73 6
            $this->getFluent($metadata)
74 6
        );
75 6
    }
76
77
    /**
78
     * Gets the names of all mapped classes known to this driver.
79
     *
80
     * @throws MappingException
81
     *
82
     * @return string[] The names of all mapped classes known to this driver.
83
     */
84 14
    public function getAllClassNames()
85
    {
86 14
        return $this->mappers->getClassNames();
87
    }
88
89
    /**
90
     * Returns whether the class with the specified name should have its metadata loaded.
91
     * This is only the case if it is either mapped as an Entity or a MappedSuperclass.
92
     *
93
     * @param string $className
94
     *
95
     * @return bool
96
     */
97 6
    public function isTransient($className)
98
    {
99
        return
100 6
            !$this->mappers->hasMapperFor($className) ||
101 6
            $this->mappers->getMapperFor($className)->isTransient();
102
    }
103
104
    /**
105
     * @param array $paths
106
     *
107
     * @throws MappingException
108
     */
109 3
    public function loadPaths(array $paths)
110
    {
111 3
        $classes = [];
0 ignored issues
show
Unused Code introduced by
$classes is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
112 3
        $includedFiles = [];
113
114 3
        foreach ($paths as $path) {
115 3
            if (!is_dir($path)) {
116 1
                throw MappingException::fileMappingDriversRequireConfiguredDirectoryPath($path);
117
            }
118
119 2
            $iterator = new RegexIterator(
120 2
                new RecursiveIteratorIterator(
121 2
                    new RecursiveDirectoryIterator($path, FilesystemIterator::SKIP_DOTS),
122
                    RecursiveIteratorIterator::LEAVES_ONLY
123 2
                ),
124 2
                '/^.+'.preg_quote($this->fileExtension).'$/i',
125
                RecursiveRegexIterator::GET_MATCH
126 2
            );
127
128 2
            foreach ($iterator as $file) {
129 2
                $sourceFile = $file[0];
130
131 2
                if (!preg_match('(^phar:)i', $sourceFile)) {
132 2
                    $sourceFile = realpath($sourceFile);
133 2
                }
134
135 2
                require_once $sourceFile;
136
137 2
                $includedFiles[] = $sourceFile;
138 2
            }
139
140 2
            $declared = get_declared_classes();
141
142 2
            foreach ($declared as $className) {
143 2
                $rc = new ReflectionClass($className);
144 2
                $sourceFile = $rc->getFileName();
145
146 2
                if (!in_array($sourceFile, $includedFiles)) {
147 2
                    continue;
148
                }
149
150 2
                if ($rc->isAbstract() || $rc->isInterface()) {
151
                    continue;
152
                }
153
154 2
                if (!$rc->implementsInterface(Mapping::class)) {
155
                    continue;
156
                }
157
158 2
                if ($this->isTransient($className)) {
159
160
                    /** @var Mapping $mapping */
161 2
                    $mapping = $rc->newInstanceWithoutConstructor();
162
163 2
                    $this->addMapping($mapping);
164 2
                }
165 2
            }
166 2
        }
167 2
    }
168
169
    /**
170
     * @param string[] $mappings
171
     *
172
     * @throws InvalidArgumentException
173
     */
174 82
    public function addMappings(array $mappings = [])
175
    {
176 82
        foreach ($mappings as $class) {
177 82
            if (!class_exists($class)) {
178 1
                throw new InvalidArgumentException("Mapping class [{$class}] does not exist");
179
            }
180
181 81
            $mapping = new $class();
182
183 81
            if (!$mapping instanceof Mapping) {
184 1
                throw new InvalidArgumentException("Mapping class [{$class}] should implement ".Mapping::class);
185
            }
186
187 80
            $this->addMapping($mapping);
188 80
        }
189 80
    }
190
191
    /**
192
     * @param Mapping $mapping
193
     *
194
     * @throws MappingException
195
     *
196
     * @return void
197
     */
198 89
    public function addMapping(Mapping $mapping)
199
    {
200 89
        $this->mappers->add($mapping);
201 89
    }
202
203
    /**
204
     * @return MapperSet
205
     */
206 6
    public function getMappers()
207
    {
208 6
        return $this->mappers;
209
    }
210
211
    /**
212
     * Override the default Fluent factory method with a custom one.
213
     * Use this to implement your own Fluent builder.
214
     * The method will receive a ClassMetadata object as its only argument.
215
     *
216
     * @param callable $factory
217
     */
218 1
    public function setFluentFactory(callable $factory)
219
    {
220 1
        $this->fluentFactory = $factory;
221 1
    }
222
223
    /**
224
     * @param ClassMetadata $metadata
225
     *
226
     * @return Fluent
227
     */
228 6
    protected function getFluent(ClassMetadata $metadata)
229
    {
230 6
        return call_user_func($this->fluentFactory, $metadata);
231
    }
232
}
233