Completed
Push — travis_redis ( f0e195...3c2177 )
by André
12:11
created

Legacy   B

Complexity

Total Complexity 37

Size/Duplication

Total Lines 390
Duplicated Lines 11.03 %

Coupling/Cohesion

Components 1
Dependencies 16

Importance

Changes 0
Metric Value
dl 43
loc 390
rs 7.2769
c 0
b 0
f 0
wmc 37
lcom 1
cbo 16

18 Methods

Rating   Name   Duplication   Size   Complexity  
A getRepository() 0 15 3
A getConfigValue() 0 4 1
A getIdManager() 0 4 1
A getInitialVarDir() 0 4 1
A getPostInsertStatements() 0 10 2
A getInitialData() 0 9 2
A initializeSchema() 0 10 2
A applyStatements() 0 6 2
A getSchemaStatements() 0 6 1
A getDatabaseHandler() 0 4 1
A externalBuildContainer() 0 4 1
A getDB() 0 4 1
B insertData() 43 60 7
B getServiceContainer() 0 39 2
A __construct() 0 13 3
A createTemporaryDirectory() 0 19 2
A cleanupVarDir() 0 10 2
A clearInternalCaches() 0 21 3

How to fix   Duplicated Code   

Duplicated Code

Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.

Common duplication problems, and corresponding solutions are:

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'] = array();
176
        $data['ezurlwildcard'] = array();
177
        $data['ezmedia'] = array();
178
        $data['ezkeyword'] = array();
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 = 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
        $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 $decorator \Stash\Pool */
263
        $pool = $this->getServiceContainer()->get('ezpublish.cache_pool');
264
265
        // Using the pool instead of decorator to clear the whole pool, not iterate items with our ez_spi prefix
266
        $pool->clear();
267
    }
268
269
    /**
270
     * Returns statements to be executed after data insert.
271
     *
272
     * @return string[]
273
     */
274
    protected function getPostInsertStatements()
275
    {
276
        if (self::$db === 'pgsql') {
277
            $setvalPath = __DIR__ . '/../../../../Core/Persistence/Legacy/Tests/_fixtures/setval.pgsql.sql';
278
279
            return array_filter(preg_split('(;\\s*$)m', file_get_contents($setvalPath)));
280
        }
281
282
        return array();
283
    }
284
285
    /**
286
     * Returns the initial database data.
287
     *
288
     * @return array
289
     */
290
    protected function getInitialData()
291
    {
292
        if (!isset(self::$initialData)) {
293
            self::$initialData = include __DIR__ . '/../../../../Core/Repository/Tests/Service/Integration/Legacy/_fixtures/clean_ezdemo_47_dump.php';
294
            // self::$initialData = include __DIR__ . '/../../../../Core/Repository/Tests/Service/Legacy/_fixtures/full_dump.php';
295
        }
296
297
        return self::$initialData;
298
    }
299
300
    /**
301
     * Initializes the database schema.
302
     */
303
    protected function initializeSchema()
304
    {
305
        if (!self::$schemaInitialized) {
306
            $statements = $this->getSchemaStatements();
307
308
            $this->applyStatements($statements);
309
310
            self::$schemaInitialized = true;
311
        }
312
    }
313
314
    /**
315
     * Applies the given SQL $statements to the database in use.
316
     *
317
     * @param array $statements
318
     */
319
    protected function applyStatements(array $statements)
320
    {
321
        foreach ($statements as $statement) {
322
            $this->getDatabaseHandler()->exec($statement);
323
        }
324
    }
325
326
    // ************* Setup copied and refactored from common.php ************
327
328
    /**
329
     * Returns the database schema as an array of SQL statements.
330
     *
331
     * @return string[]
332
     */
333
    protected function getSchemaStatements()
334
    {
335
        $schemaPath = __DIR__ . '/../../../../Core/Persistence/Legacy/Tests/_fixtures/schema.' . self::$db . '.sql';
336
337
        return array_filter(preg_split('(;\\s*$)m', file_get_contents($schemaPath)));
338
    }
339
340
    /**
341
     * Returns the database handler from the service container.
342
     *
343
     * @return \eZ\Publish\Core\Persistence\Doctrine\ConnectionHandler
344
     */
345
    protected function getDatabaseHandler()
346
    {
347
        return $this->getServiceContainer()->get('ezpublish.api.storage_engine.legacy.dbhandler');
348
    }
349
350
    /**
351
     * Returns the service container used for initialization of the repository.
352
     *
353
     * @return \eZ\Publish\Core\Base\ServiceContainer
354
     */
355
    public function getServiceContainer()
356
    {
357
        if (!isset(self::$serviceContainer)) {
358
            $config = include __DIR__ . '/../../../../../../config.php';
359
            $installDir = $config['install_dir'];
360
361
            /** @var \Symfony\Component\DependencyInjection\ContainerBuilder $containerBuilder */
362
            $containerBuilder = include $config['container_builder_path'];
363
364
            /* @var \Symfony\Component\DependencyInjection\Loader\YamlFileLoader $loader */
365
            $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...
366
            $loader->load('tests/integration_legacy.yml');
367
368
            $this->externalBuildContainer($containerBuilder);
369
370
            $containerBuilder->setParameter(
371
                'legacy_dsn',
372
                self::$dsn
373
            );
374
375
            $containerBuilder->setParameter(
376
                'io_root_dir',
377
                self::$ioRootDir . '/' . $containerBuilder->getParameter('storage_dir')
378
            );
379
380
            $containerBuilder->addCompilerPass(new Compiler\Search\SearchEngineSignalSlotPass('legacy'));
381
            $containerBuilder->addCompilerPass(new Compiler\Search\FieldRegistryPass());
382
383
            self::$serviceContainer = new ServiceContainer(
384
                $containerBuilder,
385
                $installDir,
386
                $config['cache_dir'],
387
                true,
388
                true
389
            );
390
        }
391
392
        return self::$serviceContainer;
393
    }
394
395
    /**
396
     * This is intended to be used from external repository in order to
397
     * enable container customization.
398
     *
399
     * @param \Symfony\Component\DependencyInjection\ContainerBuilder $containerBuilder
400
     */
401
    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...
402
    {
403
        // Does nothing by default
404
    }
405
406
    /**
407
     * Get the Database name.
408
     *
409
     * @return string
410
     */
411
    public function getDB()
412
    {
413
        return self::$db;
414
    }
415
}
416