Completed
Push — signal_search_issues ( 5556b2...f328ba )
by André
63:06 queued 07:22
created

Legacy::createTemporaryDirectory()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 19
Code Lines 12

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 2
eloc 12
nc 2
nop 0
dl 0
loc 19
rs 9.4285
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
 * @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) {
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...
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');
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...
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)
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...
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