Completed
Push — ezp26175-exception_on_non_defa... ( 77d2f3...ca5fc8 )
by
unknown
39:33
created

Legacy::__construct()   A

Complexity

Conditions 3
Paths 4

Size

Total Lines 13
Code Lines 7

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 3
eloc 7
nc 4
nop 0
dl 0
loc 13
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
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
     * Returns a configured repository for testing.
118
     *
119
     * @param bool $initializeFromScratch if the back end should be initialized
120
     *                                    from scratch or re-used
121
     *
122
     * @return \eZ\Publish\API\Repository\Repository
123
     */
124
    public function getRepository($initializeFromScratch = true)
125
    {
126
        if ($initializeFromScratch || !self::$schemaInitialized) {
127
            $this->initializeSchema();
128
            $this->insertData();
129
        }
130
131
        $this->clearInternalCaches();
132
        $repository = $this->getServiceContainer()->get($this->repositoryReference);
133
134
        // Set admin user as current user by default
135
        $repository->setCurrentUser(new UserReference(14));
136
137
        return $repository;
138
    }
139
140
    /**
141
     * Returns a config value for $configKey.
142
     *
143
     * @param string $configKey
144
     *
145
     * @throws Exception if $configKey could not be found.
146
     *
147
     * @return mixed
148
     */
149
    public function getConfigValue($configKey)
150
    {
151
        return $this->getServiceContainer()->getParameter($configKey);
152
    }
153
154
    /**
155
     * Returns a repository specific ID manager.
156
     *
157
     * @return \eZ\Publish\API\Repository\Tests\IdManager
158
     */
159
    public function getIdManager()
160
    {
161
        return new IdManager\Php();
162
    }
163
164
    /**
165
     * Insert the database data.
166
     */
167
    public function insertData()
168
    {
169
        $data = $this->getInitialData();
170
        $handler = $this->getDatabaseHandler();
171
        $connection = $handler->getConnection();
172
        $dbPlatform = $connection->getDatabasePlatform();
173
        $this->cleanupVarDir($this->getInitialVarDir());
174
175
        // @todo FIXME: Needs to be in fixture
176
        $data['ezcontentobject_trash'] = array();
177
        $data['ezurlwildcard'] = array();
178
        $data['ezmedia'] = array();
179
        $data['ezkeyword'] = array();
180
181 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...
182
            // Cleanup before inserting (using TRUNCATE for speed, however not possible to rollback)
183
            $q = $dbPlatform->getTruncateTableSql($handler->quoteIdentifier($table));
184
            $connection->executeUpdate($q);
185
186
            // Check that at least one row exists
187
            if (!isset($rows[0])) {
188
                continue;
189
            }
190
191
            $q = $handler->createInsertQuery();
192
            $q->insertInto($handler->quoteIdentifier($table));
193
194
            // Contains the bound parameters
195
            $values = array();
196
197
            // Binding the parameters
198
            foreach ($rows[0] as $col => $val) {
199
                $q->set(
200
                    $handler->quoteIdentifier($col),
201
                    $q->bindParam($values[$col])
202
                );
203
            }
204
205
            $stmt = $q->prepare();
206
207
            foreach ($rows as $row) {
208
                try {
209
                    // This CANNOT be replaced by:
210
                    // $values = $row
211
                    // each $values[$col] is a PHP reference which should be
212
                    // kept for parameters binding to work
213
                    foreach ($row as $col => $val) {
214
                        $values[$col] = $val;
215
                    }
216
217
                    $stmt->execute();
218
                } catch (Exception $e) {
219
                    echo "$table ( ", implode(', ', $row), " )\n";
220
                    throw $e;
221
                }
222
            }
223
        }
224
225
        $this->applyStatements($this->getPostInsertStatements());
226
    }
227
228
    protected function getInitialVarDir()
229
    {
230
        return __DIR__ . '/../../../../../../var';
231
    }
232
233
    protected function cleanupVarDir($sourceDir)
234
    {
235
        $fs = new Filesystem();
236
        $varDir = self::$ioRootDir . '/var';
237
        if ($fs->exists($varDir)) {
238
            $fs->remove($varDir);
239
        }
240
        $fs->mkdir($varDir);
241
        $fs->mirror($sourceDir, $varDir);
242
    }
243
244
    /**
245
     * CLears internal in memory caches after inserting data circumventing the
246
     * API.
247
     */
248
    protected function clearInternalCaches()
249
    {
250
        /** @var $handler \eZ\Publish\Core\Persistence\Legacy\Handler */
251
        $handler = $this->getServiceContainer()->get('ezpublish.spi.persistence.legacy');
252
253
        $contentLanguageHandler = $handler->contentLanguageHandler();
254
        if ($contentLanguageHandler instanceof CachingLanguageHandler) {
255
            $contentLanguageHandler->clearCache();
256
        }
257
258
        $contentTypeHandler = $handler->contentTypeHandler();
259
        if ($contentTypeHandler instanceof CachingContentTypeHandler) {
260
            $contentTypeHandler->clearCache();
261
        }
262
263
        /** @var $decorator \eZ\Publish\Core\Persistence\Cache\Tests\Helpers\IntegrationTestCacheServiceDecorator */
264
        $decorator = $this->getServiceContainer()->get('ezpublish.cache_pool.spi.cache.decorator');
265
266
        $decorator->clearAllTestData();
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