Failed Conditions
Pull Request — master (#2)
by Herberto
11:45
created

SchemaManager::getConnection()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 1

Importance

Changes 0
Metric Value
cc 1
eloc 1
nc 1
nop 0
dl 0
loc 3
ccs 2
cts 2
cp 1
crap 1
rs 10
c 0
b 0
f 0
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Hgraca\DoctrineTestDbRegenerationBundle\Doctrine;
6
7
use Doctrine\Common\DataFixtures\Executor\ORMExecutor;
8
use Doctrine\Common\DataFixtures\ProxyReferenceRepository;
9
use Doctrine\Common\Persistence\Mapping\ClassMetadata;
10
use Doctrine\DBAL\Connection;
11
use Doctrine\ORM\EntityManagerInterface;
12
use Doctrine\ORM\Tools\SchemaTool;
13
use Doctrine\ORM\Tools\ToolsException;
14
use Hgraca\DoctrineTestDbRegenerationBundle\StdLib\Filesystem;
15
use Hgraca\DoctrineTestDbRegenerationBundle\Symfony\TestContainer;
16
17
final class SchemaManager implements SchemaManagerInterface
18
{
19
    /**
20
     * @var string
21
     */
22
    private $testDbBackupPath;
23
24
    /**
25
     * @var MigrationsExecutor
26
     */
27
    private $migrationsExecutor;
28
29
    /**
30
     * @var string
31
     */
32
    private $databaseFilePath;
33
34
    /**
35
     * @var EntityManagerInterface
36
     */
37
    private $entityManager;
38
39
    /**
40
     * @var ClassMetadata[]
41
     */
42
    private $entityMetadata;
43
44
    /**
45
     * @var FixtureList
46
     */
47
    private $fixtureList;
48
49
    /**
50
     * @var ProxyReferenceRepository
51
     */
52
    private $referenceRepository;
53
54
    /**
55
     * @var SchemaTool|null
56
     */
57
    private $schemaTool;
58
59
    /**
60
     * @var ORMExecutor|null
61
     */
62
    private $ORMExecutor;
63
64
    /**
65
     * @var ListenerToggler
66
     */
67
    private $doctrineListenersToggler;
68
69 14
    private function __construct(
70
        FixtureList $fixtureList,
71
        EntityManagerInterface $entityManager,
72
        string $testDbBackupPath,
73
        MigrationsExecutorInterface $migrationsExecutor,
74
        ?SchemaTool $schemaTool = null,
75
        ?ORMExecutor $ORMExecutor = null,
76
        ?ProxyReferenceRepository $referenceRepository = null
77
    ) {
78 14
        $this->fixtureList = $fixtureList;
79 14
        $this->entityManager = $entityManager;
80 14
        $this->testDbBackupPath = $testDbBackupPath;
81 14
        $this->migrationsExecutor = $migrationsExecutor;
0 ignored issues
show
Documentation Bug introduced by
$migrationsExecutor is of type Hgraca\DoctrineTestDbReg...ationsExecutorInterface, but the property $migrationsExecutor was declared to be of type Hgraca\DoctrineTestDbReg...rine\MigrationsExecutor. Are you sure that you always receive this specific sub-class here, or does it make sense to add an instanceof check?

Our type inference engine has found a suspicous assignment of a value to a property. This check raises an issue when a value that can be of a given class or a super-class is assigned to a property that is type hinted more strictly.

Either this assignment is in error or an instanceof check should be added for that assignment.

class Alien {}

class Dalek extends Alien {}

class Plot
{
    /** @var  Dalek */
    public $villain;
}

$alien = new Alien();
$plot = new Plot();
if ($alien instanceof Dalek) {
    $plot->villain = $alien;
}
Loading history...
82 14
        $this->schemaTool = $schemaTool;
83 14
        $this->ORMExecutor = $ORMExecutor;
84 14
        $this->referenceRepository = $referenceRepository;
85 14
        $this->doctrineListenersToggler = new ListenerToggler($this->entityManager->getEventManager());
86 14
    }
87
88
    /**
89
     * @throws \ErrorException
90
     */
91 14
    public static function constructUsingTestContainer(
92
        TestContainer $testContainer = null,
93
        SchemaTool $schemaTool = null,
94
        ORMExecutor $ORMExecutor = null,
95
        ProxyReferenceRepository $referenceRepository = null,
96
        MigrationsExecutorInterface $migrationsExecutor = null
97
    ): SchemaManagerInterface {
98 14
        $testContainer = $testContainer ?? new TestContainer();
99
100 14
        $testDbBackupPath = $testContainer->getDbBkpDir();
101
102 14
        return new self(
103 14
            FixtureList::constructFromFixturesLoader($testContainer->getFixturesLoader()),
104 14
            $testContainer->getEntityManager(),
105 14
            $testDbBackupPath,
106 14
            $migrationsExecutor ?? new MigrationsExecutor(
107
                $testContainer->getContainer(),
108 14
                $testContainer->getEntityManager()->getConnection()
109
            ),
110 14
            $schemaTool,
111 14
            $ORMExecutor,
112 14
            $referenceRepository
113
        );
114
    }
115
116
    /**
117
     * @throws ToolsException
118
     * @throws \Exception
119
     */
120 8
    public function createTestDatabaseBackup(
121
        bool $shouldReuseExistingDbBkp = false,
122
        array $migrationsToExecute = []
123
    ): void {
124 8
        $testDbPath = $this->getDatabaseFilePath();
125
126 8
        if ($shouldReuseExistingDbBkp && $this->testDatabaseBackupExists($this->testDbBackupPath)) {
127 2
            return;
128
        }
129
130 6
        $this->createBackup($this->testDbBackupPath, $testDbPath, ...$migrationsToExecute);
131 6
    }
132
133
    /**
134
     * @throws \Exception
135
     */
136 2
    public function restoreTestDatabase(): void
137
    {
138 2
        $testDbPath = $this->getDatabaseFilePath();
139
140 2
        $this->restoreBackup($this->testDbBackupPath, $testDbPath);
141 2
    }
142
143 8
    public function removeTestDatabase(): void
144
    {
145 8
        $usedSqliteDatabaseFile = $this->getDatabaseFilePath();
146
147 8
        if (Filesystem::file_exists($usedSqliteDatabaseFile)) {
148
            Filesystem::unlink($usedSqliteDatabaseFile);
149
        }
150 8
    }
151
152
    /**
153
     * @throws \Doctrine\Common\DataFixtures\OutOfBoundsException
154
     * @throws \Exception
155
     */
156
    public function getLoadedReferenceRepository(): ProxyReferenceRepository
157
    {
158
        $this->getReferenceRepository()->load($this->testDbBackupPath);
159
160
        return $this->getReferenceRepository();
161
    }
162
163 12
    private function getDatabaseFilePath(): string
164
    {
165 12
        return $this->databaseFilePath ?? $this->databaseFilePath = $this->getConnection()->getParams()['path'];
166
    }
167
168
    /**
169
     * @return ClassMetadata[]
170
     */
171 6
    private function getEntityMetadata(): array
172
    {
173 6
        return $this->entityMetadata
174 6
            ?? $this->entityMetadata = $this->entityManager->getMetadataFactory()->getAllMetadata();
175
    }
176
177
    /**
178
     * @throws \Exception
179
     */
180 4
    private function testDatabaseBackupExists(string $testDbBackupPath): bool
181
    {
182 4
        if (Filesystem::file_exists($testDbBackupPath) && Filesystem::file_exists($testDbBackupPath . '.ser')) {
183 2
            return true;
184
        }
185
186 2
        return false;
187
    }
188
189
    /**
190
     * @throws ToolsException
191
     * @throws ToolsException
192
     * @throws \ReflectionException
193
     * @throws \Doctrine\DBAL\Migrations\MigrationException
194
     */
195 6
    private function createBackup(string $testDbBackupPath, string $testDbPath, string ...$migrationList): void
196
    {
197 6
        $this->removeTestDatabase();
198 6
        $this->createCleanSchema();
199 6
        $this->migrationsExecutor->execute(...$migrationList);
200 6
        $this->doctrineListenersToggler->disableListeners();
201 6
        $this->loadFixtures();
202 6
        $this->doctrineListenersToggler->enableListeners();
203 6
        $this->createDbBackupFile($testDbPath, $testDbBackupPath);
204 6
        $this->createFixturesBackupFile($testDbBackupPath);
205 6
    }
206
207
    /**
208
     * @throws ToolsException
209
     */
210 6
    private function createCleanSchema(): void
211
    {
212 6
        $this->getSchemaTool()->dropDatabase();
213 6
        $this->getSchemaTool()->createSchema($this->getEntityMetadata());
214 6
    }
215
216 6
    private function loadFixtures(): void
217
    {
218 6
        $this->getORMExecutor()->setReferenceRepository($this->getReferenceRepository());
219 6
        $this->getORMExecutor()->execute($this->fixtureList->getFixtures(), true);
220 6
    }
221
222 6
    private function createDbBackupFile(string $sourcePath, string $backupPath): void
223
    {
224 6
        Filesystem::rename($sourcePath, $backupPath);
225 6
    }
226
227 6
    private function createFixturesBackupFile(string $testDbBackupPath): void
228
    {
229 6
        $this->getReferenceRepository()->save($testDbBackupPath);
230 6
    }
231
232 2
    private function restoreBackup(string $testDbBackupPath, string $testDbPath): void
233
    {
234 2
        $this->entityManager->flush();
235 2
        $this->entityManager->clear();
236
237 2
        $this->recoverDbBackupFile($testDbBackupPath, $testDbPath);
238 2
    }
239
240 2
    private function recoverDbBackupFile(string $backupPath, string $sourcePath): void
241
    {
242 2
        Filesystem::copy($backupPath, $sourcePath);
243 2
    }
244
245 12
    private function getConnection(): Connection
246
    {
247 12
        return $this->entityManager->getConnection();
248
    }
249
250 6
    private function getSchemaTool(): SchemaTool
251
    {
252 6
        return $this->schemaTool ?? $this->schemaTool = new SchemaTool($this->entityManager);
253
    }
254
255 6
    private function getORMExecutor(): ORMExecutor
256
    {
257 6
        return $this->ORMExecutor ?? $this->ORMExecutor = new ORMExecutor($this->entityManager);
258
    }
259
260 6
    private function getReferenceRepository(): ProxyReferenceRepository
261
    {
262 6
        return $this->referenceRepository
263 6
            ?? $this->referenceRepository = new ProxyReferenceRepository($this->entityManager);
264
    }
265
}
266