Passed
Push — master ( 8c456b...c6c1d6 )
by Anton
03:15
created

UpdateRelationshipAction::run()   B

Complexity

Conditions 6
Paths 10

Size

Total Lines 32
Code Lines 17

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 1
Metric Value
c 1
b 0
f 1
dl 0
loc 32
rs 8.439
cc 6
eloc 17
nc 10
nop 2
1
<?php
2
/**
3
 * @author Anton Tuyakhov <[email protected]>
4
 */
5
6
namespace tuyakhov\jsonapi\actions;
7
8
use tuyakhov\jsonapi\ResourceInterface;
9
use yii\base\Model;
10
use yii\data\ActiveDataProvider;
11
use yii\db\BaseActiveRecord;
12
use yii\helpers\ArrayHelper;
13
use yii\rest\Action;
14
use yii\web\BadRequestHttpException;
15
use yii\web\NotFoundHttpException;
16
17
/**
18
 * UpdateRelationshipAction implements the API endpoint for updating relationships.
19
 * @link http://jsonapi.org/format/#crud-updating-relationships
20
 */
21
class UpdateRelationshipAction extends Action
22
{
23
    /**
24
     * Prepares the relationships to link with primary model.
25
     * @var callable
26
     */
27
    public $prepareRelationships;
28
    /**
29
     * Update of relationships independently.
30
     * @param string $id an ID of the primary resource
31
     * @param string $name a name of the related resource
32
     * @return ActiveDataProvider|BaseActiveRecord
33
     * @throws BadRequestHttpException
34
     * @throws NotFoundHttpException
35
     */
36
    public function run($id, $name)
37
    {
38
        /** @var BaseActiveRecord $model */
39
        $model = $this->findModel($id);
40
41
        if (!$model instanceof ResourceInterface) {
42
            throw new BadRequestHttpException('Impossible to update relationships for resource');
43
        }
44
45
        if (!$related = $model->getRelation($name, false)) {
46
            throw new NotFoundHttpException('Relationship does not exist');
47
        }
48
49
        if ($this->checkAccess) {
50
            call_user_func($this->checkAccess, $this->id, $model, $name);
51
        }
52
53
        $relationships = $this->prepareRelationships($related);
54
55
        if (!empty($relationships)) {
56
            $model->unlinkAll($name);
57
            $model->setResourceRelationship($name, $relationships);
58
        }
59
60
        if ($related->multiple) {
61
            return new ActiveDataProvider([
62
                'query' => $related
63
            ]);
64
        } else {
65
            return $related->one();
66
        }
67
    }
68
69
    protected function prepareRelationships($related)
70
    {
71
        if ($this->prepareRelationships !== null) {
72
            return call_user_func($this->prepareRelationships, $this, $related);
73
        }
74
75
        /** @var BaseActiveRecord $relatedClass */
76
        $relatedClass = new $related->modelClass;
77
78
        $data = \Yii::$app->getRequest()->getBodyParams();
79
        
80
        $data = ArrayHelper::keyExists($relatedClass->formName(), $data) ? $data[$relatedClass->formName()] : [];
81
        
82
        if (!ArrayHelper::isIndexed($data)) {
83
            $data = [$data];
84
        }
85
86
        $ids = [];
87
        foreach ($data as $index => $relationshipObject) {
88
            if (!isset($relationshipObject['id'])) {
89
                continue;
90
            }
91
            $ids[] = $relationshipObject['id'];
92
        }
93
94
        return $relatedClass::find()
95
            ->andWhere(['in', $relatedClass::primaryKey(), $ids])
96
            ->all();
97
    }
98
}