Completed
Pull Request — master (#35)
by
unknown
14:05
created

postConditionContract()   A

Complexity

Conditions 3
Paths 2

Size

Total Lines 17

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 10
CRAP Score 3.0067

Importance

Changes 0
Metric Value
dl 0
loc 17
ccs 10
cts 11
cp 0.9091
rs 9.7
c 0
b 0
f 0
cc 3
nc 2
nop 1
crap 3.0067
1
<?php
2
declare(strict_types=1);
3
4
/**
5
 * PHP Deal framework
6
 *
7
 * @copyright Copyright 2019, Lisachenko Alexander <[email protected]>
8
 *
9
 * This source file is subject to the license that is bundled
10
 * with this source code in the file LICENSE.
11
 */
12
13
namespace PhpDeal\Aspect;
14
15
use Doctrine\Common\Annotations\Reader;
16
use Go\Aop\Aspect;
17
use Go\Aop\Intercept\MethodInvocation;
18
use Go\Aop\Support\AnnotatedReflectionMethod;
19
use PhpDeal\Annotation\Ensure;
20
use PhpDeal\Contract\Fetcher\Parent\MethodConditionFetcher;
21
use PhpDeal\Exception\ContractViolation;
22
use Go\Lang\Annotation\Around;
23
use ReflectionMethod;
24
25
class PostconditionCheckerAspect extends AbstractContractAspect implements Aspect
26
{
27
    /**
28
     * @var MethodConditionFetcher
29
     */
30
    private $methodConditionFetcher;
31
32
    public function __construct(Reader $reader)
33
    {
34
        parent::__construct($reader);
35
        $this->methodConditionFetcher = new MethodConditionFetcher([Ensure::class], $reader);
36
    }
37
38
    /**
39
     * Verifies post-condition contract for the method
40
     *
41
     * @Around("@execution(PhpDeal\Annotation\Ensure)")
42
     * @param MethodInvocation $invocation
43
     *
44
     * @throws ContractViolation
45
     * @throws \ReflectionException
46
     * @return mixed
47
     */
48 8
    public function postConditionContract(MethodInvocation $invocation)
49
    {
50 8
        $object = $invocation->getThis();
51 8
        $args   = $this->fetchMethodArguments($invocation);
52 8
        $class  = $invocation->getMethod()->getDeclaringClass();
53 8
        if (\is_object($object) && $class->isCloneable()) {
54 8
            $args['__old'] = clone $object;
55
        }
56
57 8
        $result = $invocation->proceed();
58 8
        $args['__result'] = $result;
59 8
        $allContracts = $this->fetchAllContracts($invocation);
60
61 8
        $this->ensureContracts($invocation, $allContracts, $object, $class->name, $args);
62
63
        return $result;
64
    }
65
66
    /**
67
     * @param MethodInvocation $invocation
68
     * @return array
69
     * @throws \ReflectionException
70
     */
71 8
    private function fetchAllContracts(MethodInvocation $invocation): array
72
    {
73 8
        $allContracts = $this->fetchParentsContracts($invocation);
74
        /** @var ReflectionMethod&AnnotatedReflectionMethod $reflectionMethod */
0 ignored issues
show
Documentation introduced by
The doc-type ReflectionMethod&AnnotatedReflectionMethod could not be parsed: Unknown type name "ReflectionMethod&AnnotatedReflectionMethod" at position 0. (view supported doc-types)

This check marks PHPDoc comments that could not be parsed by our parser. To see which comment annotations we can parse, please refer to our documentation on supported doc-types.

Loading history...
75 8
        $reflectionMethod = $invocation->getMethod();
76
77 8
        foreach ($reflectionMethod->getAnnotations() as $annotation) {
78 8
            if ($annotation instanceof Ensure) {
79 8
                $allContracts[] = $annotation;
80
            }
81
        }
82
83 8
        return \array_unique($allContracts);
84
    }
85
86
    /**
87
     * @param MethodInvocation $invocation
88
     * @return array
89
     * @throws \ReflectionException
90
     */
91 8
    private function fetchParentsContracts(MethodInvocation $invocation): array
92
    {
93 8
        return $this->methodConditionFetcher->getConditions(
94 8
            $invocation->getMethod()->getDeclaringClass(),
95 8
            $invocation->getMethod()->name
96
        );
97
    }
98
}
99