Completed
Pull Request — 2.6 (#7750)
by
unknown
06:18
created

Power::getEngine()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 1 Features 0
Metric Value
cc 1
eloc 1
c 1
b 1
f 0
nc 1
nop 0
dl 0
loc 3
rs 10
1
<?php
2
namespace Doctrine\Tests\ORM\Functional\Ticket;
3
4
use Doctrine\Common\Cache\ArrayCache;
5
use Doctrine\Common\Persistence\Mapping\Driver\MappingDriver;
6
use Doctrine\DBAL\Driver\Connection;
7
use Doctrine\DBAL\Logging\DebugStack;
8
use Doctrine\ORM\Cache\CacheConfiguration;
9
use Doctrine\ORM\Cache\DefaultCacheFactory;
10
use Doctrine\ORM\Cache\Logging\StatisticsCacheLogger;
11
use Doctrine\ORM\Configuration;
12
use Doctrine\ORM\EntityManager;
13
use Doctrine\ORM\Mapping\OneToOne;
14
use Doctrine\ORM\Tools\DebugUnitOfWorkListener;
15
use Doctrine\Tests\EventListener\CacheMetadataListener;
16
use Doctrine\Tests\OrmFunctionalTestCase;
17
use Doctrine\ORM\Mapping\Cache;
18
use Doctrine\ORM\Mapping\Column;
19
use Doctrine\ORM\Mapping\Entity;
0 ignored issues
show
Bug introduced by
This use statement conflicts with another class in this namespace, Doctrine\Tests\ORM\Functional\Ticket\Entity. Consider defining an alias.

Let?s assume that you have a directory layout like this:

.
|-- OtherDir
|   |-- Bar.php
|   `-- Foo.php
`-- SomeDir
    `-- Foo.php

and let?s assume the following content of Bar.php:

// Bar.php
namespace OtherDir;

use SomeDir\Foo; // This now conflicts the class OtherDir\Foo

If both files OtherDir/Foo.php and SomeDir/Foo.php are loaded in the same runtime, you will see a PHP error such as the following:

PHP Fatal error:  Cannot use SomeDir\Foo as Foo because the name is already in use in OtherDir/Foo.php

However, as OtherDir/Foo.php does not necessarily have to be loaded and the error is only triggered if it is loaded before OtherDir/Bar.php, this problem might go unnoticed for a while. In order to prevent this error from surfacing, you must import the namespace with a different alias:

// Bar.php
namespace OtherDir;

use SomeDir\Foo as SomeDirFoo; // There is no conflict anymore.
Loading history...
20
use Doctrine\ORM\Mapping\GeneratedValue;
21
use Doctrine\ORM\Mapping\Id;
22
use Doctrine\ORM\Mapping\JoinColumn;
23
use Doctrine\ORM\Mapping\ManyToOne;
24
use Doctrine\ORM\Mapping\Table;
25
26
/**
27
 * Class Issue7735Test
28
 * @package Doctrine\Tests\ORM\Functional\Ticket\Issue7735
29
 */
30
class Issue7735Test extends OrmFunctionalTestCase
31
{
32
    /**
33
     * Depend on PC performance
34
     */
35
    private const ITERATION_COUNT_FOR_BUG_DETECTION = 1000000;
36
37
    protected const DEFAULT_CACHE_REGION_LIFE_TIME = 1;
38
39
    /**
40
     * The metadata cache shared between all functional tests.
41
     *
42
     * @var \Doctrine\Common\Cache\Cache|null
43
     */
44
    private static $_metadataCacheImpl = null;
45
46
    /**
47
     * The query cache shared between all functional tests.
48
     *
49
     * @var \Doctrine\Common\Cache\Cache|null
50
     */
51
    private static $_queryCacheImpl = null;
52
53
    /**
54
     * @var \Doctrine\ORM\Cache
55
     */
56
    protected $cache;
57
58
    /**
59
     * @throws \Doctrine\Common\Persistence\Mapping\MappingException
60
     * @throws \Doctrine\ORM\ORMException
61
     * @throws \Doctrine\ORM\OptimisticLockException
62
     * @throws \Doctrine\ORM\Tools\ToolsException
63
     */
64
    public function setUp()
65
    {
66
        $this->enableSecondLevelCache();
67
        parent::setUp();
68
69
        $this->_schemaTool->createSchema(
70
            [
71
                $this->_em->getClassMetadata(Car::class),
72
                $this->_em->getClassMetadata(Power::class),
73
                $this->_em->getClassMetadata(Engine::class),
74
            ]
75
        );
76
77
        $this->cache = $this->_em->getCache();
78
79
        $engine = new Engine('turbo');
80
        $power = new Power($engine);
81
        $car = new Car($engine);
82
83
        $this->_em->persist($car);
84
        $this->_em->persist($power);
85
        $this->_em->persist($engine);
86
87
        $this->_em->flush();
88
        $this->_em->clear();
89
        $this->evictRegions();
90
91
    }
92
93
    /**
94
     * @throws \Doctrine\Common\Persistence\Mapping\MappingException
95
     */
96
    public function testFindByReturnsCachedEntity()
97
    {
98
        for ($i = self::ITERATION_COUNT_FOR_BUG_DETECTION; $i > 0; $i--) {
99
            $carRepository = $this->_em->getRepository(Car::class);
100
            $car = $carRepository->find(1);
101
            /** @var Engine $engine */
102
            $engine = $car->getEngine();
103
            $power = $engine->getPower();
0 ignored issues
show
Unused Code introduced by
The assignment to $power is dead and can be removed.
Loading history...
104
            $model = $engine->getModel();
105
            $this->assertNotEmpty($model);
106
            $this->_em->clear();
107
        }
108
    }
109
110
111
    private function evictRegions()
112
    {
113
        $this->cache->evictQueryRegions();
114
        $this->cache->evictEntityRegions();
115
        $this->cache->evictCollectionRegions();
116
    }
117
118
    /**
119
     * Gets an EntityManager for testing purposes.
120
     *
121
     * @return EntityManager
122
     *
123
     * @throws \Doctrine\ORM\ORMException
124
     */
125
    protected function _getEntityManager(
126
        Connection $connection = null,
127
        MappingDriver $mappingDriver = null
128
    )
129
    {
130
        // NOTE: Functional tests use their own shared metadata cache, because
131
        // the actual database platform used during execution has effect on some
132
        // metadata mapping behaviors (like the choice of the ID generation).
133
        if (is_null(self::$_metadataCacheImpl)) {
134
            if (isset($GLOBALS['DOCTRINE_CACHE_IMPL'])) {
135
                self::$_metadataCacheImpl = new $GLOBALS['DOCTRINE_CACHE_IMPL'];
136
            } else {
137
                self::$_metadataCacheImpl = new ArrayCache();
138
            }
139
        }
140
141
        if (is_null(self::$_queryCacheImpl)) {
142
            self::$_queryCacheImpl = new ArrayCache();
143
        }
144
145
        $this->_sqlLoggerStack = new DebugStack();
146
        $this->_sqlLoggerStack->enabled = false;
147
148
        //FIXME: two different configs! $conn and the created entity manager have
149
        // different configs.
150
        $config = new Configuration();
151
        $config->setMetadataCacheImpl(self::$_metadataCacheImpl);
152
        $config->setQueryCacheImpl(self::$_queryCacheImpl);
153
        $config->setProxyDir(__DIR__ . '/../../../Proxies');
154
        $config->setProxyNamespace('Doctrine\Tests\Proxies');
155
156
        if (null !== $this->resultCacheImpl) {
157
            $config->setResultCacheImpl($this->resultCacheImpl);
158
        }
159
160
        $enableSecondLevelCache = getenv('ENABLE_SECOND_LEVEL_CACHE');
161
162
        if ($this->isSecondLevelCacheEnabled || $enableSecondLevelCache) {
163
164
            $cacheConfig = new CacheConfiguration();
165
            $cache = $this->getSharedSecondLevelCacheDriverImpl();
166
167
            $regionConfig = $cacheConfig->getRegionsConfiguration();
168
            $regionConfig->setDefaultLifetime(static::DEFAULT_CACHE_REGION_LIFE_TIME);
169
            $factory = new DefaultCacheFactory($regionConfig, $cache);
170
171
            $this->secondLevelCacheFactory = $factory;
172
173
            if ($this->isSecondLevelCacheLogEnabled) {
174
                $this->secondLevelCacheLogger = new StatisticsCacheLogger();
175
                $cacheConfig->setCacheLogger($this->secondLevelCacheLogger);
176
            }
177
178
            $cacheConfig->setCacheFactory($factory);
179
            $config->setSecondLevelCacheEnabled(true);
180
            $config->setSecondLevelCacheConfiguration($cacheConfig);
181
182
            $this->isSecondLevelCacheEnabled = true;
183
        }
184
185
        $config->setMetadataDriverImpl(
186
            $mappingDriver ?? $config->newDefaultAnnotationDriver(
187
                [
188
                    realpath(__DIR__ . '/../../../Models/Cache'),
189
                    realpath(__DIR__ . '/../../../Models/GeoNames')
190
                ],
191
                true
192
            )
193
        );
194
195
        $conn = $connection ?: static::$_sharedConn;
196
        $conn->getConfiguration()->setSQLLogger($this->_sqlLoggerStack);
0 ignored issues
show
Bug introduced by
The method getConfiguration() does not exist on Doctrine\DBAL\Driver\Connection. It seems like you code against a sub-type of Doctrine\DBAL\Driver\Connection such as Doctrine\DBAL\Connection. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

196
        $conn->/** @scrutinizer ignore-call */ 
197
               getConfiguration()->setSQLLogger($this->_sqlLoggerStack);
Loading history...
Bug introduced by
The method getConfiguration() does not exist on null. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

196
        $conn->/** @scrutinizer ignore-call */ 
197
               getConfiguration()->setSQLLogger($this->_sqlLoggerStack);

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
197
198
        // get rid of more global state
199
        $evm = $conn->getEventManager();
0 ignored issues
show
Bug introduced by
The method getEventManager() does not exist on Doctrine\DBAL\Driver\Connection. It seems like you code against a sub-type of Doctrine\DBAL\Driver\Connection such as Doctrine\DBAL\Connection. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

199
        /** @scrutinizer ignore-call */ 
200
        $evm = $conn->getEventManager();
Loading history...
200
        foreach ($evm->getListeners() AS $event => $listeners) {
201
            foreach ($listeners AS $listener) {
202
                $evm->removeEventListener([$event], $listener);
203
            }
204
        }
205
206
        if ($enableSecondLevelCache) {
207
            $evm->addEventListener('loadClassMetadata', new CacheMetadataListener());
208
        }
209
210
        if (isset($GLOBALS['db_event_subscribers'])) {
211
            foreach (explode(",", $GLOBALS['db_event_subscribers']) AS $subscriberClass) {
212
                $subscriberInstance = new $subscriberClass();
213
                $evm->addEventSubscriber($subscriberInstance);
214
            }
215
        }
216
217
        if (isset($GLOBALS['debug_uow_listener'])) {
218
            $evm->addEventListener(['onFlush'], new DebugUnitOfWorkListener());
219
        }
220
221
        return EntityManager::create($conn, $config);
222
    }
223
}
224
225
/**
226
 * @Entity
227
 * @Table(name="car")
228
 * @Cache(usage="READ_ONLY", region="car")
229
 */
230
class Car
231
{
232
    /**
233
     * @Id
234
     * @Column(type="integer")
235
     * @GeneratedValue(strategy="IDENTITY")
236
     */
237
    private $id;
238
239
    /**
240
     * @var Engine
241
     * @Cache("READ_ONLY")
242
     * @ManyToOne(targetEntity="Engine")
243
     * @JoinColumn(name="engine", referencedColumnName="id", nullable=false)
244
     */
245
    protected $engine;
246
247
    /**
248
     * Car constructor.
249
     * @param Engine $engine
250
     * @param string $color
251
     */
252
    public function __construct(Engine $engine)
253
    {
254
        $this->engine = $engine;
255
    }
256
257
    /**
258
     * @return mixed
259
     */
260
    public function getId()
261
    {
262
        return $this->id;
263
    }
264
265
    /**
266
     * @return Engine
267
     */
268
    public function getEngine(): Engine
269
    {
270
        return $this->engine;
271
    }
272
}
273
274
/**
275
 * @Entity
276
 * @Table(name="engine")
277
 * @Cache(usage="READ_ONLY", region="engine")
278
 */
279
class Engine
280
{
281
    /**
282
     * @Id
283
     * @Column(type="integer")
284
     * @GeneratedValue(strategy="IDENTITY")
285
     */
286
    private $id;
287
288
    /**
289
     * @var Power
290
     * @Cache("READ_ONLY")
291
     * @OneToOne(targetEntity="Power", mappedBy="engine")
292
     */
293
    private $power;
294
295
    /**
296
     * @var string
297
     * @Column(name="model", type="string", nullable=false)
298
     */
299
    private $model;
300
301
    /**
302
     * Engine constructor.
303
     * @param string $model
304
     */
305
    public function __construct(string $model)
306
    {
307
        $this->model = $model;
308
    }
309
310
    /**
311
     * @return Power
312
     */
313
    public function getPower(): Power
314
    {
315
        return $this->power;
316
    }
317
318
    /**
319
     * @return mixed
320
     */
321
    public function getId()
322
    {
323
        return $this->id;
324
    }
325
326
    /**
327
     * @return string
328
     */
329
    public function getModel(): string
330
    {
331
        return $this->model;
332
    }
333
}
334
335
/**
336
 * @Entity
337
 * @Table(name="power")
338
 * @Cache(usage="READ_ONLY", region="power")
339
 */
340
class Power
341
{
342
    /**
343
     * @Id
344
     * @Column(type="integer")
345
     * @GeneratedValue(strategy="IDENTITY")
346
     */
347
    private $id;
348
349
    /**
350
     * @var Engine
351
     * @OneToOne(targetEntity="Engine")
352
     * @Cache("READ_ONLY")
353
     * @JoinColumn(name="engine_id", referencedColumnName="id", onDelete="CASCADE")
354
     */
355
    protected $engine;
356
357
    /**
358
     * Power constructor.
359
     * @param int $horsePower
360
     * @param int $kilowatt
361
     * @param Engine $engine
362
     */
363
    public function __construct(Engine $engine)
364
    {
365
        $this->engine = $engine;
366
    }
367
368
    /**
369
     * @return Engine
370
     */
371
    public function getEngine(): Engine
372
    {
373
        return $this->engine;
374
    }
375
}
376