UpdateAction.php 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159
  1. <?php
  2. /**
  3. * Author: lf
  4. * Blog: https://blog.feehi.com
  5. * Email: job@feehi.com
  6. * Created at: 2017-08-13 00:31
  7. */
  8. namespace backend\actions;
  9. use Yii;
  10. use stdClass;
  11. use Closure;
  12. use backend\actions\helpers\Helper;
  13. use yii\base\Exception;
  14. use yii\web\Response;
  15. use yii\web\UnprocessableEntityHttpException;
  16. /**
  17. * backend update
  18. * if update occurs error, must return model or error string for display error. return true for successful update.
  19. * if GET request, the updateResult be a null, POST request the createResult is the value of doUpdate closure returns.
  20. *
  21. * Class UpdateAction
  22. * @package backend\actions
  23. */
  24. class UpdateAction extends \yii\base\Action
  25. {
  26. const UPDATE_REFERER = "_update_referer";
  27. /**
  28. * @var string|array primary key(s) name
  29. */
  30. public $primaryKeyIdentity = 'id';
  31. /**
  32. * @var string primary keys(s) from (GET or POST)
  33. */
  34. public $primaryKeyFromMethod = "GET";
  35. /**
  36. * @var array|\Closure variables will assigned to view
  37. */
  38. public $data;
  39. /**
  40. * @var string|array success update redirect to url (this value will pass yii::$app->controller->redirect($this->successRedirect) to generate url), default is (GET request) referer url
  41. */
  42. public $successRedirect;
  43. /**
  44. * @var Closure the real update logic, usually will call service layer update method
  45. */
  46. public $doUpdate;
  47. /**
  48. * @var string after success doUpdate tips message showed in page top
  49. */
  50. public $successTipsMessage = "success";
  51. /**
  52. * @var string view template path,default is action id
  53. */
  54. public $viewFile = null;
  55. public function init()
  56. {
  57. parent::init();
  58. if( $this->successTipsMessage === "success"){
  59. $this->successTipsMessage = Yii::t("app", "success");
  60. }
  61. }
  62. /**
  63. * update
  64. *
  65. * @return array|string
  66. * @throws UnprocessableEntityHttpException
  67. * @throws Exception
  68. */
  69. public function run()
  70. {
  71. //according assigned HTTP Method and param name to get value. will be passed to $this->doUpdate closure and $this->data closure.Often use for get value of primary key.
  72. $primaryKeys = Helper::getPrimaryKeys($this->primaryKeyIdentity, $this->primaryKeyFromMethod);
  73. if (Yii::$app->getRequest()->getIsPost()) {//if POST request will execute doUpdate.
  74. if (!$this->doUpdate instanceof Closure) {
  75. throw new Exception(__CLASS__ . "::doUpdate must be closure");
  76. }
  77. $postData = Yii::$app->getRequest()->post();
  78. $updateData = [];//doUpdate closure formal parameter(translate: 传递给doUpdate必包的形参)
  79. if( !empty($primaryKeys) ){
  80. foreach ($primaryKeys as $primaryKey) {
  81. array_push($updateData, $primaryKey);
  82. }
  83. }
  84. array_push($updateData, $postData, $this);
  85. /**
  86. * doUpdate(primaryKey1, primaryKey2 ..., $_POST, UpdateAction)
  87. */
  88. $updateResult = call_user_func_array($this->doUpdate, $updateData);//call doUpdate closure
  89. if( Yii::$app->getRequest()->getIsAjax() ){ //ajax
  90. Yii::$app->getResponse()->format = Response::FORMAT_JSON;
  91. if( $updateResult === true ){//only $updateResult is true represent update success
  92. return ['code'=>0, 'msg'=>'success', 'data'=>new stdClass()];
  93. }else{
  94. throw new UnprocessableEntityHttpException(Helper::getErrorString($updateResult));
  95. }
  96. }else{//not ajax
  97. if( $updateResult === true ){//only $updateResult is true represent update success
  98. Yii::$app->getSession()->setFlash('success', $this->successTipsMessage);
  99. if ($this->successRedirect) return $this->controller->redirect($this->successRedirect);//if $this->successRedirect not empty will redirect to this url
  100. $url = Yii::$app->getSession()->get(self::UPDATE_REFERER);
  101. if ($url) return $this->controller->redirect($url);//get an not empty referer will redirect to this url(often, before do update page. also to say: update page)
  102. return $this->controller->redirect(["index"]);//default is redirect to current controller index action(attention: if current controller has no index action will get a HTTP 404 error)
  103. //if doUpdate success will terminated here!!!
  104. }else{//besides true, all represent update failed.
  105. Yii::$app->getSession()->setFlash('error', Helper::getErrorString($updateResult));//if doUpdate error will set a error description string.and continue the current page.
  106. }
  107. }
  108. }
  109. //if GET request or doUpdate failed, will display the update page.
  110. if (is_array($this->data)) {
  111. $data = $this->data;//this data will assigned to view
  112. } elseif ($this->data instanceof Closure) {
  113. $params = [];
  114. if( !empty($primaryKeys) ){
  115. foreach ($primaryKeys as $primaryKey) {
  116. array_push($params, $primaryKey);
  117. }
  118. }
  119. //GET request just display update page. Only POST request will get a updateResult(returned by doUpdate closure)
  120. !isset($updateResult) && $updateResult = null;
  121. array_push($params, $updateResult, $this);
  122. $data = call_user_func_array($this->data, $params);//this data will assigned to view
  123. } else {
  124. throw new Exception(__CLASS__ . "::data only allows array or closure (with return array)");
  125. }
  126. $this->viewFile === null && $this->viewFile = $this->id;
  127. Yii::$app->getRequest()->getIsGet() && Yii::$app->getSession()->set(self::UPDATE_REFERER, Yii::$app->getRequest()->getReferrer());//set an referer, when success doUpdate may redirect this url
  128. return $this->controller->render($this->viewFile, $data);
  129. }
  130. }