ValidateSchemaService   A
last analyzed

Complexity

Total Complexity 27

Size/Duplication

Total Lines 149
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 6

Importance

Changes 0
Metric Value
wmc 27
lcom 1
cbo 6
dl 0
loc 149
rs 10
c 0
b 0
f 0

10 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 5 1
A setExcludes() 0 15 3
A addMappingPath() 0 8 2
A addMappingBundle() 0 10 1
A assertSchemaIsValid() 0 15 4
A getLastMappingValidateFilePath() 0 4 1
A needValidate() 0 19 5
A saveLastValidateTimestamp() 0 11 2
A getLastValidateTimestamp() 0 6 2
A assertAuthorizedMappingErrors() 0 19 6
1
<?php
2
3
declare(strict_types=1);
4
5
namespace steevanb\DevBundle\Service;
6
7
use Doctrine\ORM\Tools\SchemaValidator;
8
use steevanb\DevBundle\Exception\InvalidMappingException;
9
use Symfony\Bridge\Doctrine\RegistryInterface;
10
use Symfony\Component\Finder\Finder;
11
use Symfony\Component\HttpKernel\KernelInterface;
12
13
class ValidateSchemaService
14
{
15
    /** @var RegistryInterface */
16
    protected $doctrine;
17
18
    /** @var KernelInterface */
19
    protected $kernel;
20
21
    /** @var array */
22
    protected $excludedEntities = array();
23
24
    /** @var array */
25
    protected $excludedProperties = array();
26
27
    /** @var string[] */
28
    protected $mappingPaths = [];
29
30
    /** Messages from Doctrine\ORM\Tools\SchemaValidator */
31
    protected $schemaValidatorMessages = array(
32
        'The field \'%s\' ',
33
        'The field %s ',
34
        'The association %s ',
35
        'Cannot map association \'%s\' ',
36
        'The mappings %s and ',
37
        'If association %s '
38
    );
39
40
    public function __construct(RegistryInterface $doctrine, KernelInterface $kernel)
41
    {
42
        $this->doctrine = $doctrine;
43
        $this->kernel = $kernel;
44
    }
45
46
    public function setExcludes(array $excludes): self
47
    {
48
        $this->excludedEntities = array();
49
        $this->excludedProperties = array();
50
51
        foreach ($excludes as $exclude) {
52
            if (strpos($exclude, '#') === false) {
53
                $this->excludedEntities[] = $exclude;
54
            } else {
55
                $this->excludedProperties[] = $exclude;
56
            }
57
        }
58
59
        return $this;
60
    }
61
62
    public function addMappingPath(string $path): self
63
    {
64
        if (in_array($path, $this->mappingPaths) === false) {
65
            $this->mappingPaths[] = $path;
66
        }
67
68
        return $this;
69
    }
70
71
    public function addMappingBundle(string $bundle): self
72
    {
73
        $path = $this->kernel->getBundle($bundle)->getPath();
74
        $path .= DIRECTORY_SEPARATOR . 'Resources';
75
        $path .= DIRECTORY_SEPARATOR . 'config';
76
        $path .= DIRECTORY_SEPARATOR . 'doctrine';
77
        $this->addMappingPath($path);
78
79
        return $this;
80
    }
81
82
    public function assertSchemaIsValid(): self
83
    {
84
        if ($this->needValidate()) {
85
            foreach ($this->doctrine->getEntityManagers() as $managerName => $manager) {
86
                $validator = new SchemaValidator($manager);
87
                foreach ($validator->validateMapping() as $entity => $errors) {
88
                    $this->assertAuthorizedMappingErrors($managerName, $entity, $errors);
89
                }
90
            }
91
92
            $this->saveLastValidateTimestamp();
93
        }
94
95
        return $this;
96
    }
97
98
    protected function getLastMappingValidateFilePath(): string
99
    {
100
        return $this->kernel->getCacheDir() . DIRECTORY_SEPARATOR . 'dev_bundle_last_mapping_validate';
101
    }
102
103
    protected function needValidate(): bool
104
    {
105
        $lastValidateTimestamp = $this->getLastValidateTimestamp();
106
        $return = false;
107
108
        foreach ($this->mappingPaths as $path) {
109
            if (is_dir($path)) {
110
                $finder = new Finder();
111
                foreach ($finder->in($path)->files() as $file) {
112
                    if ($file->getMTime() >= $lastValidateTimestamp) {
113
                        $return = true;
114
                        continue 2;
115
                    }
116
                }
117
            }
118
        }
119
120
        return $return;
121
    }
122
123
    protected function saveLastValidateTimestamp(): self
124
    {
125
        $filePath = $this->getLastMappingValidateFilePath();
126
        if (file_exists($filePath)) {
127
            unlink($filePath);
128
        }
129
130
        file_put_contents($filePath, '');
131
132
        return $this;
133
    }
134
135
    protected function getLastValidateTimestamp(): int
136
    {
137
        $filePath = $this->getLastMappingValidateFilePath();
138
139
        return file_exists($filePath) ? filemtime($filePath) : 0;
140
    }
141
142
    protected function assertAuthorizedMappingErrors(string $managerName, string $entityName, array $errors): self
143
    {
144
        if (in_array($entityName, $this->excludedEntities) === false) {
145
            foreach ($errors as $error) {
146
                foreach ($this->excludedProperties as $excludedProperty) {
147
                    foreach ($this->schemaValidatorMessages as $schemaValidatorMessage) {
148
                        $messageStart = sprintf($schemaValidatorMessage, $excludedProperty);
149
                        if ($messageStart === substr($error, 0, strlen($messageStart))) {
150
                            continue 3;
151
                        }
152
                    }
153
                }
154
155
                throw new InvalidMappingException($managerName, $error);
156
            }
157
        }
158
159
        return $this;
160
    }
161
}
162