Magento 2: controlador de reescritura

17

¿Cómo puedo reescribir un controlador (que en realidad es una acción) en Magento 2?
Intenté, como se indica aquí, así:

Tengo mi propio módulo llamado Namespace_Modulecon un di.xmlarchivo, que se tiene en cuenta, porque el mismo sistema funciona en modelos y bloques
Ejemplo:

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

Estoy tratando de reemplazar las estadísticas de actualización del tablero con mi propia acción. Haciéndolo como anteriormente, el executemétodo en la clase original todavía se llama y no el mío.
var/cachey var/generationfueron despejados.

Marius
fuente
Esto podría ayudar a stackoverflow.com/questions/29654718/…
Tim Hallman
1
@TimHallman. Gracias, pero no quiero escribir un enrutador solo por esto. Estoy seguro de que hay una forma más limpia de hacerlo.
Marius

Respuestas:

16

Lo encontré.
En realidad, lo que publiqué en la pregunta es la forma correcta de reescribir un controlador.

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

funciona bien
El problema para mí fue esto. Olvidé mencionar que eliminé algunos módulos de Magento2 y entre ellos estaba el Reportsmódulo. No lo dije en la pregunta porque no pensé que fuera significativo.
El método anterior para reescribir los controladores (y tal vez otras clases) funciona si todas las clases que intenta cambiar existen y también todas sus clases principales.
Entonces el original se Magento\Backend\Controller\Adminhtml\Dashboard\RefreshStatisticsextiende Magento\Reports\Controller\Adminhtml\Report\Statisticsque había eliminado.
En magento 2, las rutas se recopilan escaneando las carpetas de Controllercarpetas para todos los módulos habilitados y se recopilan en una matriz.
Hasta aquí todo bien.
Termino con esta línea entre otras:

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

Luego, la solicitud coincide con la ruta magento\backend\controller\adminhtml\dashboard\refreshstatisticsy Magento comprueba si la clase correspondiente a esa ruta es una subclase de Magento\Framework\App\ActionInterface. Dado que las rutas se recopilan antes de que mi clase se identifique e instancia, la clase anterior se valida en lugar de la mía. Y la clase padre de la clase Magento\Backend\Controller\Adminhtml\Dashboard\RefreshStatisticsno existe.

Una solución para mantener el módulo de informes deshabilitado pero aún así hacerlo funcionar es crear un interceptor para el método que lea todas las rutas y reemplace la ruta mencionada anteriormente.

Así que agregué esto en di.xml

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

y mi complemento se ve así:

<?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
fuente
: - cómo extender vendor \ magento \ module-directory \ Model \ PriceCurrency.php convertAndRound (), aquí necesito cambiar la precisión, en este caso cómo usar el complemento me obliga a usar preferencia en este caso
Pradeep Kumar
6

no use el complemento de preferencia para extender cualquier módulo principal que 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>

y en 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
}

Cómo anular el bloque central, el modelo y el controlador en Magento2

Pradeep Kumar
fuente
2
Sí, esta es la mejor práctica. Pero en mi caso eliminé el módulo que contenía una clase extendida por el controlador que estoy tratando de anular. Entonces aroundno funcionaría para mí. Quería cambiar completamente el comportamiento del controlador original.
Marius
si desea cambiar el comportamiento completo, cree una nueva acción más y luego simplemente cambie la URL donde lo necesite, espero que sea una buena idea
Pradeep Kumar
2

Tengo reescribir el controlador para el modelo de revisión. archivo 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\\": ""
            }
        }
    }

registro.php archivo

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

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

En el archivo del controlador para el modelo de revisión,

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

Este es el código de trabajo para la anulación del controlador de revisión en magento2. Gracias.

Rakesh Jesadiya
fuente
: - usar preferencia no es una buena manera de extender, usar el concepto de complemento
Pradeep Kumar
@PradeepKumar, ¿puede explicar por qué es preferible usar complementos a usar preferencia?
Robbie Averill
@robbie: - mantiene la funcionalidad original o central, por ejemplo, si magneto2 se actualiza y se producen algunos cambios en la misma función, entonces perderemos esa parte, así que busque el complemento que retiene el núcleo logi
Pradeep Kumar
El complemento es mutuamente exclusivo, mientras que la preferencia es una reescritura, ¿es correcto @PradeepKumar?
Robbie Averill