Skip to content

Commit c6c1d6c

Browse files
committed
add checkAccess and prepareRelationships into UpdateRelationshipAction
1 parent ea6fa9c commit c6c1d6c

File tree

5 files changed

+116
-22
lines changed

5 files changed

+116
-22
lines changed

src/actions/UpdateRelationshipAction.php

Lines changed: 48 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -6,19 +6,30 @@
66
namespace tuyakhov\jsonapi\actions;
77

88
use tuyakhov\jsonapi\ResourceInterface;
9+
use yii\base\Model;
910
use yii\data\ActiveDataProvider;
1011
use yii\db\BaseActiveRecord;
1112
use yii\helpers\ArrayHelper;
1213
use yii\rest\Action;
1314
use yii\web\BadRequestHttpException;
1415
use yii\web\NotFoundHttpException;
1516

17+
/**
18+
* UpdateRelationshipAction implements the API endpoint for updating relationships.
19+
* @link http://jsonapi.org/format/#crud-updating-relationships
20+
*/
1621
class UpdateRelationshipAction extends Action
1722
{
1823
/**
19-
* @param $id
20-
* @param $name
21-
* @return array|null|ActiveDataProvider|\yii\db\ActiveRecord|\yii\db\ActiveRecordInterface
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
2233
* @throws BadRequestHttpException
2334
* @throws NotFoundHttpException
2435
*/
@@ -34,22 +45,12 @@ public function run($id, $name)
3445
if (!$related = $model->getRelation($name, false)) {
3546
throw new NotFoundHttpException('Relationship does not exist');
3647
}
37-
$relatedClass = $related->modelClass;
3848

39-
$data = \Yii::$app->getRequest()->getBodyParams();
40-
$data = ArrayHelper::isIndexed($data) ? $data : [$data];
41-
42-
$ids = [];
43-
foreach ($data as $index => $relationshipObject) {
44-
if (!isset($relationshipObject['id'])) {
45-
continue;
46-
}
47-
$ids[] = $relationshipObject['id'];
49+
if ($this->checkAccess) {
50+
call_user_func($this->checkAccess, $this->id, $model, $name);
4851
}
49-
/** @var BaseActiveRecord $relatedClass */
50-
$relationships = $relatedClass::find()
51-
->andWhere(['in', $relatedClass::primaryKey(), $ids])
52-
->all();
52+
53+
$relationships = $this->prepareRelationships($related);
5354

5455
if (!empty($relationships)) {
5556
$model->unlinkAll($name);
@@ -64,4 +65,34 @@ public function run($id, $name)
6465
return $related->one();
6566
}
6667
}
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+
}
6798
}

src/actions/ViewRelatedAction.php

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -37,15 +37,15 @@ public function run($id, $name)
3737
throw new BadRequestHttpException('Impossible to fetch related resource');
3838
}
3939

40-
if ($this->checkAccess) {
41-
call_user_func($this->checkAccess, $this->id, $model);
42-
}
43-
4440
/** @var ActiveQuery $related */
4541
if (!$related = $model->getRelation($name, false)) {
4642
throw new NotFoundHttpException('Resource does not exist');
4743
}
4844

45+
if ($this->checkAccess) {
46+
call_user_func($this->checkAccess, $this->id, $model, $name);
47+
}
48+
4949
if ($this->prepareDataProvider !== null) {
5050
return call_user_func($this->prepareDataProvider, $this, $related);
5151
}
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
<?php
2+
/**
3+
* @author Anton Tuyakhov <atuyakhov@gmail.com>
4+
*/
5+
6+
namespace tuyakhov\jsonapi\tests\actions;
7+
8+
9+
use tuyakhov\jsonapi\actions\UpdateRelationshipAction;
10+
use tuyakhov\jsonapi\tests\data\ActiveQuery;
11+
use tuyakhov\jsonapi\tests\data\ResourceModel;
12+
use tuyakhov\jsonapi\tests\TestCase;
13+
use yii\base\Controller;
14+
use yii\data\ActiveDataProvider;
15+
16+
class UpdateRelationshipActionTest extends TestCase
17+
{
18+
public function testSuccess()
19+
{
20+
$model = new ResourceModel();
21+
$action = new UpdateRelationshipAction('test', new Controller('test', \Yii::$app), [
22+
'modelClass' => ResourceModel::className()
23+
]);
24+
$model->setRelation('multiple', new ActiveQuery(ResourceModel::className(), ['multiple' => true]));
25+
$model->setRelation('single', new ActiveQuery(ResourceModel::className()));
26+
$action->findModel = function ($id, $action) use($model) {
27+
return $model;
28+
};
29+
ActiveQuery::$models = [new ResourceModel(), new ResourceModel()];
30+
\Yii::$app->request->setBodyParams(['ResourceModel' => ['type' => 'resource-models', 'id' => 123]]);
31+
$this->assertInstanceOf(ActiveDataProvider::className(), $dataProvider = $action->run(1, 'multiple'));
32+
$this->assertEquals(2, count($dataProvider->getModels()));
33+
$this->assertInstanceOf(ResourceModel::className(), $action->run(1, 'single'));
34+
}
35+
}

tests/data/ActiveQuery.php

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,22 @@
77

88
class ActiveQuery extends \yii\db\ActiveQuery
99
{
10+
public static $models = [];
11+
1012
public function one($db = null)
1113
{
12-
return new $this->modelClass;
14+
return isset(self::$models[0]) ? self::$models[0] : new $this->modelClass;
1315
}
1416

17+
public function all($db = null)
18+
{
19+
return self::$models;
20+
}
21+
22+
public function count($q = '*', $db = null)
23+
{
24+
return count(self::$models);
25+
}
26+
27+
1528
}

tests/data/ResourceModel.php

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,21 @@ public function setRelation($name, $value)
5252
$this->_related[$name] = $value;
5353
}
5454

55+
public static function find()
56+
{
57+
return new ActiveQuery(self::className());
58+
}
59+
60+
public static function primaryKey()
61+
{
62+
return ['id'];
63+
}
64+
65+
public function unlinkAll()
66+
{
67+
return;
68+
}
69+
5570
public function getLinks()
5671
{
5772
return [

0 commit comments

Comments
 (0)