rootlocal/yii2-crud

View on GitHub
src/actions/CreateAction.php

Summary

Maintainability
A
3 hrs
Test Coverage
B
89%
<?php

namespace rootlocal\crud\actions;

use Yii;
use rootlocal\crud\components\Action;
use yii\web\Response;
use yii\base\ErrorException;
use yii\base\InvalidConfigException;
use yii\db\ActiveRecord;
use Closure;

/**
 * Class CreateAction
 * Creates a new [[ActiveRecord]] model.
 * If creation is successful, the browser will be [[redirect]] to the 'view' page.
 *
 * examples:
 *
 * ```php
 * // lambda function:
 * public function actions()
 * {
 *      'create' => [
 *          'class' => CreateAction::class,
 *          'scenario' => Book::SCENARIO_CREATE,
 *          'model' => function ($scenario) {
 *              return new Book(['scenario' => $scenario]);
 *          }
 *      ]
 * }
 *
 * // string:
 * public function actions()
 * {
 *      'create' => [
 *          'class' => CreateAction::class,
 *          'scenario' => Book::SCENARIO_CREATE,
 *          'model' => Book::class
 *      ]
 * }
 *
 * // ActiveRecord:
 * public function actions()
 * {
 *      'create' => [
 *          'class' => CreateAction::class,
 *          'model' => new Book(['scenario' => $scenario])
 *      ]
 * }
 * ```
 *
 * @property string|ActiveRecord|Closure|array $model ActiveRecord Model
 * @property string|null $scenario scenario for model. Defaults to [[ActiveRecord::SCENARIO_DEFAULT]]
 *
 * @author Alexander Zakharov <sys@eml.ru>
 * @package rootlocal\crud\actions
 */
class CreateAction extends Action
{
    /**
     * @var string|array $redirect the URL to be redirected to. This can be in one of the following formats:
     *
     * - a string representing a URL (e.g. "http://example.com")
     * - a string representing a URL alias (e.g. "@example.com")
     * - an array in the format of `[$route, ...name-value pairs...]` (e.g. `['site/index', 'ref' => 1]`)
     *   [[\yii\helpers\Url::to()]] will be used to convert the array into a URL.
     *
     * Any relative URL that starts with a single forward slash "/" will be converted
     * into an absolute one by prepending it with the host info of the current request.
     *
     * ```php
     * <?= \yii\helpers\Html::a('Create', ['create', 'redirect' => 'index'], [
     * 'class' => 'btn btn-primary btn-sm'
     * ]) ?>
     * ```
     */
    public $redirect;

    /**
     * @var string
     */
    private $_scenario;
    /**
     * @var ActiveRecord
     */
    private $_model;


    /**
     * Runs the action.
     *
     * @param string|null $redirect the URL to be redirected to
     * @return array|string|Response response
     */
    public function run($redirect = null)
    {
        if (Yii::$app->request->isAjax) {
            Yii::$app->response->format = Response::FORMAT_JSON;
        }

        if ($redirect !== null) {
            $this->redirect = $redirect;
        }

        $model = $this->getModel();

        if ($model->load(Yii::$app->request->post()) && $model->validate()) {

            if ($model->save()) {

                Yii::$app->session->setFlash('success',
                    Yii::t('rootlocal/crud', 'Successfully completed'));

                if ($this->redirect === null) {
                    $this->redirect = ['view', 'id' => $model->getPrimaryKey()];
                }

                return Yii::$app->request->isAjax ? ['success' => true]
                    : $this->controller->redirect($this->redirect);
            }

            Yii::$app->session->setFlash('error',
                Yii::t('rootlocal/crud', 'Unable to save Model'));

            return Yii::$app->request->isAjax ? ['success' => false]
                : $this->controller->redirect($this->redirect);
        }


        if (Yii::$app->request->isAjax) {
            return $this->controller->renderAjax($this->getViewName(), ['model' => $model]);
        }

        return $this->controller->render($this->getViewName(), ['model' => $model]);
    }

    /**
     * Get ActiveRecord model
     *
     * @return ActiveRecord ActiveRecord object model
     * @throws ErrorException if Model not specified (not set)
     */
    public function getModel(): ActiveRecord
    {
        if (empty($this->_model)) {
            throw new ErrorException(Yii::t('rootlocal/crud', 'Model not specified'));
        }

        return $this->_model;
    }

    /**
     * Set ActiveRecord model
     *
     * @param string|ActiveRecord|Closure|array $model ActiveRecord model
     * @throws InvalidConfigException if the configuration is invalid
     */
    public function setModel($model): void
    {
        if (is_string($model)) {
            $objectConfig['class'] = $model;
            $objectConfig['scenario'] = $this->getScenario();
            $this->_model = Yii::createObject($objectConfig);
        } else {

            if ($model instanceof ActiveRecord) {
                $this->_model = $model;
            }

            if ($model instanceof Closure || is_array($model)) {
                $this->_model = call_user_func($model, $this->getScenario());
            }
        }

        if ($this->checkAccess && ($this->checkAccess instanceof Closure || is_array($this->checkAccess))) {
            call_user_func($this->checkAccess, $this->id, $this->_model);
        }
    }

    /**
     * Set scenario
     *
     * @param string|null $scenario scenario for model. Defaults to [[ActiveRecord::SCENARIO_DEFAULT]]
     */
    public function setScenario($scenario): void
    {
        $this->_scenario = $scenario;
        $model = $this->getModel();

        if ($model !== null) {
            $model->setScenario($scenario);
        }
    }

    /**
     * Get scenario
     *
     * @return string scenario for model. Defaults to [[ActiveRecord::SCENARIO_DEFAULT]]
     */
    public function getScenario()
    {
        if ($this->_scenario === null) {
            $this->_scenario = ActiveRecord::SCENARIO_DEFAULT;
        }

        return $this->_scenario;
    }
}