Passed
Push — master ( abc2ba...40955b )
by Anton
02:23
created

CycleInterceptor::resolveEntity()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 1
Metric Value
eloc 1
c 1
b 0
f 1
dl 0
loc 3
rs 10
cc 1
nc 1
nop 2
1
<?php
2
3
/**
4
 * Spiral Framework.
5
 *
6
 * @license   MIT
7
 * @author    Anton Titov (Wolfy-J)
8
 */
9
10
declare(strict_types=1);
11
12
namespace Spiral\Domain;
13
14
use Cycle\ORM\ORMInterface;
15
use Spiral\Core\CoreInterceptorInterface;
16
use Spiral\Core\CoreInterface;
17
use Spiral\Core\Exception\ControllerException;
18
19
/**
20
 * Automatically resolves cycle entities based on given parameter.
21
 */
22
class CycleInterceptor implements CoreInterceptorInterface
23
{
24
    // when only one entity is presented the default parameter will be checked
25
    protected const DEFAULT_PARAMETER = 'id';
26
27
    /** @var ORMInterface @internal */
28
    protected $orm;
29
30
    /** @var array */
31
    private $cache = [];
32
33
    /**
34
     * @param ORMInterface $orm
35
     */
36
    public function __construct(ORMInterface $orm)
37
    {
38
        $this->orm = $orm;
39
    }
40
41
    /**
42
     * @inheritDoc
43
     */
44
    public function process(string $controller, string $action, array $parameters, CoreInterface $core)
45
    {
46
        $entities = $this->getDeclaredEntities($controller, $action);
47
48
        foreach ($entities as $parameter => $role) {
49
            $value = $this->getParameter($role, $parameters, count($entities) === 1);
50
            if ($value === null) {
51
                throw new ControllerException(
52
                    "Entity `{$role}` can not be found",
53
                    ControllerException::NOT_FOUND
54
                );
55
            }
56
57
            $entity = $this->resolveEntity($role, $value);
58
            if ($entity === null) {
59
                throw new ControllerException(
60
                    "Entity `{$role}` can not be found",
61
                    ControllerException::NOT_FOUND
62
                );
63
            }
64
65
            $parameters[$parameter] = $entity;
66
        }
67
68
        return $core->callAction($controller, $action, $parameters);
69
    }
70
71
    /**
72
     * @param string $role
73
     * @param array  $parameters
74
     * @param bool   $useDefault
75
     * @return mixed
76
     */
77
    protected function getParameter(string $role, array $parameters, bool $useDefault = false)
78
    {
79
        if (!$useDefault) {
80
            return $parameters[$role] ?? null;
81
        }
82
83
        return $parameters[$role] ?? $parameters[self::DEFAULT_PARAMETER] ?? null;
84
    }
85
86
    /**
87
     * @param string $role
88
     * @param mixed  $parameter
89
     * @return object|null
90
     */
91
    protected function resolveEntity(string $role, $parameter): ?object
92
    {
93
        return $this->orm->getRepository($role)->findByPK($parameter);
94
    }
95
96
    /**
97
     * @param string $controller
98
     * @param string $action
99
     * @return array
100
     */
101
    private function getDeclaredEntities(string $controller, string $action): array
102
    {
103
        $key = sprintf('%s:%s', $controller, $action);
104
        if (array_key_exists($key, $this->cache)) {
105
            return $this->cache[$key];
106
        }
107
108
        $this->cache[$key] = [];
109
        try {
110
            $method = new \ReflectionMethod($controller, $action);
111
        } catch (\ReflectionException $e) {
112
            return [];
113
        }
114
115
        foreach ($method->getParameters() as $parameter) {
116
            if ($parameter->getClass() === null) {
117
                continue;
118
            }
119
120
            if ($this->orm->getSchema()->defines($parameter->getClass()->getName())) {
121
                $this->cache[$key][$parameter->getName()] = $this->orm->resolveRole($parameter->getClass()->getName());
122
            }
123
        }
124
125
        return $this->cache[$key];
126
    }
127
}
128