Failed Conditions
Push — master ( f5c6c8...c59a50 )
by Arnold
02:39
created

RouteAction::getRequest()

Size

Total Lines 1

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 1
ccs 0
cts 0
cp 0
c 0
b 0
f 0
nc 1
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
Documentation introduced by
For interfaces and abstract methods it is generally a good practice to add a @return annotation even if it is just @return void or @return null, so that implementors know what to do in the overridden method.

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 @return doc comment to communicate to implementors of these methods what they are expected to return.

Loading history...
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
        if (!$route instanceof \stdClass) {
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 beforeActionRun()
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->beforeActionRun();
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