Skip to content

Commit 6262412

Browse files
authored
✨ Dependency on parent object assets (#46)
Fixes #45
1 parent 8dba962 commit 6262412

15 files changed

Lines changed: 246 additions & 18 deletions

src/Attribute/DependencyOn.php

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,17 +8,34 @@
88

99
/**
1010
* An attribute for representing a library dependency to another enum or a manual dependency.
11+
*
12+
* When applied to an enum class, all enum cases will receive the same dependency.
1113
*/
12-
#[\Attribute(flags: \Attribute::TARGET_CLASS_CONSTANT | \Attribute::IS_REPEATABLE)]
14+
#[\Attribute(flags: \Attribute::TARGET_CLASS | \Attribute::TARGET_CLASS_CONSTANT | \Attribute::IS_REPEATABLE)]
1315
final class DependencyOn
1416
{
17+
private const useNamedParameters = 'Using this attribute without named parameters is not supported.';
18+
1519
/**
1620
* Constructs a dependency.
1721
*
1822
* @phpstan-param ObjectListInterface|string $dependency
1923
*/
2024
public function __construct(
21-
public ObjectListInterface|string $dependency,
25+
public ObjectListInterface|string|null $dependency = null,
26+
string $useNamedParameters = self::useNamedParameters,
27+
public bool $parent = false,
2228
) {
29+
if (self::useNamedParameters !== $useNamedParameters) {
30+
throw new \LogicException(self::useNamedParameters);
31+
}
32+
33+
if (null === $dependency && false === $parent) {
34+
throw new \LogicException(sprintf('%s is not configured.', DependencyOn::class));
35+
}
36+
37+
if (null !== $dependency && false !== $parent) {
38+
throw new \LogicException(sprintf('%s must not have both $dependency and $parent configured. Repeat the attribute to use both.', DependencyOn::class));
39+
}
2340
}
2441
}

src/List/ObjectListInterface.php

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66

77
use Pinto\DefinitionCollection;
88
use Pinto\DefinitionDiscovery;
9+
use Pinto\PintoMapping;
910

1011
/**
1112
* an interface.
@@ -74,5 +75,5 @@ public static function definitions(DefinitionDiscovery $definitionDiscovery): De
7475
*
7576
* @internal
7677
*/
77-
public static function libraries(): array;
78+
public static function libraries(PintoMapping $pintoMapping): array;
7879
}

src/List/ObjectListTrait.php

Lines changed: 23 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
use Pinto\DefinitionCollection;
1414
use Pinto\DefinitionDiscovery;
1515
use Pinto\ObjectType\ObjectTypeDiscovery;
16+
use Pinto\PintoMapping;
1617

1718
/**
1819
* Implements interface defaults.
@@ -95,7 +96,7 @@ public static function definitions(DefinitionDiscovery $definitionDiscovery): De
9596
*
9697
* @phpstan-return array<string, array{css?: array<string, array<string, array<mixed>>>, js?: array<string, array<mixed>>}>
9798
*/
98-
public static function libraries(): array
99+
public static function libraries(PintoMapping $pintoMapping): array
99100
{
100101
$nestedValueSet = static function (&$array, $keys, $value) {
101102
$current = &$array;
@@ -110,7 +111,7 @@ public static function libraries(): array
110111

111112
return array_reduce(
112113
static::cases(),
113-
static function (array $libraries, self $case) use ($nestedValueSet): array {
114+
static function (array $libraries, self $case) use ($pintoMapping, $nestedValueSet): array {
114115
$library = [];
115116
foreach ($case->assets() as $asset) {
116117
/** @var JsAssetInterface|CssAssetInterface $asset */
@@ -138,12 +139,28 @@ static function (array $libraries, self $case) use ($nestedValueSet): array {
138139
}
139140
}
140141

142+
$rEnum = new \ReflectionClass($case::class);
141143
$rCase = new \ReflectionEnumUnitCase($case::class, $case->name);
142-
foreach ($rCase->getAttributes(DependencyOn::class) as $r) {
144+
foreach ([
145+
...$rEnum->getAttributes(DependencyOn::class),
146+
...$rCase->getAttributes(DependencyOn::class),
147+
] as $r) {
143148
$dependencyAttr = $r->newInstance();
144-
$on = $dependencyAttr->dependency instanceof ObjectListInterface
145-
? $dependencyAttr->dependency->attachLibraries()
146-
: [$dependencyAttr->dependency];
149+
150+
$on = [];
151+
if (null !== $dependencyAttr->dependency) {
152+
$on = $dependencyAttr->dependency instanceof ObjectListInterface
153+
? $dependencyAttr->dependency->attachLibraries()
154+
: [$dependencyAttr->dependency];
155+
} elseif (true === $dependencyAttr->parent) {
156+
$definitionAttr = ($rCase->getAttributes(Definition::class)[0] ?? null)?->newInstance();
157+
if (null !== $definitionAttr) {
158+
$factoryClass = $pintoMapping->getFactoryOfCanonicalObject($definitionAttr->className) ?? throw new \LogicException('Unable to determine parent of ' . $definitionAttr->className);
159+
$factoryEnumCase = $pintoMapping->getByClass($factoryClass);
160+
$on = $factoryEnumCase->attachLibraries();
161+
}
162+
}
163+
147164
$library['dependencies'] = [
148165
...($library['dependencies'] ?? []),
149166
...$on,

src/PintoMapping.php

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -101,4 +101,14 @@ public function getCanonicalObjectClassName(string $rootObjectClassName): ?strin
101101
{
102102
return $this->lsbFactoryCanonicalObjectClasses[$rootObjectClassName] ?? null;
103103
}
104+
105+
/**
106+
* @phpstan-return class-string
107+
*/
108+
public function getFactoryOfCanonicalObject(string $objectClassName): ?string
109+
{
110+
$key = \array_search($objectClassName, $this->lsbFactoryCanonicalObjectClasses, true);
111+
112+
return false !== $key ? $key : null;
113+
}
104114
}

tests/Attribute/AttributesTest.php

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,27 @@ public function testDependencyOn(): void
2525
self::assertEquals(PintoList::Pinto_Object, $dependencyOn->dependency);
2626
}
2727

28+
public function testDependencyOnNothing(): void
29+
{
30+
static::expectException(\LogicException::class);
31+
static::expectExceptionMessage(sprintf('%s is not configured.', Attribute\DependencyOn::class));
32+
new Attribute\DependencyOn();
33+
}
34+
35+
public function testDependencyOnMultiple(): void
36+
{
37+
static::expectException(\LogicException::class);
38+
static::expectExceptionMessage(sprintf('%s must not have both $dependency and $parent configured. Repeat the attribute to use both.', Attribute\DependencyOn::class));
39+
new Attribute\DependencyOn(PintoList::Pinto_Object, parent: true);
40+
}
41+
42+
public function testDependencyOnNamedParametersRequired(): void
43+
{
44+
static::expectException(\LogicException::class);
45+
static::expectExceptionMessage('Using this attribute without named parameters is not supported.');
46+
new Attribute\DependencyOn(PintoList::Pinto_Object, '');
47+
}
48+
2849
/**
2950
* @covers \Pinto\Attribute\Build::buildMethodForThemeObject
3051
*/

tests/PintoAssetEnumTest.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,6 @@ public function testEnumAssetAttribute(): void
4848
],
4949
],
5050
],
51-
], PintoListAssetEnum::libraries());
51+
], PintoListAssetEnum::libraries(new Pinto\PintoMapping([], [], [], [], [], [])));
5252
}
5353
}

tests/PintoAssetGlobTest.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,6 @@ public function testGlob(): void
5555
],
5656
],
5757
],
58-
], PintoListAssetGlob::libraries());
58+
], PintoListAssetGlob::libraries(new Pinto\PintoMapping([], [], [], [], [], [])));
5959
}
6060
}

tests/PintoDependenciesTest.php

Lines changed: 37 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,13 @@
55
namespace Pinto\tests;
66

77
use PHPUnit\Framework\TestCase;
8-
use Pinto\tests\fixtures\Lists\PintoListDependencies;
8+
use Pinto\CanonicalProduct\Attribute\CanonicalProduct;
9+
use Pinto\DefinitionDiscovery;
10+
use Pinto\tests\fixtures\Lists\DependencyOn\PintoListDependencies;
11+
use Pinto\tests\fixtures\Lists\DependencyOn\PintoListDependenciesHierarchyChild;
12+
use Pinto\tests\fixtures\Lists\DependencyOn\PintoListDependenciesHierarchyParent;
13+
use Pinto\tests\fixtures\Objects\DependencyOn\PintoObjectDependencyOnChild;
14+
use Pinto\tests\fixtures\Objects\DependencyOn\PintoObjectDependencyOnParent;
915

1016
use function Safe\realpath;
1117

@@ -19,6 +25,7 @@ final class PintoDependenciesTest extends TestCase
1925
/**
2026
* @covers \Pinto\List\ObjectListTrait::assets
2127
* @covers \Pinto\List\ObjectListTrait::libraries
28+
* @covers \Pinto\Attribute\DependencyOn
2229
*/
2330
public function testNoAssets(): void
2431
{
@@ -66,6 +73,34 @@ public function testNoAssets(): void
6673
'foo/bar',
6774
],
6875
],
69-
], PintoListDependencies::libraries());
76+
], PintoListDependencies::libraries(new \Pinto\PintoMapping([], [], [], [], [], [])));
77+
}
78+
79+
/**
80+
* Test DependencyOn(parent).
81+
*/
82+
public function testDependencyOnParent(): void
83+
{
84+
$definitionDiscovery = new DefinitionDiscovery();
85+
$definitionDiscovery[PintoObjectDependencyOnChild::class] = PintoListDependenciesHierarchyChild::Child;
86+
$definitionDiscovery[PintoObjectDependencyOnParent::class] = PintoListDependenciesHierarchyParent::Parent;
87+
88+
$pintoMapping = new \Pinto\PintoMapping(
89+
enumClasses: [],
90+
enums: [
91+
PintoObjectDependencyOnParent::class => [PintoListDependenciesHierarchyParent::class, PintoListDependenciesHierarchyParent::Parent->name],
92+
],
93+
definitions: [],
94+
buildInvokers: [],
95+
types: [],
96+
lsbFactoryCanonicalObjectClasses: CanonicalProduct::discoverCanonicalProductObjectClasses($definitionDiscovery),
97+
);
98+
static::assertEquals([
99+
PintoListDependenciesHierarchyChild::Child->name => [
100+
'dependencies' => [
101+
'pinto/Parent',
102+
],
103+
],
104+
], PintoListDependenciesHierarchyChild::libraries($pintoMapping));
70105
}
71106
}

tests/PintoNoDefinitionsTest.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,6 @@ public function testNoAssets(): void
5050
],
5151
],
5252
],
53-
], PintoListNoDefinitions::libraries());
53+
], PintoListNoDefinitions::libraries(new \Pinto\PintoMapping([], [], [], [], [], [])));
5454
}
5555
}

tests/PintoTest.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,7 @@ public function testThemeDefinitions(): void
7272
*/
7373
public function testLibraries(): void
7474
{
75-
$themeDefinitions = PintoList::libraries();
75+
$themeDefinitions = PintoList::libraries(new \Pinto\PintoMapping([], [], [], [], [], []));
7676
static::assertEquals([
7777
'object_test' => [
7878
'js' => [

0 commit comments

Comments
 (0)