Completed
Push — master ( 930ec3...37c441 )
by Evgeny
03:09
created

JSendRenderer   A

Complexity

Total Complexity 18

Size/Duplication

Total Lines 166
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 8

Test Coverage

Coverage 85.45%

Importance

Changes 0
Metric Value
dl 0
loc 166
ccs 47
cts 55
cp 0.8545
rs 10
c 0
b 0
f 0
wmc 18
lcom 1
cbo 8

8 Methods

Rating   Name   Duplication   Size   Complexity  
A accept() 0 6 3
A response() 0 18 2
A error() 0 14 2
A _format() 0 11 3
A _success() 0 4 1
A _fail() 0 4 1
A _error() 0 13 2
A _mapStatus() 0 9 4
1
<?php
2
/**
3
 * Copyright 2016, Cake Development Corporation (http://cakedc.com)
4
 *
5
 * Licensed under The MIT License
6
 * Redistributions of files must retain the above copyright notice.
7
 *
8
 * @copyright Copyright 2016, Cake Development Corporation (http://cakedc.com)
9
 * @license MIT License (http://www.opensource.org/licenses/mit-license.php)
10
 */
11
12
namespace CakeDC\Api\Service\Renderer;
13
14
use CakeDC\Api\Exception\ValidationException;
15
use CakeDC\Api\Service\Action\Result;
16
use Cake\Core\Configure;
17
use Cake\Utility\Hash;
18
use Exception;
19
use stdClass;
20
21
/**
22
 * Class JSendRenderer
23
 * JSend content negotiation Renderer.
24
 *
25
 * @package CakeDC\Api\Service\Renderer
26
 */
27
class JSendRenderer extends BaseRenderer
28
{
29
30
    /**
31
     * Success status.
32
     */
33
    const STATUS_SUCCESS = 'success';
34
35
    /**
36
     * Fail status.
37
     */
38
    const STATUS_FAIL = 'fail';
39
40
    /**
41
     * Error status.
42
     */
43
    const STATUS_ERROR = 'error';
44
45
    /**
46
     * Response status.
47
     */
48
    public $status = self::STATUS_SUCCESS;
49
50
    /**
51
     * HTTP error code.
52
     */
53
    public $errorCode = 200;
54
55
    /**
56
     * Confirms if the specified content type is acceptable for the response.
57
     *
58
     * @return bool
59
     */
60
    public function accept()
61
    {
62
        $request = $this->_service->request();
63
64
        return ($request->accepts('application/json') || $request->accepts('text/json') || $request->accepts('text/javascript'));
65
    }
66
67
    /**
68
     * Builds the HTTP response.
69
     *
70
     * @param Result $result The result object returned by the Service.
71
     * @return bool
72
     */
73 53
    public function response(Result $result = null)
74
    {
75 53
        $response = $this->_service->response();
76 53
        $response->statusCode($result->code());
0 ignored issues
show
Bug introduced by
It seems like $result is not always an object, but can also be of type null. Maybe add an additional type check?

If a variable is not always an object, we recommend to add an additional type check to ensure your method call is safe:

function someFunction(A $objectMaybe = null)
{
    if ($objectMaybe instanceof A) {
        $objectMaybe->doSomething();
    }
}
Loading history...
77 53
        $response->type('application/json');
78 53
        $data = $result->data();
79 53
        $payload = $result->payload();
80
        $return = [
81
            'data' => $data
82 53
        ];
83 53
        if (is_array($payload)) {
84 53
            $return = Hash::merge($return, $payload);
85 53
        }
86 53
        $this->_mapStatus($result);
0 ignored issues
show
Bug introduced by
It seems like $result defined by parameter $result on line 73 can be null; however, CakeDC\Api\Service\Rende...dRenderer::_mapStatus() does not accept null, maybe add an additional type check?

It seems like you allow that null is being passed for a parameter, however the function which is called does not seem to accept null.

We recommend to add an additional type check (or disallow null for the parameter):

function notNullable(stdClass $x) { }

// Unsafe
function withoutCheck(stdClass $x = null) {
    notNullable($x);
}

// Safe - Alternative 1: Adding Additional Type-Check
function withCheck(stdClass $x = null) {
    if ($x instanceof stdClass) {
        notNullable($x);
    }
}

// Safe - Alternative 2: Changing Parameter
function withNonNullableParam(stdClass $x) {
    notNullable($x);
}
Loading history...
87 53
        $response->body($this->_format($this->status, $return));
88
89 53
        return true;
90
    }
91
92
    /**
93
     * Processes an exception thrown while processing the request.
94
     *
95
     * @param Exception $exception The exception object.
96
     * @return void
97
     */
98 9
    public function error(Exception $exception)
99
    {
100 9
        $response = $this->_service->response();
101 9
        $response->type('application/json');
102 9
        if ($exception instanceof ValidationException) {
103 1
            $data = $exception->getValidationErrors();
104 1
        } else {
105 8
            $data = null;
106
        }
107 9
        $message = $this->_buildMessage($exception);
108 9
        $trace = $this->_stackTrace($exception);
109 9
        $response->statusCode((int)$this->errorCode);
110 9
        $response->body($this->_error($message, $exception->getCode(), $data, $trace));
111 9
    }
112
113
    /**
114
     * Formats a response to JSend specification.
115
     *
116
     * @param string $status The status of the response.
117
     * @param array $response The response properties.
118
     * @return string
119
     */
120 58
    protected function _format($status, $response = [])
121
    {
122 58
        $object = new stdClass();
123 58
        $object->status = $status;
124 58
        foreach ($response as $param => $value) {
125 58
            $object->{$param} = $value;
126 58
        }
127 58
        $format = Configure::read('debug') ? JSON_PRETTY_PRINT : 0;
128
129 58
        return json_encode($object, $format);
130
    }
131
132
    /**
133
     * Creates a successful response.
134
     *
135
     * @param array $data The response data object.
136
     * @return string
137
     */
138
    protected function _success($data = null)
139
    {
140
        return $this->_format(self::STATUS_SUCCESS, ['data' => $data]);
141
    }
142
143
    /**
144
     * Creates a failure response.
145
     *
146
     * @param array $data The response data object.
147
     * @return string
148
     */
149
    protected function _fail($data = null)
150
    {
151
        return $this->_format(self::STATUS_FAIL, ['data' => $data]);
152
    }
153
154
    /**
155
     * Creates an error response.
156
     *
157
     * @param string $message The error message.
158
     * @param int $code The error code.
159
     * @param array $data The response data object.
160
     * @param array $trace The exception trace
161
     * @return string
162
     */
163 9
    protected function _error($message = 'Unknown error', $code = 0, $data = null, $trace = null)
164
    {
165
        $response = [
166 9
            'message' => $message,
167 9
            'code' => $code,
168
            'data' => $data
169 9
        ];
170 9
        if (Configure::read('debug') > 0) {
171 8
            $response['trace'] = $trace;
172 8
        }
173
174 9
        return $this->_format(self::STATUS_ERROR, $response);
175
    }
176
177
    /**
178
     * Update status based on result code
179
     *
180
     * @param Result $result
181
     * @return void
182
     */
183 53
    protected function _mapStatus(Result $result)
184
    {
185 53
        $code = (int)$result->code();
186 53
        if ($code == 0 || $code >= 200 && $code <= 399) {
187 53
            $this->status = self::STATUS_SUCCESS;
188 53
        } else {
189
            $this->status = self::STATUS_ERROR;
190
        }
191 53
    }
192
}
193