Completed
Pull Request — master (#140)
by Petr
02:20
created

TranslationExtension::afterCompile()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 7
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 7
rs 9.4285
c 0
b 0
f 0
cc 2
eloc 4
nc 2
nop 1
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\Translation\DI;
12
13
use Kdyby\Console\DI\ConsoleExtension;
14
use Kdyby\Monolog\Logger as KdybyLogger;
15
use Kdyby\Translation\Caching\PhpFileStorage;
16
use Kdyby\Translation\CatalogueCompiler;
17
use Kdyby\Translation\CatalogueFactory;
18
use Kdyby\Translation\Console\ExtractCommand;
19
use Kdyby\Translation\Diagnostics\Panel;
20
use Kdyby\Translation\FallbackResolver;
21
use Kdyby\Translation\IUserLocaleResolver;
22
use Kdyby\Translation\Latte\TranslateMacros;
23
use Kdyby\Translation\LocaleResolver\AcceptHeaderResolver;
24
use Kdyby\Translation\LocaleResolver\ChainResolver;
25
use Kdyby\Translation\LocaleResolver\LocaleParamResolver;
26
use Kdyby\Translation\LocaleResolver\SessionResolver;
27
use Kdyby\Translation\TemplateHelpers;
28
use Kdyby\Translation\TranslationLoader;
29
use Kdyby\Translation\Translator as KdybyTranslator;
30
use Latte\Engine as LatteEngine;
31
use Nette\Application\Application;
32
use Nette\Bridges\ApplicationLatte\ILatteFactory;
33
use Nette\Configurator;
34
use Nette\DI\Compiler;
35
use Nette\DI\Helpers;
36
use Nette\DI\ServiceDefinition;
37
use Nette\DI\Statement;
38
use Nette\PhpGenerator\ClassType as ClassTypeGenerator;
39
use Nette\PhpGenerator\PhpLiteral;
40
use Nette\Reflection\ClassType as ReflectionClassType;
41
use Nette\Utils\Callback;
42
use Nette\Utils\Finder;
43
use Nette\Utils\Validators;
44
use Symfony\Component\Translation\Extractor\ChainExtractor;
45
use Symfony\Component\Translation\Loader\LoaderInterface;
46
use Symfony\Component\Translation\MessageSelector;
47
use Symfony\Component\Translation\Writer\TranslationWriter;
48
use Tracy\Debugger;
49
use Tracy\IBarPanel;
50
51
class TranslationExtension extends \Nette\DI\CompilerExtension
52
{
53
54
	use \Kdyby\StrictObjects\Scream;
55
56
	/** @deprecated */
57
	const LOADER_TAG = self::TAG_LOADER;
58
	/** @deprecated */
59
	const DUMPER_TAG = self::TAG_DUMPER;
60
	/** @deprecated */
61
	const EXTRACTOR_TAG = self::TAG_EXTRACTOR;
62
63
	const TAG_LOADER = 'translation.loader';
64
	const TAG_DUMPER = 'translation.dumper';
65
	const TAG_EXTRACTOR = 'translation.extractor';
66
67
	const RESOLVER_REQUEST = 'request';
68
	const RESOLVER_HEADER = 'header';
69
	const RESOLVER_SESSION = 'session';
70
71
	/**
72
	 * @var mixed[]
73
	 */
74
	public $defaults = [
75
		'whitelist' => NULL, // array('cs', 'en'),
0 ignored issues
show
Unused Code Comprehensibility introduced by
78% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
76
		'default' => 'en',
77
		'logging' => NULL, //  TRUE for psr/log, or string for kdyby/monolog channel
78
		// 'fallback' => array('en_US', 'en'), // using custom merge strategy becase Nette's config merger appends lists of values
0 ignored issues
show
Unused Code Comprehensibility introduced by
58% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
79
		'dirs' => ['%appDir%/lang', '%appDir%/locale'],
80
		'cache' => PhpFileStorage::class,
81
		'debugger' => '%debugMode%',
82
		'resolvers' => [
83
			self::RESOLVER_SESSION => FALSE,
84
			self::RESOLVER_REQUEST => TRUE,
85
			self::RESOLVER_HEADER => TRUE,
86
		],
87
		'loaders' => [],
88
	];
89
90
	/**
91
	 * @var array
92
	 */
93
	private $loaders;
94
95
	public function __construct()
96
	{
97
		$this->defaults['cache'] = new Statement($this->defaults['cache'], ['%tempDir%/cache']);
98
	}
99
100
	public function loadConfiguration()
101
	{
102
		$this->loaders = [];
103
104
		$builder = $this->getContainerBuilder();
105
		$config = $this->getConfig();
106
107
		$translator = $builder->addDefinition($this->prefix('default'))
108
			->setClass(KdybyTranslator::class, [$this->prefix('@userLocaleResolver')])
109
			->addSetup('?->setTranslator(?)', [$this->prefix('@userLocaleResolver.param'), '@self'])
110
			->addSetup('setDefaultLocale', [$config['default']])
111
			->addSetup('setLocaleWhitelist', [$config['whitelist']]);
112
113
		Validators::assertField($config, 'fallback', 'list');
114
		$translator->addSetup('setFallbackLocales', [$config['fallback']]);
115
116
		$catalogueCompiler = $builder->addDefinition($this->prefix('catalogueCompiler'))
117
			->setClass(CatalogueCompiler::class, self::filterArgs($config['cache']));
118
119
		if ($config['debugger'] && interface_exists(IBarPanel::class)) {
120
			$builder->addDefinition($this->prefix('panel'))
121
				->setClass(Panel::class, [dirname($builder->expand('%appDir%'))])
122
				->addSetup('setLocaleWhitelist', [$config['whitelist']]);
123
124
			$translator->addSetup('?->register(?)', [$this->prefix('@panel'), '@self']);
125
			$catalogueCompiler->addSetup('enableDebugMode');
126
		}
127
128
		$this->loadLocaleResolver($config);
129
130
		$builder->addDefinition($this->prefix('helpers'))
131
			->setClass(TemplateHelpers::class)
132
			->setFactory($this->prefix('@default') . '::createTemplateHelpers');
133
134
		$builder->addDefinition($this->prefix('fallbackResolver'))
135
			->setClass(FallbackResolver::class);
136
137
		$builder->addDefinition($this->prefix('catalogueFactory'))
138
			->setClass(CatalogueFactory::class);
139
140
		$builder->addDefinition($this->prefix('selector'))
141
			->setClass(MessageSelector::class);
142
143
		$builder->addDefinition($this->prefix('extractor'))
144
			->setClass(ChainExtractor::class);
145
146
		$this->loadExtractors();
147
148
		$builder->addDefinition($this->prefix('writer'))
149
			->setClass(TranslationWriter::class);
150
151
		$this->loadDumpers();
152
153
		$builder->addDefinition($this->prefix('loader'))
154
			->setClass(TranslationLoader::class);
155
156
		$loaders = $this->loadFromFile(__DIR__ . '/config/loaders.neon');
157
		$this->loadLoaders($loaders, $config['loaders'] ?: array_keys($loaders));
158
159
		if ($this->isRegisteredConsoleExtension()) {
160
			$this->loadConsole($config);
161
		}
162
	}
163
164
	protected function loadLocaleResolver(array $config)
165
	{
166
		$builder = $this->getContainerBuilder();
167
168
		$builder->addDefinition($this->prefix('userLocaleResolver.param'))
169
			->setClass(LocaleParamResolver::class)
170
			->setAutowired(FALSE);
171
172
		$builder->addDefinition($this->prefix('userLocaleResolver.acceptHeader'))
173
			->setClass(AcceptHeaderResolver::class);
174
175
		$builder->addDefinition($this->prefix('userLocaleResolver.session'))
176
			->setClass(SessionResolver::class);
177
178
		$chain = $builder->addDefinition($this->prefix('userLocaleResolver'))
179
			->setClass(IUserLocaleResolver::class)
180
			->setFactory(ChainResolver::class);
181
182
		$resolvers = [];
183 View Code Duplication
		if ($config['resolvers'][self::RESOLVER_HEADER]) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
184
			$resolvers[] = $this->prefix('@userLocaleResolver.acceptHeader');
185
			$chain->addSetup('addResolver', [$this->prefix('@userLocaleResolver.acceptHeader')]);
186
		}
187
188 View Code Duplication
		if ($config['resolvers'][self::RESOLVER_REQUEST]) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
189
			$resolvers[] = $this->prefix('@userLocaleResolver.param');
190
			$chain->addSetup('addResolver', [$this->prefix('@userLocaleResolver.param')]);
191
		}
192
193 View Code Duplication
		if ($config['resolvers'][self::RESOLVER_SESSION]) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
194
			$resolvers[] = $this->prefix('@userLocaleResolver.session');
195
			$chain->addSetup('addResolver', [$this->prefix('@userLocaleResolver.session')]);
196
		}
197
198
		if ($config['debugger'] && interface_exists(IBarPanel::class)) {
199
			$builder->getDefinition($this->prefix('panel'))
200
				->addSetup('setLocaleResolvers', [array_reverse($resolvers)]);
201
		}
202
	}
203
204
	protected function loadConsole(array $config)
205
	{
206
		$builder = $this->getContainerBuilder();
207
208
		Validators::assertField($config, 'dirs', 'list');
209
		$builder->addDefinition($this->prefix('console.extract'))
210
			->setClass(ExtractCommand::class)
211
			->addSetup('$defaultOutputDir', [reset($config['dirs'])])
212
			->addTag(ConsoleExtension::TAG_COMMAND, 'latte');
213
	}
214
215 View Code Duplication
	protected function loadDumpers()
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
216
	{
217
		$builder = $this->getContainerBuilder();
218
219
		foreach ($this->loadFromFile(__DIR__ . '/config/dumpers.neon') as $format => $class) {
220
			$builder->addDefinition($this->prefix('dumper.' . $format))
221
				->setClass($class)
222
				->addTag(self::TAG_DUMPER, $format);
223
		}
224
	}
225
226
	protected function loadLoaders(array $loaders, array $allowed)
227
	{
228
		$builder = $this->getContainerBuilder();
229
230
		foreach ($loaders as $format => $class) {
231
			if (array_search($format, $allowed) === FALSE) {
232
				continue;
233
			}
234
			$builder->addDefinition($this->prefix('loader.' . $format))
235
				->setClass($class)
236
				->addTag(self::TAG_LOADER, $format);
237
		}
238
	}
239
240 View Code Duplication
	protected function loadExtractors()
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
241
	{
242
		$builder = $this->getContainerBuilder();
243
244
		foreach ($this->loadFromFile(__DIR__ . '/config/extractors.neon') as $format => $class) {
245
			$builder->addDefinition($this->prefix('extractor.' . $format))
246
				->setClass($class)
247
				->addTag(self::TAG_EXTRACTOR, $format);
248
		}
249
	}
250
251
	public function beforeCompile()
252
	{
253
		$builder = $this->getContainerBuilder();
254
		$config = $this->getConfig();
255
256
		$this->beforeCompileLogging($config);
257
258
		$registerToLatte = function (ServiceDefinition $def) {
259
			$def->addSetup('?->onCompile[] = function($engine) { ?::install($engine->getCompiler()); }', ['@self', new PhpLiteral(TranslateMacros::class)]);
260
261
			$def->addSetup('addProvider', ['translator', $this->prefix('@default')])
262
				->addSetup('addFilter', ['translate', [$this->prefix('@helpers'), 'translateFilterAware']]);
263
		};
264
265
		$latteFactoryService = $builder->getByType(ILatteFactory::class);
266
		if (!$latteFactoryService || !self::isOfType($builder->getDefinition($latteFactoryService)->getClass(), LatteEngine::class)) {
267
			$latteFactoryService = 'nette.latteFactory';
268
		}
269
270
		if ($builder->hasDefinition($latteFactoryService) && self::isOfType($builder->getDefinition($latteFactoryService)->getClass(), LatteEngine::class)) {
271
			$registerToLatte($builder->getDefinition($latteFactoryService));
272
		}
273
274
		if ($builder->hasDefinition('nette.latte')) {
275
			$registerToLatte($builder->getDefinition('nette.latte'));
276
		}
277
278
		$applicationService = $builder->getByType(Application::class) ?: 'application';
279
		if ($builder->hasDefinition($applicationService)) {
280
			$builder->getDefinition($applicationService)
281
				->addSetup('$service->onRequest[] = ?', [[$this->prefix('@userLocaleResolver.param'), 'onRequest']]);
282
283
			if ($config['debugger'] && interface_exists(IBarPanel::class)) {
284
				$builder->getDefinition($applicationService)
285
					->addSetup('$self = $this; $service->onStartup[] = function () use ($self) { $self->getService(?); }', [$this->prefix('default')])
286
					->addSetup('$service->onRequest[] = ?', [[$this->prefix('@panel'), 'onRequest']]);
287
			}
288
		}
289
290
		if (class_exists(Debugger::class)) {
291
			Panel::registerBluescreen();
292
		}
293
294
		$extractor = $builder->getDefinition($this->prefix('extractor'));
295 View Code Duplication
		foreach ($builder->findByTag(self::TAG_EXTRACTOR) as $extractorId => $meta) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
296
			Validators::assert($meta, 'string:2..');
297
298
			$extractor->addSetup('addExtractor', [$meta, '@' . $extractorId]);
299
300
			$builder->getDefinition($extractorId)->setAutowired(FALSE);
301
		}
302
303
		$writer = $builder->getDefinition($this->prefix('writer'));
304 View Code Duplication
		foreach ($builder->findByTag(self::TAG_DUMPER) as $dumperId => $meta) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
305
			Validators::assert($meta, 'string:2..');
306
307
			$writer->addSetup('addDumper', [$meta, '@' . $dumperId]);
308
309
			$builder->getDefinition($dumperId)->setAutowired(FALSE);
310
		}
311
312
		$this->loaders = [];
313
		foreach ($builder->findByTag(self::TAG_LOADER) as $loaderId => $meta) {
314
			Validators::assert($meta, 'string:2..');
315
			$builder->getDefinition($loaderId)->setAutowired(FALSE);
316
			$this->loaders[$meta] = $loaderId;
317
		}
318
319
		$builder->getDefinition($this->prefix('loader'))
320
			->addSetup('injectServiceIds', [$this->loaders]);
321
322
		foreach ($this->compiler->getExtensions() as $extension) {
323
			if (!$extension instanceof ITranslationProvider) {
324
				continue;
325
			}
326
327
			$config['dirs'] = array_merge($config['dirs'], array_values($extension->getTranslationResources()));
328
		}
329
330
		$config['dirs'] = array_map(function ($dir) {
331
			return str_replace((DIRECTORY_SEPARATOR === '/') ? '\\' : '/', DIRECTORY_SEPARATOR, $dir);
332
		}, $config['dirs']);
333
334
		$dirs = array_values(array_filter($config['dirs'], Callback::closure('is_dir')));
335
		if (count($dirs) > 0) {
336
			foreach ($dirs as $dir) {
337
				$builder->addDependency($dir);
338
			}
339
340
			$this->loadResourcesFromDirs($dirs);
341
		}
342
	}
343
344
	protected function beforeCompileLogging(array $config)
345
	{
346
		$builder = $this->getContainerBuilder();
347
		$translator = $builder->getDefinition($this->prefix('default'));
348
349
		if ($config['logging'] === TRUE) {
350
			$translator->addSetup('injectPsrLogger');
351
352
		} elseif (is_string($config['logging'])) { // channel for kdyby/monolog
353
			$translator->addSetup('injectPsrLogger', [
354
				new Statement(sprintf('@%s::channel', KdybyLogger::class), [$config['logging']]),
355
			]);
356
357
		} elseif ($config['logging'] !== NULL) {
358
			throw new \Kdyby\Translation\InvalidArgumentException(sprintf(
359
				'Invalid config option for logger. Valid are TRUE for general psr/log or string for kdyby/monolog channel, but %s was given',
360
				$config['logging']
361
			));
362
		}
363
	}
364
365
	protected function loadResourcesFromDirs($dirs)
366
	{
367
		$builder = $this->getContainerBuilder();
368
		$config = $this->getConfig();
369
370
		$whitelistRegexp = KdybyTranslator::buildWhitelistRegexp($config['whitelist']);
371
		$translator = $builder->getDefinition($this->prefix('default'));
372
373
		$mask = array_map(function ($value) {
374
			return '*.*.' . $value;
375
		}, array_keys($this->loaders));
376
377
		foreach (Finder::findFiles($mask)->from($dirs) as $file) {
378
			/** @var \SplFileInfo $file */
379
			if (!preg_match('~^(?P<domain>.*?)\.(?P<locale>[^\.]+)\.(?P<format>[^\.]+)$~', $file->getFilename(), $m)) {
380
				continue;
381
			}
382
383
			if ($whitelistRegexp && !preg_match($whitelistRegexp, $m['locale']) && $builder->parameters['productionMode']) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $whitelistRegexp of type string|null is loosely compared to true; 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...
384
				continue; // ignore in production mode, there is no need to pass the ignored resources
385
			}
386
387
			$this->validateResource($m['format'], $file->getPathname(), $m['locale'], $m['domain']);
388
			$translator->addSetup('addResource', [$m['format'], $file->getPathname(), $m['locale'], $m['domain']]);
389
			$builder->addDependency($file->getPathname());
390
		}
391
	}
392
393
	/**
394
	 * @param string $format
395
	 * @param string $file
396
	 * @param string $locale
397
	 * @param string $domain
398
	 */
399
	protected function validateResource($format, $file, $locale, $domain)
400
	{
401
		$builder = $this->getContainerBuilder();
402
403
		if (!isset($this->loaders[$format])) {
404
			return;
405
		}
406
407
		try {
408
			$def = $builder->getDefinition($this->loaders[$format]);
409
			$refl = ReflectionClassType::from($def->getEntity() ?: $def->getClass());
410
			$method = $refl->getConstructor();
411
			if ($method !== NULL && $method->getNumberOfRequiredParameters() > 1) {
412
				return;
413
			}
414
415
			$loader = $refl->newInstance();
416
			if (!$loader instanceof LoaderInterface) {
0 ignored issues
show
Bug introduced by
The class Symfony\Component\Transl...\Loader\LoaderInterface 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...
417
				return;
418
			}
419
420
		} catch (\ReflectionException $e) {
421
			return;
422
		}
423
424
		try {
425
			$loader->load($file, $locale, $domain);
426
427
		} catch (\Exception $e) {
428
			throw new \Kdyby\Translation\InvalidResourceException(sprintf('Resource %s is not valid and cannot be loaded.', $file), 0, $e);
429
		}
430
	}
431
432
	public function afterCompile(ClassTypeGenerator $class)
433
	{
434
		$initialize = $class->getMethod('initialize');
435
		if (class_exists(Debugger::class)) {
436
			$initialize->addBody('?::registerBluescreen();', [new PhpLiteral(Panel::class)]);
437
		}
438
	}
439
440
	/**
441
	 * {@inheritdoc}
442
	 */
443
	public function getConfig(array $defaults = NULL, $expand = TRUE)
444
	{
445
		return parent::getConfig($this->defaults) + ['fallback' => ['en_US']];
446
	}
447
448
	private function isRegisteredConsoleExtension()
449
	{
450
		foreach ($this->compiler->getExtensions() as $extension) {
451
			if ($extension instanceof ConsoleExtension) {
0 ignored issues
show
Bug introduced by
The class Kdyby\Console\DI\ConsoleExtension 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...
452
				return TRUE;
453
			}
454
		}
455
456
		return FALSE;
457
	}
458
459
	/**
460
	 * @param \Nette\Configurator $configurator
461
	 */
462
	public static function register(Configurator $configurator)
463
	{
464
		$configurator->onCompile[] = function ($config, Compiler $compiler) {
465
			$compiler->addExtension('translation', new TranslationExtension());
466
		};
467
	}
468
469
	/**
470
	 * @param string|\stdClass $statement
471
	 * @return \Nette\DI\Statement[]
472
	 */
473
	protected static function filterArgs($statement)
474
	{
475
		return Helpers::filterArguments([is_string($statement) ? new Statement($statement) : $statement]);
476
	}
477
478
	/**
479
	 * @param string|NULL $class
480
	 * @param string $type
481
	 * @return bool
482
	 */
483
	private static function isOfType($class, $type)
484
	{
485
		return $class !== NULL && ($class === $type || is_subclass_of($class, $type));
0 ignored issues
show
Bug introduced by
Due to PHP Bug #53727, is_subclass_of might return inconsistent results on some PHP versions if $type can be an interface. If so, you could instead use ReflectionClass::implementsInterface.
Loading history...
486
	}
487
488
}
489