1
|
|
|
<?php |
2
|
|
|
/** |
3
|
|
|
* @author Anton Tuyakhov <[email protected]> |
4
|
|
|
*/ |
5
|
|
|
|
6
|
|
|
namespace tuyakhov\jsonapi\actions; |
7
|
|
|
|
8
|
|
|
use Yii; |
9
|
|
|
use yii\data\ActiveDataProvider; |
10
|
|
|
use yii\db\ActiveRecordInterface; |
11
|
|
|
use yii\db\ActiveRelationTrait; |
12
|
|
|
use yii\db\BaseActiveRecord; |
13
|
|
|
use yii\helpers\ArrayHelper; |
14
|
|
|
use yii\web\ForbiddenHttpException; |
15
|
|
|
use yii\web\NotFoundHttpException; |
16
|
|
|
|
17
|
|
|
/** |
18
|
|
|
* Deletes the specified members from a relationship |
19
|
|
|
* @link http://jsonapi.org/format/#crud-updating-relationships |
20
|
|
|
*/ |
21
|
|
|
class DeleteRelationshipAction extends Action |
22
|
|
|
{ |
23
|
|
|
/** |
24
|
|
|
* Removes the relationships from primary model. |
25
|
|
|
* @var callable |
26
|
|
|
*/ |
27
|
|
|
public $unlinkRelationships; |
28
|
|
|
|
29
|
|
|
/** |
30
|
|
|
* @param string $id an ID of the primary resource |
31
|
|
|
* @param string $name a name of the related resource |
32
|
|
|
* @return ActiveDataProvider |
33
|
|
|
* @throws ForbiddenHttpException |
34
|
|
|
* @throws NotFoundHttpException |
35
|
|
|
* @throws \yii\base\InvalidConfigException |
36
|
|
|
*/ |
37
|
|
View Code Duplication |
public function run($id, $name) |
|
|
|
|
38
|
|
|
{ |
39
|
|
|
/** @var BaseActiveRecord $model */ |
40
|
|
|
$model = $this->findModel($id); |
41
|
|
|
|
42
|
|
|
if (!$related = $model->getRelation($name, false)) { |
43
|
|
|
throw new NotFoundHttpException('Relationship does not exist'); |
44
|
|
|
} |
45
|
|
|
|
46
|
|
|
if (!$related->multiple) { |
|
|
|
|
47
|
|
|
throw new ForbiddenHttpException('Unsupported request to update relationship'); |
48
|
|
|
} |
49
|
|
|
|
50
|
|
|
if ($this->checkAccess) { |
51
|
|
|
call_user_func($this->checkAccess, $this->id, $model, $name); |
52
|
|
|
} |
53
|
|
|
|
54
|
|
|
$this->unlinkRelationships($model, [$name => Yii::$app->getRequest()->getBodyParams()]); |
55
|
|
|
|
56
|
|
|
|
57
|
|
|
return new ActiveDataProvider([ |
58
|
|
|
'query' => $related |
59
|
|
|
]); |
60
|
|
|
} |
61
|
|
|
|
62
|
|
|
/** |
63
|
|
|
* Removes the relationships from primary model. |
64
|
|
|
* @param $model ActiveRecordInterface |
65
|
|
|
* @param array $data relationship links |
66
|
|
|
*/ |
67
|
|
|
protected function unlinkRelationships($model, array $data = []) |
68
|
|
|
{ |
69
|
|
|
if ($this->unlinkRelationships !== null) { |
70
|
|
|
call_user_func($this->unlinkRelationships, $this, $model, $data); |
71
|
|
|
return; |
72
|
|
|
} |
73
|
|
|
|
74
|
|
|
foreach ($data as $name => $relationship) { |
75
|
|
|
/** @var $related ActiveRelationTrait */ |
76
|
|
|
if (!$related = $model->getRelation($name, false)) { |
77
|
|
|
continue; |
78
|
|
|
} |
79
|
|
|
/** @var BaseActiveRecord $relatedClass */ |
80
|
|
|
$relatedClass = new $related->modelClass; |
|
|
|
|
81
|
|
|
$relationships = ArrayHelper::keyExists($relatedClass->formName(), $relationship) ? $relationship[$relatedClass->formName()] : []; |
82
|
|
|
|
83
|
|
|
$ids = []; |
84
|
|
View Code Duplication |
foreach ($relationships as $index => $relObject) { |
|
|
|
|
85
|
|
|
if (!isset($relObject['id'])) { |
86
|
|
|
continue; |
87
|
|
|
} |
88
|
|
|
$ids[] = $relObject['id']; |
89
|
|
|
} |
90
|
|
|
|
91
|
|
|
$records = $relatedClass::find()->andWhere(['in', $relatedClass::primaryKey(), $ids])->all(); |
92
|
|
|
foreach ($records as $record) { |
93
|
|
|
$model->unlink($name, $record); |
94
|
|
|
} |
95
|
|
|
} |
96
|
|
|
} |
97
|
|
|
} |
Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.
You can also find more detailed suggestions in the “Code” section of your repository.