OrmExtension::beforeCompile()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 5

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 5
rs 10
c 0
b 0
f 0
cc 1
nc 1
nop 0
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\ContainerBuilder;
21
use Nette\DI\ServiceDefinition;
22
use Nette\DI\Statement;
23
use Nette\PhpGenerator as Code;
24
use Nette\PhpGenerator\Method;
25
use Nette\Utils\Strings;
26
use Nette\Utils\Validators;
27
use Doctrine\DBAL\Schema\AbstractSchemaManager;
28
use Kdyby\Annotations\DI\AnnotationsExtension;
29
use Doctrine\ORM\Tools\Console\Helper\EntityManagerHelper;
30
use Doctrine\DBAL\Tools\Console\Helper\ConnectionHelper;
31
32
/**
33
 * @author Filip Procházka <[email protected]>
34
 */
35
class OrmExtension extends Nette\DI\CompilerExtension
36
{
37
38
	const ANNOTATION_DRIVER = 'annotations';
39
	const PHP_NAMESPACE = '[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff\\\\]*';
40
	const TAG_CONNECTION = 'doctrine.connection';
41
	const TAG_ENTITY_MANAGER = 'doctrine.entityManager';
42
	const TAG_BIND_TO_MANAGER = 'doctrine.bindToManager';
43
	const TAG_REPOSITORY_ENTITY = 'doctrine.repositoryEntity';
44
	const DEFAULT_PROXY_NAMESPACE = 'Kdyby\GeneratedProxy';
45
	const KDYBY_METADATA_NAMESPACE = 'Kdyby\Doctrine';
46
47
	/**
48
	 * @var array
49
	 */
50
	public $managerDefaults = [
51
		'metadataCache' => 'default',
52
		'queryCache' => 'default',
53
		'resultCache' => 'default',
54
		'hydrationCache' => 'default',
55
		'secondLevelCache' => [
56
			'enabled' => FALSE,
57
			'factoryClass' => Doctrine\ORM\Cache\DefaultCacheFactory::class,
58
			'driver' => 'default',
59
			'regions' => [
60
				'defaultLifetime' => 3600,
61
				'defaultLockLifetime' => 60,
62
			],
63
			'fileLockRegionDirectory' => '%tempDir%/cache/Doctrine.Cache.Locks', // todo fix
64
			'logging' => '%debugMode%',
65
		],
66
		'classMetadataFactory' => Kdyby\Doctrine\Mapping\ClassMetadataFactory::class,
67
		'defaultRepositoryClassName' => Kdyby\Doctrine\EntityRepository::class,
68
		'repositoryFactoryClassName' => Kdyby\Doctrine\RepositoryFactory::class,
69
		'queryBuilderClassName' => Kdyby\Doctrine\QueryBuilder::class,
70
		'autoGenerateProxyClasses' => '%debugMode%',
71
		'namingStrategy' => Doctrine\ORM\Mapping\UnderscoreNamingStrategy::class,
72
		'quoteStrategy' => Doctrine\ORM\Mapping\DefaultQuoteStrategy::class,
73
		'entityListenerResolver' => Kdyby\Doctrine\Mapping\EntityListenerResolver::class,
74
		'proxyDir' => '%tempDir%/proxies',
75
		'proxyNamespace' => self::DEFAULT_PROXY_NAMESPACE,
76
		'dql' => ['string' => [], 'numeric' => [], 'datetime' => [], 'hints' => []],
77
		'hydrators' => [],
78
		'metadata' => [],
79
		'filters' => [],
80
		'namespaceAlias' => [],
81
		'targetEntityMappings' => [],
82
	];
83
84
	/**
85
	 * @var array
86
	 */
87
	public $connectionDefaults = [
88
		'dbname' => NULL,
89
		'host' => '127.0.0.1',
90
		'port' => NULL,
91
		'user' => NULL,
92
		'password' => NULL,
93
		'charset' => 'UTF8',
94
		'driver' => 'pdo_mysql',
95
		'driverClass' => NULL,
96
		'options' => NULL,
97
		'path' => NULL,
98
		'memory' => NULL,
99
		'unix_socket' => NULL,
100
		'logging' => '%debugMode%',
101
		'platformService' => NULL,
102
		'defaultTableOptions' => [],
103
		'resultCache' => 'default',
104
		'types' => [],
105
		'schemaFilter' => NULL,
106
	];
107
108
	/**
109
	 * @var array
110
	 */
111
	public $metadataDriverClasses = [
112
		self::ANNOTATION_DRIVER => Doctrine\ORM\Mapping\Driver\AnnotationDriver::class,
113
		'static' => Doctrine\Common\Persistence\Mapping\Driver\StaticPHPDriver::class,
114
		'yml' => Doctrine\ORM\Mapping\Driver\YamlDriver::class,
115
		'yaml' => Doctrine\ORM\Mapping\Driver\YamlDriver::class,
116
		'xml' => Doctrine\ORM\Mapping\Driver\XmlDriver::class,
117
		'db' => Doctrine\ORM\Mapping\Driver\DatabaseDriver::class,
118
	];
119
120
	/**
121
	 * @var array
122
	 */
123
	private $proxyAutoloaders = [];
124
125
	/**
126
	 * @var array
127
	 */
128
	private $targetEntityMappings = [];
129
130
	/**
131
	 * @var array
132
	 */
133
	private $configuredManagers = [];
134
135
	/**
136
	 * @var array
137
	 */
138
	private $managerConfigs = [];
139
140
	/**
141
	 * @var array
142
	 */
143
	private $configuredConnections = [];
144
145
146
147
	public function loadConfiguration()
148
	{
149
		$this->proxyAutoloaders =
150
		$this->targetEntityMappings =
151
		$this->configuredConnections =
152
		$this->managerConfigs =
153
		$this->configuredManagers = [];
154
155
		if (!$this->compiler->getExtensions(AnnotationsExtension::class)) {
156
			throw new Nette\Utils\AssertionException(sprintf("You should register %s before %s.", AnnotationsExtension::class, get_class($this)));
157
		}
158
159
		$builder = $this->getContainerBuilder();
160
		$config = $this->getConfig();
161
162
		$builder->parameters[$this->prefix('debug')] = !empty($config['debug']);
163
		if (isset($config['dbname']) || isset($config['driver']) || isset($config['connection'])) {
164
			$config = ['default' => $config];
165
			$defaults = ['debug' => $builder->parameters['debugMode']];
166
167
		} else {
168
			$defaults = array_intersect_key($config, $this->managerDefaults)
169
				+ array_intersect_key($config, $this->connectionDefaults)
170
				+ ['debug' => $builder->parameters['debugMode']];
171
172
			$config = array_diff_key($config, $defaults);
173
		}
174
175
		if (empty($config)) {
176
			throw new Kdyby\Doctrine\UnexpectedValueException("Please configure the Doctrine extensions using the section '{$this->name}:' in your config file.");
177
		}
178
179
		foreach ($config as $name => $emConfig) {
180
			if (!is_array($emConfig) || (empty($emConfig['dbname']) && empty($emConfig['driver']))) {
181
				throw new Kdyby\Doctrine\UnexpectedValueException("Please configure the Doctrine extensions using the section '{$this->name}:' in your config file.");
182
			}
183
184
			/** @var mixed[] $emConfig */
185
			$emConfig = Nette\DI\Config\Helpers::merge($emConfig, $defaults);
186
			$this->processEntityManager($name, $emConfig);
187
		}
188
189
		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...
190
			if (!$this->isKdybyEventsPresent()) {
191
				throw new Nette\Utils\AssertionException('The option \'targetEntityMappings\' requires \'Kdyby\Events\DI\EventsExtension\'.', E_USER_NOTICE);
192
			}
193
194
			$listener = $builder->addDefinition($this->prefix('resolveTargetEntityListener'))
0 ignored issues
show
Deprecated Code introduced by
The method Nette\DI\Definitions\ServiceDefinition::setClass() has been deprecated with message: Use setType()

This method has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the method will be removed from the class and what other method or class to use instead.

Loading history...
195
				->setClass(Kdyby\Doctrine\Tools\ResolveTargetEntityListener::class)
196
				->addTag(Kdyby\Events\DI\EventsExtension::TAG_SUBSCRIBER);
197
198
			foreach ($this->targetEntityMappings as $originalEntity => $mapping) {
199
				$listener->addSetup('addResolveTargetEntity', [$originalEntity, $mapping['targetEntity'], $mapping]);
200
			}
201
		}
202
203
		$this->loadConsole();
204
205
		$builder->addDefinition($this->prefix('registry'))
206
			->setFactory(Kdyby\Doctrine\Registry::class, [
207
				$this->configuredConnections,
208
				$this->configuredManagers,
209
				$builder->parameters[$this->name]['dbal']['defaultConnection'],
210
				$builder->parameters[$this->name]['orm']['defaultEntityManager'],
211
			]);
212
	}
213
214
215
216
	protected function loadConsole()
217
	{
218
		$builder = $this->getContainerBuilder();
219
220
		foreach ($this->loadFromFile(__DIR__ . '/console.neon') as $i => $command) {
221
			$cli = $builder->addDefinition($this->prefix('cli.' . $i))
222
				->addTag(Kdyby\Console\DI\ConsoleExtension::TAG_COMMAND)
223
				->addTag(Nette\DI\Extensions\InjectExtension::TAG_INJECT, FALSE); // lazy injects
224
225
			if (is_string($command)) {
226
				$cli->setClass($command);
0 ignored issues
show
Deprecated Code introduced by
The method Nette\DI\Definitions\ServiceDefinition::setClass() has been deprecated with message: Use setType()

This method has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the method will be removed from the class and what other method or class to use instead.

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

This method has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the method will be removed from the class and what other method or class to use instead.

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

This method has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the method will be removed from the class and what other method or class to use instead.

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

This method has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the method will be removed from the class and what other method or class to use instead.

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

This method has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the method will be removed from the class and what other method or class to use instead.

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

This method has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the method will be removed from the class and what other method or class to use instead.

Loading history...
373
			->setClass(Kdyby\Doctrine\EntityManager::class)
374
			->setFactory(Kdyby\Doctrine\EntityManager::class . '::create', [
375
				$connectionService = $this->processConnection($name, $defaults, $isDefault),
376
				$this->prefix('@' . $name . '.ormConfiguration'),
377
				$this->prefix('@' . $name . '.evm'),
378
			])
379
			->addTag(self::TAG_ENTITY_MANAGER)
380
			->addTag('kdyby.doctrine.entityManager')
381
			->setAutowired($isDefault);
382
383
		if ($this->isTracyPresent()) {
384
			$entityManager->addSetup('?->bindEntityManager(?)', [$this->prefix('@' . $name . '.diagnosticsPanel'), '@self']);
385
		}
386
387
		$builder->addFactoryDefinition($this->prefix('repositoryFactory.' . $name . '.defaultRepositoryFactory'))
388
				->setImplement(IRepositoryFactory::class)
389
				->setParameters([EntityManagerInterface::class . ' entityManager', Doctrine\ORM\Mapping\ClassMetadata::class . ' classMetadata'])
390
				->getResultDefinition()
391
				->setFactory($config['defaultRepositoryClassName'])
392
				->setArguments([new Code\PhpLiteral('$entityManager'), new Code\PhpLiteral('$classMetadata')])
393
				->setAutowired(FALSE);
394
395
		$builder->addDefinition($this->prefix($name . '.schemaValidator'))
396
			->setFactory(Doctrine\ORM\Tools\SchemaValidator::class, ['@' . $managerServiceId])
397
			->setAutowired($isDefault);
398
399
		$builder->addDefinition($this->prefix($name . '.schemaTool'))
400
			->setFactory(Doctrine\ORM\Tools\SchemaTool::class, ['@' . $managerServiceId])
401
			->setAutowired($isDefault);
402
403
		$cacheCleaner = $builder->addDefinition($this->prefix($name . '.cacheCleaner'))
404
			->setFactory(Kdyby\Doctrine\Tools\CacheCleaner::class, ['@' . $managerServiceId])
405
			->setAutowired($isDefault);
406
407
		$builder->addDefinition($this->prefix($name . '.schemaManager'))
0 ignored issues
show
Deprecated Code introduced by
The method Nette\DI\Definitions\ServiceDefinition::setClass() has been deprecated with message: Use setType()

This method has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the method will be removed from the class and what other method or class to use instead.

Loading history...
408
			->setClass(AbstractSchemaManager::class)
409
			->setFactory('@' . Kdyby\Doctrine\Connection::class . '::getSchemaManager')
410
			->setAutowired($isDefault);
411
412
		foreach ($this->compiler->getExtensions(AnnotationsExtension::class) as $extension) {
413
			/** @var AnnotationsExtension $extension */
414
			$cacheCleaner->addSetup('addCacheStorage', [$extension->prefix('@cache.annotations')]);
415
		}
416
417
		if ($isDefault) {
418
			$builder->addDefinition($this->prefix('helper.entityManager'))
419
				->setFactory(EntityManagerHelper::class, ['@' . $managerServiceId])
420
				->addTag(Kdyby\Console\DI\ConsoleExtension::HELPER_TAG, 'em');
0 ignored issues
show
Deprecated Code introduced by
The constant Kdyby\Console\DI\ConsoleExtension::HELPER_TAG has been deprecated.

This class constant has been deprecated.

Loading history...
421
422
			$builder->addDefinition($this->prefix('helper.connection'))
423
				->setFactory(ConnectionHelper::class, [$connectionService])
424
				->addTag(Kdyby\Console\DI\ConsoleExtension::HELPER_TAG, 'db');
0 ignored issues
show
Deprecated Code introduced by
The constant Kdyby\Console\DI\ConsoleExtension::HELPER_TAG has been deprecated.

This class constant has been deprecated.

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

This method has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the method will be removed from the class and what other method or class to use instead.

Loading history...
447
			->setClass(Doctrine\ORM\Cache\CacheFactory::class)
448
			->setFactory($config['factoryClass'], [
449
				$this->prefix('@' . $name . '.cacheRegionsConfiguration'),
450
				$this->processCache($config['driver'], $name . '.secondLevel'),
451
			])
452
			->setAutowired($isDefault);
453
454
		if ($config['factoryClass'] === $this->managerDefaults['secondLevelCache']['factoryClass']
455
			|| 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...
456
		) {
457
			$cacheFactory->addSetup('setFileLockRegionDirectory', [$config['fileLockRegionDirectory']]);
458
		}
459
460
		$builder->addDefinition($this->prefix($name . '.cacheRegionsConfiguration'))
0 ignored issues
show
Deprecated Code introduced by
The method Nette\DI\Definitions\ServiceDefinition::setClass() has been deprecated with message: Use setType()

This method has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the method will be removed from the class and what other method or class to use instead.

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

This method has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the method will be removed from the class and what other method or class to use instead.

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

This method has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the method will be removed from the class and what other method or class to use instead.

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

This method has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the method will be removed from the class and what other method or class to use instead.

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

This method has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the method will be removed from the class and what other method or class to use instead.

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

This method has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the method will be removed from the class and what other method or class to use instead.

Loading history...
533
			->setClass(Kdyby\Doctrine\Connection::class)
534
			->setFactory(Kdyby\Doctrine\Connection::class . '::create', [
535
				$options,
536
				$this->prefix('@' . $name . '.dbalConfiguration'),
537
				$this->prefix('@' . $name . '.evm'),
538
			])
539
			->addSetup('setSchemaTypes', [$schemaTypes])
540
			->addSetup('setDbalTypes', [$dbalTypes])
541
			->addTag(self::TAG_CONNECTION)
542
			->addTag('kdyby.doctrine.connection')
543
			->setAutowired($isDefault);
544
545
		if ($this->isTracyPresent()) {
546
			$connection->addSetup('$panel = ?->bindConnection(?)', [$this->prefix('@' . $name . '.diagnosticsPanel'), '@self']);
547
		}
548
549
		/** @var Nette\DI\ServiceDefinition $connection */
550
551
		$this->configuredConnections[$name] = $connectionServiceId;
552
553
		if (!is_bool($config['logging'])) {
554
			$fileLogger = new Statement(Kdyby\Doctrine\Diagnostics\FileLogger::class, [Nette\DI\Helpers::expand($config['logging'], $builder->parameters)]);
555
			$configuration->addSetup('$service->getSQLLogger()->addLogger(?)', [$fileLogger]);
556
557
		} elseif ($config['logging']) {
558
			$connection->addSetup('?->enableLogging()', [new Code\PhpLiteral('$panel')]);
559
		}
560
561
		return $this->prefix('@' . $name . '.connection');
562
	}
563
564
565
566
	/**
567
	 * @param \Nette\DI\ServiceDefinition $metadataDriver
568
	 * @param string $namespace
569
	 * @param string|array|\stdClass $driver
570
	 * @param string $prefix
571
	 * @throws \Nette\Utils\AssertionException
572
	 * @return string
573
	 */
574
	protected function processMetadataDriver(Nette\DI\ServiceDefinition $metadataDriver, $namespace, $driver, $prefix)
575
	{
576
		if (!is_string($namespace) || !Strings::match($namespace, '#^' . self::PHP_NAMESPACE . '\z#')) {
577
			throw new Nette\Utils\AssertionException("The metadata namespace expects to be valid namespace, $namespace given.");
578
		}
579
		$namespace = ltrim($namespace, '\\');
580
581
		if (is_string($driver) && strpos($driver, '@') === 0) { // service reference
582
			$metadataDriver->addSetup('addDriver', [$driver, $namespace]);
583
			return $driver;
584
		}
585
586
		if (is_string($driver) || is_array($driver)) {
587
			$paths = is_array($driver) ? $driver : [$driver];
588
			foreach ($paths as $path) {
589
				if (!file_exists($path)) {
590
					throw new Nette\Utils\AssertionException("The metadata path expects to be an existing directory, $path given.");
591
				}
592
			}
593
594
			$driver = new Statement(self::ANNOTATION_DRIVER, is_array($paths) ? $paths : [$paths]);
595
		}
596
597
		$impl = $driver instanceof \stdClass ? $driver->value : ($driver instanceof Statement ? $driver->getEntity() : (string) $driver);
0 ignored issues
show
Bug introduced by
The class Nette\DI\Statement does not exist. Did you forget a USE statement, or did you not list all dependencies?

This error could be the result of:

1. Missing dependencies

PHP Analyzer uses your composer.json file (if available) to determine the dependencies of your project and to determine all the available classes and functions. It expects the composer.json to be in the root folder of your repository.

Are you sure this class is defined by one of your dependencies, or did you maybe not list a dependency in either the require or require-dev section?

2. Missing use statement

PHP does not complain about undefined classes in ìnstanceof checks. For example, the following PHP code will work perfectly fine:

if ($x instanceof DoesNotExist) {
    // Do something.
}

If you have not tested against this specific condition, such errors might go unnoticed.

Loading history...
598
		list($driver) = CacheHelpers::filterArgs($driver);
599
		/** @var Statement $driver */
600
601
		/** @var string $impl */
602
		if (isset($this->metadataDriverClasses[$impl])) {
603
			$driver = new Statement($this->metadataDriverClasses[$impl], $driver->arguments);
604
		}
605
606
		if (is_string($driver->getEntity()) && substr($driver->getEntity(), 0, 1) === '@') {
607
			$metadataDriver->addSetup('addDriver', [$driver->getEntity(), $namespace]);
608
			return $driver->getEntity();
609
		}
610
611
		if ($impl === self::ANNOTATION_DRIVER) {
612
			$driver->arguments = [
613
				'@' . Doctrine\Common\Annotations\Reader::class,
614
				Nette\Utils\Arrays::flatten($driver->arguments)
615
			];
616
		}
617
618
		$serviceName = $this->prefix($prefix . '.driver.' . str_replace('\\', '_', $namespace) . '.' . str_replace('\\', '_', $impl) . 'Impl');
619
620
		$this->getContainerBuilder()->addDefinition($serviceName)
0 ignored issues
show
Deprecated Code introduced by
The method Nette\DI\Definitions\ServiceDefinition::setClass() has been deprecated with message: Use setType()

This method has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the method will be removed from the class and what other method or class to use instead.

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

This method has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the method will be removed from the class and what other method or class to use instead.

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

This method has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the method will be removed from the class and what other method or class to use instead.

Loading history...
688
689
			if ((is_string($factory) && stripos($factory, '::getRepository') !== FALSE)
690
				|| (is_array($factory) && array_search('::getRepository', $factory) === FALSE)) {
691
				continue; // ignore
692
			}
693
			$factoryServiceName = $this->prefix('repositoryFactory.' . $originalServiceName);
694
			$factoryDef = $builder->addFactoryDefinition($factoryServiceName)
0 ignored issues
show
Unused Code introduced by
$factoryDef is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
695
				->setImplement(IRepositoryFactory::class)
696
				->setParameters([Doctrine\ORM\EntityManagerInterface::class . ' entityManager', Doctrine\ORM\Mapping\ClassMetadata::class . ' classMetadata'])
697
				->setAutowired(FALSE)
698
				->getResultDefinition()
699
				->setFactory($originalDef->getFactory());
700
			$factoryStatement = $originalDef->getFactory() ?: new Statement($originalDef->getFactory());
701
			$factoryStatement->arguments[0] = new Code\PhpLiteral('$entityManager');
702
			$factoryStatement->arguments[1] = new Code\PhpLiteral('$classMetadata');
703
			$boundManagers = $this->getServiceBoundManagers($originalDef);
0 ignored issues
show
Documentation introduced by
$originalDef is of type object<Nette\DI\Definitions\Definition>, but the function expects a object<Nette\DI\ServiceDefinition>.

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...
704
			Validators::assert($boundManagers, 'list:1', 'bound manager');
705
706
			if ($boundEntity = $originalDef->getTag(self::TAG_REPOSITORY_ENTITY)) {
707
				if (!is_string($boundEntity) || !class_exists($boundEntity)) {
708
					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\Definitions\Definition::getClass() has been deprecated with message: Use getType()

This method has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the method will be removed from the class and what other method or class to use instead.

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

This method has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the method will be removed from the class and what other method or class to use instead.

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

This method has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the method will be removed from the class and what other method or class to use instead.

Loading history...
723
				->setClass($originalDef->getClass())
0 ignored issues
show
Deprecated Code introduced by
The method Nette\DI\Definitions\Definition::getClass() has been deprecated with message: Use getType()

This method has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the method will be removed from the class and what other method or class to use instead.

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

This method has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the method will be removed from the class and what other method or class to use instead.

Loading history...
727
		}
728
729
		foreach ($this->configuredManagers as $managerName => $_) {
730
731
			$this->getServiceDefinition($builder, $this->prefix($managerName . '.repositoryFactory'))
732
				->addSetup('setServiceIdsMap', [
733
					$serviceMap[$managerName],
734
					$this->prefix('repositoryFactory.' . $managerName . '.defaultRepositoryFactory')
735
				]);
736
		}
737
	}
738
739
740
741
	protected function processEventManagers()
742
	{
743
		$builder = $this->getContainerBuilder();
744
		$customEvmService = $builder->getByType(\Doctrine\Common\EventManager::class);
745
		if ($this->isKdybyEventsPresent() || !$customEvmService) {
746
			return;
747
		}
748
749
		foreach ($this->configuredManagers as $managerName => $_) {
750
751
			$this->getServiceDefinition($builder, $this->prefix($managerName . '.evm'))
752
				->setFactory('@' . $customEvmService);
753
		}
754
	}
755
756
757
758
	/**
759
	 * @param Nette\DI\ServiceDefinition $def
760
	 * @return string[]
761
	 */
762
	protected function getServiceBoundManagers(Nette\DI\ServiceDefinition $def)
763
	{
764
		$builder = $this->getContainerBuilder();
765
		$boundManagers = $def->getTag(self::TAG_BIND_TO_MANAGER);
766
767
		return is_array($boundManagers) ? $boundManagers : [$builder->parameters[$this->name]['orm']['defaultEntityManager']];
768
	}
769
770
771
772
	public function afterCompile(Code\ClassType $class)
773
	{
774
		$init = $class->getMethod('initialize');
775
776
		if ($this->isTracyPresent()) {
777
			$init->addBody('?::registerBluescreen($this);', [new Code\PhpLiteral(Kdyby\Doctrine\Diagnostics\Panel::class)]);
778
			$this->addCollapsePathsToTracy($init);
779
		}
780
781
		foreach ($this->proxyAutoloaders as $namespace => $dir) {
782
			$originalInitialize = $init->getBody();
783
			$init->setBody('?::create(?, ?)->register();', [new Code\PhpLiteral(Kdyby\Doctrine\Proxy\ProxyAutoloader::class), $dir, $namespace]);
784
			$init->addBody((string) $originalInitialize);
785
		}
786
	}
787
788
789
790
	/**
791
     * @param array $provided
792
     * @param array $defaults
793
     * @param array $diff
794
	 * @return array
795
	 */
796
	private function resolveConfig(array $provided, array $defaults, array $diff = [])
797
	{
798
		return Nette\DI\Helpers::expand(Nette\DI\Config\Helpers::merge(
799
			array_diff_key($provided, array_diff_key($diff, $defaults)),
800
			$defaults
801
		), $this->compiler->getContainerBuilder()->parameters);
802
	}
803
804
805
	/**
806
	 * @param array $targetEntityMappings
807
	 * @return array
808
	 */
809
	private function normalizeTargetEntityMappings(array $targetEntityMappings)
810
	{
811
		$normalized = [];
812
		foreach ($targetEntityMappings as $originalEntity => $targetEntity) {
813
			$originalEntity = ltrim($originalEntity, '\\');
814
			Validators::assert($targetEntity, 'array|string');
815
			if (is_array($targetEntity)) {
816
				Validators::assertField($targetEntity, 'targetEntity', 'string');
817
				$mapping = array_merge($targetEntity, [
818
					'targetEntity' => ltrim($targetEntity['targetEntity'], '\\')
819
				]);
820
821
			} else {
822
				$mapping = [
823
					'targetEntity' => ltrim($targetEntity, '\\'),
824
				];
825
			}
826
			$normalized[$originalEntity] = $mapping;
827
		}
828
		return $normalized;
829
	}
830
831
832
833
	/**
834
	 * @return bool
835
	 */
836
	private function isTracyPresent()
837
	{
838
		return interface_exists(\Tracy\IBarPanel::class);
839
	}
840
841
842
843
	/**
844
	 * @return bool
845
	 */
846
	private function isKdybyEventsPresent()
847
	{
848
		return (bool) $this->compiler->getExtensions(\Kdyby\Events\DI\EventsExtension::class);
849
	}
850
851
852
853
	private function addCollapsePathsToTracy(Method $init)
854
	{
855
		$blueScreen = \Tracy\Debugger::class . '::getBlueScreen()';
856
		$commonDirname = dirname(Nette\Reflection\ClassType::from(Doctrine\Common\Version::class)->getFileName());
857
858
		$init->addBody($blueScreen . '->collapsePaths[] = ?;', [dirname(Nette\Reflection\ClassType::from(Kdyby\Doctrine\Exception::class)->getFileName())]);
859
		$init->addBody($blueScreen . '->collapsePaths[] = ?;', [dirname(dirname(dirname(dirname($commonDirname))))]); // this should be vendor/doctrine
860
		foreach ($this->proxyAutoloaders as $dir) {
861
			$init->addBody($blueScreen . '->collapsePaths[] = ?;', [$dir]);
862
		}
863
	}
864
865
866
867
	/**
868
	 * @param \Nette\Configurator $configurator
869
	 */
870
	public static function register(Nette\Configurator $configurator)
871
	{
872
		$configurator->onCompile[] = function ($config, Nette\DI\Compiler $compiler) {
873
			$compiler->addExtension('doctrine', new OrmExtension());
874
		};
875
	}
876
877
878
879
	/**
880
	 * @param array $array
881
	 */
882
	private static function natSortKeys(array &$array)
883
	{
884
		$keys = array_keys($array);
885
		natsort($keys);
886
		$keys = array_flip(array_reverse($keys, TRUE));
887
		$array = array_merge($keys, $array);
888
		return $array;
889
	}
890
891
	private function getServiceDefinition(ContainerBuilder $builder, string $name): ServiceDefinition
892
	{
893
		$definition = $builder->getDefinition($name);
894
		assert($definition instanceof ServiceDefinition);
0 ignored issues
show
Bug introduced by
The class Nette\DI\ServiceDefinition does not exist. Did you forget a USE statement, or did you not list all dependencies?

This error could be the result of:

1. Missing dependencies

PHP Analyzer uses your composer.json file (if available) to determine the dependencies of your project and to determine all the available classes and functions. It expects the composer.json to be in the root folder of your repository.

Are you sure this class is defined by one of your dependencies, or did you maybe not list a dependency in either the require or require-dev section?

2. Missing use statement

PHP does not complain about undefined classes in ìnstanceof checks. For example, the following PHP code will work perfectly fine:

if ($x instanceof DoesNotExist) {
    // Do something.
}

If you have not tested against this specific condition, such errors might go unnoticed.

Loading history...
895
		return $definition;
896
	}
897
898
}
899