Passed
Push — master ( 406583...13161f )
by Andreas
10:28
created

bind_data()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 6
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 6

Importance

Changes 0
Metric Value
cc 2
eloc 3
nc 2
nop 0
dl 0
loc 6
ccs 0
cts 4
cp 0
crap 6
rs 10
c 0
b 0
f 0
1
<?php
2
/**
3
 * @copyright CONTENT CONTROL GmbH, http://www.contentcontrol-berlin.de
4
 * @author Jan Floegel
5
 * @package midcom.baseclasses
6
 * @license http://www.gnu.org/licenses/lgpl.html GNU Lesser General
7
 */
8
9
use Symfony\Component\HttpFoundation\JsonResponse;
10
use Symfony\Component\HttpFoundation\Response;
11
use Symfony\Component\HttpFoundation\Request;
12
13
/**
14
 * generic REST handler baseclass
15
 * this needs to be extended by every REST handler in the application
16
 *
17
 * @package midcom.baseclasses
18
 */
19
abstract class midcom_baseclasses_components_handler_rest extends midcom_baseclasses_components_handler
20
{
21
    /**
22
     * storing request data
23
     *
24
     * @var array
25
     */
26
    protected $_request = [];
27
28
    /**
29
     * storing response data
30
     *
31
     * @var array
32
     */
33
    protected $_response;
34
35
    /**
36
     * the response status
37
     *
38
     * @var int
39
     */
40
    protected $_responseStatus = Response::HTTP_INTERNAL_SERVER_ERROR;
41
42
    /**
43
     * @var midcom_core_dbaobject
44
     */
45
    protected $_object;
46
47
    /**
48
     * the request mode (get, create, update, delete)
49
     *
50
     * @var string
51
     */
52
    protected $_mode;
53
54
    /**
55
     * the id or guid of the requested object
56
     *
57
     * @var mixed
58
     */
59
    protected $_id = false;
60
61
    /**
62
     * @inheritDoc
63
     */
64 1
    public function _on_initialize()
65
    {
66
        // try logging in over basic auth
67 1
        midcom::get()->auth->require_valid_user('basic');
68
    }
69
70
    /**
71
     * the base handler that should be pointed to by the routes
72
     */
73 1
    public function _handler_process(Request $request)
74
    {
75 1
        $this->_request['method'] = strtolower($request->getMethod());
76
77 1
        switch ($this->_request['method']) {
78 1
            case 'get':
79
            case 'delete':
80 1
                $this->_request['params'] = $request->query->all();
81 1
                break;
82
            case 'post':
83
                $this->_request['params'] = array_merge($request->request->all(), $request->query->all());
84
                break;
85
            case 'put':
86
                parse_str(file_get_contents('php://input'), $this->_request['params']);
87
                break;
88
        }
89 1
        $this->_request['params'] = array_map('trim', $this->_request['params']);
90
91
        // determine id / guid
92 1
        if (isset($this->_request['params']['id'])) {
93
            $this->_id = (int) $this->_request['params']['id'];
94
        }
95 1
        if (isset($this->_request['params']['guid'])) {
96 1
            $this->_id = $this->_request['params']['guid'];
97
        }
98 1
        return $this->_process_request();
99
    }
100
101
    /**
102
     * retrieve the object based on classname and request parameters
103
     * if we got an id, it will try to find an existing one, otherwise it will create a new one
104
     */
105
    public function retrieve_object() : midcom_core_dbaobject
106
    {
107
        // already got an object
108
        if ($this->_object) {
109
            return $this->_object;
110
        }
111
112
        $classname = $this->get_object_classname();
113
        // create mode
114
        if ($this->_mode == "create") {
115
            $this->_object = new $classname;
116
            return $this->_object;
117
        }
118
119
        // for all other modes, we need an id or guid
120
        if (!$this->_id) {
121
            throw new midcom_error("Missing id / guid for " . $this->_mode . " mode");
122
        }
123
124
        // try finding existing object
125
        $this->_object = new $classname($this->_id);
126
        return $this->_object;
127
    }
128
129
    /**
130
     * binds the request data to the object
131
     */
132
    public function bind_data()
133
    {
134
        $this->_check_object();
135
136
        foreach ($this->_request['params'] as $field => $value) {
137
            $this->_object->{$field} = $value;
138
        }
139
    }
140
141
    /**
142
     * writes the changes to the dba object to the db
143
     */
144
    public function persist_object()
145
    {
146
        $this->_check_object();
147
148
        $stat = false;
149
        if ($this->_mode == "create") {
150
            $stat = $this->_object->create();
151
        }
152
        if ($this->_mode == "update") {
153
            $stat = $this->_object->update();
154
        }
155
156
        if (!$stat) {
157
            throw new midcom_error("Failed to " . $this->_mode . " object, last error was: " . midcom_connection::get_error_string());
158
        }
159
        $this->_responseStatus = Response::HTTP_OK;
160
        $this->_response["id"] = $this->_object->id;
161
        $this->_response["guid"] = $this->_object->guid;
162
        $this->_response["message"] = $this->_mode . " ok";
163
    }
164
165
    /**
166
     * Do the processing: will call the corresponding handler method and set the mode
167
     */
168 1
    protected function _process_request() : JsonResponse
169
    {
170
        try {
171
            // call corresponding method
172 1
            if ($this->_request['method'] == 'get') {
173 1
                $this->_mode = 'get';
174 1
                $this->handle_get();
175
            }
176
            // post and put might be used for create/update
177 1
            if (in_array($this->_request['method'], ['post', 'put'])) {
178
                if ($this->_id) {
179
                    $this->_mode = 'update';
180
                    $this->handle_update();
181
                } else {
182
                    $this->_mode = 'create';
183
                    $this->handle_create();
184
                }
185
            }
186 1
            if ($this->_request['method'] == 'delete') {
187
                $this->_mode = 'delete';
188
                $this->handle_delete();
189
            }
190
191
            // no response has been set
192 1
            if ($this->_response === null) {
193 1
                $this->_stop('Could not handle request, unknown method', 405);
194
            }
195 1
        } catch (midcom_error $e) {
196 1
            $this->_responseStatus = $e->getCode();
197 1
            return $this->_send_response($e->getMessage());
198
        }
199
200 1
        return $this->_send_response();
201
    }
202
203
    /**
204
     * sends the response as json
205
     * containing the current response data
206
     */
207 1
    private function _send_response(string $message = null) : JsonResponse
208
    {
209
        // always add status code and message
210 1
        $this->_response['code'] = $this->_responseStatus;
211 1
        if ($message) {
212 1
            $this->_response['message'] = $message;
213
        }
214 1
        $exporter = new midcom_helper_exporter_json();
215 1
        return JsonResponse::fromJsonString($exporter->array2data($this->_response), $this->_responseStatus);
216
    }
217
218
    /**
219
     * stops the application and outputs the info message with corresponding statuscode
220
     */
221
    protected function _stop(string $message, int $statuscode = Response::HTTP_INTERNAL_SERVER_ERROR)
222
    {
223
        throw new midcom_error($message, $statuscode);
224
    }
225
226
    /**
227
     * helper function for checking if an object has been
228
     * retrieved before using a function that needs one
229
     */
230
    private function _check_object()
231
    {
232
        if (!$this->_object) {
233
            throw new midcom_error("No object given");
234
        }
235
    }
236
237
    /**
238
     * the classname of the object we expect
239
     */
240
    abstract public function get_object_classname() : string;
241
242
    // these RESTful methods might be overwritten, but contain a default implementation
243
    public function handle_get()
244
    {
245
        $this->retrieve_object();
246
        $this->_responseStatus = Response::HTTP_OK;
247
        $this->_response["object"] = $this->_object;
248
        $this->_response["message"] = "get ok";
249
    }
250
251
    public function handle_create()
252
    {
253
        $this->retrieve_object();
254
        $this->bind_data();
255
        $this->persist_object();
256
    }
257
258
    public function handle_update()
259
    {
260
        $this->retrieve_object();
261
        $this->bind_data();
262
        $this->persist_object();
263
    }
264
265
    public function handle_delete()
266
    {
267
        $this->retrieve_object();
268
        if (!$this->_object->delete()) {
269
            throw new midcom_error("Failed to delete object, last error was: " . midcom_connection::get_error_string());
270
        }
271
        // on success, return id
272
        $this->_responseStatus = Response::HTTP_OK;
273
        $this->_response["id"] = $this->_object->id;
274
        $this->_response["guid"] = $this->_object->guid;
275
        $this->_response["message"] = $this->_mode . "ok";
276
    }
277
}
278