Completed
Branch FET-9222-rest-api-writes (b5e9a6)
by
unknown
164:32 queued 152:41
created

Write::delete()   B

Complexity

Conditions 5
Paths 5

Size

Total Lines 66
Code Lines 47

Duplication

Lines 15
Ratio 22.73 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 5
eloc 47
c 1
b 0
f 0
nc 5
nop 2
dl 15
loc 66
rs 8.6045

How to fix   Long Method   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
namespace EventEspresso\core\libraries\rest_api\controllers\model;
3
4
use EE_DB_Only_Field_Base;
5
use \WP_REST_Request;
6
use \WP_REST_Response;
7
use EventEspresso\core\libraries\rest_api\Capabilities;
8
use EventEspresso\core\libraries\rest_api\ModelDataTranslator;
9
use EventEspresso\core\libraries\rest_api\RestException;
10
use \EEM_Base;
11
use \EE_Base_Class;
12
use \EE_Registry;
13
use \EE_Datetime_Field;
14
use \EEM_Soft_Delete_Base;
15
use EE_Restriction_Generator_Base;
16
use EED_Core_Rest_Api;
17
use EEH_Inflector;
18
use EE_Error;
19
20
if (! defined('EVENT_ESPRESSO_VERSION')) {
21
    exit('No direct script access allowed');
22
}
23
24
25
26
/**
27
 * Write controller for models
28
 * Handles requests relating to GET-ting model information
29
 *
30
 * @package               Event Espresso
31
 * @subpackage
32
 * @author                Mike Nelson
33
 */
34
class Write extends Base
35
{
36
37
38
39
    public function __construct()
40
    {
41
        parent::__construct();
42
        EE_Registry::instance()->load_helper('Inflector');
43
    }
44
45
46
47
    /**
48
     * Handles requests to get all (or a filtered subset) of entities for a particular model
49
     *
50
     * @param WP_REST_Request $request
51
     * @param string          $version
52
     * @param string          $model_name
53
     * @return WP_REST_Response|\WP_Error
54
     */
55 View Code Duplication
    public static function handleRequestInsert(WP_REST_Request $request, $version, $model_name)
56
    {
57
        $controller = new Write();
58
        try {
59
            $controller->setRequestedVersion($version);
60
            return $controller->sendResponse(
61
                $controller->insert(
62
                    $controller->getModelVersionInfo()->loadModel($model_name),
0 ignored issues
show
Bug introduced by
It seems like $controller->getModelVer...>loadModel($model_name) can be null; however, insert() does not accept null, maybe add an additional type check?

Unless you are absolutely sure that the expression can never be null because of other conditions, we strongly recommend to add an additional type check to your code:

/** @return stdClass|null */
function mayReturnNull() { }

function doesNotAcceptNull(stdClass $x) { }

// With potential error.
function withoutCheck() {
    $x = mayReturnNull();
    doesNotAcceptNull($x); // Potential error here.
}

// Safe - Alternative 1
function withCheck1() {
    $x = mayReturnNull();
    if ( ! $x instanceof stdClass) {
        throw new \LogicException('$x must be defined.');
    }
    doesNotAcceptNull($x);
}

// Safe - Alternative 2
function withCheck2() {
    $x = mayReturnNull();
    if ($x instanceof stdClass) {
        doesNotAcceptNull($x);
    }
}
Loading history...
63
                    $request
64
                )
65
            );
66
        } catch (\Exception $e) {
67
            return $controller->sendResponse($e);
68
        }
69
    }
70
71
72
73
    /**
74
     * Handles a request from \WP_REST_Server to update an EE model
75
     *
76
     * @param WP_REST_Request $request
77
     * @param string          $version
78
     * @param string          $model_name
79
     * @return WP_REST_Response|\WP_Error
80
     */
81 View Code Duplication
    public static function handleRequestUpdate(WP_REST_Request $request, $version, $model_name)
82
    {
83
        $controller = new Write();
84
        try {
85
            $controller->setRequestedVersion($version);
86
            return $controller->sendResponse(
87
                $controller->update(
88
                    $controller->getModelVersionInfo()->loadModel($model_name),
0 ignored issues
show
Bug introduced by
It seems like $controller->getModelVer...>loadModel($model_name) can be null; however, update() does not accept null, maybe add an additional type check?

Unless you are absolutely sure that the expression can never be null because of other conditions, we strongly recommend to add an additional type check to your code:

/** @return stdClass|null */
function mayReturnNull() { }

function doesNotAcceptNull(stdClass $x) { }

// With potential error.
function withoutCheck() {
    $x = mayReturnNull();
    doesNotAcceptNull($x); // Potential error here.
}

// Safe - Alternative 1
function withCheck1() {
    $x = mayReturnNull();
    if ( ! $x instanceof stdClass) {
        throw new \LogicException('$x must be defined.');
    }
    doesNotAcceptNull($x);
}

// Safe - Alternative 2
function withCheck2() {
    $x = mayReturnNull();
    if ($x instanceof stdClass) {
        doesNotAcceptNull($x);
    }
}
Loading history...
89
                    $request
90
                )
91
            );
92
        } catch (\Exception $e) {
93
            return $controller->sendResponse($e);
94
        }
95
    }
96
97
98
99
    /**
100
     * Deletes a single model object and returns it. Unless
101
     *
102
     * @param WP_REST_Request $request
103
     * @param string          $version
104
     * @param string          $model_name
105
     * @return WP_REST_Response|\WP_Error
106
     */
107 View Code Duplication
    public static function handleRequestDelete(WP_REST_Request $request, $version, $model_name)
108
    {
109
        $controller = new Write();
110
        try {
111
            $controller->setRequestedVersion($version);
112
            return $controller->sendResponse(
113
                $controller->delete(
114
                    $controller->getModelVersionInfo()->loadModel($model_name),
0 ignored issues
show
Bug introduced by
It seems like $controller->getModelVer...>loadModel($model_name) can be null; however, delete() does not accept null, maybe add an additional type check?

Unless you are absolutely sure that the expression can never be null because of other conditions, we strongly recommend to add an additional type check to your code:

/** @return stdClass|null */
function mayReturnNull() { }

function doesNotAcceptNull(stdClass $x) { }

// With potential error.
function withoutCheck() {
    $x = mayReturnNull();
    doesNotAcceptNull($x); // Potential error here.
}

// Safe - Alternative 1
function withCheck1() {
    $x = mayReturnNull();
    if ( ! $x instanceof stdClass) {
        throw new \LogicException('$x must be defined.');
    }
    doesNotAcceptNull($x);
}

// Safe - Alternative 2
function withCheck2() {
    $x = mayReturnNull();
    if ($x instanceof stdClass) {
        doesNotAcceptNull($x);
    }
}
Loading history...
115
                    $request
116
                )
117
            );
118
        } catch (\Exception $e) {
119
            return $controller->sendResponse($e);
120
        }
121
    }
122
123
124
125
    /**
126
     * Inserts a new model object according to the $request
127
     *
128
     * @param EEM_Base        $model
129
     * @param WP_REST_Request $request
130
     * @return array
131
     * @throws EE_Error
132
     * @throws RestException
133
     */
134
    public function insert(EEM_Base $model, WP_REST_Request $request)
135
    {
136
        Capabilities::verifyAtLeastPartialAccessTo($model, EEM_Base::caps_edit, 'create');
137
        $default_cap_to_check_for = EE_Restriction_Generator_Base::get_default_restrictions_cap();
138 View Code Duplication
        if (! current_user_can($default_cap_to_check_for)) {
139
            throw new RestException(
140
                'rest_cannot_create_' . EEH_Inflector::pluralize_and_lower(($model->get_this_model_name())),
141
                sprintf(
142
                    esc_html__(
143
                        // @codingStandardsIgnoreStart
144
                        'For now, only those with the admin capability to "%1$s" are allowed to use the REST API to insert data into Event Espresso.',
145
                        // @codingStandardsIgnoreEnd
146
                        'event_espresso'
147
                    ),
148
                    $default_cap_to_check_for
149
                ),
150
                array('status' => 403)
151
            );
152
        }
153
        $submitted_json_data = array_merge((array)$request->get_body_params(), (array)$request->get_json_params());
154
        $model_data = ModelDataTranslator::prepareConditionsQueryParamsForModels(
155
            $submitted_json_data,
156
            $model,
157
            $this->getModelVersionInfo()->requestedVersion(),
158
            true
159
        );
160
        $model_obj = EE_Registry::instance()->load_class(
161
            $model->get_this_model_name(),
162
            array($model_data, $model->get_timezone()),
163
            false,
164
            false
165
        );
166
        $model_obj->save();
167
        $new_id = $model_obj->ID();
168
        if (! $new_id) {
169
            throw new RestException(
170
                'rest_insertion_failed',
171
                sprintf(__('Could not insert new %1$s', 'event_espresso'), $model->get_this_model_name())
172
            );
173
        }
174
        return $this->returnModelObjAsJsonResponse($model_obj, $request);
175
    }
176
177
178
179
    /**
180
     * Updates an existing model object according to the $request
181
     *
182
     * @param EEM_Base        $model
183
     * @param WP_REST_Request $request
184
     * @return array
185
     * @throws EE_Error
186
     */
187
    public function update(EEM_Base $model, WP_REST_Request $request)
188
    {
189
        Capabilities::verifyAtLeastPartialAccessTo($model, EEM_Base::caps_edit, 'edit');
190
        $default_cap_to_check_for = EE_Restriction_Generator_Base::get_default_restrictions_cap();
191 View Code Duplication
        if (! current_user_can($default_cap_to_check_for)) {
192
            throw new RestException(
193
                'rest_cannot_edit_' . EEH_Inflector::pluralize_and_lower(($model->get_this_model_name())),
194
                sprintf(
195
                    esc_html__(
196
                        // @codingStandardsIgnoreStart
197
                        'For now, only those with the admin capability to "%1$s" are allowed to use the REST API to update data into Event Espresso.',
198
                        // @codingStandardsIgnoreEnd
199
                        'event_espresso'
200
                    ),
201
                    $default_cap_to_check_for
202
                ),
203
                array('status' => 403)
204
            );
205
        }
206
        $obj_id = $request->get_param('id');
207
        if (! $obj_id) {
208
            throw new RestException(
209
                'rest_edit_failed',
210
                sprintf(__('Could not edit %1$s', 'event_espresso'), $model->get_this_model_name())
211
            );
212
        }
213
        $model_data = ModelDataTranslator::prepareConditionsQueryParamsForModels(
214
            $this->getBodyParams($request),
215
            $model,
216
            $this->getModelVersionInfo()->requestedVersion(),
217
            true
218
        );
219
        $model_obj = $model->get_one_by_ID($obj_id);
220
        $model_obj->save($model_data);
221
        return $this->returnModelObjAsJsonResponse($model_obj, $request);
222
    }
223
224
225
226
    /**
227
     * Updates an existing model object according to the $request
228
     *
229
     * @param EEM_Base        $model
230
     * @param WP_REST_Request $request
231
     * @return array of either the soft-deleted item, or
232
     * @throws EE_Error
233
     */
234
    public function delete(EEM_Base $model, WP_REST_Request $request)
235
    {
236
        Capabilities::verifyAtLeastPartialAccessTo($model, EEM_Base::caps_delete, 'delete');
237
        $default_cap_to_check_for = EE_Restriction_Generator_Base::get_default_restrictions_cap();
238 View Code Duplication
        if (! current_user_can($default_cap_to_check_for)) {
239
            throw new RestException(
240
                'rest_cannot_delete_' . EEH_Inflector::pluralize_and_lower(($model->get_this_model_name())),
241
                sprintf(
242
                    esc_html__(
243
                        // @codingStandardsIgnoreStart
244
                        'For now, only those with the admin capability to "%1$s" are allowed to use the REST API to delete data into Event Espresso.',
245
                        // @codingStandardsIgnoreEnd
246
                        'event_espresso'
247
                    ),
248
                    $default_cap_to_check_for
249
                ),
250
                array('status' => 403)
251
            );
252
        }
253
        $obj_id = $request->get_param('id');
254
        $requested_permanent_delete = filter_var($request->get_param('force'), FILTER_VALIDATE_BOOLEAN);
255
        $requested_allow_blocking = filter_var($request->get_param('allow_blocking'), FILTER_VALIDATE_BOOLEAN);
256
        if ($requested_permanent_delete) {
257
            $read_controller = new Read();
258
            $read_controller->setRequestedVersion($this->getRequestedVersion());
259
            $simulated_get_request = new WP_REST_Request('GET', $request->get_route());
260
            $simulated_get_request->set_url_params($request->get_url_params());
261
            $simulated_get_request->set_query_params(
262
                array(
263
                    'caps' => EEM_Base::caps_delete
264
                )
265
            );
266
            //not just grab the entity, but also use sendResponse to verify in case there's an error retrieving it
267
            $original_response = $read_controller->sendResponse(
268
                $read_controller->getOneOrReportPermissionError(
269
                    $model,
270
                    $simulated_get_request,
271
                    EEM_Base::caps_delete
272
                )
273
            );
274
            if ($original_response instanceof WP_REST_Response) {
0 ignored issues
show
Bug introduced by
The class WP_REST_Response does not exist. Is this class maybe located in a folder that is not analyzed, or in a newer version of your dependencies than listed in your composer.lock/composer.json?
Loading history...
275
                $original_entity = $original_response->get_data();
276
            } else {
277
                $original_entity = null;
278
            }
279
            $deleted = (bool)$model->delete_permanently_by_ID($obj_id, $requested_allow_blocking);
280
            return array(
281
                'deleted'  => $deleted,
282
                'previous' => $original_entity,
283
            );
284
        } else {
285
            if ($model instanceof EEM_Soft_Delete_Base) {
286
                $model->delete_by_ID($obj_id, $requested_allow_blocking);
287
                return $this->getOneBasedOnRequest($model, $request, $obj_id);
288
            } else {
289
                throw new RestException(
290
                    'rest_trash_not_supported',
291
                    501,
292
                    sprintf(
293
                        esc_html__('%1$s do not support trashing. Set force=1 to delete.', 'event_espresso'),
294
                        EEH_Inflector::pluralize($model->get_this_model_name())
295
                    )
296
                );
297
            }
298
        }
299
    }
300
301
302
303
    /**
304
     * Returns an array ready to be converted into a JSON response, based solely on the model object
305
     *
306
     * @param EE_Base_Class $model_obj
307
     * @param WP_REST_Request $request
308
     * @return array ready for a response
309
     */
310
    protected function returnModelObjAsJsonResponse(EE_Base_Class $model_obj, WP_REST_Request $request)
311
    {
312
        $model = $model_obj->get_model();
313
        //create an array exactly like the wpdb results row,
314
        // so we can pass it to controllers/model/Read::create_entity_from_wpdb_result()
315
        $simulated_db_row = array();
316
        foreach ($model->field_settings(true) as $field_name => $field_obj) {
317
            //we need to reconstruct the normal wpdb results, including the db-only fields
318
            //like a secondary table's primary key. The models expect those (but don't care what value they have)
319
            if( $field_obj instanceof EE_DB_Only_Field_Base){
320
                $raw_value = true;
321
            } elseif ($field_obj instanceof EE_Datetime_Field) {
322
                $raw_value = $model_obj->get_DateTime_object($field_name);
323
            } else {
324
                $raw_value = $model_obj->get_raw($field_name);
325
            }
326
            $simulated_db_row[$field_obj->get_qualified_column()] = $field_obj->prepare_for_use_in_db($raw_value);
327
        }
328
        $read_controller = new Read();
329
        $read_controller->setRequestedVersion($this->getRequestedVersion());
330
        //the simulates request really doesn't need any info downstream
331
        $simulated_request = new WP_REST_Request('GET');
332
        return $read_controller->createEntityFromWpdbResult(
333
            $model_obj->get_model(),
0 ignored issues
show
Bug introduced by
It seems like $model_obj->get_model() can be null; however, createEntityFromWpdbResult() does not accept null, maybe add an additional type check?

Unless you are absolutely sure that the expression can never be null because of other conditions, we strongly recommend to add an additional type check to your code:

/** @return stdClass|null */
function mayReturnNull() { }

function doesNotAcceptNull(stdClass $x) { }

// With potential error.
function withoutCheck() {
    $x = mayReturnNull();
    doesNotAcceptNull($x); // Potential error here.
}

// Safe - Alternative 1
function withCheck1() {
    $x = mayReturnNull();
    if ( ! $x instanceof stdClass) {
        throw new \LogicException('$x must be defined.');
    }
    doesNotAcceptNull($x);
}

// Safe - Alternative 2
function withCheck2() {
    $x = mayReturnNull();
    if ($x instanceof stdClass) {
        doesNotAcceptNull($x);
    }
}
Loading history...
334
            $simulated_db_row,
335
            $simulated_request
336
        );
337
    }
338
339
340
341
    /**
342
     * Gets the item affected by this request
343
     *
344
     * @param EEM_Base        $model
345
     * @param WP_REST_Request $request
346
     * @param  int|string     $obj_id
347
     * @return \WP_Error|array
348
     */
349
    protected function getOneBasedOnRequest(EEM_Base $model, WP_REST_Request $request, $obj_id)
350
    {
351
        $requested_version = $this->getRequestedVersion($request->get_route());
352
        $get_request = new WP_REST_Request(
353
            'GET',
354
            EED_Core_Rest_Api::ee_api_namespace
355
            . $requested_version
356
            . '/'
357
            . EEH_Inflector::pluralize_and_lower($model->get_this_model_name())
358
            . '/'
359
            . $obj_id
360
        );
361
        $get_request->set_url_params(
362
            array(
363
                'id'      => $obj_id,
364
                'include' => $request->get_param('include'),
365
            )
366
        );
367
        $read_controller = new Read();
368
        $read_controller->setRequestedVersion($this->getRequestedVersion());
369
        return $read_controller->getEntityFromModel($model, $get_request);
370
    }
371
}
372
// End of file Read.php
373