gabaros
gabaros

Reputation: 763

Yii2 rest save multiple models

Using a REST approach I want to be able to save more than one model in a single action.

class MyController extends ActiveController {
    public $modelClass = 'models\MyModel';
}

class MyModel extends ActiveRecord { 
 ...
}

That automagically creates actions for a REST api. The problem is that I want to save more than one model, using only that code in a POST will result in a new record just for MyModel. What if I need to save AnotherModel?

Thanks for any suggestion.

Upvotes: 2

Views: 2452

Answers (2)

Salem Ouerdani
Salem Ouerdani

Reputation: 7916

ActiveController implements a common set of basic actions for supporting RESTful access to ActiveRecord. For more advanced use you will need to override them or just merge to them your own custom actions where you will be implementing your own code & logic.

Check in your app the /vendor/yiisoft/yii2/rest/ folder to see how ActiveController is structured and what is doing each of its actions.

Now to start by overriding an ActiveController's action by a custom one, you can do it within your controller. Here is a first example where i'm overriding the createAction:

1-

class MyController extends ActiveController
{
    public $modelClass = 'models\MyModel';

    public function actions()
    {
        $actions = parent::actions();
        unset($actions['create']);
        return $actions;
    }

    public function actionCreate(){
        // your code
    }
} 

2-

Or you can follow the ActiveController's structure which you can see in /vendor/yiisoft/yii2/rest/ActiveController.php by placing your custom actions in separate files. Here is an example where I'm overriding the updateAction by a custom one where i'm initializing its parameters from myController class :

class MyController extends ActiveController
{
    public $modelClass = 'models\MyModel';

    public function actions() {

        $actions = parent::actions();

        $custom_actions = [
            'update' => [
                'class' => 'app\controllers\actions\WhateverAction',
                'modelClass' => $this->modelClass,
                'checkAccess' => [$this, 'checkAccess'],
                'scenario' => $this->updateScenario,
                'params'      => \Yii::$app->request->bodyParams,
            ],
        ];

        return array_merge($actions, $custom_actions);
    }
}

Now let's say as example that in my new action file app\controllers\actions\WhateverAction.php I'm expecting the Post Request (which i'm storing in $params) to have a subModels attribute storing a list of child models to which I'm going to apply some extra code like relating them with their parent model if they already exists in first place :

namespace app\controllers\actions;

use Yii;
use yii\base\Model;
use yii\db\ActiveRecord;
use yii\web\ServerErrorHttpException;
use yii\rest\Action;
use app\models\YourSubModel;

class WhateverAction extends Action
{

    public $scenario = Model::SCENARIO_DEFAULT;
    public $params;

    public function run($id)
    {
        $model = $this->findModel($id);

        if ($this->checkAccess) {
            call_user_func($this->checkAccess, $this->id, $model);
        }

        $model->scenario = $this->scenario;
        $model->load($this->params, '');

        foreach ($this->params["subModels"] as $subModel) {
          /**
            * your code related to each of your model's posted child
            * for example those lines will relate each child model
            * to the parent model by saving that to database as their
            * relationship has been defined in their respective models (many_to_many or one_to_many)
            *
            **/
            $subModel = YourSubModel::findOne($subModel['id']);
            if (!$subModel) throw new ServerErrorHttpException('Failed to update due to unknown related objects.');
            $subModel->link('myParentModelName', $model);
            //...
        }

        // ...

        return $model;
    }
}

Upvotes: 4

n099y
n099y

Reputation: 414

So if I understand you wish to add a new database entry not only for the model you are querying, but for another model.

The best place to do this would be in the AfterSave() or BeforeSave() functions of the first model class. Which one would depend on the data you are saving.

Upvotes: 0

Related Questions