Skip to content

Commit 64a5075

Browse files
committed
add view related action
1 parent 7dcb7ef commit 64a5075

File tree

7 files changed

+201
-54
lines changed

7 files changed

+201
-54
lines changed

src/UpdateRelationshipAction.php

Lines changed: 0 additions & 51 deletions
This file was deleted.
Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
<?php
2+
/**
3+
* @author Anton Tuyakhov <atuyakhov@gmail.com>
4+
*/
5+
6+
namespace tuyakhov\jsonapi\actions;
7+
8+
use tuyakhov\jsonapi\ResourceInterface;
9+
use yii\data\ActiveDataProvider;
10+
use yii\db\BaseActiveRecord;
11+
use yii\helpers\ArrayHelper;
12+
use yii\rest\Action;
13+
use yii\web\BadRequestHttpException;
14+
use yii\web\NotFoundHttpException;
15+
16+
class UpdateRelationshipAction extends Action
17+
{
18+
/**
19+
* @param $id
20+
* @param $name
21+
* @return array|null|ActiveDataProvider|\yii\db\ActiveRecord|\yii\db\ActiveRecordInterface
22+
* @throws BadRequestHttpException
23+
* @throws NotFoundHttpException
24+
*/
25+
public function run($id, $name)
26+
{
27+
/** @var BaseActiveRecord $model */
28+
$model = $this->findModel($id);
29+
30+
if (!$model instanceof ResourceInterface) {
31+
throw new BadRequestHttpException('Impossible to update relationships for resource');
32+
}
33+
34+
if (!$related = $model->getRelation($name, false)) {
35+
throw new NotFoundHttpException('Relationship does not exist');
36+
}
37+
$relatedClass = $related->modelClass;
38+
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'];
48+
}
49+
/** @var BaseActiveRecord $relatedClass */
50+
$relationships = $relatedClass::find()
51+
->andWhere(['in', $relatedClass::primaryKey(), $ids])
52+
->all();
53+
54+
if (!empty($relationships)) {
55+
$model->unlinkAll($name);
56+
$model->setResourceRelationship($name, $relationships);
57+
}
58+
59+
if ($related->multiple) {
60+
return new ActiveDataProvider([
61+
'query' => $related
62+
]);
63+
} else {
64+
return $related->one();
65+
}
66+
}
67+
}

src/actions/ViewRelatedAction.php

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
<?php
2+
/**
3+
* @author Anton Tuyakhov <atuyakhov@gmail.com>
4+
*/
5+
6+
namespace tuyakhov\jsonapi\actions;
7+
8+
9+
use tuyakhov\jsonapi\ResourceInterface;
10+
use yii\data\ActiveDataProvider;
11+
use yii\db\ActiveQuery;
12+
use yii\rest\Action;
13+
use yii\web\BadRequestHttpException;
14+
use yii\web\NotFoundHttpException;
15+
16+
class ViewRelatedAction extends Action
17+
{
18+
/**
19+
* Prepares the data provider that should return the requested collection of the models.
20+
* @var callable
21+
*/
22+
public $prepareDataProvider;
23+
24+
/**
25+
* @param $id
26+
* @param $name
27+
* @return ActiveDataProvider|\yii\db\ActiveRecordInterface
28+
* @throws BadRequestHttpException
29+
* @throws NotFoundHttpException
30+
*/
31+
public function run($id, $name)
32+
{
33+
$model = $this->findModel($id);
34+
35+
if (!$model instanceof ResourceInterface) {
36+
throw new BadRequestHttpException('Impossible to fetch related resource');
37+
}
38+
39+
if ($this->checkAccess) {
40+
call_user_func($this->checkAccess, $this->id, $model);
41+
}
42+
43+
/** @var ActiveQuery $related */
44+
if (!$related = $model->getRelation($name, false)) {
45+
throw new NotFoundHttpException('Resource does not exist');
46+
}
47+
48+
if ($this->prepareDataProvider !== null) {
49+
return call_user_func($this->prepareDataProvider, $this, $related);
50+
}
51+
52+
if ($related->multiple) {
53+
return new ActiveDataProvider([
54+
'query' => $related
55+
]);
56+
} else {
57+
return $related->one();
58+
}
59+
}
60+
}

tests/JsonApiParserTest.php

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,6 @@
11
<?php
22
/**
3-
* @link http://www.stombox.com/
4-
* @copyright Copyright (c) 2015 Stombox LLC
5-
* @license http://www.stombox.com/license/
3+
* @author Anton Tuyakhov <atuyakhov@gmail.com>
64
*/
75

86
namespace tuyakhov\jsonapi\tests;
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
<?php
2+
/**
3+
* @author Anton Tuyakhov <atuyakhov@gmail.com>
4+
*/
5+
namespace tuyakhov\jsonapi\tests\actions;
6+
7+
use tuyakhov\jsonapi\tests\TestCase;
8+
use tuyakhov\jsonapi\actions\ViewRelatedAction;
9+
use yii\base\Controller;
10+
use tuyakhov\jsonapi\tests\data\ResourceModel;
11+
use yii\data\ActiveDataProvider;
12+
use \tuyakhov\jsonapi\tests\data\ActiveQuery;
13+
use yii\web\NotFoundHttpException;
14+
15+
class ViewRelatedActionTest extends TestCase
16+
{
17+
18+
public function testSuccess()
19+
{
20+
$model = new ResourceModel();
21+
$action = new ViewRelatedAction('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+
30+
$this->assertInstanceOf(ActiveDataProvider::className(), $action->run(1, 'multiple'));
31+
$this->assertInstanceOf(ResourceModel::className(), $action->run(1, 'single'));
32+
}
33+
34+
public function testInvalidRelation()
35+
{
36+
$action = new ViewRelatedAction('test', new Controller('test', \Yii::$app), [
37+
'modelClass' => ResourceModel::className()
38+
]);
39+
$action->findModel = function ($id, $action) {
40+
return new ResourceModel();
41+
};
42+
$this->expectException(NotFoundHttpException::class);
43+
$action->run(1, 'invalid');
44+
}
45+
}

tests/data/ActiveQuery.php

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
<?php
2+
/**
3+
* @author Anton Tuyakhov <atuyakhov@gmail.com>
4+
*/
5+
namespace tuyakhov\jsonapi\tests\data;
6+
7+
8+
class ActiveQuery extends \yii\db\ActiveQuery
9+
{
10+
public function one($db = null)
11+
{
12+
return new $this->modelClass;
13+
}
14+
15+
}

tests/data/ResourceModel.php

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
use tuyakhov\jsonapi\ResourceInterface;
99
use tuyakhov\jsonapi\ResourceTrait;
1010
use yii\base\Model;
11+
use yii\db\ActiveQuery;
1112

1213
class ResourceModel extends Model implements ResourceInterface
1314
{
@@ -22,6 +23,8 @@ class ResourceModel extends Model implements ResourceInterface
2223
public $extraField1 = 'testExtra';
2324
public $extraField2 = 42;
2425

26+
private $_related = [];
27+
2528
public function getId()
2629
{
2730
return static::$id;
@@ -36,4 +39,14 @@ public function extraFields()
3639
{
3740
return static::$extraFields;
3841
}
42+
43+
public function getRelation($name)
44+
{
45+
return isset($this->_related[$name]) ? $this->_related[$name] : null;
46+
}
47+
48+
public function setRelation($name, $value)
49+
{
50+
$this->_related[$name] = $value;
51+
}
3952
}

0 commit comments

Comments
 (0)