Magento 2: riscrivere il controller


17

come posso riscrivere un controller (che in realtà è un'azione) in Magento 2?
Ho provato, come indicato qui in questo modo:

Ho il mio modulo chiamato Namespace_Modulecon un di.xmlfile, che viene preso in considerazione, perché lo stesso sistema funziona su modelli e blocchi
Esempio:

<?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>

Sto cercando di sostituire le statistiche di aggiornamento del dashboard con la mia azione. Facendolo come sopra, il executemetodo nella classe originale viene ancora chiamato e non mio.
var/cachee var/generationsono stati cancellati.



1
@TimHallman. Grazie, ma non voglio scrivere un router solo per questo. Sono sicuro che esiste un modo più pulito di farlo.
Marius

Risposte:


16

Trovato.
In realtà quello che ho pubblicato nella domanda è il modo corretto di riscrivere un controller.

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

funziona bene.
Il problema per me era questo. Ho dimenticato di dire che ho rimosso alcuni moduli Magento2 e tra questi c'era il Reportsmodulo. Non l'ho dichiarato nella domanda perché non pensavo fosse significativo.
Il metodo sopra per riscrivere i controller (e forse altre classi) funziona se esistono tutte le classi che stai tentando di cambiare e anche tutte le loro classi principali.
Quindi l'originale si Magento\Backend\Controller\Adminhtml\Dashboard\RefreshStatisticsestende Magento\Reports\Controller\Adminhtml\Report\Statisticsche avevo rimosso.
In magento 2 i percorsi sono raccolti scansionando le cartelle Controllercartelle per tutti i moduli abilitati e sono raccolti in un array.
Fin qui tutto bene.
Concludo con questa linea tra le altre:

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

Quindi la richiesta viene abbinata alla rotta magento\backend\controller\adminhtml\dashboard\refreshstatisticse Magento verifica se la classe corrispondente a quella rotta è una sottoclasse di Magento\Framework\App\ActionInterface. Poiché i percorsi vengono raccolti prima che la mia classe venga identificata e istanziata, la vecchia classe viene convalidata anziché la mia. E la classe genitore della classe Magento\Backend\Controller\Adminhtml\Dashboard\RefreshStatisticsnon esiste.

Una soluzione per mantenere il modulo dei report disabilitato ma ancora farlo funzionare è creare un intercettore per il metodo che legge tutti i percorsi e sostituisce il percorso sopra menzionato.

Quindi l'ho aggiunto di.xml

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

e il mio plugin è simile al seguente:

<?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;
    }
}

: - come estendere il fornitore \ magento \ module-directory \ Model \ PriceCurrency.php convertAndRound (), qui devo cambiare la precisione, in questo caso come usare il plugin mi costringe a usare le preferenze in questo caso
Pradeep Kumar

6

non usare la preferenza usa il plugin per estendere qualsiasi modulo principale che è in di.xml

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

e in 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
}

Come sovrascrivere Core Block, Model e controller in Magento2


2
sì, questa è la migliore pratica. Ma nel mio caso ho rimosso il modulo che conteneva una classe estesa dal controller che sto cercando di ignorare. Quindi aroundnon funzionerebbe per me. Volevo cambiare completamente il comportamento del controller originale.
Marius

se vuoi cambiare il comportamento completo, quindi crea un'altra nuova azione e poi cambia l'url di cui hai bisogno, spero che questa sia una buona idea
Pradeep Kumar,

2

Ho riscritto il controller per il modello di revisione. file 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\\": ""
            }
        }
    }

file registration.php

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

file 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>

Nel file del controller per il modello di revisione,

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;
        }
    }

Questo è un codice funzionante per l'override del controller di revisione in magento2. Grazie.


: - usare le preferenze non è un buon modo per estenderle, usa il concetto di plugin
Pradeep Kumar il

@PradeepKumar puoi spiegare perché usare i plugin è preferibile usare le preferenze?
Robbie Averill,

@robbie: - mantiene la funzionalità originale o di base, ad esempio se magneto2 è aggiornato e alcuni cambiamenti si verificano nella stessa funzione, allora perderemo quella parte, quindi andiamo per il plug-in che conserva i log di base
Pradeep Kumar,

Il plug-in si esclude a vicenda mentre la preferenza è una riscrittura: è corretto @PradeepKumar?
Robbie Averill il
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.