Magento 2: przepisz kontroler

17

jak mogę przepisać kontroler (to właściwie akcja) w Magento 2?
Próbowałem, zgodnie z instrukcją tutaj :

Mam własny moduł wywoływany Namespace_Modulez di.xmlplikiem, który jest brany pod uwagę, ponieważ ten sam system działa na modelach i blokach.
Przykład:

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

Próbuję zastąpić statystyki odświeżania deski rozdzielczej własną akcją. Robiąc to tak jak powyżej, executemetoda w oryginalnej klasie wciąż jest wywoływana, a nie moja.
var/cachei var/generationzostały oczyszczone.

Marius
źródło
To może pomóc stackoverflow.com/questions/29654718/…
Tim Hallman
1
@TimHallman. Dzięki, ale nie chcę pisać routera tylko do tego. Jestem pewien, że jest na to czystszy sposób.
Marius

Odpowiedzi:

16

Znaleziono to.
Właściwie to, co napisałem w pytaniu, to poprawny sposób przepisania kontrolera.

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

działa ładnie.
Problem był dla mnie taki. Zapomniałem wspomnieć, że usunąłem niektóre moduły Magento2, a wśród nich był to Reportsmoduł. Nie podałem tego w pytaniu, ponieważ nie sądziłem, że to miało znaczenie.
Powyższa metoda przepisywania kontrolerów (i być może innych klas) działa, jeśli istnieją wszystkie klasy, które próbujesz zmienić, i wszystkie ich klasy nadrzędne.
Tak więc oryginał Magento\Backend\Controller\Adminhtml\Dashboard\RefreshStatisticsrozciąga się Magento\Reports\Controller\Adminhtml\Report\Statistics, który usunąłem.
W magento 2 trasy są zbierane przez skanowanie folderów Controllerfolderów w poszukiwaniu wszystkich włączonych modułów i są gromadzone w tablicy.
Jak na razie dobrze.
Skończyłem z tą linią między innymi:

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

Następnie żądanie jest dopasowane do trasy, magento\backend\controller\adminhtml\dashboard\refreshstatisticsa Magento sprawdza, czy klasa odpowiadająca tej trasie jest podklasą Magento\Framework\App\ActionInterface. Ponieważ trasy są zbierane, zanim moja klasa powinna zostać zidentyfikowana i utworzona instancja, stara klasa jest sprawdzana zamiast mojej własnej. A klasa nadrzędna tej klasy Magento\Backend\Controller\Adminhtml\Dashboard\RefreshStatisticsnie istnieje.

Rozwiązaniem, które pozwala wyłączyć moduł raportów, ale nadal działa, jest utworzenie przechwytywacza dla metody, która odczytuje wszystkie trasy i zastępuje trasę wspomnianą powyżej.

Więc dodałem to w di.xml

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

a moja wtyczka wygląda następująco:

<?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
źródło
: - jak rozszerzyć vendor \ magento \ moduł-katalog \ Model \ PriceCurrency.php convertAndRound (), tutaj muszę zmienić precyzję, w tym przypadku jak użyć wtyczki zmusić mnie do korzystania z preferencji w tym przypadku
Pradeep Kumar
6

nie używaj preferencji użyj wtyczki, aby rozszerzyć moduł podstawowy znajdujący się w pliku di.xml

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

oraz w 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
}

Jak zastąpić blok podstawowy, model i kontroler w Magento2

Pradeep Kumar
źródło
2
tak, to najlepsza praktyka. Ale w moim przypadku usunąłem moduł zawierający klasę rozszerzoną przez kontroler, który próbuję zastąpić. Więc aroundnie zadziałałoby dla mnie. Chciałem całkowicie zmienić zachowanie oryginalnego kontrolera.
Marius
jeśli chcesz zmienić pełne zachowanie, stwórz jeszcze jedną akcję, a następnie zmień adres URL tam, gdzie kiedykolwiek byłeś potrzebny, mam nadzieję, że to będzie dobry pomysł
Pradeep Kumar
2

Mam przepisać kontroler do modelu recenzji. plik 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\\": ""
            }
        }
    }

plik register.php

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

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

W pliku kontrolnym dla modelu recenzji,

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

To działa kod zastępujący kontroler recenzji w magento2. Dzięki.

Rakesh Jesadiya
źródło
: - użycie preferencji nie jest dobrym sposobem na rozszerzenie, skorzystaj z koncepcji wtyczek
Pradeep Kumar
@PradeepKumar czy możesz wyjaśnić, dlaczego używanie wtyczek jest lepsze niż używanie preferencji?
Robbie Averill,
@robbie: - zachowuje oryginalną lub podstawową funkcjonalność, np. jeśli uaktualni się magneto2 i niektóre zmiany dokonają się w tej samej funkcji, wówczas stracimy tę część, więc idź do wtyczki zachowaj podstawowe logi
Pradeep Kumar
Wtyczka wyklucza się wzajemnie, podczas gdy preferencja to przepisywanie - czy to poprawne @PradeepKumar?
Robbie Averill,