CreateAction.php 6.0 KB

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