Completed
Push — master ( 53b39a...145473 )
by Andreas
16:13
created

retrieve_object()   A

Complexity

Conditions 4
Paths 4

Size

Total Lines 22
Code Lines 10

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 20

Importance

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