Completed
Push — ezp30878_cant_add_image_with_p... ( e19ea7...263f1b )
by
unknown
20:16
created

Legacy::getRepository()   A

Complexity

Conditions 3
Paths 2

Size

Total Lines 15

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 3
nc 2
nop 1
dl 0
loc 15
rs 9.7666
c 0
b 0
f 0
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
namespace eZ\Publish\API\Repository\Tests\SetupFactory;
10
11
use eZ\Publish\Core\Base\ServiceContainer;
12
use Symfony\Component\DependencyInjection\ContainerBuilder;
13
use eZ\Publish\API\Repository\Tests\SetupFactory;
14
use eZ\Publish\API\Repository\Tests\IdManager;
15
use eZ\Publish\Core\Persistence\Legacy\Content\Type\MemoryCachingHandler as CachingContentTypeHandler;
16
use eZ\Publish\Core\Persistence\Legacy\Content\Language\CachingHandler as CachingLanguageHandler;
17
use Exception;
18
use eZ\Publish\Core\Repository\Values\User\UserReference;
19
use Symfony\Component\Filesystem\Filesystem;
20
use eZ\Publish\Core\Base\Container\Compiler;
21
22
/**
23
 * A Test Factory is used to setup the infrastructure for a tests, based on a
24
 * specific repository implementation to test.
25
 */
26
class Legacy extends SetupFactory
27
{
28
    /**
29
     * Data source name.
30
     *
31
     * @var string
32
     */
33
    protected static $dsn;
34
35
    /**
36
     * Root dir for IO operations.
37
     *
38
     * @var string
39
     */
40
    protected static $ioRootDir;
41
42
    /**
43
     * Database type (sqlite, mysql, ...).
44
     *
45
     * @var string
46
     */
47
    protected static $db;
48
49
    /**
50
     * Service container.
51
     *
52
     * @var \eZ\Publish\Core\Base\ServiceContainer
53
     */
54
    protected static $serviceContainer;
55
56
    /**
57
     * If the DB schema has already been initialized.
58
     *
59
     * @var bool
60
     */
61
    protected static $schemaInitialized = false;
62
63
    /**
64
     * Initial database data.
65
     *
66
     * @var array
67
     */
68
    protected static $initialData;
69
70
    protected $repositoryReference = 'ezpublish.api.repository';
71
72
    /**
73
     * Creates a new setup factory.
74
     */
75
    public function __construct()
76
    {
77
        self::$dsn = getenv('DATABASE');
78
        if (!self::$dsn) {
79
            self::$dsn = 'sqlite://:memory:';
80
        }
81
82
        self::$db = preg_replace('(^([a-z]+).*)', '\\1', self::$dsn);
83
84
        if (!isset(self::$ioRootDir)) {
85
            self::$ioRootDir = $this->createTemporaryDirectory();
86
        }
87
    }
88
89
    /**
90
     * Creates a temporary directory and returns it.
91
     *
92
     * @return string
93
     * @throw \RuntimeException If the root directory can't be created
94
     */
95
    private function createTemporaryDirectory()
96
    {
97
        $tmpFile = tempnam(
98
            sys_get_temp_dir(),
99
            'ez_legacy_tests_' . time()
100
        );
101
        unlink($tmpFile);
102
103
        $fs = new Filesystem();
104
        $fs->mkdir($tmpFile);
105
106
        $varDir = $tmpFile . '/var';
107
        if ($fs->exists($varDir)) {
108
            $fs->remove($varDir);
109
        }
110
        $fs->mkdir($varDir);
111
112
        return $tmpFile;
113
    }
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
        $connection = $handler->getConnection();
171
        $dbPlatform = $connection->getDatabasePlatform();
172
        $this->cleanupVarDir($this->getInitialVarDir());
173
174
        // @todo FIXME: Needs to be in fixture
175
        $data['ezcontentobject_trash'] = [];
176
        $data['ezurlwildcard'] = [];
177
        $data['ezmedia'] = [];
178
        $data['ezkeyword'] = [];
179
180 View Code Duplication
        foreach ($data as $table => $rows) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

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.

Loading history...
181
            // Cleanup before inserting (using TRUNCATE for speed, however not possible to rollback)
182
            $q = $dbPlatform->getTruncateTableSql($handler->quoteIdentifier($table));
183
            $connection->executeUpdate($q);
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 = [];
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
        $fs = new Filesystem();
235
        $varDir = self::$ioRootDir . '/var';
236
        if ($fs->exists($varDir)) {
237
            $fs->remove($varDir);
238
        }
239
        $fs->mkdir($varDir);
240
        $fs->mirror($sourceDir, $varDir);
241
    }
242
243
    /**
244
     * CLears internal in memory caches after inserting data circumventing the
245
     * API.
246
     */
247
    protected function clearInternalCaches()
248
    {
249
        /** @var $handler \eZ\Publish\Core\Persistence\Legacy\Handler */
250
        $handler = $this->getServiceContainer()->get('ezpublish.spi.persistence.legacy');
251
252
        $contentLanguageHandler = $handler->contentLanguageHandler();
253
        if ($contentLanguageHandler instanceof CachingLanguageHandler) {
254
            $contentLanguageHandler->clearCache();
255
        }
256
257
        $contentTypeHandler = $handler->contentTypeHandler();
258
        if ($contentTypeHandler instanceof CachingContentTypeHandler) {
259
            $contentTypeHandler->clearCache();
260
        }
261
262
        /** @var \eZ\Publish\Core\Persistence\Cache\CacheServiceDecorator $decorator */
263
        $decorator = $this->getServiceContainer()->get('ezpublish.cache_pool.spi.cache.decorator');
264
265
        $decorator->clear();
266
    }
267
268
    /**
269
     * Returns statements to be executed after data insert.
270
     *
271
     * @return string[]
272
     */
273
    protected function getPostInsertStatements()
274
    {
275
        if (self::$db === 'pgsql') {
276
            $setvalPath = __DIR__ . '/../../../../Core/Persistence/Legacy/Tests/_fixtures/setval.pgsql.sql';
277
278
            return array_filter(preg_split('(;\\s*$)m', file_get_contents($setvalPath)));
279
        }
280
281
        return [];
282
    }
283
284
    /**
285
     * Returns the initial database data.
286
     *
287
     * @return array
288
     */
289
    protected function getInitialData()
290
    {
291
        if (!isset(self::$initialData)) {
292
            self::$initialData = include __DIR__ . '/../../../../Core/Repository/Tests/Service/Integration/Legacy/_fixtures/clean_ezdemo_47_dump.php';
293
            // self::$initialData = include __DIR__ . '/../../../../Core/Repository/Tests/Service/Legacy/_fixtures/full_dump.php';
294
        }
295
296
        return self::$initialData;
297
    }
298
299
    /**
300
     * Initializes the database schema.
301
     */
302
    protected function initializeSchema()
303
    {
304
        if (!self::$schemaInitialized) {
305
            $statements = $this->getSchemaStatements();
306
307
            $this->applyStatements($statements);
308
309
            self::$schemaInitialized = true;
310
        }
311
    }
312
313
    /**
314
     * Applies the given SQL $statements to the database in use.
315
     *
316
     * @param array $statements
317
     */
318
    protected function applyStatements(array $statements)
319
    {
320
        foreach ($statements as $statement) {
321
            $this->getDatabaseHandler()->exec($statement);
322
        }
323
    }
324
325
    // ************* Setup copied and refactored from common.php ************
326
327
    /**
328
     * Returns the database schema as an array of SQL statements.
329
     *
330
     * @return string[]
331
     */
332
    protected function getSchemaStatements()
333
    {
334
        $schemaPath = __DIR__ . '/../../../../Core/Persistence/Legacy/Tests/_fixtures/schema.' . self::$db . '.sql';
335
336
        return array_filter(preg_split('(;\\s*$)m', file_get_contents($schemaPath)));
337
    }
338
339
    /**
340
     * Returns the database handler from the service container.
341
     *
342
     * @return \eZ\Publish\Core\Persistence\Doctrine\ConnectionHandler
343
     */
344
    protected function getDatabaseHandler()
345
    {
346
        return $this->getServiceContainer()->get('ezpublish.api.storage_engine.legacy.dbhandler');
347
    }
348
349
    /**
350
     * Returns the service container used for initialization of the repository.
351
     *
352
     * @return \eZ\Publish\Core\Base\ServiceContainer
353
     */
354
    public function getServiceContainer()
355
    {
356
        if (!isset(self::$serviceContainer)) {
357
            $config = include __DIR__ . '/../../../../../../config.php';
358
            $installDir = $config['install_dir'];
359
360
            /** @var \Symfony\Component\DependencyInjection\ContainerBuilder $containerBuilder */
361
            $containerBuilder = include $config['container_builder_path'];
362
363
            /* @var \Symfony\Component\DependencyInjection\Loader\YamlFileLoader $loader */
364
            $loader->load('search_engines/legacy.yml');
0 ignored issues
show
Bug introduced by
The variable $loader does not exist. Did you forget to declare it?

This check marks access to variables or properties that have not been declared yet. While PHP has no explicit notion of declaring a variable, accessing it before a value is assigned to it is most likely a bug.

Loading history...
365
            $loader->load('tests/integration_legacy.yml');
366
367
            $this->externalBuildContainer($containerBuilder);
368
369
            $containerBuilder->setParameter(
370
                'legacy_dsn',
371
                self::$dsn
372
            );
373
374
            $containerBuilder->setParameter(
375
                'io_root_dir',
376
                self::$ioRootDir . '/' . $containerBuilder->getParameter('storage_dir')
377
            );
378
379
            $containerBuilder->addCompilerPass(new Compiler\Search\SearchEngineSignalSlotPass('legacy'));
380
            $containerBuilder->addCompilerPass(new Compiler\Search\FieldRegistryPass());
381
382
            // load overrides just before creating test Container
383
            $loader->load('tests/override.yml');
384
385
            self::$serviceContainer = new ServiceContainer(
386
                $containerBuilder,
387
                $installDir,
388
                $config['cache_dir'],
389
                true,
390
                true
391
            );
392
        }
393
394
        return self::$serviceContainer;
395
    }
396
397
    /**
398
     * This is intended to be used from external repository in order to
399
     * enable container customization.
400
     *
401
     * @param \Symfony\Component\DependencyInjection\ContainerBuilder $containerBuilder
402
     */
403
    protected function externalBuildContainer(ContainerBuilder $containerBuilder)
0 ignored issues
show
Unused Code introduced by
The parameter $containerBuilder is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
404
    {
405
        // Does nothing by default
406
    }
407
408
    /**
409
     * Get the Database name.
410
     *
411
     * @return string
412
     */
413
    public function getDB()
414
    {
415
        return self::$db;
416
    }
417
}
418