Magento потерял сообщения после перенаправления

У меня проблема с сообщениями magento. Я создаю пользовательский модуль, который теоретически должен иметь возможность ограничить доступ к некоторым частям магазина. Я создал наблюдателя, который подключается к событию controller_action_predispatch и проверяет, может ли пользователь запрашивать текущий запрос. Если действие не может быть доступно, наблюдатель перенаправляет пользователя и устанавливает информацию об ошибке. Я хочу настроить URL-адрес перенаправления на страницу, с которой клиент приходит, чтобы не нажимать на весь магазин. Я смотрю на HTTP_REFERER и использую его, если он установлен, иначе я перенаправляю клиента на домашнюю страницу. Проблема в том, что в последнем случае (перенаправление домашней страницы) все работает отлично, но когда я устанавливаю url на основе референта, я не вижу сообщения об ошибке в окне сообщения.

Код от наблюдателя ($name variable - строка):

Mage::getSingleton('core/session')->addError('Acces to '.$name.' section is denied');
$url = Mage::helper('core/http')->getHttpReferer() ? Mage::helper('core/http')->getHttpReferer()  : Mage::getUrl();
Mage::app()->getResponse()->setRedirect($url);

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

Я думал, что проблема заключается в полном url и моем локальном установлении (я использую .local domain), но поэтому я попытался добавить

$url = str_replace(Mage::getBaseUrl(), '/', $url);

но это не помогло.

Я также попытался перенаправить, используя php header() функцию без какого-либо результата.

Все кеширование отключено. Рабочий процесс, который вызывает проблему, выглядит следующим образом:

  • Я собираюсь перейти на любую доступную страницу (например, клиент/учетная запись).
  • Нажмите на ссылку тележки (корзина для этой учетной записи отключена)
  • Возврат в/клиент/учетную запись и сообщение об ошибке отображается
  • Нажмите ссылку на тележку снова
  • Возврат в/клиент/аккаунт, но не сообщение об ошибке

Любой намек на то, где искать, будет оценен.

Ответ 1

Ваши сообщения теряются, потому что вы используете неблагоприятный путь для перенаправления в controller_action_predispatch. С одной стороны, ваше решение приводит к тому, что "сообщение потеряно", а с другой стороны, оно отнимает вычислительную мощность вашего сервера.

Когда вы посмотрите на Mage_Core_Controller_Varien_Action::dispatch(), вы увидите, что ваше решение не останавливает выполнение текущего действия, но оно должно делать это с помощью перенаправления. Вместо этого Magento выполняет текущее действие до конца, включая рендеринг сообщения, которое вы добавили ранее. Поэтому неудивительно, почему сообщение теряется при следующем запросе клиента, Magento уже его отобразил, с ответом сервера, который включает в себя вашу переадресацию.

Далее вы увидите в Mage_Core_Controller_Varien_Action::dispatch() только одну возможность остановить выполнение текущего действия и пропустить прямо к перенаправлению, что находится в строке 428 catch (Mage_Core_Controller_Varien_Exception $e) [...]. Поэтому вам нужно использовать Mage_Core_Controller_Varien_Exception, который довольно непопулярен, но единственное правильное решение для вашей цели. Единственная проблема заключается в том, что у этого класса есть ошибка, так как он был введен в Magento 1.3.2. Но это можно легко устранить.

Просто создайте свой собственный класс, который получен из Mage_Core_Controller_Varien_Exception:

/**
 * Controller exception that can fork different actions, 
 * cause forward or redirect
 */
class Your_Module_Controller_Varien_Exception 
    extends Mage_Core_Controller_Varien_Exception
{
    /**
     * Bugfix
     * 
     * @see Mage_Core_Controller_Varien_Exception::prepareRedirect()
     */
    public function prepareRedirect($path, $arguments = array())
    {
        $this->_resultCallback = self::RESULT_REDIRECT;
        $this->_resultCallbackParams = array($path, $arguments);
        return $this;
    }
}

Итак, теперь вы можете полностью реализовать свое решение с помощью этого:

/**
 * Your observer
 */
class Your_Module_Model_Observer
{
    /**
     * Called before frontend action dispatch
     * (controller_action_predispatch)
     * 
     * @param Varien_Event_Observer $observer
     */
    public function onFrontendActionDispatch($observer)
    {
        // [...]

        /* @var $action Mage_Core_Model_Session */
        $session = Mage::getSingleton('core/session');
        /* @var $helper Mage_Core_Helper_Http */
        $helper = Mage::helper('core/http');
        // puts your message in the session
        $session->addError('Your message');
        // prepares the redirect url
        $params = array();
        $params['_direct'] = $helper->getHttpReferer() 
            ? $helper->getHttpReferer() : Mage::getHomeUrl();
        // force the redirect
        $exception = new Your_Module_Controller_Varien_Exception();
        $exception->prepareRedirect('', $params);
        throw $exception;
    }
}

Ответ 2

//A Success Message
Mage::getSingleton('core/session')->addSuccess("Some success message");

//A Error Message
Mage::getSingleton('core/session')->addError("Some error message");

//A Info Message (See link below)
Mage::getSingleton('core/session')->addNotice("This is just a FYI message...");

//These lines are required to get it to work
session_write_close(); //THIS LINE IS VERY IMPORTANT!
$this->_redirect('module/controller/action');

// or
$url = 'path/to/your/page';
$this->_redirectUrl($url);

Это будет работать в контроллере, но если вы попытаетесь перенаправить после того, как вывод уже отправлен, вы можете сделать это только через javascript:

<script language="javascript" type="text/javascript">
window.location.href="module/controller/action/getparam1/value1/etc";
</script>    

Ответ 3

это будет работать, поэтому попробуйте:

$url = 'path/to/your/page';
$this->_redirectUrl($url);
return false;

Это означает, что вы больше не разрешаете выполнять что-либо еще.