Skip to content

Commit 3f5d9c5

Browse files
Added spiral attributes for advanced annotations support
1 parent b838279 commit 3f5d9c5

File tree

5 files changed

+75
-47
lines changed

5 files changed

+75
-47
lines changed

composer.json

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,11 +23,12 @@
2323
},
2424
"require": {
2525
"php": "^7.2 || ^8.0",
26-
"doctrine/annotations": "^1.11",
26+
"spiral/attributes": "dev-master",
2727
"symfony/polyfill-php80": "^1.20"
2828
},
2929
"require-dev": {
3030
"composer/package-versions-deprecated": "^1.8",
31+
"doctrine/annotations": "^1.11",
3132
"phpstan/phpstan": "^0.12",
3233
"phpstan/phpstan-strict-rules": "^0.12",
3334
"phpunit/phpunit": "^8.5 || ^9.0",
@@ -56,6 +57,9 @@
5657
"@phpunit"
5758
]
5859
},
60+
"suggest": {
61+
"doctrine/annotations": "^1.0 for Doctrine metadata driver support"
62+
},
5963
"minimum-stability": "dev",
6064
"prefer-stable": true
6165
}

src/AnnotationLoader.php

Lines changed: 57 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -17,20 +17,21 @@
1717

1818
namespace Biurad\Annotations;
1919

20-
use Doctrine\Common\Annotations\Reader as AnnotationReader;
21-
use Doctrine\Common\Annotations\SimpleAnnotationReader;
2220
use FilesystemIterator;
2321
use RecursiveDirectoryIterator;
2422
use RecursiveIteratorIterator;
2523
use ReflectionClass;
24+
use ReflectionClassConstant;
2625
use ReflectionMethod;
26+
use ReflectionParameter;
2727
use ReflectionProperty;
2828
use Reflector;
2929
use RegexIterator;
30+
use Spiral\Attributes\ReaderInterface;
3031

3132
class AnnotationLoader implements LoaderInterface
3233
{
33-
/** @var null|AnnotationReader */
34+
/** @var ReaderInterface */
3435
private $annotation;
3536

3637
/** @var ListenerInterface[] */
@@ -40,15 +41,11 @@ class AnnotationLoader implements LoaderInterface
4041
private $resources = [];
4142

4243
/**
43-
* @param null|AnnotationReader $reader
44+
* @param ReaderInterface $reader
4445
*/
45-
public function __construct(?AnnotationReader $reader = null)
46+
public function __construct(ReaderInterface $reader)
4647
{
4748
$this->annotation = $reader;
48-
49-
if (null === $reader && \interface_exists(AnnotationReader::class)) {
50-
$this->annotation = new SimpleAnnotationReader();
51-
}
5249
}
5350

5451
/**
@@ -57,10 +54,6 @@ public function __construct(?AnnotationReader $reader = null)
5754
public function attachListener(ListenerInterface ...$listeners): void
5855
{
5956
foreach ($listeners as $listener) {
60-
if ($this->annotation instanceof SimpleAnnotationReader) {
61-
$this->annotation->addNamespace($listener->getAnnotation());
62-
}
63-
6457
$this->listeners[] = $listener;
6558
}
6659
}
@@ -89,15 +82,9 @@ public function load(): iterable
8982

9083
continue;
9184
}
92-
93-
if (!\file_exists($resource) || \is_dir($resource)) {
94-
continue;
95-
}
96-
97-
(function () use ($resource): void {
98-
require $resource;
99-
})->call($listener->getBinding());
10085
}
86+
87+
//TODO: Read annotations from functions ...
10188
}
10289

10390
foreach ($this->listeners as $listener) {
@@ -110,7 +97,8 @@ public function load(): iterable
11097
/**
11198
* Finds annotations in the given resource
11299
*
113-
* @param string $resource
100+
* @param string $resource
101+
* @param ListenerInterface $listener
114102
*
115103
* @return array<string,array<string,mixed>>
116104
*/
@@ -139,7 +127,12 @@ private function findAnnotations(string $resource, ListenerInterface $listener):
139127
$annotations[$className]['class'] = $annotation;
140128
}
141129

142-
$reflections = \array_merge($classReflection->getMethods(), $classReflection->getProperties());
130+
// Reflections belonging to class object.
131+
$reflections = \array_merge(
132+
$classReflection->getMethods(),
133+
$classReflection->getProperties(),
134+
$classReflection->getConstants()
135+
);
143136

144137
foreach ($reflections as $reflection) {
145138
if ($reflection instanceof ReflectionMethod && $reflection->isAbstract()) {
@@ -150,6 +143,16 @@ private function findAnnotations(string $resource, ListenerInterface $listener):
150143
if ($reflection instanceof ReflectionMethod) {
151144
$annotations[$className]['method'][] = [$reflection, $annotation];
152145

146+
foreach ($this->getMethodParameter($reflection->getParameters(), $listener) as $parameter) {
147+
$annotations[$className]['method_property'][] = $parameter;
148+
}
149+
150+
continue;
151+
}
152+
153+
if ($reflection instanceof ReflectionClassConstant) {
154+
$annotations[$className]['constant'][] = [$reflection, $annotation];
155+
153156
continue;
154157
}
155158

@@ -164,7 +167,7 @@ private function findAnnotations(string $resource, ListenerInterface $listener):
164167
}
165168

166169
/**
167-
* @param ReflectionClass|ReflectionMethod|ReflectionProperty $reflection
170+
* @param Reflector $reflection
168171
*
169172
* @return iterable<object>
170173
*/
@@ -173,31 +176,29 @@ private function getAnnotations(Reflector $reflection, ListenerInterface $listen
173176
$annotationClass = $listener->getAnnotation();
174177
$annotations = [];
175178

176-
if (\PHP_VERSION_ID >= 80000) {
177-
foreach ($reflection->getAttributes($annotationClass) as $attribute) {
178-
yield $attribute->newInstance();
179-
}
180-
}
181-
182-
if (null === $this->annotation) {
183-
return;
184-
}
185-
186179
switch (true) {
187180
case $reflection instanceof ReflectionClass:
188-
$annotations = $this->annotation->getClassAnnotations($reflection);
181+
$annotations = $this->annotation->getClassMetadata($reflection);
189182

190183
break;
191184

192185
case $reflection instanceof ReflectionMethod:
193-
$annotations = $this->annotation->getMethodAnnotations($reflection);
186+
$annotations = $this->annotation->getFunctionMetadata($reflection);
194187

195188
break;
196189

197190
case $reflection instanceof ReflectionProperty:
198-
$annotations = $this->annotation->getPropertyAnnotations($reflection);
191+
$annotations = $this->annotation->getPropertyMetadata($reflection);
192+
193+
break;
194+
195+
case $reflection instanceof ReflectionClassConstant:
196+
$annotations = $this->annotation->getConstantMetadata($reflection);
199197

200198
break;
199+
200+
case $reflection instanceof ReflectionParameter:
201+
$annotations = $this->annotation->getParameterMetadata($reflection);
201202
}
202203

203204
foreach ($annotations as $annotation) {
@@ -207,6 +208,25 @@ private function getAnnotations(Reflector $reflection, ListenerInterface $listen
207208
}
208209
}
209210

211+
/**
212+
* @param array $parameters
213+
* @param ListenerInterface $listener
214+
*
215+
* @return iterable<object>
216+
*/
217+
private function getMethodParameter(array $parameters, ListenerInterface $listener): iterable
218+
{
219+
foreach ($listener->getArguments() as $name) {
220+
foreach ($parameters as $parameter) {
221+
if ($parameter->getName() === $name) {
222+
foreach ($this->getAnnotations($parameter, $listener) as $annotation) {
223+
yield [$parameter, $annotation];
224+
}
225+
}
226+
}
227+
}
228+
}
229+
210230
/**
211231
* Finds classes in the given resource directory
212232
*

src/ListenerInterface.php

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -36,10 +36,10 @@ public function onAnnotation(array $annotations);
3636
public function getAnnotation(): string;
3737

3838
/**
39-
* Add a binding, so we can load from php files
40-
* which are not class type.
39+
* This methods gets the annotation from a function or method's
40+
* paramater.
4141
*
42-
* @return object
42+
* @return string[]
4343
*/
44-
public function getBinding(): object;
44+
public function getArguments(): array;
4545
}

tests/AnnotationLoaderTest.php

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,11 +18,12 @@
1818
namespace Biurad\Annotations\Tests;
1919

2020
use Biurad\Annotations\AnnotationLoader;
21-
use Doctrine\Common\Annotations\AnnotationReader;
2221
use Doctrine\Common\Annotations\AnnotationRegistry;
2322
use PHPUnit\Framework\TestCase;
2423
use ReflectionMethod;
2524
use ReflectionProperty;
25+
use Spiral\Attributes\AnnotationReader;
26+
use Spiral\Attributes\NativeAttributeReader;
2627

2728
/**
2829
* AnnotationLoaderTest
@@ -31,7 +32,10 @@ class AnnotationLoaderTest extends TestCase
3132
{
3233
protected function setUp(): void
3334
{
34-
AnnotationRegistry::registerLoader('class_exists');
35+
// doctrine/annotations ^1.0 compatibility.
36+
if (\method_exists(AnnotationRegistry::class, 'registerLoader')) {
37+
AnnotationRegistry::registerLoader('\\class_exists');
38+
}
3539
}
3640

3741
/**
@@ -102,7 +106,7 @@ public function testAttach(): void
102106
*/
103107
public function testAttachAttribute(): void
104108
{
105-
$annotation = new AnnotationLoader(new AnnotationReader());
109+
$annotation = new AnnotationLoader(new NativeAttributeReader());
106110
$result = [];
107111

108112
$annotation->attachListener(new Fixtures\SampleListener());

tests/Fixtures/SampleListener.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -35,9 +35,9 @@ public function __construct(?SampleCollector $collector = null)
3535
/**
3636
* {@inheritdoc}
3737
*/
38-
public function getBinding(): object
38+
public function getArguments(): array
3939
{
40-
return $this->collector;
40+
return ['parameter'];
4141
}
4242

4343
/**

0 commit comments

Comments
 (0)