创建可重用控制器动作

常用的动作,例如通过主键删除AR模型,或者从AJAX autocomplete获取数据,可以移到可复用控制器动作中,然后附加到需要的控制器上。

在这个小节中,我们将会创建一个可复用删除动作,它会通过主键删除指定的AR模型。

准备

  1. 按照官方指南http://www.yiiframework.com/doc-2.0/guide-start-installation.html的描述,使用Composer包管理器创建一个新的yii2-app-basic应用。
  2. 创建一个新的数据库并配置它。
  3. 创建并应用如下migration:
  1. <?php
  2. use yii\db\Migration;
  3. class m160308_093233_create_post_table extends Migration
  4. {
  5. public function up()
  6. {
  7. $this->createTable('{{%post}}', [
  8. 'id' => $this->primaryKey(),
  9. 'title' => $this->string()->notNull(),
  10. 'text' => $this->text()->notNull(),
  11. ]);
  12. }
  13. public function down()
  14. {
  15. $this->dropTable('{{%post}}');
  16. }
  17. }
  1. 使用Gii为帖子和评论生成模型。
  2. 在Gii中生成标准的CRUD控制器app\controllers\PostController
  3. 确保CRUD正常工作:

创建可重用控制器动作 - 图1

  1. 在一个成功的例子中,添加一些帖子示例。

如何做…

执行如下步骤:

  1. 创建动作文件夹,添加DeleteAction独立动作:
  1. <?php
  2. namespace app\actions;
  3. use yii\base\Action;
  4. use yii\base\InvalidConfigException;
  5. use yii\web\MethodNotAllowedHttpException;
  6. use yii\web\NotFoundHttpException;
  7. class DeleteAction extends Action
  8. {
  9. public $modelClass;
  10. public $redirectTo = ['index'];
  11. public function init()
  12. {
  13. if (empty($this->modelClass)) {
  14. throw new InvalidConfigException('Empty model class.');
  15. }
  16. parent::init();
  17. }
  18. public function run($id)
  19. {
  20. if (!\Yii::$app->getRequest()->getIsPost()) {
  21. throw new MethodNotAllowedHttpException('Method not allowed.');
  22. }
  23. $model = $this->findModel($id);
  24. $model->delete();
  25. return $this->controller->redirect($this->redirectTo);
  26. }
  27. /**
  28. * @param $id
  29. * @return \yii\db\ActiveRecord
  30. * @throws NotFoundHttpException
  31. */
  32. private function findModel($id)
  33. {
  34. $class = $this->modelClass;
  35. if (($model = $class::findOne($id)) !== null) {
  36. return $model;
  37. } else {
  38. throw new NotFoundHttpException('Page does not exist.');
  39. }
  40. }
  41. }
  1. 现在我们需要将它附加到controllers/PostController.php控制器中。移除控制器的actionDeletebehaviors方法,并在actions方法中附加你自己的动作:
  1. <?php
  2. namespace app\controllers;
  3. use app\actions\DeleteAction;
  4. use Yii;
  5. use app\models\Post;
  6. use app\models\PostSearch;
  7. use yii\web\Controller;
  8. use yii\web\NotFoundHttpException;
  9. class PostController extends Controller
  10. {
  11. public function actions()
  12. {
  13. return [
  14. 'delete' => [
  15. 'class' => DeleteAction::className(),
  16. 'modelClass' => Post::className(),
  17. ],
  18. ];
  19. }
  20. public function actionIndex() { ... }
  21. public function actionView($id) { ... }
  22. public function actionCreate() { ... }
  23. public function actionUpdate($id) { ... }
  24. protected function findModel($id)
  25. {
  26. if (($model = Post::findOne($id)) !== null) {
  27. return $model;
  28. } else {
  29. throw new NotFoundHttpException('The requested page does not exist.');
  30. }
  31. }
  32. }
  1. 完成了。确保删除操作可以正常工作,并且在删除之后,你将会被重定向到一个对应的index动作中。

工作原理…

为了创建一个额外的控制器动作,你需要从yii\base\Action中继承你的类。唯一需要强制实现的方法是run。在我们的例子中,它使用Yii的自动参数绑定特性,从$_GET接收名叫$id的参数,并尝试删除一个对应的模型。

为了是它可配置,我们创建了两个可配置的公共属性。modelName保存了模型的名称,以及redirectTo指定了用户会被重定向的路由。

这个配置本身是通过在你的控制器中实现动作方法来完成的。这里,你可以附加这个动作一次或者多次,并配置它的公共属性。

如果你需要重定向到别的动作,或者渲染一个指定的视图,你可以通过控制器属性,访问原始的控制器对象。

参考