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