Completed
Push — master ( 557937...679e28 )
by Melech
05:02
created

EntityMiddleware::checkParamForEntity()   A

Complexity

Conditions 4
Paths 3

Size

Total Lines 16
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 4
eloc 5
c 1
b 0
f 0
nc 3
nop 4
dl 0
loc 16
rs 10
1
<?php
2
3
declare(strict_types=1);
4
5
/*
6
 * This file is part of the Valkyrja Framework package.
7
 *
8
 * (c) Melech Mizrachi <[email protected]>
9
 *
10
 * For the full copyright and license information, please view the LICENSE
11
 * file that was distributed with this source code.
12
 */
13
14
namespace Valkyrja\Routing\Middleware;
15
16
use Valkyrja\Http\Request;
17
use Valkyrja\Http\Response;
18
use Valkyrja\ORM\Entity;
19
use Valkyrja\ORM\ORM;
20
use Valkyrja\ORM\Repository;
21
use Valkyrja\Routing\Route;
22
use Valkyrja\Routing\Support\Abort;
23
use Valkyrja\Support\Type\Cls;
24
use Valkyrja\Support\Type\Str;
25
26
/**
27
 * Class EntityMiddleware.
28
 *
29
 * @author Melech Mizrachi
30
 */
31
class EntityMiddleware extends RouteMiddleware
32
{
33
    protected static ORM $orm;
34
35
    /**
36
     * Middleware handler for before a request is dispatched.
37
     *
38
     * @param Request $request The request
39
     *
40
     * @return Request|Response
41
     */
42
    public static function before(Request $request)
43
    {
44
        if (($route = self::$route ?? null) && $matches = $route->getMatches()) {
45
            static::checkParamsForEntities($route, $matches);
46
        }
47
48
        return $request;
49
    }
50
51
    /**
52
     * Get the ORM repository for a given entity.
53
     *
54
     * @param string $entity
55
     *
56
     * @return Repository
57
     */
58
    protected static function getOrmRepository(string $entity): Repository
59
    {
60
        return static::getOrm()->getRepository($entity);
61
    }
62
63
    /**
64
     * Get the ORM service.
65
     *
66
     * @return ORM
67
     */
68
    protected static function getOrm(): ORM
69
    {
70
        return self::$orm ?? self::$container->getSingleton(ORM::class);
71
    }
72
73
    /**
74
     * Check route params for entities.
75
     *
76
     * @param Route $route   The route
77
     * @param array $matches The matches
78
     *
79
     * @return void
80
     */
81
    protected static function checkParamsForEntities(Route $route, array $matches): void
82
    {
83
        $params       = $route->getParams() ?? [];
84
        $dependencies = $route->getDependencies() ?? [];
85
        $counter      = 0;
86
87
        // Iterate through the params
88
        foreach ($params as $param => $paramValue) {
89
            $counter++;
90
91
            static::checkParamForEntity($param, $dependencies, $matches, $counter);
92
        }
93
94
        $route->setMatches($matches);
95
        $route->setDependencies($dependencies);
96
    }
97
98
    /**
99
     * Check a route param for entity.
100
     *
101
     * @param string $param             The params
102
     * @param array  $routeDependencies The route dependencies
103
     * @param array  $matches           The matches
104
     * @param int    $counter           The counter
105
     *
106
     * @return void
107
     */
108
    protected static function checkParamForEntity(
109
        string $param,
110
        array &$routeDependencies,
111
        array &$matches,
112
        int $counter
113
    ): void {
114
        if (! Str::contains($param, '@')) {
115
            return;
116
        }
117
118
        // Get the class
119
        [, $class] = explode('@', $param);
120
121
        // Check if a param
122
        if ($class && Cls::inherits($class, Entity::class)) {
123
            static::checkDependenciesForEntities($param, $routeDependencies, $matches, $class, $counter);
124
        }
125
    }
126
127
    /**
128
     * Check dependencies for entities.
129
     *
130
     * @param string $param             The params
131
     * @param array  $routeDependencies The route dependencies
132
     * @param array  $matches           The matches
133
     * @param string $class             The entity class
134
     * @param int    $counter           The counter
135
     *
136
     * @return void
137
     */
138
    protected static function checkDependenciesForEntities(
139
        string $param,
140
        array &$routeDependencies,
141
        array &$matches,
142
        string $class,
143
        int $counter
144
    ): void {
145
        $dependencies = [];
146
        // Set found to false for this param
147
        $found = false;
148
149
        foreach ($routeDependencies as $dependencyKey => $dependency) {
150
            if (! $found && $class === $dependency) {
151
                static::findAndSetEntity($class, $param, $matches[$counter]);
152
153
                // Set found to true in case another dependency is also the same class
154
                $found = true;
155
156
                continue;
157
            }
158
159
            $dependencies[] = $dependency;
160
        }
161
162
        $routeDependencies = $dependencies;
163
    }
164
165
    /**
166
     * Find and set an entity.
167
     *
168
     * @param string $class The entity class
169
     * @param string $param The param name
170
     * @param mixed  $value [optional] The value
171
     *
172
     * @return void
173
     */
174
    protected static function findAndSetEntity(string $class, string $param, &$value): void
175
    {
176
        // Attempt to get the entity from the ORM repository
177
        $entity = static::findEntity($class, $value);
178
179
        if (! $entity) {
180
            static::entityNotFound($class, $value);
181
        }
182
183
        // Set the entity with the param name as the service id into the container
184
        self::$container->setSingleton($param, $entity);
185
186
        // Replace the route match with this entity
187
        $value = $entity;
188
    }
189
190
    /**
191
     * Find an entity.
192
     *
193
     * @param string $entity The entity class
194
     * @param mixed  $value  [optional] The value
195
     *
196
     * @return Entity|null
197
     */
198
    protected static function findEntity(string $entity, $value): ?Entity
199
    {
200
        return static::getOrmRepository($entity)
201
                     ->findOne($value)
202
                     ->getOneOrNull();
203
    }
204
205
    /**
206
     * Do when an entity was not found with the given value.
207
     *
208
     * @param string $entity The entity not found
209
     * @param mixed  $value  [optional] The value used to check for the entity
210
     *
211
     * @return void
212
     */
213
    protected static function entityNotFound(string $entity, $value): void
0 ignored issues
show
Unused Code introduced by
The parameter $entity is not used and could be removed. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unused  annotation

213
    protected static function entityNotFound(/** @scrutinizer ignore-unused */ string $entity, $value): void

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
Unused Code introduced by
The parameter $value is not used and could be removed. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unused  annotation

213
    protected static function entityNotFound(string $entity, /** @scrutinizer ignore-unused */ $value): void

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
214
    {
215
        Abort::abort();
216
    }
217
}
218