Completed
Push — master ( 7d4b49...c115fe )
by Andreas
26:15 queued 26:15
created

midcom_baseclasses_components_handler_rest   A

Complexity

Total Complexity 36

Size/Duplication

Total Lines 265
Duplicated Lines 0 %

Test Coverage

Coverage 32.35%

Importance

Changes 0
Metric Value
eloc 97
dl 0
loc 265
ccs 33
cts 102
cp 0.3235
rs 9.52
c 0
b 0
f 0
wmc 36

14 Methods

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