Completed
Push — master ( 51150f...078ca3 )
by
unknown
02:17
created

InheritCheckerAspect::fetchMethodContracts()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 14

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 7
CRAP Score 3

Importance

Changes 0
Metric Value
dl 0
loc 14
ccs 7
cts 7
cp 1
rs 9.7998
c 0
b 0
f 0
cc 3
nc 3
nop 1
crap 3
1
<?php
2
3
namespace PhpDeal\Aspect;
4
5
use Doctrine\Common\Annotations\Reader;
6
use Go\Aop\Aspect;
7
use Go\Aop\Intercept\MethodInvocation;
8
use Go\Lang\Annotation\Around;
9
use PhpDeal\Annotation\Ensure;
10
use PhpDeal\Annotation\Invariant;
11
use PhpDeal\Annotation\Verify;
12
use PhpDeal\Contract\Fetcher\Parent\InvariantFetcher;
13
use PhpDeal\Contract\Fetcher\Parent\MethodConditionFetcher;
14
use PhpDeal\Exception\ContractViolation;
15
use ReflectionClass;
16
17
class InheritCheckerAspect extends AbstractContractAspect implements Aspect
18
{
19
    /**
20
     * @var MethodConditionFetcher
21
     */
22
    private $methodConditionFetcher;
23
24
    /** @var InvariantFetcher */
25
    private $invariantFetcher;
26
27
    public function __construct(Reader $reader)
28
    {
29
        parent::__construct($reader);
30
        $this->methodConditionFetcher = new MethodConditionFetcher([Ensure::class, Verify::class, Invariant::class], $reader);
31
        $this->invariantFetcher = new InvariantFetcher([Invariant::class], $reader);
32
    }
33
34
    /**
35
     * Verifies inherit contracts for the method
36
     *
37
     * @Around("@execution(PhpDeal\Annotation\Inherit)")
38
     * @param MethodInvocation $invocation
39
     *
40
     * @throws ContractViolation
41
     * @return mixed
42
     */
43 2
    public function inheritMethodContracts(MethodInvocation $invocation)
44
    {
45 2
        $object = $invocation->getThis();
46 2
        $args   = $this->fetchMethodArguments($invocation);
47 2
        $class  = $invocation->getMethod()->getDeclaringClass();
48 2
        if ($class->isCloneable()) {
49 2
            $args['__old'] = clone $object;
50
        }
51
52 2
        $result = $invocation->proceed();
53 2
        $args['__result'] = $result;
54 2
        $allContracts = $this->fetchMethodContracts($invocation);
55
56 2
        $this->ensureContracts($invocation, $allContracts, $object, $class->name, $args);
57
58 1
        return $result;
59
    }
60
61
    /**
62
     * @Around("@within(PhpDeal\Annotation\Inherit) && execution(public **->*(*))")
63
     * @param MethodInvocation $invocation
64
     * @return mixed
65
     */
66
    public function inheritClassContracts(MethodInvocation $invocation)
67
    {
68
        $object = $invocation->getThis();
69
        $args   = $this->fetchMethodArguments($invocation);
70
        $class  = $invocation->getMethod()->getDeclaringClass();
71
        if ($class->isCloneable()) {
72
            $args['__old'] = clone $object;
73
        }
74
75
        $result = $invocation->proceed();
76
        $args['__result'] = $result;
77
78
        $allContracts = $this->fetchClassContracts($class);
79
        $this->ensureContracts($invocation, $allContracts, $object, $class->name, $args);
80
81
        return $result;
82
    }
83
84
    /**
85
     * @param MethodInvocation $invocation
86
     * @return array
87
     */
88 2
    private function fetchMethodContracts(MethodInvocation $invocation)
89
    {
90 2
        $allContracts = $this->fetchParentsMethodContracts($invocation);
91
92 2
        foreach ($invocation->getMethod()->getAnnotations() as $annotation) {
93 2
            $annotationClass = \get_class($annotation);
94
95 2
            if (\in_array($annotationClass, [Ensure::class, Verify::class, Invariant::class], true)) {
96 2
                $allContracts[] = $annotation;
97
            }
98
        }
99
100 2
        return array_unique($allContracts);
101
    }
102
103
    /**
104
     * @param MethodInvocation $invocation
105
     * @return array
106
     */
107 2
    private function fetchParentsMethodContracts(MethodInvocation $invocation)
108
    {
109 2
        return $this->methodConditionFetcher->getConditions(
110 2
            $invocation->getMethod()->getDeclaringClass(),
111 2
            $invocation->getMethod()->name
112
        );
113
    }
114
115
    /**
116
     * @param ReflectionClass $class
117
     * @return array
118
     */
119
    private function fetchClassContracts(ReflectionClass $class)
120
    {
121
        $allContracts = $this->invariantFetcher->getConditions($class);
122
        foreach ($this->reader->getClassAnnotations($class) as $annotation) {
123
            if ($annotation instanceof Invariant) {
124
                $allContracts[] = $annotation;
125
            }
126
        }
127
128
        return array_unique($allContracts);
129
    }
130
}
131