MethodMatch::annotatedMethodMatchBind()   A
last analyzed

Complexity

Conditions 3
Paths 3

Size

Total Lines 15
Code Lines 8

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 8
c 1
b 0
f 0
dl 0
loc 15
rs 10
cc 3
nc 3
nop 3
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Ray\Aop;
6
7
use Doctrine\Common\Annotations\Reader;
0 ignored issues
show
Bug introduced by
This use statement conflicts with another class in this namespace, Ray\Aop\Reader. Consider defining an alias.

Let?s assume that you have a directory layout like this:

.
|-- OtherDir
|   |-- Bar.php
|   `-- Foo.php
`-- SomeDir
    `-- Foo.php

and let?s assume the following content of Bar.php:

// Bar.php
namespace OtherDir;

use SomeDir\Foo; // This now conflicts the class OtherDir\Foo

If both files OtherDir/Foo.php and SomeDir/Foo.php are loaded in the same runtime, you will see a PHP error such as the following:

PHP Fatal error:  Cannot use SomeDir\Foo as Foo because the name is already in use in OtherDir/Foo.php

However, as OtherDir/Foo.php does not necessarily have to be loaded and the error is only triggered if it is loaded before OtherDir/Bar.php, this problem might go unnoticed for a while. In order to prevent this error from surfacing, you must import the namespace with a different alias:

// Bar.php
namespace OtherDir;

use SomeDir\Foo as SomeDirFoo; // There is no conflict anymore.
Loading history...
8
use Ray\ServiceLocator\ServiceLocator;
9
use ReflectionClass;
0 ignored issues
show
Bug introduced by
This use statement conflicts with another class in this namespace, Ray\Aop\ReflectionClass. Consider defining an alias.

Let?s assume that you have a directory layout like this:

.
|-- OtherDir
|   |-- Bar.php
|   `-- Foo.php
`-- SomeDir
    `-- Foo.php

and let?s assume the following content of Bar.php:

// Bar.php
namespace OtherDir;

use SomeDir\Foo; // This now conflicts the class OtherDir\Foo

If both files OtherDir/Foo.php and SomeDir/Foo.php are loaded in the same runtime, you will see a PHP error such as the following:

PHP Fatal error:  Cannot use SomeDir\Foo as Foo because the name is already in use in OtherDir/Foo.php

However, as OtherDir/Foo.php does not necessarily have to be loaded and the error is only triggered if it is loaded before OtherDir/Bar.php, this problem might go unnoticed for a while. In order to prevent this error from surfacing, you must import the namespace with a different alias:

// Bar.php
namespace OtherDir;

use SomeDir\Foo as SomeDirFoo; // There is no conflict anymore.
Loading history...
10
use ReflectionMethod;
0 ignored issues
show
Bug introduced by
This use statement conflicts with another class in this namespace, Ray\Aop\ReflectionMethod. Consider defining an alias.

Let?s assume that you have a directory layout like this:

.
|-- OtherDir
|   |-- Bar.php
|   `-- Foo.php
`-- SomeDir
    `-- Foo.php

and let?s assume the following content of Bar.php:

// Bar.php
namespace OtherDir;

use SomeDir\Foo; // This now conflicts the class OtherDir\Foo

If both files OtherDir/Foo.php and SomeDir/Foo.php are loaded in the same runtime, you will see a PHP error such as the following:

PHP Fatal error:  Cannot use SomeDir\Foo as Foo because the name is already in use in OtherDir/Foo.php

However, as OtherDir/Foo.php does not necessarily have to be loaded and the error is only triggered if it is loaded before OtherDir/Bar.php, this problem might go unnoticed for a while. In order to prevent this error from surfacing, you must import the namespace with a different alias:

// Bar.php
namespace OtherDir;

use SomeDir\Foo as SomeDirFoo; // There is no conflict anymore.
Loading history...
11
12
use function array_key_exists;
13
use function get_class;
14
15
final class MethodMatch
16
{
17
    /** @var Reader */
18
    private $reader;
19
20
    /** @var BindInterface */
21
    private $bind;
22
23
    public function __construct(BindInterface $bind)
24
    {
25
        $this->bind = $bind;
26
        $this->reader = ServiceLocator::getReader();
27
    }
28
29
    /**
30
     * @param ReflectionClass<object> $class
31
     * @param Pointcut[]              $pointcuts
32
     */
33
    public function __invoke(ReflectionClass $class, ReflectionMethod $method, array $pointcuts): void
34
    {
35
        /** @var array<int, object> $annotations */
36
        $annotations = $this->reader->getMethodAnnotations($method);
37
        // priority bind
38
        foreach ($pointcuts as $key => $pointcut) {
39
            if ($pointcut instanceof PriorityPointcut) {
40
                $this->annotatedMethodMatchBind($class, $method, $pointcut);
41
                unset($pointcuts[$key]);
42
            }
43
        }
44
45
        $onion = $this->onionOrderMatch($class, $method, $pointcuts, $annotations);
46
47
        // default binding
48
        foreach ($onion as $pointcut) {
49
            $this->annotatedMethodMatchBind($class, $method, $pointcut);
50
        }
51
    }
52
53
    /**
54
     * @param ReflectionClass<object> $class
55
     */
56
    private function annotatedMethodMatchBind(ReflectionClass $class, ReflectionMethod $method, Pointcut $pointCut): void
57
    {
58
        $isMethodMatch = $pointCut->methodMatcher->matchesMethod($method, $pointCut->methodMatcher->getArguments());
59
        if (! $isMethodMatch) {
60
            return;
61
        }
62
63
        $isClassMatch = $pointCut->classMatcher->matchesClass($class, $pointCut->classMatcher->getArguments());
64
        if (! $isClassMatch) {
65
            return;
66
        }
67
68
        /** @var MethodInterceptor[] $interceptors */
69
        $interceptors = $pointCut->interceptors;
70
        $this->bind->bindInterceptors($method->name, $interceptors);
71
    }
72
73
    /**
74
     * @param ReflectionClass<object> $class
75
     * @param Pointcut[]              $pointcuts
76
     * @param array<int, object>      $annotations
77
     *
78
     * @return Pointcut[]
79
     */
80
    private function onionOrderMatch(
81
        ReflectionClass $class,
82
        ReflectionMethod $method,
83
        array $pointcuts,
84
        array $annotations
85
    ): array {
86
        // method bind in annotation order
87
        foreach ($annotations as $annotation) {
88
            $annotationIndex = get_class($annotation);
89
            if (array_key_exists($annotationIndex, $pointcuts)) {
90
                $this->annotatedMethodMatchBind($class, $method, $pointcuts[$annotationIndex]);
91
                unset($pointcuts[$annotationIndex]);
92
            }
93
        }
94
95
        return $pointcuts;
96
    }
97
}
98