Bestehende Controller-Funktion überschreiben/anpassen

Hallo,

ich fange gerade erst mit Shopware an und komme nicht so recht vorran.
Ich möchte den Controller des Kontaktformulars bearbeiten und zwar würde ich gerne die Funktion replaceVariables (engine/Shopware/Controllers/Frontend/Forms.php)  updatesicher anpassen.
Hier möchte ich erst einmal einfach nur das Datumsformat ändern. Ich dachte mir eventuell den Controller zu Vererben und die Funktion zu überschreiben, bin mir aber nicht sicher ob das der richtige Weg ist und wie ich dem System sagen würde, dass es meinen Controller anstelle des Originalen aufrufen soll.

Hier ist eine mögliche Subklasse die ich erstellt habe:

_postData as $key => $value) {
            if ($this->_elements[$key]['typ'] == "text2") {
                $names = explode(";", $this->_elements[$key]['name']);
                $content = str_replace("{sVars." . $names[0] . "}", $value[0], $content);
                $content = str_replace("{sVars." . $names[1] . "}", $value[1], $content);
            } else {
                $content = str_replace("{sVars." . $this->_elements[$key]['name'] . "}", $value, $content);
            }
        }
 
        $content = str_replace("{sIP}", $_SERVER['REMOTE_ADDR'], $content);
        $content = str_replace("{sDateTime}", date("d.m.Y H:i"), $content);
        $content = str_replace('{sShopname}', Shopware()->Config()->shopName, $content);
 
        return strip_tags($content);
    }

}
?>

Ich hoffe ihr könnt mir weiterhelfen und eventuell bessere/richtige Ansätze verraten.

 

Viele Grüße 

Glodi

Hallo,

das was Du vor hast geht schonmal prinzipiell nicht. Die Methode ist private. Das heißt sie wird zwar vererbt (weil immer alles vererbt wird), aber Du kannst sie nicht überschreiben (Prinzip der Sichtbarkeiten in der OOP). Dafür bräuchtest du mindestes protected als Sichtbarkeit, damit die Basis-Methode in Kindsklassen überschreibbar ist.

 

Was Du aber machen kannst: Du kannst einen Hook für die indexAction() erstellen. Damit erreichst du dann über Umwege Dein ursprüngliches Zeil. Leider geht das in Shopware nicht anders. Du musst also einen eigenen Controller machen, der die indexAction durch einen sogenannten Hook überschreibt. So, das heißt Du musst prinzipiell den ganzen Klassen Code kopieren und Ihn in Deinem Hook auf Deine Bedürfnisse anpassen. Anders gehts leider nicht.

 

Wie man Hooks, bzw. Plugins erstellt, findest Du in der Entwickler Doku: Shopware controller

Mehr über Hooks und was das eigentlich ist, findest Du hier: Understanding the Shopware hook system

 

MFG

 

derwunner

1 „Gefällt mir“

Hallo derwunner,
vielen Dank für deine schnelle Antwort :slight_smile: Oh das ist peinlich, heute ist nicht mein Tag… natürlich kann man keine private Funktion auf diese Weise überschreiben.
(Interessehalber: Könnte man die Funktion auf diese Weise überschreiben wenn sie public wäre und wenn ja wie würde mann dann vorgehen?)

Verstehe ich es richtig, dass ich ein Plugin mit dem kopierten + modifizierten Controller erzeuge und in der Bootstrap.php den Controller registriere. Oder wie überschreibe ich die indexAction bzw. Controller? Leider finde ich kein ähnliches Beispiel wie man so etwas macht und aus der Doku werde ich leider nicht viel schlauer. Anbei mein mögliches Plugin.

Viele Grüße
Glodi

Plugin:

Bootstrap.php

class Shopware_Plugins_Frontend_GlodiFormsController_Bootstrap extends Shopware_Components_Plugin_Bootstrap
{
    public function getVersion()
    {
        $info = json_decode(file_get_contents( __DIR__. DIRECTORY_SEPARATOR .'plugin.json'), true);
        if ($info) {
            return $info['currentVersion'];
        } else {
            throw new Exception('The plugin has an invalid version file.');
        }
    }

    public function getLabel()
    {
        return 'GlodiFormsController';
    }

    public function uninstall()
    {
        return true;
    }

    public function update($oldVersion)
    {
        return true;
    }

    public function install()
    {
        $this->registerController('Frontend', 'GlodiFormsController');

        return true;
    }
}

Controllers/Frontend/GlodiFormsController.php

Request()->getParam('sFid');
        $id = ($id) ? $id : $this->Request()->getParam('id');

        $this->View()->forceMail = (int)$this->Request()->getParam('forceMail');
        $this->View()->id = $id;
        $this->View()->sSupport = $this->getContent($id);
        $this->View()->rand = md5(uniqid(mt_rand(), true));

        $success = $this->Request()->getParam('success');
        if ($success) {
            $this->View()->sSupport = array_merge($this->View()->sSupport, array('sElements' => ''));
        }

        $this->View()->assign('success', $success);

        if ($this->Request()->isPost()) {
            $this->handleFormPost($id);
        }
    }

//...

    /**
     * replaces placeholder variables
     * @param string $content
     * @return string
     */
    private function replaceVariables($content)
    {
        foreach ($this->_postData as $key => $value) {
            if ($this->_elements[$key]['typ'] == "text2") {
                $names = explode(";", $this->_elements[$key]['name']);
                $content = str_replace("{sVars." . $names[0] . "}", $value[0], $content);
                $content = str_replace("{sVars." . $names[1] . "}", $value[1], $content);
            } else {
                $content = str_replace("{sVars." . $this->_elements[$key]['name'] . "}", $value, $content);
            }
        }

        $content = str_replace("{sIP}", $_SERVER['REMOTE_ADDR'], $content);
        $content = str_replace("{sDateTime}", date("d.m.Y H:i:s"), $content);
        $content = str_replace('{sShopname}', Shopware()->Config()->shopName, $content);

        return strip_tags($content);
    }
//...
}

 

Du beschreibst die alte Plugin Struktur. Die würde ich auf keinen Fall für neue Plugins benutzen. Entwickle neue Plugins am besten immer nach dem 5.2 Plugin System.

Aber generell muss ich wohl etwas revedieren. Ganz so leicht ist es dann doch nicht. Du hast ein sehr unglückliches Beispiel gewählt für “Controller überschreiben”. Direkt überschreiben kannst Du das soviel ich weiß nicht, aber es gibt jeweils zu jeder Controller Action ein pre- und postDispatch Event. Also pre logischerweise vor und post nach der jerweiligen Action.

Mit Hooks habe ich mich bisher auch noch nicht näher beschäftigt, weil es immer keine gute Idee ist, irgendeine Funktionalität zu überschreiben. Man muss dann nämlich dafür sorgen tragen, wenn Updates kommen seitens Shopware, dass das Plugin dann immer noch läuft. Wesentlich besser ist es, so etwas über Events abzubilden. Darin kann man nämlich auch mehr als genug das Standard Verhalten beeinflussen und man läuft vorallem dabei nicht Gefahr, dass es in der nächsten Shopware Version nicht mehr geht.

Ich kam bisher recht gut ohne Hooks aus, da es eigentlich für fast alles Events oder etwas vergleichbares gibt. Man braucht eigentlich kaum eine Methode zu überschreiben. Wie gesagt, das bringt nur mehr Nachteile als Vorteile mit sich.

Aber generell kannst Du nach dem 5.2er Plugin System wie folgt Dich auf solche Events abonnieren (am Beispiel von der Artikel Detail Seite):

 'onPostDispatchDetail'
        ];
    }

    public function install(InstallContext $context)
    {
        // prepare plugin, e. g. create own db tables
    }

    public function uninstall(UninstallContext $context)
    {
        // clean up, e. g. drop plugin db tables
    }

    public function onPostDispatchDetail(\Enlight_Event_EventArgs $arguments)
    {
        /**
         * @var $controller \Shopware_Controllers_Frontend_Index
         */
        $controller = $arguments->getSubject();
        /**
         * @var $request \Zend_Controller_Request_Http
         */
        $request = $controller->Request();
        /**
         * @var $response \Zend_Controller_Response_Http
         */
        $response = $controller->Response();

        /**
         * @var $view \Enlight_View_Default
         */
        $view = $controller->View();

        // do your database article check here, in sArticles you will find the most article data you may need that are already fetched from the database by shopware itself (you are in after action event)
        $sArticle = $view->getAssign('sArticle');

        // add your own plugin template here, that it overrides the themes' template:
        $view->Engine()->addTemplateDir(
            $this->getPath() . DIRECTORY_SEPARATOR . 'Resources' . DIRECTORY_SEPARATOR . 'Themes' . DIRECTORY_SEPARATOR
        );

        $sArticle['someCustomVar'] = 'hello article detail page!';
        $view->assign('someCustomVar', $sArticle);
    }
}

Nach der neuen Plugin Struktur müssen Plugins auch unter custom/plugins liegen. Dort entsrpricht dann jeder Unterordner einem Plugin. Die Bootstrap.php wird zu einer genamespacten Klasse, die genauso heißen muss, wie der Plugin Ordner, bzw. wie das Plugin selbst. Denn danach sucht Shopware. Und diese würde beispielhaft wie oben aussehen, wenn wir davon ausgehen, dass Dein Plugin “CompanyPlugin” heißt.

 

 

MFG

 

derwunner

2 „Gefällt mir“

Vielen Dank :slight_smile: Also ist es wohl besser ich reagiere auf das Event:

$mail = Shopware()->Events()->filter('Shopware_Controllers_Frontend_Forms_commitForm_Mail', $mail, array('subject' => $this));

und lese den body von $mail aus um dort das Datum mit dem gewünschten Format zu ersetzen. Ich möchte nämlich die unglückliche 12-Stunden Zeitform auf 24-Stunden ändern.
Dies ist denke ich dann der “sicherere” aber etwas umständlichere Weg.

Viele Grüße
Glodi

So habe jetzt mal ein minimal Plugin geschrieben, das auf das Shopware_Controllers_Frontend_Forms_commitForm_Mail reagiert und die Mail manipuliert.
 

Anbei meine Lösung für Einsteiger die das selbe Problem haben:

Die Datei liegt in einem Ordner “GlodiKontaktFormular”, der Ordner muss gezippt werden und in über den Pluginmanager hochgeladen und aktiviert werden:

 'onPostDispatchDetail'
     ];
    }

        public function install(InstallContext $context)
        {
            // prepare plugin, e. g. create own db tables
        }

        public function uninstall(UninstallContext $context)
        {
            // clean up, e. g. drop plugin db tables
        }

        public function onPostDispatchDetail(\Enlight_Event_EventArgs $args)
        {
          //Wird von $mail = Shopware()->Events()- >filter('Shopware_Controllers_Frontend_Forms_commitForm_Mail', $mail, array('subject' => $this)); in der Datei engine/Shopware/Controllers/Frontend/Forms.php aufgerufen

          $mail = $args->getReturn();
          $mail->setBodyText("Test Boddddddy");
          return $mail;

        }
}