Completed
Push — siteaccessaware-layer-only ( 37e924...bf143e )
by André
31:12 queued 14:22
created

Legacy::insertData()   C

Complexity

Conditions 9
Paths 42

Size

Total Lines 66
Code Lines 35

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 9
eloc 35
nc 42
nop 0
dl 0
loc 66
rs 6.4099
c 0
b 0
f 0

How to fix   Long Method   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

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