Completed
Pull Request — master (#22)
by Matthew
06:23 queued 04:03
created

ResponseHandler::respondWithError()   D

Complexity

Conditions 9
Paths 16

Size

Total Lines 38
Code Lines 28

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 9
eloc 28
nc 16
nop 2
dl 0
loc 38
rs 4.909
c 0
b 0
f 0
1
<?php
2
3
namespace Ps2alerts\Api\Utility;
4
5
use League\Fractal\TransformerAbstract;
6
use Ps2alerts\Api\Contract\EndpointInterface;
7
use Ps2alerts\Api\Contract\FractalAwareInterface;
8
use Ps2alerts\Api\Contract\FractalAwareTrait;
9
use Ps2alerts\Api\Contract\UtilityAwareInterface;
10
use Ps2alerts\Api\Contract\UtilityAwareTrait;
11
use Psr\Http\Message\ResponseInterface;
12
use Ps2alerts\Api\Contract\HttpMessageAwareInterface;
13
use Ps2alerts\Api\Contract\HttpMessageAwareTrait;
14
15
abstract class ResponseHandler implements
16
    FractalAwareInterface,
17
    EndpointInterface,
18
    HttpMessageAwareInterface,
19
    UtilityAwareInterface
20
{
21
    use FractalAwareTrait;
22
    use HttpMessageAwareTrait;
23
    use UtilityAwareTrait;
24
25
    const CODE_WRONG_ARGS     = 'API-MALFORMED-REQUEST';
26
    const CODE_NOT_FOUND      = 'API-NOT-FOUND';
27
    const CODE_INTERNAL_ERROR = 'API-DOH';
28
    const CODE_EXTERNAL_ERROR = 'API-NOT-MY-PROBLEM';
29
    const CODE_UNAUTHORIZED   = 'API-UNAUTHORIZED';
30
    const CODE_FORBIDDEN      = 'API-DENIED';
31
    const CODE_EMPTY          = 'API-EMPTY';
32
33
    /**
34
     * Stores the status code
35
     *
36
     * @var integer
37
     */
38
    protected $statusCode = 200;
39
40
    /**
41
     * Flag whether to send back a "is cached" header
42
     *
43
     * @var boolean
44
     */
45
    protected $sendCachedHeader = false;
46
47
    /**
48
     * Getter for statusCode
49
     *
50
     * @return int
51
     */
52
    public function getStatusCode()
53
    {
54
        return $this->statusCode;
55
    }
56
57
    /**
58
     * Setter for statusCode
59
     *
60
     * @param integer $statusCode Value to set
61
     *
62
     * @return self
63
     */
64
    public function setStatusCode(int $statusCode)
65
    {
66
        $this->statusCode = (int) $statusCode;
67
        return $this;
68
    }
69
70
    /**
71
     * Master function to split out appropriate calls
72
     *
73
     * @param  string              $kind     The kind of data we wish to return
74
     * @param  array               $data     The data itself
75
     * @param  TransformerAbstract $transformer The transformer class to call
76
     *
77
     * @return ResponseInterface
78
     */
79
    public function respond(string $kind, array $data, TransformerAbstract $transformer)
0 ignored issues
show
Coding Style introduced by
respond uses the super-global variable $_GET which is generally not recommended.

Instead of super-globals, we recommend to explicitly inject the dependencies of your class. This makes your code less dependent on global state and it becomes generally more testable:

// Bad
class Router
{
    public function generate($path)
    {
        return $_SERVER['HOST'].$path;
    }
}

// Better
class Router
{
    private $host;

    public function __construct($host)
    {
        $this->host = $host;
    }

    public function generate($path)
    {
        return $this->host.$path;
    }
}

class Controller
{
    public function myAction(Request $request)
    {
        // Instead of
        $page = isset($_GET['page']) ? intval($_GET['page']) : 1;

        // Better (assuming you use the Symfony2 request)
        $page = $request->query->get('page', 1);
    }
}
Loading history...
80
    {
81
        // Detect what embeds we need
82
        if (!empty($_GET['embed'])) {
83
            $this->getFractalManager()->parseIncludes($_GET['embed']);
84
        }
85
86
        switch ($kind) {
87
            case 'item':
88
                return $this->respondWithItem($data, $transformer);
89
            case 'collection':
90
                return $this->respondWithCollection($data, $transformer);
91
            default:
92
                return $this->respondWithError('No Response was defined. Please report this!', self::CODE_INTERNAL_ERROR);
93
        }
94
    }
95
96
    /**
97
     * Builds an item response in Fractal then hands off to the responder
98
     *
99
     * @param  array               $item        The item to transform
100
     * @param  TransformerAbstract $transformer The Transformer to pass through to Fractal
101
     *
102
     * @return ResponseInterface
103
     */
104
    public function respondWithItem(array $item, TransformerAbstract $transformer)
105
    {
106
        return $this->respondWithData($this->getFractalUtility()->createItem($item, $transformer));
107
    }
108
109
    /**
110
     * Builds a collection of items from Fractal then hands off to the responder
111
     *
112
     * @param  array               $collection  The collection to transform
113
     * @param  TransformerAbstract $transformer The Transformer to pass through to Fractal
114
     *
115
     * @return ResponseInterface
116
     */
117
    public function respondWithCollection(array $collection, TransformerAbstract $transformer)
118
    {
119
        return $this->respondWithData($this->getFractalUtility()->createCollection($collection, $transformer));
120
    }
121
122
    /**
123
     * Responds gracefully with an error.
124
     *
125
     * @param  string $message   Response message to put in the error
126
     * @param  int    $code Error code to set
127
     *
128
     * @return ResponseInterface
129
     */
130
    public function respondWithError(string $message, $code)
131
    {
132
        switch ($code) {
133
            case self::CODE_WRONG_ARGS:
134
                $this->setStatusCode(400);
135
                break;
136
            case self::CODE_UNAUTHORIZED:
137
                $this->setStatusCode(401);
138
                break;
139
            case self::CODE_FORBIDDEN:
140
                $this->setStatusCode(403);
141
                break;
142
            case self::CODE_EMPTY:
143
            case self::CODE_NOT_FOUND:
144
                $this->setStatusCode(404);
145
                break;
146
            case self::CODE_INTERNAL_ERROR:
147
            case self::CODE_EXTERNAL_ERROR:
148
                $this->setStatusCode(500);
149
                break;
150
        }
151
        
152
        if ($this->getStatusCode() === 200) {
153
            trigger_error(
154
                '200 code sent when we\'re attempting to respond with an error!',
155
                E_USER_ERROR
156
            );
157
        }
158
159
        // Pass to responder
160
        return $this->respondWithData([
161
            'error' => [
162
                'code' => $code,
163
                'http_code' => $this->getStatusCode(),
164
                'message' => $message,
165
            ]
166
        ]);
167
    }
168
169
    /**
170
     * The final step where the formatted array is now sent back as a response in JSON form
171
     *
172
     * @param  array $data
173
     *
174
     * @return ResponseInterface
175
     */
176
    public function respondWithData(array $data)
177
    {
178
        $response = $this->getResponse();
179
180
        $response->getBody()->write(json_encode($data));
181
182
        $response = $response->withStatus($this->getStatusCode());
183
        $response = $response->withHeader('Content-Type', 'application/json');
184
        $response = $response->withHeader('X-Redis-Cache-Status', $this->getRedisUtility()->getFlag());
185
        $response = $response->withHeader('X-Redis-Cache-Hits', $this->getRedisUtility()->getHitCount());
186
        $response = $response->withHeader('X-Redis-Cache-Misses', $this->getRedisUtility()->getMissCount());
187
188
        // This is the end of the road. FIRE ZE RESPONSE!
189
        return $response;
190
    }
191
}