1
|
|
|
<?php |
2
|
|
|
|
3
|
|
|
/** |
4
|
|
|
* File containing the Test Setup Factory base class. |
5
|
|
|
* |
6
|
|
|
* @copyright Copyright (C) eZ Systems AS. All rights reserved. |
7
|
|
|
* @license For full copyright and license information view LICENSE file distributed with this source code. |
8
|
|
|
* |
9
|
|
|
* @version //autogentag// |
10
|
|
|
*/ |
11
|
|
|
namespace eZ\Publish\API\Repository\Tests\SetupFactory; |
12
|
|
|
|
13
|
|
|
use eZ\Publish\Core\Base\ServiceContainer; |
14
|
|
|
use Symfony\Component\DependencyInjection\ContainerBuilder; |
15
|
|
|
use eZ\Publish\API\Repository\Tests\SetupFactory; |
16
|
|
|
use eZ\Publish\API\Repository\Tests\IdManager; |
17
|
|
|
use eZ\Publish\Core\Persistence\Legacy\Content\Type\MemoryCachingHandler as CachingContentTypeHandler; |
18
|
|
|
use eZ\Publish\Core\Persistence\Legacy\Content\Language\CachingHandler as CachingLanguageHandler; |
19
|
|
|
use Exception; |
20
|
|
|
use eZ\Publish\Core\Repository\Values\User\UserReference; |
21
|
|
|
use Symfony\Component\Filesystem\Filesystem; |
22
|
|
|
|
23
|
|
|
/** |
24
|
|
|
* A Test Factory is used to setup the infrastructure for a tests, based on a |
25
|
|
|
* specific repository implementation to test. |
26
|
|
|
*/ |
27
|
|
|
class Legacy extends SetupFactory |
28
|
|
|
{ |
29
|
|
|
/** |
30
|
|
|
* Data source name. |
31
|
|
|
* |
32
|
|
|
* @var string |
33
|
|
|
*/ |
34
|
|
|
protected static $dsn; |
35
|
|
|
|
36
|
|
|
/** |
37
|
|
|
* Root dir for IO operations. |
38
|
|
|
* |
39
|
|
|
* @var string |
40
|
|
|
*/ |
41
|
|
|
protected static $ioRootDir; |
42
|
|
|
|
43
|
|
|
/** |
44
|
|
|
* Database type (sqlite, mysql, ...). |
45
|
|
|
* |
46
|
|
|
* @var string |
47
|
|
|
*/ |
48
|
|
|
protected static $db; |
49
|
|
|
|
50
|
|
|
/** |
51
|
|
|
* Service container. |
52
|
|
|
* |
53
|
|
|
* @var \eZ\Publish\Core\Base\ServiceContainer |
54
|
|
|
*/ |
55
|
|
|
protected static $serviceContainer; |
56
|
|
|
|
57
|
|
|
/** |
58
|
|
|
* If the DB schema has already been initialized. |
59
|
|
|
* |
60
|
|
|
* @var bool |
61
|
|
|
*/ |
62
|
|
|
protected static $schemaInitialized = false; |
63
|
|
|
|
64
|
|
|
/** |
65
|
|
|
* Initial database data. |
66
|
|
|
* |
67
|
|
|
* @var array |
68
|
|
|
*/ |
69
|
|
|
protected static $initialData; |
70
|
|
|
|
71
|
|
|
protected $repositoryReference = 'ezpublish.api.repository'; |
72
|
|
|
|
73
|
|
|
/** |
74
|
|
|
* Creates a new setup factory. |
75
|
|
|
*/ |
76
|
|
|
public function __construct() |
77
|
|
|
{ |
78
|
|
|
self::$dsn = getenv('DATABASE'); |
79
|
|
|
if (!self::$dsn) { |
80
|
|
|
self::$dsn = 'sqlite://:memory:'; |
81
|
|
|
} |
82
|
|
|
|
83
|
|
|
self::$db = preg_replace('(^([a-z]+).*)', '\\1', self::$dsn); |
84
|
|
|
|
85
|
|
|
if (!isset(self::$ioRootDir)) { |
86
|
|
|
self::$ioRootDir = $this->createTemporaryDirectory(); |
87
|
|
|
} |
88
|
|
|
} |
89
|
|
|
|
90
|
|
|
/** |
91
|
|
|
* Creates a temporary directory and returns it. |
92
|
|
|
* |
93
|
|
|
* @return string |
94
|
|
|
* @throw \RuntimeException If the root directory can't be created |
95
|
|
|
*/ |
96
|
|
|
private function createTemporaryDirectory() |
97
|
|
|
{ |
98
|
|
|
$tmpFile = tempnam( |
99
|
|
|
sys_get_temp_dir(), |
100
|
|
|
'ez_legacy_tests_' . time() |
101
|
|
|
); |
102
|
|
|
unlink($tmpFile); |
103
|
|
|
|
104
|
|
|
$fs = new Filesystem(); |
105
|
|
|
$fs->mkdir($tmpFile); |
106
|
|
|
|
107
|
|
|
$varDir = $tmpFile . '/var'; |
108
|
|
|
if ($fs->exists($varDir)) { |
109
|
|
|
$fs->remove($varDir); |
110
|
|
|
} |
111
|
|
|
$fs->mkdir($varDir); |
112
|
|
|
|
113
|
|
|
return $tmpFile; |
114
|
|
|
} |
115
|
|
|
/** |
116
|
|
|
* Returns a configured repository for testing. |
117
|
|
|
* |
118
|
|
|
* @param bool $initializeFromScratch if the back end should be initialized |
119
|
|
|
* from scratch or re-used |
120
|
|
|
* |
121
|
|
|
* @return \eZ\Publish\API\Repository\Repository |
122
|
|
|
*/ |
123
|
|
|
public function getRepository($initializeFromScratch = true) |
124
|
|
|
{ |
125
|
|
|
if ($initializeFromScratch || !self::$schemaInitialized) { |
126
|
|
|
$this->initializeSchema(); |
127
|
|
|
$this->insertData(); |
128
|
|
|
} |
129
|
|
|
|
130
|
|
|
$this->clearInternalCaches(); |
131
|
|
|
$repository = $this->getServiceContainer()->get($this->repositoryReference); |
132
|
|
|
|
133
|
|
|
// Set admin user as current user by default |
134
|
|
|
$repository->setCurrentUser(new UserReference(14)); |
135
|
|
|
|
136
|
|
|
return $repository; |
137
|
|
|
} |
138
|
|
|
|
139
|
|
|
/** |
140
|
|
|
* Returns a config value for $configKey. |
141
|
|
|
* |
142
|
|
|
* @param string $configKey |
143
|
|
|
* |
144
|
|
|
* @throws Exception if $configKey could not be found. |
145
|
|
|
* |
146
|
|
|
* @return mixed |
147
|
|
|
*/ |
148
|
|
|
public function getConfigValue($configKey) |
149
|
|
|
{ |
150
|
|
|
return $this->getServiceContainer()->getParameter($configKey); |
151
|
|
|
} |
152
|
|
|
|
153
|
|
|
/** |
154
|
|
|
* Returns a repository specific ID manager. |
155
|
|
|
* |
156
|
|
|
* @return \eZ\Publish\API\Repository\Tests\IdManager |
157
|
|
|
*/ |
158
|
|
|
public function getIdManager() |
159
|
|
|
{ |
160
|
|
|
return new IdManager\Php(); |
161
|
|
|
} |
162
|
|
|
|
163
|
|
|
/** |
164
|
|
|
* Insert the database data. |
165
|
|
|
*/ |
166
|
|
|
public function insertData() |
167
|
|
|
{ |
168
|
|
|
$data = $this->getInitialData(); |
169
|
|
|
$handler = $this->getDatabaseHandler(); |
170
|
|
|
$this->cleanupVarDir($this->getInitialVarDir()); |
171
|
|
|
|
172
|
|
|
// @todo FIXME: Needs to be in fixture |
173
|
|
|
$data['ezcontentobject_trash'] = array(); |
174
|
|
|
$data['ezurlwildcard'] = array(); |
175
|
|
|
$data['ezmedia'] = array(); |
176
|
|
|
$data['ezkeyword'] = array(); |
177
|
|
|
|
178
|
|
View Code Duplication |
foreach ($data as $table => $rows) { |
|
|
|
|
179
|
|
|
// Cleanup before inserting |
180
|
|
|
$deleteQuery = $handler->createDeleteQuery(); |
181
|
|
|
$deleteQuery->deleteFrom($handler->quoteIdentifier($table)); |
182
|
|
|
$stmt = $deleteQuery->prepare(); |
183
|
|
|
$stmt->execute(); |
184
|
|
|
|
185
|
|
|
// Check that at least one row exists |
186
|
|
|
if (!isset($rows[0])) { |
187
|
|
|
continue; |
188
|
|
|
} |
189
|
|
|
|
190
|
|
|
$q = $handler->createInsertQuery(); |
191
|
|
|
$q->insertInto($handler->quoteIdentifier($table)); |
192
|
|
|
|
193
|
|
|
// Contains the bound parameters |
194
|
|
|
$values = array(); |
195
|
|
|
|
196
|
|
|
// Binding the parameters |
197
|
|
|
foreach ($rows[0] as $col => $val) { |
198
|
|
|
$q->set( |
199
|
|
|
$handler->quoteIdentifier($col), |
200
|
|
|
$q->bindParam($values[$col]) |
201
|
|
|
); |
202
|
|
|
} |
203
|
|
|
|
204
|
|
|
$stmt = $q->prepare(); |
205
|
|
|
|
206
|
|
|
foreach ($rows as $row) { |
207
|
|
|
try { |
208
|
|
|
// This CANNOT be replaced by: |
209
|
|
|
// $values = $row |
210
|
|
|
// each $values[$col] is a PHP reference which should be |
211
|
|
|
// kept for parameters binding to work |
212
|
|
|
foreach ($row as $col => $val) { |
213
|
|
|
$values[$col] = $val; |
214
|
|
|
} |
215
|
|
|
|
216
|
|
|
$stmt->execute(); |
217
|
|
|
} catch (Exception $e) { |
218
|
|
|
echo "$table ( ", implode(', ', $row), " )\n"; |
219
|
|
|
throw $e; |
220
|
|
|
} |
221
|
|
|
} |
222
|
|
|
} |
223
|
|
|
|
224
|
|
|
$this->applyStatements($this->getPostInsertStatements()); |
225
|
|
|
} |
226
|
|
|
|
227
|
|
|
protected function getInitialVarDir() |
228
|
|
|
{ |
229
|
|
|
return __DIR__ . '/../../../../../../var'; |
230
|
|
|
} |
231
|
|
|
|
232
|
|
|
protected function cleanupVarDir($sourceDir) |
233
|
|
|
{ |
234
|
|
|
if ($this->getServiceContainer()->getInnerContainer()->has('ezpublish.core.io.flysystem.default_filesystem')) { |
235
|
|
|
$this->getServiceContainer()->getInnerContainer()->get('ezpublish.core.io.flysystem.default_filesystem')->flushCache(); |
236
|
|
|
} |
237
|
|
|
$fs = new Filesystem(); |
238
|
|
|
$varDir = self::$ioRootDir . '/var'; |
239
|
|
|
if ($fs->exists($varDir)) { |
240
|
|
|
$fs->remove($varDir); |
241
|
|
|
} |
242
|
|
|
$fs->mkdir($varDir); |
243
|
|
|
$fs->mirror($sourceDir, $varDir); |
244
|
|
|
} |
245
|
|
|
|
246
|
|
|
/** |
247
|
|
|
* CLears internal in memory caches after inserting data circumventing the |
248
|
|
|
* API. |
249
|
|
|
*/ |
250
|
|
|
protected function clearInternalCaches() |
251
|
|
|
{ |
252
|
|
|
/** @var $handler \eZ\Publish\Core\Persistence\Legacy\Handler */ |
253
|
|
|
$handler = $this->getServiceContainer()->get('ezpublish.spi.persistence.legacy'); |
254
|
|
|
|
255
|
|
|
$contentLanguageHandler = $handler->contentLanguageHandler(); |
256
|
|
|
if ($contentLanguageHandler instanceof CachingLanguageHandler) { |
257
|
|
|
$contentLanguageHandler->clearCache(); |
258
|
|
|
} |
259
|
|
|
|
260
|
|
|
$contentTypeHandler = $handler->contentTypeHandler(); |
261
|
|
|
if ($contentTypeHandler instanceof CachingContentTypeHandler) { |
262
|
|
|
$contentTypeHandler->clearCache(); |
263
|
|
|
} |
264
|
|
|
|
265
|
|
|
/** @var $decorator \eZ\Publish\Core\Persistence\Cache\Tests\Helpers\IntegrationTestCacheServiceDecorator */ |
266
|
|
|
$decorator = $this->getServiceContainer()->get('ezpublish.cache_pool.spi.cache.decorator'); |
267
|
|
|
|
268
|
|
|
$decorator->clearAllTestData(); |
269
|
|
|
} |
270
|
|
|
|
271
|
|
|
/** |
272
|
|
|
* Returns statements to be executed after data insert. |
273
|
|
|
* |
274
|
|
|
* @return string[] |
275
|
|
|
*/ |
276
|
|
|
protected function getPostInsertStatements() |
277
|
|
|
{ |
278
|
|
|
if (self::$db === 'pgsql') { |
279
|
|
|
$setvalPath = __DIR__ . '/../../../../Core/Persistence/Legacy/Tests/_fixtures/setval.pgsql.sql'; |
280
|
|
|
|
281
|
|
|
return array_filter(preg_split('(;\\s*$)m', file_get_contents($setvalPath))); |
282
|
|
|
} |
283
|
|
|
|
284
|
|
|
return array(); |
285
|
|
|
} |
286
|
|
|
|
287
|
|
|
/** |
288
|
|
|
* Returns the initial database data. |
289
|
|
|
* |
290
|
|
|
* @return array |
291
|
|
|
*/ |
292
|
|
|
protected function getInitialData() |
293
|
|
|
{ |
294
|
|
|
if (!isset(self::$initialData)) { |
295
|
|
|
self::$initialData = include __DIR__ . '/../../../../Core/Repository/Tests/Service/Integration/Legacy/_fixtures/clean_ezdemo_47_dump.php'; |
296
|
|
|
// self::$initialData = include __DIR__ . '/../../../../Core/Repository/Tests/Service/Legacy/_fixtures/full_dump.php'; |
297
|
|
|
} |
298
|
|
|
|
299
|
|
|
return self::$initialData; |
300
|
|
|
} |
301
|
|
|
|
302
|
|
|
/** |
303
|
|
|
* Initializes the database schema. |
304
|
|
|
*/ |
305
|
|
|
protected function initializeSchema() |
306
|
|
|
{ |
307
|
|
|
if (!self::$schemaInitialized) { |
308
|
|
|
$statements = $this->getSchemaStatements(); |
309
|
|
|
|
310
|
|
|
$this->applyStatements($statements); |
311
|
|
|
|
312
|
|
|
self::$schemaInitialized = true; |
313
|
|
|
} |
314
|
|
|
} |
315
|
|
|
|
316
|
|
|
/** |
317
|
|
|
* Applies the given SQL $statements to the database in use. |
318
|
|
|
* |
319
|
|
|
* @param array $statements |
320
|
|
|
*/ |
321
|
|
|
protected function applyStatements(array $statements) |
322
|
|
|
{ |
323
|
|
|
foreach ($statements as $statement) { |
324
|
|
|
$this->getDatabaseHandler()->exec($statement); |
325
|
|
|
} |
326
|
|
|
} |
327
|
|
|
|
328
|
|
|
// ************* Setup copied and refactored from common.php ************ |
329
|
|
|
|
330
|
|
|
/** |
331
|
|
|
* Returns the database schema as an array of SQL statements. |
332
|
|
|
* |
333
|
|
|
* @return string[] |
334
|
|
|
*/ |
335
|
|
|
protected function getSchemaStatements() |
336
|
|
|
{ |
337
|
|
|
$schemaPath = __DIR__ . '/../../../../Core/Persistence/Legacy/Tests/_fixtures/schema.' . self::$db . '.sql'; |
338
|
|
|
|
339
|
|
|
return array_filter(preg_split('(;\\s*$)m', file_get_contents($schemaPath))); |
340
|
|
|
} |
341
|
|
|
|
342
|
|
|
/** |
343
|
|
|
* Returns the database handler from the service container. |
344
|
|
|
* |
345
|
|
|
* @return \eZ\Publish\Core\Persistence\Doctrine\ConnectionHandler |
346
|
|
|
*/ |
347
|
|
|
protected function getDatabaseHandler() |
348
|
|
|
{ |
349
|
|
|
return $this->getServiceContainer()->get('ezpublish.api.storage_engine.legacy.dbhandler'); |
350
|
|
|
} |
351
|
|
|
|
352
|
|
|
/** |
353
|
|
|
* Returns the service container used for initialization of the repository. |
354
|
|
|
* |
355
|
|
|
* @return \eZ\Publish\Core\Base\ServiceContainer |
356
|
|
|
*/ |
357
|
|
|
protected function getServiceContainer() |
358
|
|
|
{ |
359
|
|
|
if (!isset(self::$serviceContainer)) { |
360
|
|
|
$config = include __DIR__ . '/../../../../../../config.php'; |
361
|
|
|
$installDir = $config['install_dir']; |
362
|
|
|
|
363
|
|
|
/** @var \Symfony\Component\DependencyInjection\ContainerBuilder $containerBuilder */ |
364
|
|
|
$containerBuilder = include $config['container_builder_path']; |
365
|
|
|
|
366
|
|
|
/* @var \Symfony\Component\DependencyInjection\Loader\YamlFileLoader $loader */ |
367
|
|
|
$loader->load('tests/integration_legacy.yml'); |
|
|
|
|
368
|
|
|
|
369
|
|
|
$this->externalBuildContainer($containerBuilder); |
370
|
|
|
|
371
|
|
|
$containerBuilder->setParameter( |
372
|
|
|
'legacy_dsn', |
373
|
|
|
self::$dsn |
374
|
|
|
); |
375
|
|
|
|
376
|
|
|
$containerBuilder->setParameter( |
377
|
|
|
'io_root_dir', |
378
|
|
|
self::$ioRootDir . '/' . $containerBuilder->getParameter('storage_dir') |
379
|
|
|
); |
380
|
|
|
|
381
|
|
|
self::$serviceContainer = new ServiceContainer( |
382
|
|
|
$containerBuilder, |
383
|
|
|
$installDir, |
384
|
|
|
$config['cache_dir'], |
385
|
|
|
true, |
386
|
|
|
true |
387
|
|
|
); |
388
|
|
|
} |
389
|
|
|
|
390
|
|
|
return self::$serviceContainer; |
391
|
|
|
} |
392
|
|
|
|
393
|
|
|
/** |
394
|
|
|
* This is intended to be used from external repository in order to |
395
|
|
|
* enable container customization. |
396
|
|
|
* |
397
|
|
|
* @param \Symfony\Component\DependencyInjection\ContainerBuilder $containerBuilder |
398
|
|
|
*/ |
399
|
|
|
protected function externalBuildContainer(ContainerBuilder $containerBuilder) |
|
|
|
|
400
|
|
|
{ |
401
|
|
|
// Does nothing by default |
402
|
|
|
} |
403
|
|
|
|
404
|
|
|
/** |
405
|
|
|
* Get the Database name. |
406
|
|
|
* |
407
|
|
|
* @return string |
408
|
|
|
*/ |
409
|
|
|
public function getDB() |
410
|
|
|
{ |
411
|
|
|
return self::$db; |
412
|
|
|
} |
413
|
|
|
} |
414
|
|
|
|
Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.
You can also find more detailed suggestions in the “Code” section of your repository.