Completed
Branch FET/rest-relation-endpoints (02db8d)
by
unknown
27:05 queued 18:22
created

Write::getBothModelObjects()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 26

Duplication

Lines 15
Ratio 57.69 %

Importance

Changes 0
Metric Value
cc 2
nc 2
nop 3
dl 15
loc 26
rs 9.504
c 0
b 0
f 0
1
<?php
2
3
namespace EventEspresso\core\libraries\rest_api\controllers\model;
4
5
use DomainException;
6
use EE_DB_Only_Field_Base;
7
use EE_HABTM_Relation;
8
use EE_Model_Relation_Base;
9
use EventEspresso\core\exceptions\InvalidDataTypeException;
10
use EventEspresso\core\exceptions\InvalidInterfaceException;
11
use EventEspresso\core\services\loaders\LoaderFactory;
12
use Exception;
13
use InvalidArgumentException;
14
use ReflectionException;
15
use \WP_REST_Request;
16
use \WP_REST_Response;
17
use EventEspresso\core\libraries\rest_api\Capabilities;
18
use EventEspresso\core\libraries\rest_api\ModelDataTranslator;
19
use EventEspresso\core\libraries\rest_api\RestException;
20
use \EEM_Base;
21
use \EE_Base_Class;
22
use \EE_Registry;
23
use \EE_Datetime_Field;
24
use \EEM_Soft_Delete_Base;
25
use EE_Restriction_Generator_Base;
26
use EED_Core_Rest_Api;
27
use EEH_Inflector;
28
use EE_Error;
29
30
/**
31
 * Write controller for models
32
 * Handles requests relating to GET-ting model information
33
 *
34
 * @package               Event Espresso
35
 * @subpackage
36
 * @author                Mike Nelson
37
 */
38
class Write extends Base
39
{
40
41
42
    public function __construct()
43
    {
44
        parent::__construct();
45
        EE_Registry::instance()->load_helper('Inflector');
46
    }
47
48
49
    /**
50
     * Handles requests to get all (or a filtered subset) of entities for a particular model
51
     *
52
     * @param WP_REST_Request $request
53
     * @param string          $version
54
     * @param string          $model_name
55
     * @return WP_REST_Response|\WP_Error
56
     */
57 View Code Duplication
    public static function handleRequestInsert(WP_REST_Request $request, $version, $model_name)
58
    {
59
        $controller = new Write();
60
        try {
61
            $controller->setRequestedVersion($version);
62
            return $controller->sendResponse(
63
                $controller->insert(
64
                    $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...
65
                    $request
66
                )
67
            );
68
        } catch (Exception $e) {
69
            return $controller->sendResponse($e);
70
        }
71
    }
72
73
74
    /**
75
     * Handles a request from \WP_REST_Server to update an EE model
76
     *
77
     * @param WP_REST_Request $request
78
     * @param string          $version
79
     * @param string          $model_name
80
     * @return WP_REST_Response|\WP_Error
81
     */
82 View Code Duplication
    public static function handleRequestUpdate(WP_REST_Request $request, $version, $model_name)
83
    {
84
        $controller = new Write();
85
        try {
86
            $controller->setRequestedVersion($version);
87
            return $controller->sendResponse(
88
                $controller->update(
89
                    $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...
90
                    $request
91
                )
92
            );
93
        } catch (Exception $e) {
94
            return $controller->sendResponse($e);
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
     * Inserts a new model object according to the $request
126
     *
127
     * @param EEM_Base        $model
128
     * @param WP_REST_Request $request
129
     * @return array
130
     * @throws EE_Error
131
     * @throws RestException
132
     */
133
    public function insert(EEM_Base $model, WP_REST_Request $request)
134
    {
135
        Capabilities::verifyAtLeastPartialAccessTo($model, EEM_Base::caps_edit, 'create');
136
        $default_cap_to_check_for = EE_Restriction_Generator_Base::get_default_restrictions_cap();
137 View Code Duplication
        if (! current_user_can($default_cap_to_check_for)) {
138
            throw new RestException(
139
                'rest_cannot_create_' . EEH_Inflector::pluralize_and_lower(($model->get_this_model_name())),
140
                sprintf(
141
                    esc_html__(
142
                    // @codingStandardsIgnoreStart
143
                        'For now, only those with the admin capability to "%1$s" are allowed to use the REST API to insert data into Event Espresso.',
144
                        // @codingStandardsIgnoreEnd
145
                        'event_espresso'
146
                    ),
147
                    $default_cap_to_check_for
148
                ),
149
                array('status' => 403)
150
            );
151
        }
152
        $submitted_json_data = array_merge((array) $request->get_body_params(), (array) $request->get_json_params());
153
        $model_data = ModelDataTranslator::prepareConditionsQueryParamsForModels(
154
            $submitted_json_data,
155
            $model,
156
            $this->getModelVersionInfo()->requestedVersion(),
157
            true
158
        );
159
        $model_obj = EE_Registry::instance()->load_class(
160
            $model->get_this_model_name(),
161
            array($model_data, $model->get_timezone()),
162
            false,
163
            false
164
        );
165
        $model_obj->save();
166
        $new_id = $model_obj->ID();
167
        if (! $new_id) {
168
            throw new RestException(
169
                'rest_insertion_failed',
170
                sprintf(__('Could not insert new %1$s', 'event_espresso'), $model->get_this_model_name())
171
            );
172
        }
173
        return $this->returnModelObjAsJsonResponse($model_obj, $request);
174
    }
175
176
177
    /**
178
     * Updates an existing model object according to the $request
179
     *
180
     * @param EEM_Base        $model
181
     * @param WP_REST_Request $request
182
     * @return array
183
     * @throws EE_Error
184
     */
185
    public function update(EEM_Base $model, WP_REST_Request $request)
186
    {
187
        Capabilities::verifyAtLeastPartialAccessTo($model, EEM_Base::caps_edit, 'edit');
188
        $default_cap_to_check_for = EE_Restriction_Generator_Base::get_default_restrictions_cap();
189 View Code Duplication
        if (! current_user_can($default_cap_to_check_for)) {
190
            throw new RestException(
191
                'rest_cannot_edit_' . EEH_Inflector::pluralize_and_lower(($model->get_this_model_name())),
192
                sprintf(
193
                    esc_html__(
194
                    // @codingStandardsIgnoreStart
195
                        'For now, only those with the admin capability to "%1$s" are allowed to use the REST API to update data into Event Espresso.',
196
                        // @codingStandardsIgnoreEnd
197
                        'event_espresso'
198
                    ),
199
                    $default_cap_to_check_for
200
                ),
201
                array('status' => 403)
202
            );
203
        }
204
        $obj_id = $request->get_param('id');
205
        if (! $obj_id) {
206
            throw new RestException(
207
                'rest_edit_failed',
208
                sprintf(__('Could not edit %1$s', 'event_espresso'), $model->get_this_model_name())
209
            );
210
        }
211
        $model_data = ModelDataTranslator::prepareConditionsQueryParamsForModels(
212
            $this->getBodyParams($request),
213
            $model,
214
            $this->getModelVersionInfo()->requestedVersion(),
215
            true
216
        );
217
        $model_obj = $model->get_one_by_ID($obj_id);
218 View Code Duplication
        if (! $model_obj instanceof EE_Base_Class) {
219
            $lowercase_model_name = strtolower($model->get_this_model_name());
220
            throw new RestException(
221
                sprintf('rest_%s_invalid_id', $lowercase_model_name),
222
                sprintf(__('Invalid %s ID.', 'event_espresso'), $lowercase_model_name),
223
                array('status' => 404)
224
            );
225
        }
226
        $model_obj->save($model_data);
227
        return $this->returnModelObjAsJsonResponse($model_obj, $request);
228
    }
229
230
231
    /**
232
     * Updates an existing model object according to the $request
233
     *
234
     * @param EEM_Base        $model
235
     * @param WP_REST_Request $request
236
     * @return array of either the soft-deleted item, or
237
     * @throws EE_Error
238
     */
239
    public function delete(EEM_Base $model, WP_REST_Request $request)
240
    {
241
        Capabilities::verifyAtLeastPartialAccessTo($model, EEM_Base::caps_delete, 'delete');
242
        $default_cap_to_check_for = EE_Restriction_Generator_Base::get_default_restrictions_cap();
243 View Code Duplication
        if (! current_user_can($default_cap_to_check_for)) {
244
            throw new RestException(
245
                'rest_cannot_delete_' . EEH_Inflector::pluralize_and_lower(($model->get_this_model_name())),
246
                sprintf(
247
                    esc_html__(
248
                    // @codingStandardsIgnoreStart
249
                        'For now, only those with the admin capability to "%1$s" are allowed to use the REST API to delete data into Event Espresso.',
250
                        // @codingStandardsIgnoreEnd
251
                        'event_espresso'
252
                    ),
253
                    $default_cap_to_check_for
254
                ),
255
                array('status' => 403)
256
            );
257
        }
258
        $obj_id = $request->get_param('id');
259
        // this is where we would apply more fine-grained caps
260
        $model_obj = $model->get_one_by_ID($obj_id);
261 View Code Duplication
        if (! $model_obj instanceof EE_Base_Class) {
262
            $lowercase_model_name = strtolower($model->get_this_model_name());
263
            throw new RestException(
264
                sprintf('rest_%s_invalid_id', $lowercase_model_name),
265
                sprintf(__('Invalid %s ID.', 'event_espresso'), $lowercase_model_name),
266
                array('status' => 404)
267
            );
268
        }
269
        $requested_permanent_delete = filter_var($request->get_param('force'), FILTER_VALIDATE_BOOLEAN);
270
        $requested_allow_blocking = filter_var($request->get_param('allow_blocking'), FILTER_VALIDATE_BOOLEAN);
271
        if ($requested_permanent_delete) {
272
            $previous = $this->returnModelObjAsJsonResponse($model_obj, $request);
273
            $deleted = (bool) $model->delete_permanently_by_ID($obj_id, $requested_allow_blocking);
274
            return array(
275
                'deleted'  => $deleted,
276
                'previous' => $previous,
277
            );
278
        } else {
279
            if ($model instanceof EEM_Soft_Delete_Base) {
280
                $model->delete_by_ID($obj_id, $requested_allow_blocking);
281
                return $this->returnModelObjAsJsonResponse($model_obj, $request);
282
            } else {
283
                throw new RestException(
284
                    'rest_trash_not_supported',
285
                    501,
286
                    sprintf(
287
                        esc_html__('%1$s do not support trashing. Set force=1 to delete.', 'event_espresso'),
288
                        EEH_Inflector::pluralize($model->get_this_model_name())
289
                    )
290
                );
291
            }
292
        }
293
    }
294
295
296
    /**
297
     * Returns an array ready to be converted into a JSON response, based solely on the model object
298
     *
299
     * @param EE_Base_Class   $model_obj
300
     * @param WP_REST_Request $request
301
     * @return array ready for a response
302
     */
303
    protected function returnModelObjAsJsonResponse(EE_Base_Class $model_obj, WP_REST_Request $request)
304
    {
305
        $model = $model_obj->get_model();
306
        // create an array exactly like the wpdb results row,
307
        // so we can pass it to controllers/model/Read::create_entity_from_wpdb_result()
308
        $simulated_db_row = array();
309
        foreach ($model->field_settings(true) as $field_name => $field_obj) {
310
            // we need to reconstruct the normal wpdb results, including the db-only fields
311
            // like a secondary table's primary key. The models expect those (but don't care what value they have)
312
            if ($field_obj instanceof EE_DB_Only_Field_Base) {
313
                $raw_value = true;
314
            } elseif ($field_obj instanceof EE_Datetime_Field) {
315
                $raw_value = $model_obj->get_DateTime_object($field_name);
316
            } else {
317
                $raw_value = $model_obj->get_raw($field_name);
318
            }
319
            $simulated_db_row[ $field_obj->get_qualified_column() ] = $field_obj->prepare_for_use_in_db($raw_value);
320
        }
321
        $read_controller = LoaderFactory::getLoader()->getNew('EventEspresso\core\libraries\rest_api\controllers\model\Read');
322
        $read_controller->setRequestedVersion($this->getRequestedVersion());
323
        // the simulates request really doesn't need any info downstream
324
        $simulated_request = new WP_REST_Request('GET');
325
        // set the caps context on the simulated according to the original request.
326
        switch ($request->get_method()) {
327
            case 'POST':
328
            case 'PUT':
329
                $caps_context = EEM_Base::caps_edit;
330
                break;
331
            case 'DELETE':
332
                $caps_context = EEM_Base::caps_delete;
333
                break;
334
            default:
335
                $caps_context = EEM_Base::caps_read_admin;
336
        }
337
        $simulated_request->set_param('caps', $caps_context);
338
        return $read_controller->createEntityFromWpdbResult(
339
            $model_obj->get_model(),
340
            $simulated_db_row,
341
            $simulated_request
342
        );
343
    }
344
345
346
    /**
347
     * Gets the item affected by this request
348
     *
349
     * @param EEM_Base        $model
350
     * @param WP_REST_Request $request
351
     * @param  int|string     $obj_id
352
     * @return \WP_Error|array
353
     */
354
    protected function getOneBasedOnRequest(EEM_Base $model, WP_REST_Request $request, $obj_id)
355
    {
356
        $requested_version = $this->getRequestedVersion($request->get_route());
357
        $get_request = new WP_REST_Request(
358
            'GET',
359
            EED_Core_Rest_Api::ee_api_namespace
360
            . $requested_version
361
            . '/'
362
            . EEH_Inflector::pluralize_and_lower($model->get_this_model_name())
363
            . '/'
364
            . $obj_id
365
        );
366
        $get_request->set_url_params(
367
            array(
368
                'id'      => $obj_id,
369
                'include' => $request->get_param('include'),
370
            )
371
        );
372
        $read_controller = new Read();
0 ignored issues
show
Bug introduced by
The call to Read::__construct() misses a required argument $fields_calculator.

This check looks for function calls that miss required arguments.

Loading history...
373
        $read_controller->setRequestedVersion($this->getRequestedVersion());
374
        return $read_controller->getEntityFromModel($model, $get_request);
375
    }
376
377
    /**
378
     * Adds a relation between the specified models (if it doesn't already exist.)
379
     * @since $VID:$
380
     * @param WP_REST_Request $request
381
     * @return WP_REST_Response
382
     */
383 View Code Duplication
    public static function handleRequestAddRelation(WP_REST_Request $request, $version, $model_name, $related_model_name)
384
    {
385
        $controller = new Write();
386
        try {
387
            $controller->setRequestedVersion($version);
388
            $main_model = $controller->validateModel($model_name);
389
            $controller->validateModel($related_model_name);
390
            return $controller->sendResponse(
391
                $controller->addRelation(
392
                    $main_model,
393
                    $main_model->related_settings_for($related_model_name),
394
                    $request
395
                )
396
            );
397
        } catch (Exception $e) {
398
            return $controller->sendResponse($e);
399
        }
400
    }
401
402
    /**
403
     * Adds a relation between the two model specified model objects.
404
     * @since $VID:$
405
     * @param EEM_Base $model
406
     * @param EE_Model_Relation_Base $relation
407
     * @param WP_REST_Request $request
408
     * @return array
409
     * @throws EE_Error
410
     * @throws InvalidArgumentException
411
     * @throws InvalidDataTypeException
412
     * @throws InvalidInterfaceException
413
     * @throws RestException
414
     * @throws DomainException
415
     */
416
    public function addRelation(EEM_Base $model, EE_Model_Relation_Base $relation, WP_REST_Request $request)
417
    {
418
        list($model_obj, $other_obj) = $this->getBothModelObjects($model, $relation, $request);
419
        $extra_params = array();
420
        if ($relation instanceof EE_HABTM_Relation) {
421
            $extra_params = array_intersect_key(
422
                ModelDataTranslator::prepareConditionsQueryParamsForModels(
423
                    $request->get_body_params(),
424
                    $relation->get_join_model(),
0 ignored issues
show
Bug introduced by
It seems like $relation->get_join_model() can be null; however, prepareConditionsQueryParamsForModels() 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...
425
                    $this->getModelVersionInfo()->requestedVersion(),
426
                    true
427
                ),
428
                $relation->getNonKeyFields()
429
            );
430
        }
431
        // Add a relation.
432
        $related_obj = $model_obj->_add_relation_to(
433
            $other_obj,
434
            $relation->get_other_model()->get_this_model_name(),
435
            $extra_params
436
        );
437
        $response = array(
438
            strtolower($model->get_this_model_name()) => $this->returnModelObjAsJsonResponse($model_obj, $request),
439
            strtolower($relation->get_other_model()->get_this_model_name()) => $this->returnModelObjAsJsonResponse($related_obj, $request),
440
        );
441
        if ($relation instanceof EE_HABTM_Relation) {
442
            $join_model_obj = $relation->get_join_model()->get_one(
443
                array(
444
                    array(
445
                        $model->primary_key_name() => $model_obj->ID(),
446
                        $relation->get_other_model()->primary_key_name() => $related_obj->ID()
447
                    )
448
                )
449
            );
450
            $response['join'][ strtolower($relation->get_join_model()->get_this_model_name()) ] = $this->returnModelObjAsJsonResponse($join_model_obj, $request);
451
        }
452
        return $response;
453
    }
454
455
456
    /**
457
     * Removes the relation between the specified models (if it exists).
458
     * @since $VID:$
459
     * @param WP_REST_Request $request
460
     * @return WP_REST_Response
461
     */
462 View Code Duplication
    public static function handleRequestRemoveRelation(WP_REST_Request $request, $version, $model_name, $related_model_name)
463
    {
464
        $controller = new Write();
465
        try {
466
            $controller->setRequestedVersion($version);
467
            $main_model = $controller->getModelVersionInfo()->loadModel($model_name);
468
            return $controller->sendResponse(
469
                $controller->removeRelation(
470
                    $main_model,
471
                    $main_model->related_settings_for($related_model_name),
472
                    $request
473
                )
474
            );
475
        } catch (Exception $e) {
476
            return $controller->sendResponse($e);
477
        }
478
    }
479
480
    /**
481
     * Adds a relation between the two model specified model objects.
482
     * @since $VID:$
483
     * @param EEM_Base $model
484
     * @param EE_Model_Relation_Base $relation
485
     * @param WP_REST_Request $request
486
     * @return array
487
     * @throws DomainException
488
     * @throws EE_Error
489
     * @throws InvalidArgumentException
490
     * @throws InvalidDataTypeException
491
     * @throws InvalidInterfaceException
492
     * @throws RestException
493
     */
494
    public function removeRelation(EEM_Base $model, EE_Model_Relation_Base $relation, WP_REST_Request $request)
495
    {
496
        // This endpoint doesn't accept body parameters (it's understandable to think it might, so let developers know
497
        // up-front that it doesn't.)
498
        if (!empty($request->get_body_params())) {
499
            $body_params = $request->get_body_params();
500
            throw new RestException(
501
                'invalid_field',
502
                sprintf(
503
                    esc_html__('This endpoint doesn\'t accept post body arguments, you sent in %1$s', 'event_espresso'),
504
                    implode(array_keys($body_params))
505
                )
506
            );
507
        }
508
        list($model_obj, $other_obj) = $this->getBothModelObjects($model, $relation, $request);
509
        // Remember the old relation, if it used a join entry.
510
        $join_model_obj = null;
511
        if ($relation instanceof EE_HABTM_Relation) {
512
            $join_model_obj = $relation->get_join_model()->get_one(
513
                array(
514
                    array(
515
                        $model->primary_key_name() => $model_obj->ID(),
516
                        $relation->get_other_model()->primary_key_name() => $other_obj->ID()
517
                    )
518
                )
519
            );
520
        }
521
        // Remove the relation.
522
        $related_obj = $model_obj->_remove_relation_to(
523
            $other_obj,
524
            $relation->get_other_model()->get_this_model_name()
525
        );
526
        $response = array(
527
            strtolower($model->get_this_model_name()) => $this->returnModelObjAsJsonResponse($model_obj, $request),
528
            strtolower($relation->get_other_model()->get_this_model_name()) => $this->returnModelObjAsJsonResponse($related_obj, $request),
529
        );
530
        if ($relation instanceof EE_HABTM_Relation) {
531
            $join_model_obj_after_removal = $relation->get_join_model()->get_one(
0 ignored issues
show
Unused Code introduced by
$join_model_obj_after_removal is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
532
                array(
533
                    array(
534
                        $model->primary_key_name() => $model_obj->ID(),
535
                        $relation->get_other_model()->primary_key_name() => $other_obj->ID()
536
                    )
537
                )
538
            );
539
            if ($join_model_obj instanceof EE_Base_Class) {
540
                $response['join'][ strtolower($relation->get_join_model()->get_this_model_name()) ] = $this->returnModelObjAsJsonResponse($join_model_obj, $request);
541
            } else {
542
                $response['join'][ strtolower($relation->get_join_model()->get_this_model_name()) ] = null;
543
            }
544
        }
545
        return $response;
546
    }
547
548
    /**
549
     * Gets the model objects indicated by the model, relation object, and request.
550
     * Throws an exception if the first object doesn't exist, and currently if the related object also doesn't exist.
551
     * However, this behaviour may change, as we may add support for simultaneously creating and relating data.
552
     * @since $VID:$
553
     * @param EEM_Base $model
554
     * @param EE_Model_Relation_Base $relation
555
     * @param WP_REST_Request $request
556
     * @return array {
557
     * @type EE_Base_Class $model_obj
558
     * @type EE_Base_Class|null $other_model_obj
559
     * }
560
     * @throws RestException
561
     */
562
    protected function getBothModelObjects(EEM_Base $model, EE_Model_Relation_Base $relation, WP_REST_Request $request)
563
    {
564
        // Check generic caps. For now, we're only allowing access to this endpoint to full admins.
565
        Capabilities::verifyAtLeastPartialAccessTo($model, EEM_Base::caps_edit, 'edit');
566
        $default_cap_to_check_for = EE_Restriction_Generator_Base::get_default_restrictions_cap();
567 View Code Duplication
        if (! current_user_can($default_cap_to_check_for)) {
568
            throw new RestException(
569
                'rest_cannot_edit_' . EEH_Inflector::pluralize_and_lower(($model->get_this_model_name())),
570
                sprintf(
571
                    esc_html__(
572
                        // @codingStandardsIgnoreStart
573
                        'For now, only those with the admin capability to "%1$s" are allowed to use the REST API to add relations in Event Espresso.',
574
                        // @codingStandardsIgnoreEnd
575
                        'event_espresso'
576
                    ),
577
                    $default_cap_to_check_for
578
                ),
579
                array('status' => 403)
580
            );
581
        }
582
        // Get the main model object.
583
        $model_obj = $this->getOneOrThrowException($model, $request->get_param('id'));
584
        // For now, we require the other model object to exist too. This might be relaxed later.
585
        $other_obj = $this->getOneOrThrowException($relation->get_other_model(), $request->get_param('related_id'));
0 ignored issues
show
Bug introduced by
It seems like $relation->get_other_model() can be null; however, getOneOrThrowException() 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...
586
        return array($model_obj,$other_obj);
587
    }
588
589
    /**
590
     * Gets the model with that ID or throws a REST exception.
591
     * @since $VID:$
592
     * @param EEM_Base $model
593
     * @param $id
594
     * @return EE_Base_Class
595
     * @throws RestException
596
     */
597
    protected function getOneOrThrowException(EEM_Base $model, $id)
598
    {
599
        $model_obj = $model->get_one_by_ID($id);
600
        // @todo: check they can permission for it. For now unnecessary because only full admins can use this endpoint.
601
        if ($model_obj instanceof EE_Base_Class) {
602
            return $model_obj;
603
        }
604
        $lowercase_model_name = strtolower($model->get_this_model_name());
605
        throw new RestException(
606
            sprintf('rest_%s_invalid_id', $lowercase_model_name),
607
            sprintf(__('Invalid %s ID.', 'event_espresso'), $lowercase_model_name),
608
            array('status' => 404)
609
        );
610
    }
611
}
612