jasny /
controller
These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more
| 1 | <?php |
||
| 2 | |||
| 3 | namespace Jasny\Controller; |
||
| 4 | |||
| 5 | use Psr\Http\Message\ServerRequestInterface; |
||
| 6 | use Psr\Http\Message\ResponseInterface; |
||
| 7 | |||
| 8 | /** |
||
| 9 | * Execute controller on given route |
||
| 10 | */ |
||
| 11 | trait RouteAction |
||
| 12 | { |
||
| 13 | /** |
||
| 14 | * Get request, set for controller |
||
| 15 | * |
||
| 16 | * @return ServerRequestInterface |
||
| 17 | */ |
||
| 18 | abstract public function getRequest(); |
||
| 19 | |||
| 20 | /** |
||
| 21 | * Get response. set for controller |
||
| 22 | * |
||
| 23 | * @return ResponseInterface |
||
| 24 | */ |
||
| 25 | abstract public function getResponse(); |
||
| 26 | |||
| 27 | /** |
||
| 28 | * Respond with a server error |
||
| 29 | * |
||
| 30 | * @param string $message |
||
| 31 | * @param int $code HTTP status code |
||
| 32 | */ |
||
| 33 | abstract public function notFound($message = '', $code = 404); |
||
|
0 ignored issues
–
show
|
|||
| 34 | |||
| 35 | /** |
||
| 36 | * Check if response is 2xx succesful, or empty |
||
| 37 | * |
||
| 38 | * @return boolean |
||
| 39 | */ |
||
| 40 | abstract public function isSuccessful(); |
||
| 41 | |||
| 42 | |||
| 43 | /** |
||
| 44 | * Get the route |
||
| 45 | * |
||
| 46 | * @return \stdClass |
||
| 47 | */ |
||
| 48 | 13 | protected function getRoute() |
|
| 49 | { |
||
| 50 | 13 | $route = $this->getRequest()->getAttribute('route'); |
|
| 51 | |||
| 52 | 13 | if (!isset($route)) { |
|
| 53 | 1 | throw new \LogicException("Route has not been set"); |
|
| 54 | } |
||
| 55 | |||
| 56 | 12 | if (is_array($route)) { |
|
| 57 | 1 | $route = (object)$route; |
|
| 58 | 1 | } |
|
| 59 | |||
| 60 | 12 | View Code Duplication | if (!$route instanceof \stdClass) { |
|
1 ignored issue
–
show
This code seems to be duplicated across your project.
Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation. You can also find more detailed suggestions in the “Code” section of your repository. Loading history...
|
|||
| 61 | 1 | $type = (is_object($route) ? get_class($route) . ' ' : '') . gettype($route); |
|
| 62 | 1 | throw new \UnexpectedValueException("Expected route to be a stdClass object, not a $type"); |
|
| 63 | } |
||
| 64 | |||
| 65 | 11 | return $route; |
|
| 66 | } |
||
| 67 | |||
| 68 | /** |
||
| 69 | * Get the method name of the action |
||
| 70 | * |
||
| 71 | * @param string $action |
||
| 72 | * @return string |
||
| 73 | */ |
||
| 74 | 11 | protected function getActionMethod($action) |
|
| 75 | { |
||
| 76 | 11 | return \Jasny\camelcase($action) . 'Action'; |
|
| 77 | } |
||
| 78 | |||
| 79 | /** |
||
| 80 | * Called before executing the action. |
||
| 81 | * If the response is no longer a success statuc (>= 300), the action will not be executed. |
||
| 82 | * |
||
| 83 | * <code> |
||
| 84 | * protected function beforeAction() |
||
| 85 | * { |
||
| 86 | * $this->respondWith('json'); // Respond with JSON by default |
||
| 87 | * |
||
| 88 | * if ($this->auth->getUser()->getCredits() <= 0) { |
||
| 89 | * $this->paymentRequired(); |
||
| 90 | * } |
||
| 91 | * } |
||
| 92 | * </code> |
||
| 93 | */ |
||
| 94 | 10 | protected function beforeAction() |
|
| 95 | { |
||
| 96 | 10 | } |
|
| 97 | |||
| 98 | /** |
||
| 99 | * Run the controller |
||
| 100 | * |
||
| 101 | * @return ResponseInterface |
||
| 102 | */ |
||
| 103 | 13 | public function run() |
|
| 104 | { |
||
| 105 | 13 | $route = $this->getRoute(); |
|
| 106 | 11 | $method = $this->getActionMethod(isset($route->action) ? $route->action : 'default'); |
|
| 107 | |||
| 108 | 11 | if (!method_exists($this, $method)) { |
|
| 109 | 1 | return $this->notFound(); |
|
| 110 | } |
||
| 111 | |||
| 112 | 10 | $this->beforeAction(); |
|
| 113 | |||
| 114 | 10 | if ($this->isSuccessful()) { |
|
| 115 | 9 | $args = isset($route->args) ? $route->args |
|
| 116 | 9 | : $this->getFunctionArgs($route, new \ReflectionMethod($this, $method)); |
|
| 117 | |||
| 118 | 8 | call_user_func_array([$this, $method], $args); |
|
| 119 | 8 | } |
|
| 120 | 9 | } |
|
| 121 | |||
| 122 | /** |
||
| 123 | * Get the arguments for a function from a route using reflection |
||
| 124 | * |
||
| 125 | * @param object $route |
||
| 126 | * @param \ReflectionFunctionAbstract $refl |
||
| 127 | * @return array |
||
| 128 | */ |
||
| 129 | 6 | protected function getFunctionArgs($route, \ReflectionFunctionAbstract $refl) |
|
| 130 | { |
||
| 131 | 6 | $args = []; |
|
| 132 | 6 | $params = $refl->getParameters(); |
|
| 133 | |||
| 134 | 6 | foreach ($params as $param) { |
|
| 135 | 6 | $key = $param->name; |
|
| 136 | |||
| 137 | 6 | if (property_exists($route, $key)) { |
|
| 138 | 5 | $value = $route->$key; |
|
| 139 | 5 | } else { |
|
| 140 | 4 | if (!$param->isOptional()) { |
|
| 141 | 1 | $fn = $refl instanceof \ReflectionMethod ? $refl->class . '::' . $refl->name : $refl->name; |
|
| 142 | 1 | throw new \RuntimeException("Missing argument '$key' for {$fn}()"); |
|
| 143 | } |
||
| 144 | |||
| 145 | 3 | $value = $param->isDefaultValueAvailable() ? $param->getDefaultValue() : null; |
|
| 146 | } |
||
| 147 | |||
| 148 | 5 | $args[$key] = $value; |
|
| 149 | 5 | } |
|
| 150 | |||
| 151 | 5 | return $args; |
|
| 152 | } |
||
| 153 | } |
||
| 154 |
For interface and abstract methods, it is impossible to infer the return type from the immediate code. In these cases, it is generally advisible to explicitly annotate these methods with a
@returndoc comment to communicate to implementors of these methods what they are expected to return.