Magento 2: réécrire le contrôleur

17

comment puis-je réécrire un contrôleur (c'est en fait une action) dans Magento 2?
J'ai essayé, comme indiqué ici comme ceci:

J'ai mon propre module appelé Namespace_Moduleavec un di.xmlfichier, qui est pris en considération, car le même système fonctionne sur les modèles et les blocs.
Exemple:

<?xml version="1.0"?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../../../lib/internal/Magento/Framework/ObjectManager/etc/config.xsd">
    <!-- this one doesn't work for a controller action -->
    <preference for="Magento\Backend\Controller\Adminhtml\Dashboard\RefreshStatistics" 
         type="Namespace\Module\Controller\Adminhtml\Dashboard\RefreshStatistics" />
    <!-- this one works for a model -->
    <preference for="Magento\Customer\Model\Resource\GroupRepository" 
        type="Namespace\Module\Model\Resource\Customer\GroupRepository" />
     <!-- this one works also for a block -->
    <preference for="Magento\Backend\Block\Dashboard" 
        type="Namespace\Module\Block\Backend\Dashboard" />
</config>

J'essaie de remplacer les statistiques de rafraîchissement du tableau de bord par ma propre action. En procédant comme ci-dessus, la executeméthode de la classe d'origine est toujours appelée et non la mienne.
var/cacheet var/generationont été effacés.

Marius
la source
Cela pourrait aider stackoverflow.com/questions/29654718/…
Tim Hallman
1
@TimHallman. Merci, mais je ne veux pas écrire un routeur juste pour ça. Je suis sûr qu'il existe une façon plus propre de le faire.
Marius

Réponses:

16

Je l'ai trouvé.
En fait, ce que j'ai posté dans la question, c'est la bonne façon de réécrire un contrôleur.

<preference for="Magento\Backend\Controller\Adminhtml\Dashboard\RefreshStatistics" 
     type="Namespace\Module\Controller\Adminhtml\Dashboard\RefreshStatistics" />

fonctionne bien.
Le problème pour moi était le suivant. J'ai oublié de mentionner que j'ai supprimé certains modules Magento2 et parmi ceux-ci c'était le Reportsmodule. Je ne l'ai pas dit dans la question parce que je ne pensais pas que c'était significatif.
La méthode ci-dessus pour réécrire les contrôleurs (et peut-être d'autres classes) fonctionne si toutes les classes que vous essayez de changer existent et toutes leurs classes parentes également.
Donc, l'original Magento\Backend\Controller\Adminhtml\Dashboard\RefreshStatisticss'étend Magento\Reports\Controller\Adminhtml\Report\Statisticsque j'avais supprimé.
Dans magento 2, les itinéraires sont collectés en analysant les dossiers des Controllerdossiers pour tous les modules activés et ils sont collectés dans un tableau.
Jusqu'ici tout va bien.
Je me retrouve avec cette ligne entre autres:

[magento\backend\controller\adminhtml\dashboard\refreshstatistics] => Magento\Backend\Controller\Adminhtml\Dashboard\RefreshStatistics

Ensuite, la demande est mise en correspondance avec l'itinéraire magento\backend\controller\adminhtml\dashboard\refreshstatisticset Magento vérifie si la classe correspondant à cet itinéraire est une sous-classe de Magento\Framework\App\ActionInterface. Étant donné que les itinéraires sont collectés avant que ma classe ne soit identifiée et instanciée, l'ancienne classe est validée à la place de la mienne. Et la classe parente de la classe Magento\Backend\Controller\Adminhtml\Dashboard\RefreshStatisticsn'existe pas.

Une solution pour garder le module de rapports désactivé mais le faire fonctionner est de créer un intercepteur pour la méthode qui lit toutes les routes et de remplacer la route mentionnée ci-dessus.

J'ai donc ajouté ceci dans di.xml

<type name="Magento\Framework\App\Router\ActionList\Reader">
    <plugin name="namespace-module-route" type="Namespace\Module\Model\Plugin\ActionListReader" sortOrder="100" />
</type>

et mon plugin ressemble à ceci:

<?php
namespace Namespace\Module\Model\Plugin;

class ActionListReader
{
    public function afterRead(\Magento\Framework\App\Router\ActionList\Reader\Interceptor $subject, $actions)
    {
        $actions['magento\backend\controller\adminhtml\dashboard\refreshstatistics'] = 'Namespace\Module\Controller\Adminhtml\Dashboard\RefreshStatistics';
        return $actions;
    }
}
Marius
la source
: - comment étendre vendor \ magento \ module-directory \ Model \ PriceCurrency.php convertAndRound (), ici je dois changer la précision, dans ce cas, comment utiliser le plugin, il me force à utiliser la préférence dans ce cas
Pradeep Kumar
6

ne pas utiliser de préférence utiliser le plugin pour étendre n'importe quel module de base qui est en di.xml

<type name="Magento\Catalog\Controller\Product\View">
    <plugin name="product-cont-test-module" type="Sugarcode\Test\Model\Plugin\Product" sortOrder="10"/>
</type>

et dans Product.php

public function aroundExecute(\Magento\Catalog\Controller\Product\View $subject, \Closure $proceed)
{
    echo 'I Am in Local Controller Before <br>';
    $returnValue = $proceed(); // it get you old function return value
    //$name='#'.$returnValue->getName().'#';
    //$returnValue->setName($name);
    echo 'I Am in Local Controller  After <br>';
    return $returnValue;// if its object make sure it return same object which you addition data
}

Comment remplacer le bloc de base, le modèle et le contrôleur dans Magento2

Pradeep Kumar
la source
2
oui, c'est la meilleure pratique. Mais dans mon cas, j'ai supprimé le module qui contenait une classe étendue par le contrôleur que j'essaie de remplacer. Donc ça aroundne marcherait pas pour moi. Je voulais changer complètement le comportement du contrôleur d'origine.
Marius
si vous voulez changer le comportement complet, puis créez une nouvelle action et changez simplement l'URL là où vous en avez besoin, j'espère que ce sera une bonne idée
Pradeep Kumar
2

J'ai réécrire le contrôleur pour le modèle d'examen. Fichier composer.json:

{
        "name": "apple/module-review",
        "description": "N/A",
        "require": {
            "php": "~5.5.0|~5.6.0|~7.0.0",
            "magento/framework": "100.0.*"
        },
        "type": "magento2-module",
        "version": "100.0.2",
        "license": [
            "OSL-3.0",
            "AFL-3.0"
        ],
        "autoload": {
            "files": [
                "registration.php"
            ],
            "psr-4": {
                "Apple\\Review\\": ""
            }
        }
    }

fichier registration.php

    \Magento\Framework\Component\ComponentRegistrar::register(
        \Magento\Framework\Component\ComponentRegistrar::MODULE,
        'Apple_Review',
        __DIR__
    );

fichier app / code / Apple / Review / etc / module.xml:

    app/code/Apple/Review/etc/di.xml file for override review controller.
    <?xml version="1.0"?>
    <!--
    /**
     * Copyright © 2015 Magento. All rights reserved.
     * See COPYING.txt for license details.
     */
    -->
    <config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:ObjectManager/etc/config.xsd">
        <preference for="Magento\Review\Controller\Product\Post" type="Apple\Review\Controller\Post" />   
    </config>

Dans le fichier du contrôleur pour le modèle de révision,

app / code / Apple / Review / Controller / Post.php

    use Magento\Review\Controller\Product as ProductController;
    use Magento\Framework\Controller\ResultFactory;
    use Magento\Review\Model\Review;

    class Post extends \Magento\Review\Controller\Product\Post
    {
        public function execute()
        {
           $resultRedirect = $this->resultFactory->create(ResultFactory::TYPE_REDIRECT);
            if (!$this->formKeyValidator->validate($this->getRequest())) {
                $resultRedirect->setUrl($this->_redirect->getRefererUrl());
                return $resultRedirect;
            }

            $data = $this->reviewSession->getFormData(true);
            if ($data) {
                $rating = [];
                if (isset($data['ratings']) && is_array($data['ratings'])) {
                    $rating = $data['ratings'];
                }
            } else {
                $data = $this->getRequest()->getPostValue();
                $rating = $this->getRequest()->getParam('ratings', []);
            }

            if (($product = $this->initProduct()) && !empty($data)) {
                /** @var \Magento\Review\Model\Review $review */
                $review = $this->reviewFactory->create()->setData($data);

                $validate = $review->validate();
                if ($validate === true) {
                    try {
                        $review->setEntityId($review->getEntityIdByCode(Review::ENTITY_PRODUCT_CODE))
                            ->setEntityPkValue($product->getId())
                            ->setStatusId(Review::STATUS_PENDING)
                            ->setCustomerId($this->customerSession->getCustomerId())
                            ->setStoreId($this->storeManager->getStore()->getId())
                            ->setStores([$this->storeManager->getStore()->getId()])
                            ->save();

                        foreach ($rating as $ratingId => $optionId) {
                            $this->ratingFactory->create()
                                ->setRatingId($ratingId)
                                ->setReviewId($review->getId())
                                ->setCustomerId($this->customerSession->getCustomerId())
                                ->addOptionVote($optionId, $product->getId());
                        }

                        $review->aggregate();
                        $this->messageManager->addSuccess(__('You submitted your review for moderation.Thanks'));
                    } catch (\Exception $e) {
                        $this->reviewSession->setFormData($data);
                        $this->messageManager->addError(__('We can\'t post your review right now.'));
                    }
                } else {
                    $this->reviewSession->setFormData($data);
                    if (is_array($validate)) {
                        foreach ($validate as $errorMessage) {
                            $this->messageManager->addError($errorMessage);
                        }
                    } else {
                        $this->messageManager->addError(__('We can\'t post your review right now.'));
                    }
                }
            }
            $redirectUrl = $this->reviewSession->getRedirectUrl(true);
            $resultRedirect->setUrl($redirectUrl ?: $this->_redirect->getRedirectUrl());
            return $resultRedirect;
        }
    }

Il s'agit du code de travail pour la révision du contrôleur dans magento2. Merci.

Rakesh Jesadiya
la source
: - utiliser les préférences n'est pas un bon moyen d'étendre, utiliser le concept de plugin
Pradeep Kumar
@PradeepKumar pouvez-vous expliquer pourquoi l'utilisation de plugins est préférable à l'utilisation de préférence?
Robbie Averill
@robbie: - il conserve les fonctionnalités d'origine ou de base, par exemple si magneto2 est mis à niveau et que certains changements se produisent dans la même fonction, nous perdrons cette partie, alors optez pour le plugin, il conserve la logique de base
Pradeep Kumar
Le plugin est mutuellement exclusif alors que la préférence est une réécriture - est-ce correct @PradeepKumar?
Robbie Averill