Magento 2: menulis ulang pengontrol

17

bagaimana saya bisa menulis ulang sebuah pengontrol (itu sebenarnya sebuah tindakan) di Magento 2?
Saya mencoba, seperti yang diperintahkan di sini seperti ini:

Saya memiliki modul saya sendiri yang disebut Namespace_Moduledengan di.xmlfile, yang dipertimbangkan, karena sistem yang sama bekerja pada model dan blok
Contoh:

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

Saya mencoba mengganti statistik refresh dasbor dengan tindakan saya sendiri. Melakukannya seperti di atas, executemetode di kelas asli masih dipanggil dan bukan milik saya.
var/cachedan var/generationdibersihkan.

Marius
sumber
Ini mungkin membantu stackoverflow.com/questions/29654718/…
Tim Hallman
1
@TimHallman. Terima kasih, tetapi saya tidak ingin menulis router hanya untuk ini. Saya yakin ada cara yang lebih bersih untuk melakukannya.
Marius

Jawaban:

16

Menemukannya.
Sebenarnya apa yang saya posting dalam pertanyaan adalah cara yang benar untuk menulis ulang controller.

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

berfungsi dengan baik.
Masalahnya bagi saya adalah ini. Saya lupa menyebutkan bahwa saya menghapus beberapa modul Magento2 dan di antaranya adalah Reportsmodul. Saya tidak menyatakannya dalam pertanyaan karena saya pikir itu tidak penting.
Metode di atas untuk pengontrol penulisan ulang (dan mungkin kelas lain) berfungsi jika semua kelas yang Anda coba ubah ada dan semua kelas induknya juga.
Jadi yang asli Magento\Backend\Controller\Adminhtml\Dashboard\RefreshStatisticsmeluas Magento\Reports\Controller\Adminhtml\Report\Statisticsyang telah saya hapus.
Dalam magento 2 rute dikumpulkan dengan memindai folder Controllerfolder untuk semua modul yang diaktifkan dan mereka dikumpulkan dalam array.
Sejauh ini baik.
Saya berakhir dengan baris ini antara lain:

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

Kemudian permintaan dicocokkan dengan rute magento\backend\controller\adminhtml\dashboard\refreshstatisticsdan Magento memeriksa apakah kelas yang sesuai dengan rute itu adalah subkelas dari Magento\Framework\App\ActionInterface. Karena rute dikumpulkan sebelum kelas saya harus diidentifikasi dan dipakai, kelas lama divalidasi bukan milikku. Dan kelas induk dari kelas Magento\Backend\Controller\Adminhtml\Dashboard\RefreshStatisticstersebut tidak ada.

Solusi untuk menjaga modul laporan dinonaktifkan tetapi tetap membuatnya bekerja adalah dengan membuat interseptor untuk metode yang membaca semua rute dan mengganti rute yang disebutkan di atas.

Jadi saya menambahkan ini di.xml

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

dan plugin saya terlihat seperti ini:

<?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
sumber
: - cara memperluas vendor \ magento \ module-directory \ Model \ PriceCurrency.php convertAndRound (), di sini saya perlu mengubah presisi, dalam hal ini cara menggunakan plugin, memaksa saya untuk menggunakan preferensi dalam kasus ini
Pradeep Kumar
6

jangan gunakan plugin gunakan preferensi untuk memperluas modul inti apa pun yang ada di di.xml

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

dan di 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
}

Cara Mengesampingkan Blok Inti, Model, dan pengontrol di Magento2

Pradeep Kumar
sumber
2
ya, ini adalah praktik terbaik. Tetapi dalam kasus saya, saya menghapus modul yang berisi kelas yang diperpanjang oleh controller yang saya coba timpa. Jadi aroundtidak akan bekerja untuk saya. Saya ingin benar-benar mengubah perilaku pengontrol asli.
Marius
jika Anda ingin mengubah perilaku lengkap kemudian buat satu tindakan baru dan kemudian hanya mengubah url di mana pun Anda butuhkan, saya harap ini akan menjadi ide yang bagus
Pradeep Kumar
2

Saya memiliki pengontrol penulisan ulang untuk model review. 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 pendaftaran.php

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

file app / code / Apple / Tinjauan / 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>

Dalam file controller untuk model ulasan,

app / code / Apple / Tinjauan / Pengendali / 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;
        }
    }

Ini adalah kode kerja untuk penggantian pengontrol peninjauan di magento2. Terima kasih.

Rakesh Jesadiya
sumber
: - menggunakan preferensi bukan cara yang baik untuk memperpanjang, gunakan konsep plugin
Pradeep Kumar
@PradeepKumar dapatkah Anda menjelaskan mengapa menggunakan plugin lebih disukai daripada menggunakan preferensi?
Robbie Averill
@robbie: - itu menjaga fungsionalitas asli atau inti, ex jika magneto2 ditingkatkan dan beberapa perubahan terjadi dalam fungsi yang sama maka kita akan kehilangan bagian itu, jadi pergi untuk plugin itu mempertahankan inti logi
Pradeep Kumar
Plugin ini saling eksklusif sedangkan preferensi adalah penulisan ulang- apakah benar @PradeepKumar?
Robbie Averill