Skip to content

Commit d8f26b0

Browse files
authored
Collect attributes from interfaces and traits (#38)
1 parent ca67a62 commit d8f26b0

File tree

8 files changed

+132
-9
lines changed

8 files changed

+132
-9
lines changed

CHANGELOG.md

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,29 @@
11
# CHANGELOG
22

3+
## v2.1.0
4+
5+
### New Requirements
6+
7+
None
8+
9+
### New features
10+
11+
Attributes are now collected from interfaces and traits as well as classes.
12+
13+
### Deprecated Features
14+
15+
None
16+
17+
### Backward Incompatible Changes
18+
19+
None
20+
21+
### Other Changes
22+
23+
None
24+
25+
26+
327
## v2.0.2
428

529
### New Requirements

src/Filter/InterfaceFilter.php renamed to src/Filter/ClassFilter.php

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -6,22 +6,20 @@
66
use olvlvl\ComposerAttributeCollector\Logger;
77
use Throwable;
88

9+
use function class_exists;
910
use function interface_exists;
11+
use function trait_exists;
1012

11-
final class InterfaceFilter implements Filter
13+
final class ClassFilter implements Filter
1214
{
1315
public function filter(string $filepath, string $class, Logger $log): bool
1416
{
1517
try {
16-
if (interface_exists($class)) {
17-
return false;
18-
}
18+
return class_exists($class) || interface_exists($class) || trait_exists($class);
1919
} catch (Throwable $e) {
2020
$log->warning("Discarding '$class' because an error occurred during loading: {$e->getMessage()}");
2121

2222
return false;
2323
}
24-
25-
return true;
2624
}
2725
}

src/Plugin.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
use olvlvl\ComposerAttributeCollector\Datastore\FileDatastore;
1212
use olvlvl\ComposerAttributeCollector\Datastore\RuntimeDatastore;
1313
use olvlvl\ComposerAttributeCollector\Filter\ContentFilter;
14-
use olvlvl\ComposerAttributeCollector\Filter\InterfaceFilter;
14+
use olvlvl\ComposerAttributeCollector\Filter\ClassFilter;
1515
use olvlvl\ComposerAttributeCollector\Logger\ComposerLogger;
1616

1717
use function file_exists;
@@ -164,7 +164,7 @@ private static function buildFileFilter(): Filter
164164
{
165165
return new Filter\Chain([
166166
new ContentFilter(),
167-
new InterfaceFilter()
167+
new ClassFilter()
168168
]);
169169
}
170170

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
<?php
2+
3+
namespace Acme\Attribute;
4+
5+
use Attribute;
6+
7+
#[Attribute(flags: Attribute::TARGET_CLASS)]
8+
final class AutowiredService
9+
{
10+
/**
11+
* @param true|list<class-string>|class-string $as
12+
*/
13+
public function __construct(
14+
public ?string $name = null,
15+
public ?string $factory = null,
16+
public bool|array|string $as = true,
17+
) {
18+
}
19+
}

tests/Acme/Filter/ClassFilterTest.php

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
<?php
2+
3+
namespace Acme\Filter;
4+
5+
use olvlvl\ComposerAttributeCollector\Filter\ClassFilter;
6+
use olvlvl\ComposerAttributeCollector\Logger;
7+
use PHPUnit\Framework\TestCase;
8+
use tests\olvlvl\ComposerAttributeCollector\FakeLogger;
9+
10+
final class ClassFilterTest extends TestCase
11+
{
12+
private string $path;
13+
private ClassFilter $sut;
14+
private FakeLogger $log;
15+
16+
protected function setUp(): void
17+
{
18+
// The path doesn't matter.
19+
$this->path = uniqid();
20+
$this->sut = new ClassFilter();
21+
$this->log = new FakeLogger();
22+
23+
parent::setUp();
24+
}
25+
26+
public function testWithClass(): void
27+
{
28+
$actual = $this->sut->filter($this->path, \Acme\PSR4\CreateMenuHandler::class, $this->log);
29+
30+
$this->assertTrue($actual);
31+
}
32+
33+
public function testWithInterface(): void
34+
{
35+
$actual = $this->sut->filter($this->path, \Acme\PSR4\SignatureMapProvider::class, $this->log);
36+
37+
$this->assertTrue($actual);
38+
}
39+
40+
public function testWithTrait(): void
41+
{
42+
$actual = $this->sut->filter($this->path, \Acme\PSR4\SampleTrait::class, $this->log);
43+
44+
$this->assertTrue($actual);
45+
}
46+
47+
public function testDiscardOnError(): void
48+
{
49+
$log = $this->createMock(Logger::class);
50+
$log->expects($this->once())
51+
->method('warning')
52+
->with($this->stringStartsWith("Discarding 'Acme\PSR4\MissingInterface"));
53+
54+
$actual = $this->sut->filter($this->path, \Acme\PSR4\MissingInterface::class, $log);
55+
56+
$this->assertFalse($actual);
57+
}
58+
}

tests/Acme/PSR4/SampleTrait.php

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
<?php
2+
3+
namespace Acme\PSR4;
4+
5+
trait SampleTrait
6+
{
7+
}
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
<?php
2+
3+
namespace Acme\PSR4;
4+
5+
use Acme\Attribute\AutowiredService;
6+
7+
#[AutowiredService(factory: '@Acme\PSR4\SignatureMap\SignatureMapProviderFactory::create')]
8+
interface SignatureMapProvider
9+
{
10+
}

tests/PluginTest.php

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
use Acme\Attribute\ActiveRecord\Serial;
1717
use Acme\Attribute\ActiveRecord\Text;
1818
use Acme\Attribute\ActiveRecord\Varchar;
19+
use Acme\Attribute\AutowiredService;
1920
use Acme\Attribute\Get;
2021
use Acme\Attribute\Handler;
2122
use Acme\Attribute\Permission;
@@ -129,7 +130,13 @@ public static function provideTargetClasses(): array
129130
[
130131
[ new Index('active'), \Acme\PSR4\ActiveRecord\Article::class ],
131132
]
132-
]
133+
],
134+
[
135+
AutowiredService::class,
136+
[
137+
[ new AutowiredService(factory: '@Acme\PSR4\SignatureMap\SignatureMapProviderFactory::create'), \Acme\PSR4\SignatureMapProvider::class ],
138+
]
139+
],
133140

134141
];
135142
}

0 commit comments

Comments
 (0)