WebpackEncoreBundleExtension::beforeCompile()   A
last analyzed

Complexity

Conditions 2
Paths 2

Size

Total Lines 20
Code Lines 12

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 8
CRAP Score 2

Importance

Changes 4
Bugs 0 Features 0
Metric Value
cc 2
eloc 12
c 4
b 0
f 0
nc 2
nop 0
dl 0
loc 20
ccs 8
cts 8
cp 1
crap 2
rs 9.8666
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
	/**
22
	 * {@inheritdoc}
23
	 */
24
	public function getConfigSchema(): Nette\Schema\Schema
25
	{
26
		return Nette\Schema\Expect::structure([
27
			'output_path' => Nette\Schema\Expect::string()->nullable(), # The path where Encore is building the assets - i.e. Encore.setOutputPath()
28
			'builds' => Nette\Schema\Expect::array()->items('string')->assert(function (array $value): bool {
29
				if (isset($value[self::ENTRYPOINT_DEFAULT_NAME])) {
30
					throw new Nette\Utils\AssertionException(sprintf('Key "%s" can\'t be used as build name.', self::ENTRYPOINT_DEFAULT_NAME));
31
				}
32
33
				return TRUE;
34
			}),
35
			'crossorigin' => Nette\Schema\Expect::string()->nullable()->assert(function (?string $value): bool {
36
				if (!in_array($value, self::CROSSORIGIN_ALLOWED_VALUES, TRUE)) {
37
					throw new Nette\Utils\AssertionException(sprintf('Value "%s" for setting "crossorigin" is not allowed', $value));
38
				}
39
40
				return TRUE;
41
			}), # crossorigin value when Encore.enableIntegrityHashes() is used, can be NULL (default), anonymous or use-credentials
42 1
			'cache' => Nette\Schema\Expect::structure([
43 1
				'enabled' => Nette\Schema\Expect::bool(FALSE),
44 1
				'storage' => Nette\Schema\Expect::string('@' . Nette\Caching\IStorage::class)->dynamic(),
45 1
			]),
46
			'latte' => Nette\Schema\Expect::structure([
47 1
				'js_assets_macro_name' => Nette\Schema\Expect::string('encore_js'),
48 1
				'css_assets_macro_name' => Nette\Schema\Expect::string('encore_css'),
49
			]),
50
		]);
51 1
	}
52 1
53
	/**
54
	 * {@inheritdoc}
55 1
	 */
56 1
	public function loadConfiguration(): void
57 1
	{
58 1
		$builder = $this->getContainerBuilder();
59 1
		$cache = $this->registerCache($this->getConfig()->cache->enabled, $this->getConfig()->cache->storage);
60
		$lookups = [];
61
62 1
		if (NULL !== $this->getConfig()->output_path) {
63
			$lookups[] = $this->createEntryPointLookupStatement(self::ENTRYPOINT_DEFAULT_NAME, $this->getConfig()->output_path, $cache);
64 1
		}
65
66
		foreach ($this->getConfig()->builds as $name => $path) {
67
			$lookups[] = $this->createEntryPointLookupStatement($name, $path, $cache);
68 1
		}
69 1
70 1
		$builder->addDefinition($this->prefix('entryPointLookupProvider'))
71 1
			->setType(SixtyEightPublishers\WebpackEncoreBundle\EntryPoint\IEntryPointLookupProvider::class)
72 1
			->setFactory(SixtyEightPublishers\WebpackEncoreBundle\EntryPoint\EntryPointLookupProvider::class, [
73
				'lookups' => $lookups,
74 1
				'defaultName' => NULL !== $this->getConfig()->output_path ? self::ENTRYPOINT_DEFAULT_NAME : NULL,
75
			]);
76
77
		$defaultAttributes = [];
78
79
		if (NULL !== $this->getConfig()->crossorigin) {
80
			$defaultAttributes['crossorigin'] = $this->getConfig()->crossorigin;
81
		}
82
83 1
		$builder->addDefinition($this->prefix('tagRenderer'))
84 1
			->setType(SixtyEightPublishers\WebpackEncoreBundle\Latte\TagRenderer::class)
85
			->setAutowired(FALSE)
86 1
			->setArguments([
87
				'defaultAttributes' => $defaultAttributes,
88
			]);
89
	}
90 1
91
	/**
92 1
	 * {@inheritdoc}
93 1
	 */
94 1
	public function beforeCompile(): void
95
	{
96
		$builder = $this->getContainerBuilder();
97 1
98 1
		if (NULL === $builder->getByType(Symfony\Component\Asset\Packages::class, FALSE)) {
99 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).');
100 1
		}
101 1
102
		$latteFactory = $builder->getDefinition($builder->getByType(Latte\Engine::class) ?? 'nette.latteFactory');
103 1
104
		$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...
105
			'name' => 'webpackEncoreTagRenderer',
106
			'value' => $this->prefix('@tagRenderer'),
107
		]);
108
109
		$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...
110
			'@self',
111
			new Nette\PhpGenerator\PhpLiteral(SixtyEightPublishers\WebpackEncoreBundle\Latte\WebpackEncoreMacros::class),
112 1
			$this->getConfig()->latte->js_assets_macro_name,
113
			$this->getConfig()->latte->css_assets_macro_name,
114 1
		]);
115 1
	}
116 1
117 1
	/**
118
	 * @param string                                      $name
119
	 * @param string                                      $path
120
	 * @param Nette\DI\Definitions\ServiceDefinition|NULL $cache
121
	 *
122
	 * @return Nette\DI\Definitions\Statement
123
	 */
124
	private function createEntryPointLookupStatement(string $name, string $path, ?Nette\DI\Definitions\ServiceDefinition $cache): Nette\DI\Definitions\Statement
125
	{
126
		return new Nette\DI\Definitions\Statement(SixtyEightPublishers\WebpackEncoreBundle\EntryPoint\EntryPointLookup::class, [
127 1
			'buildName' => $name,
128
			'entryPointJsonPath' => $path . '/' . self::ENTRYPOINTS_FILE_NAME,
129 1
			'cache' => $cache,
130 1
		]);
131
	}
132
133 1
	/**
134
	 * @param bool  $enabled
135 1
	 * @param mixed $storage
136 1
	 *
137 1
	 * @return Nette\DI\Definitions\ServiceDefinition|NULL
138 1
	 */
139 1
	private function registerCache(bool $enabled, $storage): ?Nette\DI\Definitions\ServiceDefinition
140
	{
141
		if (FALSE === $enabled) {
142 1
			return NULL;
143 1
		}
144 1
145 1
		$builder = $this->getContainerBuilder();
146 1
147
		if (!is_string($storage) || !Nette\Utils\Strings::startsWith($storage, '@')) {
148 1
			$storage = $builder->addDefinition($this->prefix('cache.storage'))
149
				->setType(Nette\Caching\IStorage::class)
150
				->setFactory($storage)
151
				->addTag(Nette\DI\Extensions\InjectExtension::TAG_INJECT);
152
		}
153
154
		return $builder->addDefinition($this->prefix('cache.cache'))
155
			->setType(Nette\Caching\Cache::class)
156
			->setArguments([
157
				'storage' => $storage,
158 1
				'namespace' => str_replace('\\', '.', SixtyEightPublishers\WebpackEncoreBundle\EntryPoint\IEntryPointLookup::class),
159
			])
160 1
			->addTag(Nette\DI\Extensions\InjectExtension::TAG_INJECT);
161 1
	}
162
}
163