Mit PreDispatch Controller-Actions ändern

Einen Core-Controller umzuleiten fühlt sich irgendwie nicht so richtig schick an. Alleine deswegen weil eine merkwürdige require-Anweisung im Kopf des Controllers stehen muss. Aber wie geht es besser? Predispatch ist die Antwort auf die Frage.

Bei jedem Controller wird vor dem Aufruf der Action ein PreDispatch und ein PostDispatch aufgerufen. Zwischen den beiden findet die eigentliche Aktion, also die Implementierung statt. Will man nun die weiteren Schritte im Checkout nur erlauben falls eine bestimmte Mindestmenge oder ein Mindestumsatz erfüllt ist reicht es nicht aus nur den "zur Kasse"-Button zu entfernen. Wichtig ist ebenfalls das der Checkout nicht über den Direktlink aufgerufen werden kann.

Wir hängen uns also als den PreDispatch Event des Controllers. Dazu ergänzen wir die config.xml wie folgt:

<global>
	[..]
	<events>

		<controller_action_predispatch_checkout>
		    <observers>
		        <mindestumsatz_controller_action_predispatch_checkout>
		            <class>mindestumsatz/observer</class>
		            <method>controller_action_predispatch_checkout</method>
		        </mindestumsatz_controller_action_predispatch_checkout>
		    </observers>
		</controller_action_predispatch_checkout>

	</events>
	[..]
</global>

Bevor nun die Action des Controllers aufgerufen wird unsere Methode controller_action_predispatch_checkout im Observer-Model aufgerufen:

<?php

class Codex_Mindestumsatz_Model_Observer {

    public function controller_action_predispatch_checkout( $event ) {

        $controller = $event->getControllerAction();
        /* @var $controller Mage_Checkout_CartController */

        if( $controller->getRequest()->getControllerName() == 'onepage' && !Mage::helper('mindestumsatz')->getIsMindestumsatz() ) {
            /*
             * Wenn der Mindestumsatz nicht erfüllt wurde aber der Checkout onepage aufgerufen wird
             * auf den Cart-Index umleiten
             */

            $controller->getResponse()->setRedirect( Mage::getUrl('*/cart') );
            $controller->getResponse()->sendResponse();

            $controller->getRequest()->setDispatched( true );
        }

    }

}

Da wir uns komplett am Modul checkout angedockt haben müssen wir nun noch abfragen ob der Controller den Namen "onepage" hat. Falls zutreffend wollen wir direkt auf den Warenkorb umleiten. Dazu holen wir uns vom Controller den Response, starten einen Redirect und sorgen, mittels setDispatched dafür das alles andere nicht weiterverarbeitet wird. Fertig, und alles ohne einen Controller Rewrite!

Update: Eine weitere (ähnliche) Möglichkeit stellt Karl Spies in seinem Blog-Beitrag vor.



Ein Beitrag von Tobias Vogt
Tobias's avatar

Tobias Vogt arbeitet seit 2008 mit Magento und ist seit 2011 durch Magento zertifizierter Entwickler. Beschäftigt ist er bei der code-x GmbH, einer Agentur für Internet und Marketing aus Paderborn. Er gehört zum Gründer-Team der Webguys und ist seit November 2011 Bachelor of Science (Wirtschaftsinformatik). Sie erreichen Ihn per E-Mail unter tobi@webguys.de.

Alle Beiträge von Tobias

Kommentare
Fabian Blechschmidt am

Habe mich gerade in Anlehnung an Saschas und Vinais Lösung vom letzten Hackathon mal mit setRedirect rumgeschlagen, aber es nicht zum Laufen bekommen, das klappt auf Anhieb :) https://github.com/magento-hackathon/HoneySpam/blob/master/app/code/community/Hackathon/HoneySpam/Model/Observer.php#L84


$e = new Mage_Core_Controller_Varien_Exception();
$e->prepareRedirect(
    $request->getOriginalPathInfo(),
    array_merge(
        $request->getParams(),
        array('___store' => $storeViewFromAcceptLanguage))
    );
throw $e;
Magento App Factory Blog» Magento CMS Contact Form am

[...] immediately afterwards. There are interesting articles on dispatch observers at the Mage::log() and Webguys blogs. This config.xml snippet configures the event [...]

Tobias Vogt am

Ich habe mal PHP-Tags zu deinem Code hinzugefügt damit er lesbar ist :) Guter Hinweis, danke!

Barry Krein am

Mit diesem Code werden noch zu abarbeitende Error Messages ausgegeben:


$controller = $observer->getControllerAction()->setFlag('',Mage_Core_Controller_Varien_Action::FLAG_NO_DISPATCH,true);
$controller->getResponse()->setRedirect('customer/account/login');

Das sendResponse() ist hier dann nicht mehr nötig sowie setDispatched(true).

Das sendResponse() hat dummerweise die Messages die ich im pre-dispatch gesetzt habe gelöscht.

Tobias Vogt am

Danke :)

Vinai am

Sehr clever, gefällt mir!

Viele Grüße!

Links 34/2011: Magento, e-Commerce und Entwicklung allgemein am

[...] Controller Actions mit Events überschreiben neue Anregungen. Ähnlich dazu auch folgender Text: mit PreDispatch Controller-Actions ändern.Eine schöne Idee, die ich aufgreifen möchte, wird bei magebase beschrieben: man soll die [...]

Dein Kommentar