перенаправить на предыдущий адрес, с которого данные формы были отправлены с моделью в yii2

Я создал виджет для отображения формы в разделе нижнего колонтитула layouts/main.php.

Это файл виджета с именем common\widget\SubscriberFormWidget.php.

<?php
namespace common\widgets;

use Yii;
use yii\base\Widget;
use common\models\Subscriber;

class SubscriberFormWidget extends Widget
{

    /**
      *@return string
      */

    public function run()
    {
        $model = new Subscriber();
         return $this->render('_form', [
            'model' => $model
        ]);
    }
}

Это файл _form, используемый в приведенном выше виджете, расположенный в common\widget\views\_form.php.

<?php

use yii\helpers\Html;
use yii\widgets\ActiveForm;

/* @var $this yii\web\View */
/* @var $model common\models\Subscriber */
/* @var $form yii\widgets\ActiveForm */
?>

    <?php $form = ActiveForm::begin(['action' => ['subscriber/subscribe']]); ?>
    <div class="row">
        <div class="col-md-6">
            <?= $form->field($model, 'email')->textInput(['maxlength' => true, 'placeholder' => 'Enter @ Email to subscribe!'])->label(false) ?>
        </div>
        <div class="col-md-6">
            <?= Html::submitButton('Subscribe', ['class' => 'btn btn-success']) ?>
        </div>
    </div>

    <?php ActiveForm::end(); ?>

Это файл контроллера frontend\controllers\SubscriberController.php

<?php

namespace frontend\controllers;

use Yii;
use common\models\Subscriber;
use common\models\SubscriberSearch;
use yii\web\Controller;
use yii\web\NotFoundHttpException;
use yii\filters\VerbFilter;

/**
 * SubscriberController implements the CRUD actions for Subscriber model.
 */
class SubscriberController extends Controller
{


    /**
     * Creates a new Subscriber model.
     * If creation is successful, the browser will be redirected to the 'view' page.
     * @return mixed
     */
    public function actionSubscribe()
    {
        $model = new Subscriber();

        if ($model->load(Yii::$app->request->post()) && $model->validate()) {
            if ($model->sendEmail()) {
                Yii::$app->session->setFlash('success', 'You have successfully subscribed My-Blog. You will get notification whenever New post is published');

                return $this->redirect(Yii::$app->request->referrer);
            } else {
                Yii::$app->session->setFlash('error', 'Sorry, we are unable to subscribe for the provided email address.');
            }
        }

        return $this->redirect([Yii::$app->request->referrer, ['model' => $model]]);
    }

    /**
     * Creates a new Subscriber model.
     * If unsubscribe is successful, the browser will be redirected to the 'view' page.
     * @return mixed
     */
}

Я использовал виджет в layouts\main.php в разделе нижнего колонтитула

<footer class="footer">
    <div class="container">
        <div class="row">
            <div class="col-md-3">
                <p class="pull-left">&copy; <?= Html::encode(Yii::$app->name) ?> <?= date('Y') ?></p>
            </div>
            <div class="col-md-6 text-justify" style="border-left : 2px solid black; border-right: 2px solid black">
                <?= SubscriberFormWidget::widget(); ?>
                <p>
                    Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s when an unknown printer took a galley of type and scrambled it to make a type specimen book. It has survived not only five centuries, but also the leap into elec
                </p>
            </div>
            <div class="col-md-3">
                 <p class="pull-right"><?= Yii::powered() ?></p>
            </div>
        </div>
    </div>
</footer>

Эта модель используется для контроллера common\models\Subscriber.php.

   <?php

namespace common\models;

use Yii;
use yii\behaviors\TimestampBehavior;
use yii\db\ActiveRecord;
use yii\db\Expression;

/**
 * This is the model class for table "subscriber".
 *
 * @property int $id
 * @property string $email
 * @property string $token
 * @property int $status
 * @property int $created_at
 * @property int $updated_at
 */
class Subscriber extends \yii\db\ActiveRecord
{
    const STATUS_DEACTIVE = 0;
    const STATUS_ACTIVE = 1;

    /**
     * @inheritdoc
     */
    public static function tableName()
    {
        return 'subscriber';
    }

    public function behaviors()
    {
        return [
            'timestamp' => [
                'class' => TimestampBehavior::className(),
                'attributes' => [
                    ActiveRecord::EVENT_BEFORE_INSERT => ['created_at', 'updated_at'],
                    ActiveRecord::EVENT_BEFORE_UPDATE => ['updated_at'],
                ],
                'value' => new Expression('NOW()'),
            ],
        ];
    }

    /**
     * @inheritdoc
     */
    public function rules()
    {
        return [
            [['email'], 'required'],
            [['status', 'created_at', 'updated_at'], 'safe'],
            [['email'], 'string', 'max' => 60],
            [['token'], 'string', 'max' => 255],
            [['token'], 'unique'],
            [['email'], 'unique',  'targetClass' => '\common\models\Subscriber', 'message' => 'This email has already subscribed our blog.','filter' => ['!=','status' ,0]],
        ];
    }

    /**
     * @inheritdoc
     */
    public function attributeLabels()
    {
        return [
            'id' => 'ID',
            'email' => 'Email',
            'token' => 'Token',
            'status' => 'Status',
            'created_at' => 'Created At',
            'updated_at' => 'Updated At',
        ];
    }

    /**
     * Generates subscriber token
     */
    public function generateSubscriberToken()
    {
       return $this->token = Yii::$app->security->generateRandomString() . '_' . time();
    }

    /**
     * Send Email when successfully subscribe
     */

     public function sendEmail()
    {
        $subscribers = self::find()->where(['email' => $this->email])->one();

        //set flag for sending email
        $sendMail = false;
        //email subject
        $subject = '';

        //generate token
        $token = $this->generateSubscriberToken();

        //if email found in subscribers
        if ($subscribers !== null) {

            //check if inactive
            if ($subscribers->status !== self::STATUS_ACTIVE) {

                //assign token
                $subscribers->token = $token;

                //set status to active
                $subscribers->status = self::STATUS_ACTIVE;

                print_r($subscribers->errors);
                //update the recrod
                if (!$subscribers->save()) {
                    return false;
                }

                //set subject
                $subject = 'Welcome back ' . $this->email . 'Thank you for subscribing ' . Yii::$app->name . '<br /><br /> You will receive notification whenever new trick or post is published to website';
                $sendMail = true;
            }
        } else { //if email does not exist only then insert a new record
            $this->status = 1;
            if (!$this->save()) {

                return false;
            }
            $subject = 'Thank you ' . $this->email . ' for subscribing ' . Yii::$app->name . '<br /><br /> You will receive notification whenever new trick or post is published to website';
            $sendMail = true;
        }

        //check if send mail flag set
        if ($sendMail) {
            return Yii::$app->mailer
                ->compose()
                ->setFrom(['[email protected]' => Yii::$app->name . ' robot'])
                ->setTo('piyush@localhost')
                ->setSubject('Subscription : ' . Yii::$app->name)
                ->setHtmlBody($subject)
                ->send();
        }

    }
}

Теперь я хочу, чтобы форма работала с проверкой. Если пользователь вводит какой-либо неверный ввод, например, уже зарегистрирован, сообщение об этом должно вернуться для просмотра файла, из которого отправлены данные формы.


person Piyush Gupta    schedule 12.02.2018    source источник
comment
@muhammad Это не работает .... пожалуйста, проверьте   -  person Piyush Gupta    schedule 12.02.2018
comment
проблема в том, что вы проверяете с помощью $model->validate(), но внутри правил вы не используете какую-либо проверку, например, если электронная почта уже существует, вместо этого вы используете функцию sendMail, чтобы проверить, что если пользователь уже существует и является active или inactive, а затем добавляете в сообщение сеанса flash, оно будет отображать ошибку во флэш-сообщениях только тогда, когда страница обновляется после добавления сообщения или перенаправления, вы отправляете форму с перезагрузкой страницы?   -  person Muhammad Omer Aslam    schedule 12.02.2018
comment
Я использовал правило в модели public function rules() { return [[['email'], 'required'], [['status', 'created_at', 'updated_at'], 'safe'], [['email '], 'string', 'max' =› 60], [['токен'], 'string', 'max' =› 255], [['токен'], 'уникальный'], [['email '], 'unique', 'targetClass' =› '\common\models\Subscriber', 'message' =› 'Это письмо уже подписано на наш блог.','filter' =› ['!=','status ' ,0]], ]; }   -  person Piyush Gupta    schedule 12.02.2018
comment
хорошо, подожди минутку, дай мне проверить   -  person Muhammad Omer Aslam    schedule 12.02.2018
comment
добавил ответ, чтобы посмотреть, поможет ли он вам   -  person Muhammad Omer Aslam    schedule 12.02.2018


Ответы (2)


Controlelr::redirect() принимает параметр url и необязательный параметр status code.
Вы неправильно называете его в приведенном вами фрагменте.
Я полагаю, вы пытаетесь использовать только параметр url (один аргумент массива) и пропустить код состояния.

Вы также не можете полагаться на то, что реферер укажет вам на предыдущую страницу. Вам нужно сохранить маршрут для возврата на странице формы

Url::remember([Yii::$app->requestedRoute]);

а затем используйте это, чтобы вернуться к форме

return $this->redirect([Url::previous(), ['model' => $model]]);
person csminb    schedule 12.02.2018
comment
Да, это связано с тем, что реферер содержит полный URL, а не маршрут, возможно, безопаснее использовать \yii\helpers\Url::remember() и \yii\helpers\Url::previous() - person csminb; 12.02.2018
comment
@PiyushGupta я обновил ответ. Я думаю, что этот подход несколько лучше, поскольку Yii::$app->request->referrer может быть практически любым (нулевой или внешний домен или любые данные, отправленные пользователем) - person csminb; 12.02.2018
comment
Я также подробно обновил вопрос с кодом. надеюсь, вы поймете проблему.... @csminb - person Piyush Gupta; 12.02.2018
comment
он все еще должен работать. добавьте Url::remember в SubscriberFormWidget.php непосредственно перед рендерингом и используйте $this->redirect([Url::previous(), ['model' => $model]]); в actionSubscribe() - person csminb; 12.02.2018
comment
Он перенаправляет меня на localhost/my-blog/frontend /web/my-blog/frontend/web/site/about вместо локальный/мой-блог/интерфейс/веб/сайт/о............. @csminb - person Piyush Gupta; 12.02.2018

Вы можете установить Yii::$app->user->returnUrl, а затем использовать $this->goBack(), чтобы вернуться на предыдущую страницу, какой бы она ни была.

Хороший подход — добавить функцию beforeAction внутрь вашего контроллера SubscribeController, как показано ниже.

public function beforeAction($action)
{
    if (parent::beforeAction($action)) {
        if($action->id=='subscribe'){
            Yii::$app->user->returnUrl = Yii::$app->request->referrer;
        }
    }
    return true;
} 

и заменить строку

return $this->redirect([Yii::$app->request->referrer, ['model' => $model]]);

со следующим

return $this->goBack();

Теперь, с какой бы страницы вы ни отправили форму нижнего колонтитула, она вернется на эту страницу.

Еще я заметил, что вы не проверяете переменную sessionFlash error в своей форме, вам нужно получить сообщение об ошибке, например

if(Yii::$app->session->hasFlash('error')){

   echo '<div class="alert alert-danger">
          <strong>Danger!</strong>'. Yii::$app->session->getFlash('error').'
       </div>';
}

Лучший способ отображения сообщений sessionFlash представлен в моем < strong>previous answer вы можете следить за этим, чтобы не добавлять код вручную везде, он автоматически покажет вам сообщения сеанса после установки.

Надеюсь, это поможет вам

person Muhammad Omer Aslam    schedule 12.02.2018
comment
Спасибо, ваш код отлично работает для перенаправления предыдущего адреса. но не показывает сообщение об ошибке. предположим, что если электронная почта уже подписана с активным статусом, то она должна отображать сообщение об ошибке, которое я использую в правиле () с фильтром - person Piyush Gupta; 12.02.2018
comment
хорошо, судя по заголовку, проблема заключалась в перенаправлении. Используете ли вы проверку клиента во внешнем интерфейсе для формы, показывает ли она ошибку во время выполнения, когда электронная почта не предоставлена? - person Muhammad Omer Aslam; 12.02.2018
comment
да, моя проблема решена на 90%, но перенаправление с сообщением об ошибке модели все еще ожидается. Нет, я не использую другую проверку, кроме функции rule(), используемой в модели... - person Piyush Gupta; 12.02.2018
comment
Почему бы не проверить вашу форму через ajax перед отправкой. yii2-cookbook.readthedocs.io/forms-activeform-js - person Kalu; 12.02.2018
comment
хорошо, дай мне немного времени, дай мне добраться до дома, и я разберусь с этим @PiyushGupta - person Muhammad Omer Aslam; 12.02.2018
comment
хорошо @Muhammad, ты нашел какое-нибудь решение, чтобы решить эту проблему без использования ajax? - person Piyush Gupta; 14.02.2018