Completed
Push — master ( bace46...1643b4 )
by Steevan
10:24
created

ValidateSchemaService::addMappingPath()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 8
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Importance

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