Completed
Push — master ( 98e4ef...5952d3 )
by Jáchym
03:01
created

OrmExtension   F

Complexity

Total Complexity 105

Size/Duplication

Total Lines 858
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 24

Importance

Changes 0
Metric Value
wmc 105
lcom 1
cbo 24
dl 0
loc 858
rs 1.133
c 0
b 0
f 0

19 Methods

Rating   Name   Duplication   Size   Complexity  
A processCache() 0 4 1
A beforeCompile() 0 5 1
A loadConsole() 0 17 3
B processSecondLevelCache() 0 51 5
C loadConfiguration() 0 66 13
F processEntityManager() 0 198 20
C processConnection() 0 71 8
C processMetadataDriver() 0 58 18
D processRepositories() 0 87 17
A processEventManagers() 0 12 4
A getServiceBoundManagers() 0 7 2
A afterCompile() 0 15 3
A resolveConfig() 0 7 1
A normalizeTargetEntityMappings() 0 21 3
A isTracyPresent() 0 4 1
A isKdybyEventsPresent() 0 4 1
A addCollapsePathsToTracy() 0 11 2
A register() 0 6 1
A natSortKeys() 0 8 1

How to fix   Complexity   

Complex Class

Complex classes like OrmExtension often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes. You can also have a look at the cohesion graph to spot any un-connected, or weakly-connected components.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use OrmExtension, and based on these observations, apply Extract Interface, too.

1
<?php
2
3
/**
4
 * This file is part of the Kdyby (http://www.kdyby.org)
5
 *
6
 * Copyright (c) 2008 Filip Procházka ([email protected])
7
 *
8
 * For the full copyright and license information, please view the file license.txt that was distributed with this source code.
9
 */
10
11
namespace Kdyby\Doctrine\DI;
12
13
use Doctrine;
14
use Doctrine\Common\Proxy\AbstractProxyFactory;
15
use Doctrine\ORM\EntityManagerInterface;
16
use Doctrine\ORM\Repository\DefaultRepositoryFactory;
17
use Kdyby;
18
use Kdyby\DoctrineCache\DI\Helpers as CacheHelpers;
19
use Nette;
20
use Nette\DI\Statement;
21
use Nette\PhpGenerator as Code;
22
use Nette\PhpGenerator\Method;
23
use Nette\Utils\Strings;
24
use Nette\Utils\Validators;
25
use Doctrine\DBAL\Schema\AbstractSchemaManager;
26
use Kdyby\Annotations\DI\AnnotationsExtension;
27
use Doctrine\ORM\Tools\Console\Helper\EntityManagerHelper;
28
use Doctrine\DBAL\Tools\Console\Helper\ConnectionHelper;
29
30
/**
31
 * @author Filip Procházka <[email protected]>
32
 */
33
class OrmExtension extends Nette\DI\CompilerExtension
34
{
35
36
	const ANNOTATION_DRIVER = 'annotations';
37
	const PHP_NAMESPACE = '[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff\\\\]*';
38
	const TAG_CONNECTION = 'doctrine.connection';
39
	const TAG_ENTITY_MANAGER = 'doctrine.entityManager';
40
	const TAG_BIND_TO_MANAGER = 'doctrine.bindToManager';
41
	const TAG_REPOSITORY_ENTITY = 'doctrine.repositoryEntity';
42
	const DEFAULT_PROXY_NAMESPACE = 'Kdyby\GeneratedProxy';
43
	const KDYBY_METADATA_NAMESPACE = 'Kdyby\Doctrine';
44
45
	/**
46
	 * @var array
47
	 */
48
	public $managerDefaults = [
49
		'metadataCache' => 'default',
50
		'queryCache' => 'default',
51
		'resultCache' => 'default',
52
		'hydrationCache' => 'default',
53
		'secondLevelCache' => [
54
			'enabled' => FALSE,
55
			'factoryClass' => Doctrine\ORM\Cache\DefaultCacheFactory::class,
56
			'driver' => 'default',
57
			'regions' => [
58
				'defaultLifetime' => 3600,
59
				'defaultLockLifetime' => 60,
60
			],
61
			'fileLockRegionDirectory' => '%tempDir%/cache/Doctrine.Cache.Locks', // todo fix
62
			'logging' => '%debugMode%',
63
		],
64
		'classMetadataFactory' => Kdyby\Doctrine\Mapping\ClassMetadataFactory::class,
65
		'defaultRepositoryClassName' => Kdyby\Doctrine\EntityRepository::class,
66
		'repositoryFactoryClassName' => Kdyby\Doctrine\RepositoryFactory::class,
67
		'queryBuilderClassName' => Kdyby\Doctrine\QueryBuilder::class,
68
		'autoGenerateProxyClasses' => '%debugMode%',
69
		'namingStrategy' => Doctrine\ORM\Mapping\UnderscoreNamingStrategy::class,
70
		'quoteStrategy' => Doctrine\ORM\Mapping\DefaultQuoteStrategy::class,
71
		'entityListenerResolver' => Kdyby\Doctrine\Mapping\EntityListenerResolver::class,
72
		'proxyDir' => '%tempDir%/proxies',
73
		'proxyNamespace' => self::DEFAULT_PROXY_NAMESPACE,
74
		'dql' => ['string' => [], 'numeric' => [], 'datetime' => [], 'hints' => []],
75
		'hydrators' => [],
76
		'metadata' => [],
77
		'filters' => [],
78
		'namespaceAlias' => [],
79
		'targetEntityMappings' => [],
80
	];
81
82
	/**
83
	 * @var array
84
	 */
85
	public $connectionDefaults = [
86
		'dbname' => NULL,
87
		'host' => '127.0.0.1',
88
		'port' => NULL,
89
		'user' => NULL,
90
		'password' => NULL,
91
		'charset' => 'UTF8',
92
		'driver' => 'pdo_mysql',
93
		'driverClass' => NULL,
94
		'options' => NULL,
95
		'path' => NULL,
96
		'memory' => NULL,
97
		'unix_socket' => NULL,
98
		'logging' => '%debugMode%',
99
		'platformService' => NULL,
100
		'defaultTableOptions' => [],
101
		'resultCache' => 'default',
102
		'types' => [],
103
		'schemaFilter' => NULL,
104
	];
105
106
	/**
107
	 * @var array
108
	 */
109
	public $metadataDriverClasses = [
110
		self::ANNOTATION_DRIVER => Kdyby\Doctrine\Mapping\AnnotationDriver::class,
111
		'static' => Doctrine\Common\Persistence\Mapping\Driver\StaticPHPDriver::class,
112
		'yml' => Doctrine\ORM\Mapping\Driver\YamlDriver::class,
113
		'yaml' => Doctrine\ORM\Mapping\Driver\YamlDriver::class,
114
		'xml' => Doctrine\ORM\Mapping\Driver\XmlDriver::class,
115
		'db' => Doctrine\ORM\Mapping\Driver\DatabaseDriver::class,
116
	];
117
118
	/**
119
	 * @var array
120
	 */
121
	private $proxyAutoloaders = [];
122
123
	/**
124
	 * @var array
125
	 */
126
	private $targetEntityMappings = [];
127
128
	/**
129
	 * @var array
130
	 */
131
	private $configuredManagers = [];
132
133
	/**
134
	 * @var array
135
	 */
136
	private $managerConfigs = [];
137
138
	/**
139
	 * @var array
140
	 */
141
	private $configuredConnections = [];
142
143
144
145
	public function loadConfiguration()
146
	{
147
		$this->proxyAutoloaders =
148
		$this->targetEntityMappings =
149
		$this->configuredConnections =
150
		$this->managerConfigs =
151
		$this->configuredManagers = [];
152
153
		if (!$this->compiler->getExtensions(AnnotationsExtension::class)) {
154
			throw new Nette\Utils\AssertionException(sprintf("You should register %s before %s.", AnnotationsExtension::class, get_class($this)));
155
		}
156
157
		$builder = $this->getContainerBuilder();
158
		$config = $this->getConfig();
159
160
		$builder->parameters[$this->prefix('debug')] = !empty($config['debug']);
161
		if (isset($config['dbname']) || isset($config['driver']) || isset($config['connection'])) {
162
			$config = ['default' => $config];
163
			$defaults = ['debug' => $builder->parameters['debugMode']];
164
165
		} else {
166
			$defaults = array_intersect_key($config, $this->managerDefaults)
167
				+ array_intersect_key($config, $this->connectionDefaults)
168
				+ ['debug' => $builder->parameters['debugMode']];
169
170
			$config = array_diff_key($config, $defaults);
171
		}
172
173
		if (empty($config)) {
174
			throw new Kdyby\Doctrine\UnexpectedValueException("Please configure the Doctrine extensions using the section '{$this->name}:' in your config file.");
175
		}
176
177
		foreach ($config as $name => $emConfig) {
178
			if (!is_array($emConfig) || (empty($emConfig['dbname']) && empty($emConfig['driver']))) {
179
				throw new Kdyby\Doctrine\UnexpectedValueException("Please configure the Doctrine extensions using the section '{$this->name}:' in your config file.");
180
			}
181
182
			/** @var mixed[] $emConfig */
183
			$emConfig = Nette\DI\Config\Helpers::merge($emConfig, $defaults);
184
			$this->processEntityManager($name, $emConfig);
185
		}
186
187
		if ($this->targetEntityMappings) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $this->targetEntityMappings of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using ! empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
188
			if (!$this->isKdybyEventsPresent()) {
189
				throw new Nette\Utils\AssertionException('The option \'targetEntityMappings\' requires \'Kdyby\Events\DI\EventsExtension\'.', E_USER_NOTICE);
190
			}
191
192
			$listener = $builder->addDefinition($this->prefix('resolveTargetEntityListener'))
0 ignored issues
show
Deprecated Code introduced by
The method Nette\DI\ServiceDefinition::setClass() has been deprecated.

This method has been deprecated.

Loading history...
193
				->setClass(Kdyby\Doctrine\Tools\ResolveTargetEntityListener::class)
194
				->addTag(Kdyby\Events\DI\EventsExtension::TAG_SUBSCRIBER);
195
196
			foreach ($this->targetEntityMappings as $originalEntity => $mapping) {
197
				$listener->addSetup('addResolveTargetEntity', [$originalEntity, $mapping['targetEntity'], $mapping]);
198
			}
199
		}
200
201
		$this->loadConsole();
202
203
		$builder->addDefinition($this->prefix('registry'))
0 ignored issues
show
Deprecated Code introduced by
The method Nette\DI\ServiceDefinition::setClass() has been deprecated.

This method has been deprecated.

Loading history...
204
			->setClass(Kdyby\Doctrine\Registry::class, [
205
				$this->configuredConnections,
206
				$this->configuredManagers,
207
				$builder->parameters[$this->name]['dbal']['defaultConnection'],
208
				$builder->parameters[$this->name]['orm']['defaultEntityManager'],
209
			]);
210
	}
211
212
213
214
	protected function loadConsole()
215
	{
216
		$builder = $this->getContainerBuilder();
217
218
		foreach ($this->loadFromFile(__DIR__ . '/console.neon') as $i => $command) {
0 ignored issues
show
Bug introduced by
The expression $this->loadFromFile(__DIR__ . '/console.neon') of type array|string is not guaranteed to be traversable. How about adding an additional type check?

There are different options of fixing this problem.

  1. If you want to be on the safe side, you can add an additional type-check:

    $collection = json_decode($data, true);
    if ( ! is_array($collection)) {
        throw new \RuntimeException('$collection must be an array.');
    }
    
    foreach ($collection as $item) { /** ... */ }
    
  2. If you are sure that the expression is traversable, you might want to add a doc comment cast to improve IDE auto-completion and static analysis:

    /** @var array $collection */
    $collection = json_decode($data, true);
    
    foreach ($collection as $item) { /** .. */ }
    
  3. Mark the issue as a false-positive: Just hover the remove button, in the top-right corner of this issue for more options.

Loading history...
219
			$cli = $builder->addDefinition($this->prefix('cli.' . $i))
220
				->addTag(Kdyby\Console\DI\ConsoleExtension::TAG_COMMAND)
221
				->addTag(Nette\DI\Extensions\InjectExtension::TAG_INJECT, FALSE); // lazy injects
222
223
			if (is_string($command)) {
224
				$cli->setClass($command);
0 ignored issues
show
Deprecated Code introduced by
The method Nette\DI\ServiceDefinition::setClass() has been deprecated.

This method has been deprecated.

Loading history...
225
226
			} else {
227
				throw new Kdyby\Doctrine\NotSupportedException;
228
			}
229
		}
230
	}
231
232
233
234
	protected function processEntityManager($name, array $defaults)
235
	{
236
		$builder = $this->getContainerBuilder();
237
		$config = $this->resolveConfig($defaults, $this->managerDefaults, $this->connectionDefaults);
238
239
		if ($isDefault = !isset($builder->parameters[$this->name]['orm']['defaultEntityManager'])) {
240
			$builder->parameters[$this->name]['orm']['defaultEntityManager'] = $name;
241
		}
242
243
		$metadataDriver = $builder->addDefinition($this->prefix($name . '.metadataDriver'))
0 ignored issues
show
Deprecated Code introduced by
The method Nette\DI\ServiceDefinition::setClass() has been deprecated.

This method has been deprecated.

Loading history...
244
			->setClass(Doctrine\Common\Persistence\Mapping\Driver\MappingDriverChain::class)
245
			->setAutowired(FALSE);
246
		/** @var \Nette\DI\ServiceDefinition $metadataDriver */
247
248
		Validators::assertField($config, 'metadata', 'array');
249
		Validators::assertField($config, 'targetEntityMappings', 'array');
250
		$config['targetEntityMappings'] = $this->normalizeTargetEntityMappings($config['targetEntityMappings']);
251
		foreach ($this->compiler->getExtensions() as $extension) {
252
			if ($extension instanceof IEntityProvider) {
253
				$metadata = $extension->getEntityMappings();
254
				Validators::assert($metadata, 'array');
255
				foreach ($metadata as $namespace => $nsConfig) {
256
					if (array_key_exists($namespace, $config['metadata'])) {
257
						throw new Nette\Utils\AssertionException(sprintf('The namespace %s is already configured, provider cannot change it', $namespace));
258
					}
259
					$config['metadata'][$namespace] = $nsConfig;
260
				}
261
			}
262
263
			if ($extension instanceof ITargetEntityProvider) {
264
				$targetEntities = $extension->getTargetEntityMappings();
265
				Validators::assert($targetEntities, 'array');
266
				$config['targetEntityMappings'] = Nette\Utils\Arrays::mergeTree($config['targetEntityMappings'], $this->normalizeTargetEntityMappings($targetEntities));
267
			}
268
269
			if ($extension instanceof IDatabaseTypeProvider) {
270
				$providedTypes = $extension->getDatabaseTypes();
271
				Validators::assert($providedTypes, 'array');
272
273
				if (!isset($defaults['types'])) {
274
					$defaults['types'] = [];
275
				}
276
277
				$defaults['types'] = array_merge($defaults['types'], $providedTypes);
278
			}
279
		}
280
281
		foreach (self::natSortKeys($config['metadata']) as $namespace => $driver) {
282
			$this->processMetadataDriver($metadataDriver, $namespace, $driver, $name);
283
		}
284
285
		$this->processMetadataDriver($metadataDriver, self::KDYBY_METADATA_NAMESPACE, __DIR__ . '/../Entities', $name);
286
287
		if (empty($config['metadata'])) {
288
			$metadataDriver->addSetup('setDefaultDriver', [
289
				new Statement($this->metadataDriverClasses[self::ANNOTATION_DRIVER], [
290
					[$builder->expand('%appDir%')],
0 ignored issues
show
Deprecated Code introduced by
The method Nette\DI\ContainerBuilder::expand() has been deprecated.

This method has been deprecated.

Loading history...
291
					2 => $this->prefix('@cache.' . $name . '.metadata')
292
				])
293
			]);
294
		}
295
296
		if ($config['repositoryFactoryClassName'] === 'default') {
297
			$config['repositoryFactoryClassName'] = DefaultRepositoryFactory::class;
298
		}
299
		$builder->addDefinition($this->prefix($name . '.repositoryFactory'))
0 ignored issues
show
Deprecated Code introduced by
The method Nette\DI\ServiceDefinition::setClass() has been deprecated.

This method has been deprecated.

Loading history...
300
			->setClass($config['repositoryFactoryClassName'])
301
			->setAutowired(FALSE);
302
303
		Validators::assertField($config, 'namespaceAlias', 'array');
304
		Validators::assertField($config, 'hydrators', 'array');
305
		Validators::assertField($config, 'dql', 'array');
306
		Validators::assertField($config['dql'], 'string', 'array');
307
		Validators::assertField($config['dql'], 'numeric', 'array');
308
		Validators::assertField($config['dql'], 'datetime', 'array');
309
		Validators::assertField($config['dql'], 'hints', 'array');
310
311
		$autoGenerateProxyClasses = is_bool($config['autoGenerateProxyClasses'])
312
			? ($config['autoGenerateProxyClasses'] ? AbstractProxyFactory::AUTOGENERATE_ALWAYS : AbstractProxyFactory::AUTOGENERATE_NEVER)
313
			: $config['autoGenerateProxyClasses'];
314
315
		$configuration = $builder->addDefinition($this->prefix($name . '.ormConfiguration'))
0 ignored issues
show
Deprecated Code introduced by
The method Nette\DI\ServiceDefinition::setClass() has been deprecated.

This method has been deprecated.

Loading history...
316
			->setClass(Kdyby\Doctrine\Configuration::class)
317
			->addSetup('setMetadataCacheImpl', [$this->processCache($config['metadataCache'], $name . '.metadata')])
318
			->addSetup('setQueryCacheImpl', [$this->processCache($config['queryCache'], $name . '.query')])
319
			->addSetup('setResultCacheImpl', [$this->processCache($config['resultCache'], $name . '.ormResult')])
320
			->addSetup('setHydrationCacheImpl', [$this->processCache($config['hydrationCache'], $name . '.hydration')])
321
			->addSetup('setMetadataDriverImpl', [$this->prefix('@' . $name . '.metadataDriver')])
322
			->addSetup('setClassMetadataFactoryName', [$config['classMetadataFactory']])
323
			->addSetup('setDefaultRepositoryClassName', [$config['defaultRepositoryClassName']])
324
			->addSetup('setQueryBuilderClassName', [$config['queryBuilderClassName']])
325
			->addSetup('setRepositoryFactory', [$this->prefix('@' . $name . '.repositoryFactory')])
326
			->addSetup('setProxyDir', [$config['proxyDir']])
327
			->addSetup('setProxyNamespace', [$config['proxyNamespace']])
328
			->addSetup('setAutoGenerateProxyClasses', [$autoGenerateProxyClasses])
329
			->addSetup('setEntityNamespaces', [$config['namespaceAlias']])
330
			->addSetup('setCustomHydrationModes', [$config['hydrators']])
331
			->addSetup('setCustomStringFunctions', [$config['dql']['string']])
332
			->addSetup('setCustomNumericFunctions', [$config['dql']['numeric']])
333
			->addSetup('setCustomDatetimeFunctions', [$config['dql']['datetime']])
334
			->addSetup('setDefaultQueryHints', [$config['dql']['hints']])
335
			->addSetup('setNamingStrategy', CacheHelpers::filterArgs($config['namingStrategy']))
336
			->addSetup('setQuoteStrategy', CacheHelpers::filterArgs($config['quoteStrategy']))
337
			->addSetup('setEntityListenerResolver', CacheHelpers::filterArgs($config['entityListenerResolver']))
338
			->setAutowired(FALSE);
339
		/** @var Nette\DI\ServiceDefinition $configuration */
340
341
		$this->proxyAutoloaders[$config['proxyNamespace']] = $config['proxyDir'];
342
343
		$this->processSecondLevelCache($name, $config['secondLevelCache'], $isDefault);
344
345
		Validators::assertField($config, 'filters', 'array');
346
		foreach ($config['filters'] as $filterName => $filterClass) {
347
			$configuration->addSetup('addFilter', [$filterName, $filterClass]);
348
		}
349
350
		if ($config['targetEntityMappings']) {
351
			$configuration->addSetup('setTargetEntityMap', [array_map(function ($mapping) {
352
				return $mapping['targetEntity'];
353
			}, $config['targetEntityMappings'])]);
354
			$this->targetEntityMappings = Nette\Utils\Arrays::mergeTree($this->targetEntityMappings, $config['targetEntityMappings']);
355
		}
356
357
		if ($this->isKdybyEventsPresent()) {
358
			$builder->addDefinition($this->prefix($name . '.evm'))
0 ignored issues
show
Deprecated Code introduced by
The method Nette\DI\ServiceDefinition::setClass() has been deprecated.

This method has been deprecated.

Loading history...
359
				->setClass(Kdyby\Events\NamespacedEventManager::class, [Kdyby\Doctrine\Events::NS . '::'])
360
				->addSetup('$dispatchGlobalEvents', [TRUE]) // for BC
361
				->setAutowired(FALSE);
362
363
		} else {
364
			$builder->addDefinition($this->prefix($name . '.evm'))
0 ignored issues
show
Deprecated Code introduced by
The method Nette\DI\ServiceDefinition::setClass() has been deprecated.

This method has been deprecated.

Loading history...
365
				->setClass('Doctrine\Common\EventManager')
366
				->setAutowired(FALSE);
367
		}
368
369
		// entity manager
370
		$entityManager = $builder->addDefinition($managerServiceId = $this->prefix($name . '.entityManager'))
0 ignored issues
show
Deprecated Code introduced by
The method Nette\DI\ServiceDefinition::setClass() has been deprecated.

This method has been deprecated.

Loading history...
371
			->setClass(Kdyby\Doctrine\EntityManager::class)
372
			->setFactory(Kdyby\Doctrine\EntityManager::class . '::create', [
373
				$connectionService = $this->processConnection($name, $defaults, $isDefault),
374
				$this->prefix('@' . $name . '.ormConfiguration'),
375
				$this->prefix('@' . $name . '.evm'),
376
			])
377
			->addTag(self::TAG_ENTITY_MANAGER)
378
			->addTag('kdyby.doctrine.entityManager')
379
			->setAutowired($isDefault);
380
381
		if ($this->isTracyPresent()) {
382
			$entityManager->addSetup('?->bindEntityManager(?)', [$this->prefix('@' . $name . '.diagnosticsPanel'), '@self']);
383
		}
384
385
		$builder->addDefinition($this->prefix('repositoryFactory.' . $name . '.defaultRepositoryFactory'))
0 ignored issues
show
Deprecated Code introduced by
The method Nette\DI\ServiceDefinition::setClass() has been deprecated.

This method has been deprecated.

Loading history...
386
				->setClass($config['defaultRepositoryClassName'])
387
				->setImplement(IRepositoryFactory::class)
388
				->setArguments([new Code\PhpLiteral('$entityManager'), new Code\PhpLiteral('$classMetadata')])
389
				->setParameters([EntityManagerInterface::class . ' entityManager', Doctrine\ORM\Mapping\ClassMetadata::class . ' classMetadata'])
390
				->setAutowired(FALSE);
391
392
		$builder->addDefinition($this->prefix($name . '.schemaValidator'))
0 ignored issues
show
Deprecated Code introduced by
The method Nette\DI\ServiceDefinition::setClass() has been deprecated.

This method has been deprecated.

Loading history...
393
			->setClass(Doctrine\ORM\Tools\SchemaValidator::class, ['@' . $managerServiceId])
394
			->setAutowired($isDefault);
395
396
		$builder->addDefinition($this->prefix($name . '.schemaTool'))
0 ignored issues
show
Deprecated Code introduced by
The method Nette\DI\ServiceDefinition::setClass() has been deprecated.

This method has been deprecated.

Loading history...
397
			->setClass(Doctrine\ORM\Tools\SchemaTool::class, ['@' . $managerServiceId])
398
			->setAutowired($isDefault);
399
400
		$cacheCleaner = $builder->addDefinition($this->prefix($name . '.cacheCleaner'))
0 ignored issues
show
Deprecated Code introduced by
The method Nette\DI\ServiceDefinition::setClass() has been deprecated.

This method has been deprecated.

Loading history...
401
			->setClass(Kdyby\Doctrine\Tools\CacheCleaner::class, ['@' . $managerServiceId])
402
			->setAutowired($isDefault);
403
404
		$builder->addDefinition($this->prefix($name . '.schemaManager'))
0 ignored issues
show
Deprecated Code introduced by
The method Nette\DI\ServiceDefinition::setClass() has been deprecated.

This method has been deprecated.

Loading history...
405
			->setClass(AbstractSchemaManager::class)
406
			->setFactory('@' . Kdyby\Doctrine\Connection::class . '::getSchemaManager')
407
			->setAutowired($isDefault);
408
409
		foreach ($this->compiler->getExtensions(AnnotationsExtension::class) as $extension) {
410
			/** @var AnnotationsExtension $extension */
411
			$cacheCleaner->addSetup('addCacheStorage', [$extension->prefix('@cache.annotations')]);
412
		}
413
414
		if ($isDefault) {
415
			$builder->addDefinition($this->prefix('helper.entityManager'))
0 ignored issues
show
Deprecated Code introduced by
The method Nette\DI\ServiceDefinition::setClass() has been deprecated.

This method has been deprecated.

Loading history...
416
				->setClass(EntityManagerHelper::class, ['@' . $managerServiceId])
417
				->addTag(Kdyby\Console\DI\ConsoleExtension::HELPER_TAG, 'em');
0 ignored issues
show
Documentation introduced by
'em' is of type string, but the function expects a boolean.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
Deprecated Code introduced by
The constant Kdyby\Console\DI\ConsoleExtension::HELPER_TAG has been deprecated.

This class constant has been deprecated.

Loading history...
418
419
			$builder->addDefinition($this->prefix('helper.connection'))
0 ignored issues
show
Deprecated Code introduced by
The method Nette\DI\ServiceDefinition::setClass() has been deprecated.

This method has been deprecated.

Loading history...
420
				->setClass(ConnectionHelper::class, [$connectionService])
421
				->addTag(Kdyby\Console\DI\ConsoleExtension::HELPER_TAG, 'db');
0 ignored issues
show
Documentation introduced by
'db' is of type string, but the function expects a boolean.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
Deprecated Code introduced by
The constant Kdyby\Console\DI\ConsoleExtension::HELPER_TAG has been deprecated.

This class constant has been deprecated.

Loading history...
422
423
			$builder->addAlias($this->prefix('schemaValidator'), $this->prefix($name . '.schemaValidator'));
424
			$builder->addAlias($this->prefix('schemaTool'), $this->prefix($name . '.schemaTool'));
425
			$builder->addAlias($this->prefix('cacheCleaner'), $this->prefix($name . '.cacheCleaner'));
426
			$builder->addAlias($this->prefix('schemaManager'), $this->prefix($name . '.schemaManager'));
427
		}
428
429
		$this->configuredManagers[$name] = $managerServiceId;
430
		$this->managerConfigs[$name] = $config;
431
	}
432
433
434
435
	protected function processSecondLevelCache($name, array $config, $isDefault)
436
	{
437
		if (!$config['enabled']) {
438
			return;
439
		}
440
441
		$builder = $this->getContainerBuilder();
442
443
		$cacheFactory = $builder->addDefinition($this->prefix($name . '.cacheFactory'))
0 ignored issues
show
Deprecated Code introduced by
The method Nette\DI\ServiceDefinition::setClass() has been deprecated.

This method has been deprecated.

Loading history...
444
			->setClass(Doctrine\ORM\Cache\CacheFactory::class)
445
			->setFactory($config['factoryClass'], [
446
				$this->prefix('@' . $name . '.cacheRegionsConfiguration'),
447
				$this->processCache($config['driver'], $name . '.secondLevel'),
448
			])
449
			->setAutowired($isDefault);
450
451
		if ($config['factoryClass'] === $this->managerDefaults['secondLevelCache']['factoryClass']
452
			|| is_subclass_of($config['factoryClass'], $this->managerDefaults['secondLevelCache']['factoryClass'])
0 ignored issues
show
Bug introduced by
Due to PHP Bug #53727, is_subclass_of might return inconsistent results on some PHP versions if $this->managerDefaults['...Cache']['factoryClass'] can be an interface. If so, you could instead use ReflectionClass::implementsInterface.
Loading history...
453
		) {
454
			$cacheFactory->addSetup('setFileLockRegionDirectory', [$config['fileLockRegionDirectory']]);
455
		}
456
457
		$builder->addDefinition($this->prefix($name . '.cacheRegionsConfiguration'))
0 ignored issues
show
Deprecated Code introduced by
The method Nette\DI\ServiceDefinition::setClass() has been deprecated.

This method has been deprecated.

Loading history...
458
			->setClass(Doctrine\ORM\Cache\RegionsConfiguration::class, [
459
				$config['regions']['defaultLifetime'],
460
				$config['regions']['defaultLockLifetime'],
461
			])
462
			->setAutowired($isDefault);
463
464
		$logger = $builder->addDefinition($this->prefix($name . '.cacheLogger'))
0 ignored issues
show
Deprecated Code introduced by
The method Nette\DI\ServiceDefinition::setClass() has been deprecated.

This method has been deprecated.

Loading history...
465
			->setClass(Doctrine\ORM\Cache\Logging\CacheLogger::class)
466
			->setFactory(Doctrine\ORM\Cache\Logging\CacheLoggerChain::class)
467
			->setAutowired(FALSE);
468
469
		if ($config['logging']) {
470
			$logger->addSetup('setLogger', [
471
				'statistics',
472
				new Statement(Doctrine\ORM\Cache\Logging\StatisticsCacheLogger::class)
473
			]);
474
		}
475
476
		$builder->addDefinition($cacheConfigName = $this->prefix($name . '.ormCacheConfiguration'))
0 ignored issues
show
Deprecated Code introduced by
The method Nette\DI\ServiceDefinition::setClass() has been deprecated.

This method has been deprecated.

Loading history...
477
			->setClass(Doctrine\ORM\Cache\CacheConfiguration::class)
478
			->addSetup('setCacheFactory', [$this->prefix('@' . $name . '.cacheFactory')])
479
			->addSetup('setCacheLogger', [$this->prefix('@' . $name . '.cacheLogger')])
480
			->setAutowired($isDefault);
481
482
		$configuration = $builder->getDefinition($this->prefix($name . '.ormConfiguration'));
483
		$configuration->addSetup('setSecondLevelCacheEnabled');
484
		$configuration->addSetup('setSecondLevelCacheConfiguration', ['@' . $cacheConfigName]);
485
	}
486
487
488
489
	protected function processConnection($name, array $defaults, $isDefault = FALSE)
490
	{
491
		$builder = $this->getContainerBuilder();
492
		$config = $this->resolveConfig($defaults, $this->connectionDefaults, $this->managerDefaults);
493
494
		if ($isDefault) {
495
			$builder->parameters[$this->name]['dbal']['defaultConnection'] = $name;
496
		}
497
498
		if (isset($defaults['connection'])) {
499
			return $this->prefix('@' . $defaults['connection'] . '.connection');
500
		}
501
502
		// config
503
		$configuration = $builder->addDefinition($this->prefix($name . '.dbalConfiguration'))
0 ignored issues
show
Deprecated Code introduced by
The method Nette\DI\ServiceDefinition::setClass() has been deprecated.

This method has been deprecated.

Loading history...
504
			->setClass(Doctrine\DBAL\Configuration::class)
505
			->addSetup('setResultCacheImpl', [$this->processCache($config['resultCache'], $name . '.dbalResult')])
506
			->addSetup('setSQLLogger', [new Statement(Doctrine\DBAL\Logging\LoggerChain::class)])
507
			->addSetup('setFilterSchemaAssetsExpression', [$config['schemaFilter']])
508
			->setAutowired(FALSE);
509
510
		// types
511
		Validators::assertField($config, 'types', 'array');
512
		$schemaTypes = $dbalTypes = [];
513
		foreach ($config['types'] as $dbType => $className) {
514
			$typeInst = Code\Helpers::createObject($className, []);
515
			/** @var Doctrine\DBAL\Types\Type $typeInst */
516
			$dbalTypes[$typeInst->getName()] = $className;
517
			$schemaTypes[$dbType] = $typeInst->getName();
518
		}
519
520
		// tracy panel
521
		if ($this->isTracyPresent()) {
522
			$builder->addDefinition($this->prefix($name . '.diagnosticsPanel'))
0 ignored issues
show
Deprecated Code introduced by
The method Nette\DI\ServiceDefinition::setClass() has been deprecated.

This method has been deprecated.

Loading history...
523
				->setClass(Kdyby\Doctrine\Diagnostics\Panel::class)
524
				->setAutowired(FALSE);
525
		}
526
527
		// connection
528
		$options = array_diff_key($config, array_flip(['types', 'resultCache', 'connection', 'logging']));
529
		$connection = $builder->addDefinition($connectionServiceId = $this->prefix($name . '.connection'))
0 ignored issues
show
Deprecated Code introduced by
The method Nette\DI\ServiceDefinition::setClass() has been deprecated.

This method has been deprecated.

Loading history...
530
			->setClass(Kdyby\Doctrine\Connection::class)
531
			->setFactory(Kdyby\Doctrine\Connection::class . '::create', [
532
				$options,
533
				$this->prefix('@' . $name . '.dbalConfiguration'),
534
				$this->prefix('@' . $name . '.evm'),
535
			])
536
			->addSetup('setSchemaTypes', [$schemaTypes])
537
			->addSetup('setDbalTypes', [$dbalTypes])
538
			->addTag(self::TAG_CONNECTION)
539
			->addTag('kdyby.doctrine.connection')
540
			->setAutowired($isDefault);
541
542
		if ($this->isTracyPresent()) {
543
			$connection->addSetup('$panel = ?->bindConnection(?)', [$this->prefix('@' . $name . '.diagnosticsPanel'), '@self']);
544
		}
545
546
		/** @var Nette\DI\ServiceDefinition $connection */
547
548
		$this->configuredConnections[$name] = $connectionServiceId;
549
550
		if (!is_bool($config['logging'])) {
551
			$fileLogger = new Statement(Kdyby\Doctrine\Diagnostics\FileLogger::class, [$builder->expand($config['logging'])]);
0 ignored issues
show
Deprecated Code introduced by
The method Nette\DI\ContainerBuilder::expand() has been deprecated.

This method has been deprecated.

Loading history...
552
			$configuration->addSetup('$service->getSQLLogger()->addLogger(?)', [$fileLogger]);
553
554
		} elseif ($config['logging']) {
555
			$connection->addSetup('?->enableLogging()', [new Code\PhpLiteral('$panel')]);
556
		}
557
558
		return $this->prefix('@' . $name . '.connection');
559
	}
560
561
562
563
	/**
564
	 * @param \Nette\DI\ServiceDefinition $metadataDriver
565
	 * @param string $namespace
566
	 * @param string|object $driver
567
	 * @param string $prefix
568
	 * @throws \Nette\Utils\AssertionException
569
	 * @return string
570
	 */
571
	protected function processMetadataDriver(Nette\DI\ServiceDefinition $metadataDriver, $namespace, $driver, $prefix)
572
	{
573
		if (!is_string($namespace) || !Strings::match($namespace, '#^' . self::PHP_NAMESPACE . '\z#')) {
574
			throw new Nette\Utils\AssertionException("The metadata namespace expects to be valid namespace, $namespace given.");
575
		}
576
		$namespace = ltrim($namespace, '\\');
577
578
		if (is_string($driver) && strpos($driver, '@') === 0) { // service reference
579
			$metadataDriver->addSetup('addDriver', [$driver, $namespace]);
580
			return $driver;
581
		}
582
583
		if (is_string($driver) || is_array($driver)) {
584
			$paths = is_array($driver) ? $driver : [$driver];
585
			foreach ($paths as $path) {
586
				if (($pos = strrpos($path, '*')) !== FALSE) {
587
					$path = substr($path, 0, $pos);
588
				}
589
590
				if (!file_exists($path)) {
591
					throw new Nette\Utils\AssertionException("The metadata path expects to be an existing directory, $path given.");
592
				}
593
			}
594
595
			$driver = new Statement(self::ANNOTATION_DRIVER, is_array($paths) ? $paths : [$paths]);
596
		}
597
598
		$impl = $driver instanceof \stdClass ? $driver->value : ($driver instanceof Statement ? $driver->getEntity() : (string) $driver);
599
		list($driver) = CacheHelpers::filterArgs($driver);
600
		/** @var Statement $driver */
601
602
		/** @var string $impl */
603
		if (isset($this->metadataDriverClasses[$impl])) {
604
			$driver = new Statement($this->metadataDriverClasses[$impl], $driver->arguments);
605
		}
606
607
		if (is_string($driver->getEntity()) && substr($driver->getEntity(), 0, 1) === '@') {
608
			$metadataDriver->addSetup('addDriver', [$driver->getEntity(), $namespace]);
609
			return $driver->getEntity();
610
		}
611
612
		if ($impl === self::ANNOTATION_DRIVER) {
613
			$driver->arguments = [
614
				Nette\Utils\Arrays::flatten($driver->arguments),
615
				2 => $this->prefix('@cache.' . $prefix . '.metadata')
616
			];
617
		}
618
619
		$serviceName = $this->prefix($prefix . '.driver.' . str_replace('\\', '_', $namespace) . '.' . str_replace('\\', '_', $impl) . 'Impl');
620
621
		$this->getContainerBuilder()->addDefinition($serviceName)
0 ignored issues
show
Deprecated Code introduced by
The method Nette\DI\ServiceDefinition::setClass() has been deprecated.

This method has been deprecated.

Loading history...
622
			->setClass(Doctrine\Common\Persistence\Mapping\Driver\MappingDriver::class)
623
			->setFactory($driver->getEntity(), $driver->arguments)
624
			->setAutowired(FALSE);
625
626
		$metadataDriver->addSetup('addDriver', ['@' . $serviceName, $namespace]);
627
		return '@' . $serviceName;
628
	}
629
630
631
632
	/**
633
	 * @param string|\stdClass $cache
634
	 * @param string $suffix
635
	 * @return string
636
	 */
637
	protected function processCache($cache, $suffix)
638
	{
639
		return CacheHelpers::processCache($this, $cache, $suffix, $this->getContainerBuilder()->parameters[$this->prefix('debug')]);
640
	}
641
642
643
644
	public function beforeCompile()
645
	{
646
		$this->processRepositories();
647
		$this->processEventManagers();
648
	}
649
650
651
652
	protected function processRepositories()
653
	{
654
		$builder = $this->getContainerBuilder();
655
656
		$disabled = TRUE;
657
		foreach ($this->configuredManagers as $managerName => $_) {
658
			$factoryClassName = $builder->getDefinition($this->prefix($managerName . '.repositoryFactory'))->getClass();
0 ignored issues
show
Deprecated Code introduced by
The method Nette\DI\ServiceDefinition::getClass() has been deprecated.

This method has been deprecated.

Loading history...
659
			if ($factoryClassName === Kdyby\Doctrine\RepositoryFactory::class || in_array(Kdyby\Doctrine\RepositoryFactory::class, class_parents($factoryClassName), TRUE)) {
660
				$disabled = FALSE;
661
			}
662
		}
663
664
		if ($disabled) {
665
			return;
666
		}
667
668
		if (!method_exists($builder, 'findByType')) {
669
			foreach ($this->configuredManagers as $managerName => $_) {
670
				$builder->getDefinition($this->prefix($managerName . '.repositoryFactory'))
671
					->addSetup('setServiceIdsMap', [[], $this->prefix('repositoryFactory.' . $managerName . '.defaultRepositoryFactory')]);
672
			}
673
674
			return;
675
		}
676
677
		$serviceMap = array_fill_keys(array_keys($this->configuredManagers), []);
678
		foreach ($builder->findByType(Doctrine\ORM\EntityRepository::class) as $originalServiceName => $originalDef) {
679
			if (is_string($originalDef)) {
680
				$originalServiceName = $originalDef;
681
				$originalDef = $builder->getDefinition($originalServiceName);
682
			}
683
684
			if (strpos($originalServiceName, $this->name . '.') === 0) {
685
				continue; // ignore
686
			}
687
688
			$originalDefFactory = $originalDef->getFactory();
689
			$factory = ($originalDefFactory !== NULL) ? $originalDefFactory->getEntity() : $originalDef->getClass();
0 ignored issues
show
Deprecated Code introduced by
The method Nette\DI\ServiceDefinition::getClass() has been deprecated.

This method has been deprecated.

Loading history...
690
			if (stripos($factory, '::getRepository') !== FALSE) {
691
				continue; // ignore
692
			}
693
694
			$factoryServiceName = $this->prefix('repositoryFactory.' . $originalServiceName);
695
			$factoryDef = $builder->addDefinition($factoryServiceName, $originalDef)
696
				->setImplement(IRepositoryFactory::class)
697
				->setParameters([Doctrine\ORM\EntityManagerInterface::class . ' entityManager', Doctrine\ORM\Mapping\ClassMetadata::class . ' classMetadata'])
698
				->setAutowired(FALSE);
699
			$factoryStatement = $factoryDef->getFactory() ?: new Statement($factoryDef->getClass());
0 ignored issues
show
Deprecated Code introduced by
The method Nette\DI\ServiceDefinition::getClass() has been deprecated.

This method has been deprecated.

Loading history...
700
			$factoryStatement->arguments[0] = new Code\PhpLiteral('$entityManager');
701
			$factoryStatement->arguments[1] = new Code\PhpLiteral('$classMetadata');
702
			$factoryDef->setArguments($factoryStatement->arguments);
703
704
			$boundManagers = $this->getServiceBoundManagers($originalDef);
705
			Validators::assert($boundManagers, 'list:1', 'bound manager');
706
707
			if ($boundEntity = $originalDef->getTag(self::TAG_REPOSITORY_ENTITY)) {
708
				if (!is_string($boundEntity) || !class_exists($boundEntity)) {
709
					throw new Nette\Utils\AssertionException(sprintf('The entity "%s" for repository "%s" cannot be autoloaded.', $boundEntity, $originalDef->getClass()));
0 ignored issues
show
Deprecated Code introduced by
The method Nette\DI\ServiceDefinition::getClass() has been deprecated.

This method has been deprecated.

Loading history...
710
				}
711
				$entityArgument = $boundEntity;
712
713
			} else {
714
				throw new Nette\Utils\AssertionException(sprintf(
715
					'The magic auto-detection of entity for repository %s for %s was removed from Kdyby.' .
716
					'You have to specify %s tag with classname of the related entity in order to use this feature.',
717
					$originalDef->getClass(),
0 ignored issues
show
Deprecated Code introduced by
The method Nette\DI\ServiceDefinition::getClass() has been deprecated.

This method has been deprecated.

Loading history...
718
					IRepositoryFactory::class,
719
					self::TAG_REPOSITORY_ENTITY
720
				));
721
			}
722
723
			$builder->removeDefinition($originalServiceName);
724
			$builder->addDefinition($originalServiceName)
0 ignored issues
show
Deprecated Code introduced by
The method Nette\DI\ServiceDefinition::setClass() has been deprecated.

This method has been deprecated.

Loading history...
725
				->setClass($originalDef->getClass())
0 ignored issues
show
Deprecated Code introduced by
The method Nette\DI\ServiceDefinition::getClass() has been deprecated.

This method has been deprecated.

Loading history...
726
				->setFactory(sprintf('@%s::getRepository', $this->configuredManagers[$boundManagers[0]]), [$entityArgument]);
727
728
			$serviceMap[$boundManagers[0]][$originalDef->getClass()] = $factoryServiceName;
0 ignored issues
show
Deprecated Code introduced by
The method Nette\DI\ServiceDefinition::getClass() has been deprecated.

This method has been deprecated.

Loading history...
729
		}
730
731
		foreach ($this->configuredManagers as $managerName => $_) {
732
			$builder->getDefinition($this->prefix($managerName . '.repositoryFactory'))
733
				->addSetup('setServiceIdsMap', [
734
					$serviceMap[$managerName],
735
					$this->prefix('repositoryFactory.' . $managerName . '.defaultRepositoryFactory')
736
				]);
737
		}
738
	}
739
740
741
742
	protected function processEventManagers()
743
	{
744
		$builder = $this->getContainerBuilder();
745
		$customEvmService = $builder->getByType(\Doctrine\Common\EventManager::class);
746
		if ($this->isKdybyEventsPresent() || !$customEvmService) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $customEvmService of type string|null is loosely compared to false; this is ambiguous if the string can be empty. You might want to explicitly use === null instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For string values, the empty string '' is a special case, in particular the following results might be unexpected:

''   == false // true
''   == null  // true
'ab' == false // false
'ab' == null  // false

// It is often better to use strict comparison
'' === false // false
'' === null  // false
Loading history...
747
			return;
748
		}
749
750
		foreach ($this->configuredManagers as $managerName => $_) {
751
			$builder->getDefinition($this->prefix($managerName . '.evm'))->setFactory('@' . $customEvmService);
752
		}
753
	}
754
755
756
757
	/**
758
	 * @param Nette\DI\ServiceDefinition $def
759
	 * @return string[]
760
	 */
761
	protected function getServiceBoundManagers(Nette\DI\ServiceDefinition $def)
762
	{
763
		$builder = $this->getContainerBuilder();
764
		$boundManagers = $def->getTag(self::TAG_BIND_TO_MANAGER);
765
766
		return is_array($boundManagers) ? $boundManagers : [$builder->parameters[$this->name]['orm']['defaultEntityManager']];
767
	}
768
769
770
771
	public function afterCompile(Code\ClassType $class)
772
	{
773
		$init = $class->getMethod('initialize');
774
775
		if ($this->isTracyPresent()) {
776
			$init->addBody('?::registerBluescreen($this);', [new Code\PhpLiteral(Kdyby\Doctrine\Diagnostics\Panel::class)]);
777
			$this->addCollapsePathsToTracy($init);
778
		}
779
780
		foreach ($this->proxyAutoloaders as $namespace => $dir) {
781
			$originalInitialize = $init->getBody();
782
			$init->setBody('?::create(?, ?)->register();', [new Code\PhpLiteral(Kdyby\Doctrine\Proxy\ProxyAutoloader::class), $dir, $namespace]);
783
			$init->addBody((string) $originalInitialize);
784
		}
785
	}
786
787
788
789
	/**
790
	 * @param $provided
791
	 * @param $defaults
792
	 * @param $diff
793
	 * @return array
794
	 */
795
	private function resolveConfig(array $provided, array $defaults, array $diff = [])
796
	{
797
		return $this->getContainerBuilder()->expand(Nette\DI\Config\Helpers::merge(
0 ignored issues
show
Deprecated Code introduced by
The method Nette\DI\ContainerBuilder::expand() has been deprecated.

This method has been deprecated.

Loading history...
798
			array_diff_key($provided, array_diff_key($diff, $defaults)),
799
			$defaults
800
		));
801
	}
802
803
804
	/**
805
	 * @param array $targetEntityMappings
806
	 * @return array
807
	 */
808
	private function normalizeTargetEntityMappings(array $targetEntityMappings)
809
	{
810
		$normalized = [];
811
		foreach ($targetEntityMappings as $originalEntity => $targetEntity) {
812
			$originalEntity = ltrim($originalEntity, '\\');
813
			Validators::assert($targetEntity, 'array|string');
814
			if (is_array($targetEntity)) {
815
				Validators::assertField($targetEntity, 'targetEntity', 'string');
816
				$mapping = array_merge($targetEntity, [
817
					'targetEntity' => ltrim($targetEntity['targetEntity'], '\\')
818
				]);
819
820
			} else {
821
				$mapping = [
822
					'targetEntity' => ltrim($targetEntity, '\\'),
823
				];
824
			}
825
			$normalized[$originalEntity] = $mapping;
826
		}
827
		return $normalized;
828
	}
829
830
831
832
	/**
833
	 * @return bool
834
	 */
835
	private function isTracyPresent()
836
	{
837
		return interface_exists(\Tracy\IBarPanel::class);
838
	}
839
840
841
842
	/**
843
	 * @return bool
844
	 */
845
	private function isKdybyEventsPresent()
846
	{
847
		return (bool) $this->compiler->getExtensions(\Kdyby\Events\DI\EventsExtension::class);
848
	}
849
850
851
852
	private function addCollapsePathsToTracy(Method $init)
853
	{
854
		$blueScreen = \Tracy\Debugger::class . '::getBlueScreen()';
855
		$commonDirname = dirname(Nette\Reflection\ClassType::from(Doctrine\Common\Version::class)->getFileName());
856
857
		$init->addBody($blueScreen . '->collapsePaths[] = ?;', [dirname(Nette\Reflection\ClassType::from(Kdyby\Doctrine\Exception::class)->getFileName())]);
858
		$init->addBody($blueScreen . '->collapsePaths[] = ?;', [dirname(dirname(dirname(dirname($commonDirname))))]); // this should be vendor/doctrine
859
		foreach ($this->proxyAutoloaders as $dir) {
860
			$init->addBody($blueScreen . '->collapsePaths[] = ?;', [$dir]);
861
		}
862
	}
863
864
865
866
	/**
867
	 * @param \Nette\Configurator $configurator
868
	 */
869
	public static function register(Nette\Configurator $configurator)
870
	{
871
		$configurator->onCompile[] = function ($config, Nette\DI\Compiler $compiler) {
872
			$compiler->addExtension('doctrine', new OrmExtension());
873
		};
874
	}
875
876
877
878
	/**
879
	 * @param array $array
880
	 */
881
	private static function natSortKeys(array &$array)
882
	{
883
		$keys = array_keys($array);
884
		natsort($keys);
885
		$keys = array_flip(array_reverse($keys, TRUE));
886
		$array = array_merge($keys, $array);
887
		return $array;
888
	}
889
890
}
891