Skip to content

Commit 5e30d61

Browse files
committed
Make the discovered Drupal extensions accessible via a service
1 parent bb3dcfe commit 5e30d61

File tree

7 files changed

+175
-0
lines changed

7 files changed

+175
-0
lines changed

extension.neon

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,8 @@ rules:
4646
services:
4747
-
4848
class: mglaman\PHPStanDrupal\Drupal\ServiceMap
49+
-
50+
class: mglaman\PHPStanDrupal\Drupal\ExtensionMap
4951
-
5052
class: mglaman\PHPStanDrupal\Drupal\EntityDataRepository
5153
arguments:

src/Drupal/DrupalAutoloader.php

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -196,6 +196,9 @@ class: Drupal\jsonapi\Routing\JsonApiParamEnhancer
196196
&& class_exists('Drupal\TestTools\PhpUnitCompatibility\PhpUnit8\ClassWriter')) {
197197
\Drupal\TestTools\PhpUnitCompatibility\PhpUnit8\ClassWriter::mutateTestBase($this->autoloader);
198198
}
199+
200+
$extension_map = $container->getByType(ExtensionMap::class);
201+
$extension_map->setExtensions($this->moduleData, $this->themeData, $profiles);
199202
}
200203

201204
protected function loadLegacyIncludes(): void

src/Drupal/Extension.php

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22

33
namespace mglaman\PHPStanDrupal\Drupal;
44

5+
use Symfony\Component\Yaml\Yaml;
6+
57
/**
68
* Defines an extension (file) object.
79
*
@@ -58,6 +60,16 @@ class Extension
5860
*/
5961
public $origin = '';
6062

63+
/**
64+
* @var array|null
65+
*/
66+
private $info;
67+
68+
/**
69+
* @var string[]|null
70+
*/
71+
private $dependencies;
72+
6173
/**
6274
* Constructs a new Extension object.
6375
*
@@ -167,4 +179,49 @@ public function load(): bool
167179
}
168180
return false;
169181
}
182+
183+
/**
184+
* @return string[]
185+
*/
186+
public function getDependencies(): array
187+
{
188+
if (\is_array($this->dependencies)) {
189+
return $this->dependencies;
190+
}
191+
192+
$info = $this->parseInfo();
193+
$dependencies = $info['dependencies'] ?? [];
194+
195+
if ($dependencies === []) {
196+
return $this->dependencies = $dependencies;
197+
}
198+
199+
$this->dependencies = [];
200+
201+
// @see \Drupal\Core\Extension\Dependency::createFromString().
202+
foreach ($dependencies as $dependency) {
203+
if (\strpos($dependency, ':') !== false) {
204+
[, $dependency] = \explode(':', $dependency);
205+
}
206+
207+
$parts = \explode('(', $dependency, 2);
208+
$this->dependencies[] = \trim($parts[0]);
209+
}
210+
211+
return $this->dependencies;
212+
}
213+
214+
private function parseInfo(): array
215+
{
216+
if (\is_array($this->info)) {
217+
return $this->info;
218+
}
219+
220+
$infoContent = \file_get_contents(\sprintf('%s/%s', $this->root, $this->getPathname()));
221+
if (false === $infoContent) {
222+
throw new \RuntimeException(\sprintf('Cannot read "%s', $this->getPathname()));
223+
}
224+
225+
return $this->info = Yaml::parse($infoContent);
226+
}
170227
}

src/Drupal/ExtensionMap.php

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
<?php declare(strict_types=1);
2+
3+
namespace mglaman\PHPStanDrupal\Drupal;
4+
5+
final class ExtensionMap
6+
{
7+
/** @var Extension[] */
8+
private static $modules = [];
9+
10+
/** @var Extension[] */
11+
private static $themes = [];
12+
13+
/** @var Extension[] */
14+
private static $profiles = [];
15+
16+
/**
17+
* @return Extension[]
18+
*/
19+
public function getModules(): array
20+
{
21+
return self::$modules;
22+
}
23+
24+
public function getModule(string $name): ?Extension
25+
{
26+
return self::$modules[$name] ?? null;
27+
}
28+
29+
/**
30+
* @return Extension[]
31+
*/
32+
public function getThemes(): array
33+
{
34+
return self::$themes;
35+
}
36+
37+
public function getTheme(string $name): ?Extension
38+
{
39+
return self::$themes[$name] ?? null;
40+
}
41+
42+
/**
43+
* @return Extension[]
44+
*/
45+
public function getProfiles(): array
46+
{
47+
return self::$profiles;
48+
}
49+
50+
public function getProfile(string $name): ?Extension
51+
{
52+
return self::$profiles[$name] ?? null;
53+
}
54+
55+
/**
56+
* @param Extension[] $modules
57+
* @param Extension[] $themes
58+
* @param Extension[] $profiles
59+
*/
60+
public function setExtensions(array $modules, array $themes, array $profiles): void
61+
{
62+
self::$modules = $modules;
63+
self::$themes = $themes;
64+
self::$profiles = $profiles;
65+
}
66+
}
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
name: module_with_dependencies
2+
type: module
3+
core_version_requirement: ^8 || ^9
4+
dependencies:
5+
- drupal:node
6+
- foo:bar (>=2.0.x)
7+
- service_map
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
name: module_without_dependencies
2+
type: module
3+
core_version_requirement: ^8 || ^9

tests/src/Drupal/ExtensionTest.php

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
<?php declare(strict_types=1);
2+
3+
namespace mglaman\PHPStanDrupal\Tests\Drupal;
4+
5+
use mglaman\PHPStanDrupal\Drupal\Extension;
6+
use PHPUnit\Framework\TestCase;
7+
8+
final class ExtensionTest extends TestCase
9+
{
10+
11+
/**
12+
* @dataProvider dependenciesProvider
13+
*/
14+
public function testDependencies(array $dependencies, string $pathInfoFile): void
15+
{
16+
self::assertSame(
17+
$dependencies,
18+
(new Extension(__DIR__ . '/../../fixtures/drupal', 'module', $pathInfoFile))->getDependencies()
19+
);
20+
}
21+
22+
public function dependenciesProvider(): \Generator
23+
{
24+
yield [
25+
[
26+
'node',
27+
'bar',
28+
'service_map',
29+
],
30+
'/modules/module_with_dependencies/module_with_dependencies.info.yml',
31+
];
32+
yield [
33+
[],
34+
'/modules/module_without_dependencies/module_without_dependencies.info.yml'
35+
];
36+
}
37+
}

0 commit comments

Comments
 (0)