Passed
Pull Request — master (#3)
by
unknown
06:37
created

WebpackEncoreBundleExtension::getConfigSchema()   A

Complexity

Conditions 3
Paths 1

Size

Total Lines 25
Code Lines 16

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 4
CRAP Score 3

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 3
eloc 16
c 1
b 0
f 0
nc 1
nop 0
dl 0
loc 25
ccs 4
cts 4
cp 1
crap 3
rs 9.7333
1
<?php
2
3
declare(strict_types=1);
4
5
namespace SixtyEightPublishers\WebpackEncoreBundle\DI;
6
7
use Latte;
8
use Nette;
9
use Symfony;
10
use RuntimeException;
11
use SixtyEightPublishers;
12
13
final class WebpackEncoreBundleExtension extends Nette\DI\CompilerExtension
14
{
15
	private const ENTRYPOINTS_FILE_NAME = 'entrypoints.json';
16
17
	private const ENTRYPOINT_DEFAULT_NAME = '_default';
18
19
	private const CROSSORIGIN_ALLOWED_VALUES = [NULL, 'anonymous', 'use-credentials'];
20
21
	public function getConfigSchema(): Nette\Schema\Schema
22
	{
23
		return Nette\Schema\Expect::structure([
24
			'output_path' => Nette\Schema\Expect::string()->nullable(), # The path where Encore is building the assets - i.e. Encore.setOutputPath()
25
			'builds' => Nette\Schema\Expect::array()->items('string')->assert(function (array $value): bool {
26
				if (isset($value[self::ENTRYPOINT_DEFAULT_NAME])) {
27
					throw new Nette\Utils\AssertionException(sprintf('Key "%s" can\'t be used as build name.', self::ENTRYPOINT_DEFAULT_NAME));
28
				}
29
30
				return TRUE;
31
			}),
32
			'crossorigin' => Nette\Schema\Expect::string()->nullable()->assert(function (?string $value): bool {
33
				if (!in_array($value, self::CROSSORIGIN_ALLOWED_VALUES, TRUE)) {
34
					throw new Nette\Utils\AssertionException(sprintf('Value "%s" for setting "crossorigin" is not allowed', $value));
35
				}
36
37
				return TRUE;
38
			}), # crossorigin value when Encore.enableIntegrityHashes() is used, can be NULL (default), anonymous or use-credentials
39
			'cache' => Nette\Schema\Expect::structure([
40
				'enabled' => Nette\Schema\Expect::bool(FALSE),
41
				'storage' => Nette\Schema\Expect::string('@' . Nette\Caching\IStorage::class)->dynamic(),
42 1
			]),
43 1
			'latte' => Nette\Schema\Expect::structure([
44 1
				'js_assets_macro_name' => Nette\Schema\Expect::string('encore_js'),
45 1
				'css_assets_macro_name' => Nette\Schema\Expect::string('encore_css'),
46
			]),
47 1
		]);
48 1
	}
49
50
	public function loadConfiguration(): void
51 1
	{
52 1
		$builder = $this->getContainerBuilder();
53
		$cache = $this->registerCache($this->getConfig()->cache->enabled, $this->getConfig()->cache->storage);
54
		$lookups = [];
55 1
56 1
		if (NULL !== $this->getConfig()->output_path) {
57 1
			$lookups[] = $this->createEntryPointLookupStatement(self::ENTRYPOINT_DEFAULT_NAME, $this->getConfig()->output_path, $cache);
58 1
		}
59 1
60
		foreach ($this->getConfig()->builds as $name => $path) {
61
			$lookups[] = $this->createEntryPointLookupStatement($name, $path, $cache);
62 1
		}
63
64 1
		$builder->addDefinition($this->prefix('entryPointLookupProvider'))
65
			->setType(SixtyEightPublishers\WebpackEncoreBundle\EntryPoint\IEntryPointLookupProvider::class)
66
			->setFactory(SixtyEightPublishers\WebpackEncoreBundle\EntryPoint\EntryPointLookupProvider::class, [
67
				'lookups' => $lookups,
68 1
				'defaultName' => NULL !== $this->getConfig()->output_path ? self::ENTRYPOINT_DEFAULT_NAME : NULL,
69 1
			]);
70 1
71 1
		$defaultAttributes = [];
72 1
73
		if (NULL !== $this->getConfig()->crossorigin) {
74 1
			$defaultAttributes['crossorigin'] = $this->getConfig()->crossorigin;
75
		}
76
77
		$builder->addDefinition($this->prefix('tagRenderer'))
78
			->setType(SixtyEightPublishers\WebpackEncoreBundle\Latte\TagRenderer::class)
79
			->setAutowired(FALSE)
80
			->setArguments([
81
				'defaultAttributes' => $defaultAttributes,
82
			]);
83 1
	}
84 1
85
	public function beforeCompile(): void
86 1
	{
87
		$builder = $this->getContainerBuilder();
88
89
		if (NULL === $builder->getByType(Symfony\Component\Asset\Packages::class, FALSE)) {
90 1
			throw new RuntimeException('Missing service of type Symfony\Component\Asset\Packages that is required by this package. You can configure and register it manually or you can use package 68publishers/asset (recommended way).');
91
		}
92 1
93 1
		$latteFactory = $builder->getDefinition($builder->getByType(Latte\Engine::class) ?? 'nette.latteFactory');
94 1
95
		$latteFactory->getResultDefinition()->addSetup('addProvider', [
0 ignored issues
show
Bug introduced by
Are you sure the usage of $latteFactory->getResultDefinition() targeting Nette\DI\Definitions\Definition::__call() seems to always return null.

This check looks for function or method calls that always return null and whose return value is used.

class A
{
    function getObject()
    {
        return null;
    }

}

$a = new A();
if ($a->getObject()) {

The method getObject() can return nothing but null, so it makes no sense to use the return value.

The reason is most likely that a function or method is imcomplete or has been reduced for debug purposes.

Loading history...
96
			'name' => 'webpackEncoreTagRenderer',
97 1
			'value' => $this->prefix('@tagRenderer'),
98 1
		]);
99 1
100 1
		$latteFactory->getResultDefinition()->addSetup('?->onCompile[] = function ($engine) { ?::install(?, ?, $engine->getCompiler()); }', [
0 ignored issues
show
Bug introduced by
Are you sure the usage of $latteFactory->getResultDefinition() targeting Nette\DI\Definitions\Definition::__call() seems to always return null.

This check looks for function or method calls that always return null and whose return value is used.

class A
{
    function getObject()
    {
        return null;
    }

}

$a = new A();
if ($a->getObject()) {

The method getObject() can return nothing but null, so it makes no sense to use the return value.

The reason is most likely that a function or method is imcomplete or has been reduced for debug purposes.

Loading history...
101 1
			'@self',
102
			new Nette\PhpGenerator\PhpLiteral(SixtyEightPublishers\WebpackEncoreBundle\Latte\WebpackEncoreMacros::class),
103 1
			$this->getConfig()->latte->js_assets_macro_name,
104
			$this->getConfig()->latte->css_assets_macro_name,
105
		]);
106
	}
107
108
	/**
109
	 * @param string                                      $name
110
	 * @param string                                      $path
111
	 * @param Nette\DI\Definitions\ServiceDefinition|NULL $cache
112 1
	 *
113
	 * @return Nette\DI\Definitions\Statement
114 1
	 */
115 1
	private function createEntryPointLookupStatement(string $name, string $path, ?Nette\DI\Definitions\ServiceDefinition $cache): Nette\DI\Definitions\Statement
116 1
	{
117 1
		return new Nette\DI\Definitions\Statement(SixtyEightPublishers\WebpackEncoreBundle\EntryPoint\EntryPointLookup::class, [
118
			'buildName' => $name,
119
			'entryPointJsonPath' => $path . '/' . self::ENTRYPOINTS_FILE_NAME,
120
			'cache' => $cache,
121
		]);
122
	}
123
124
	/**
125
	 * @param bool  $enabled
126
	 * @param mixed $storage
127 1
	 *
128
	 * @return Nette\DI\Definitions\ServiceDefinition|NULL
129 1
	 */
130 1
	private function registerCache(bool $enabled, $storage): ?Nette\DI\Definitions\ServiceDefinition
131
	{
132
		if (FALSE === $enabled) {
133 1
			return NULL;
134
		}
135 1
136 1
		$builder = $this->getContainerBuilder();
137 1
138 1
		if (!is_string($storage) || !Nette\Utils\Strings::startsWith($storage, '@')) {
139 1
			$storage = $builder->addDefinition($this->prefix('cache.storage'))
140
				->setType(Nette\Caching\IStorage::class)
141
				->setFactory($storage)
142 1
				->addTag(Nette\DI\Extensions\InjectExtension::TAG_INJECT);
143 1
		}
144 1
145 1
		return $builder->addDefinition($this->prefix('cache.cache'))
146 1
			->setType(Nette\Caching\Cache::class)
147
			->setArguments([
148 1
				'storage' => $storage,
149
				'namespace' => str_replace('\\', '.', SixtyEightPublishers\WebpackEncoreBundle\EntryPoint\IEntryPointLookup::class),
150
			])
151
			->addTag(Nette\DI\Extensions\InjectExtension::TAG_INJECT);
152
	}
153
}
154