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


49

Je suis coincé dans les blocs et contrôleurs du modèle principal de Magento2. Quelqu'un peut-il aider à ce sujet?

Prenons comme exemple la barre d’outils de la liste où il me faut ajouter une nouvelle option de tri appelée tri par le plus populaire . Comment puis-je l'ajouter? Je suppose que pour cela, nous devons ajouter une option au niveau du bloc et une condition au List.phpniveau de la collection.


1
Ignorer les classes de base est une mauvaise idée et peut être effectué de différentes manières. Pouvez-vous décrire votre cas spécifique?
KAndy

@KAndy: - prenons l'exemple de la barre d'outils de liste où j'ai besoin d'ajouter une nouvelle option de tri appelée la plus populaire puis comment l'ajouter. J'espère que nous devons ajouter une option au niveau du bloc et de la condition au niveau de la collection List.php
Pradeep Kumar

Vous devez utiliser exactement après Execute Plugin sur \ Magento \ Catalogue \ Block \ Product \ ProductList \ Toolbar :: getAvailableOrders pour cela. Si un autre utilise des plugins, le client reçoit toutes les commandes. en cas d'utilisation de rewrites, vous obtenez des conflits de modules et un module ne fonctionnera pas
KAndy

@KAndy: - pouvez - vous s'il vous plaît donner un exemple de code que je ne reçois pas plug - in i besoin di.xml et le plugin de code php comment il fonctionne et aussi comment ajouter une nouvelle colonne pour la grille d'administration à l' aide plug - in Help please grid ex pour moi dans le plugin Code ex
Pradeep Kumar

@Kandy: - partagez un exemple de code de plug-in dans le modèle du produit, ajoutez du texte avec le produit getname ()
Pradeep Kumar

Réponses:


30

Magento2 a donné un très bon concept appelé Plugin

nous pouvons faire quoi que ce soit après et avant la fonction principale et nous avons également un autre appelant qui fera à la fois avant et après le code ci-dessous qui couvrira toutes les informations

Créez un fichier di.xml dans Mymodule / etc / di.xml

<?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="../../../../../lib/internal/Magento/Framework/ObjectManager/etc/config.xsd">
   <type name="Magento\Catalog\Block\Product\View">
        <plugin name="inroduct-custom-module" type="Sugarcode\Test\Block\Plugin\Product\View" sortOrder="1"/>
    </type>
    <type name="Magento\Catalog\Model\Product">
        <plugin name="getname-test-module" type="Sugarcode\Test\Model\Plugin\Product" sortOrder="10"/>
    </type>
</config>

dans cet exemple, j'ai pris l'exemple du produit Modèle et bloc de vue produit

J'ai utilisé environ dans le bloc de la vue du produit qui contient n'importe quelle fonction, préfixe et ensuite, assurez-vous que le paramètre 2 doit être le premier, quel est l'objet de votre deuxième fermeture, qui conserve les anciennes informations de retour

<?php
namespace Sugarcode\Test\Block\Plugin\Product;

class View 
{ 
    public function aroundGetProduct(\Magento\Catalog\Block\Product\View $subject, \Closure $proceed)
    {

        echo 'Do Some Logic Before <br>';
        $returnValue = $proceed(); // it get you old function return value
        //$name='#'.$returnValue->getName().'#';
        //$returnValue->setName($name);
        echo 'Do Some Logic  After <br>';
        return $returnValue; // if its object make sure it return same object which you addition data
    }


}

Dans le modèle i Utilisé avant et après c'est

<?php
/**
 * Copyright © 2015 Magento. All rights reserved.
 * See COPYING.txt for license details.
 */
namespace Sugarcode\Test\Model\Plugin;

class Product
{        
    public function beforeSetName(\Magento\Catalog\Model\Product $subject, $name)
    {
        return array('(' . $name . ')');
    }

     public function afterGetName(\Magento\Catalog\Model\Product $subject, $result)
    {
        return '|' . $result . '|';
    }

}

De cette manière, nous pouvons conserver l'ancien code. Ainsi, si demain le code de base de Magento est mis à jour, nous aurons à la fois le nouveau code mis à jour et notre logique personnalisée si nous remplaçons directement le code mis à jour de cette fonction ou de ce fichier :-)

http://devdocs.magento.com/guides/v2.0/extension-dev-guide/plugins.html


Et si vous voulez ajouter une nouvelle méthode à une classe? Autre que la préférence, quelle option avons-nous?
MagePsycho

@MagePsycho: - si vous avez quelque chose de nouveau, cela signifie qu'il est sorti de magento. si son bloc crée un nouveau bloc et l'étend du noyau mais sans préférence. si certains modèles écrivent une séquence, j'espère qu'il n'en sera pas autrement
Pradeep Kumar le

19

Je l'ai finalement eu !!!!
Je suis les étapes ci-dessous pour remplacer le bloc, le contrôleur et le modèle que j'ai extraits. Exemple de modèle de produit et de vue de produit Contrôleur de bloc et vue / Action

Créez un fichier appelé di.xml dans votre /etc/di.xml

<?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="../../../../../lib/internal/Magento/Framework/ObjectManager/etc/config.xsd">
    <preference for="Magento\Catalog\Model\Product" type="Sugarcode\Test\Model\Product" />
    <preference for="Magento\Catalog\Block\Product\View" type="Sugarcode\Test\Block\Product\View" />
    <preference for="Magento\Catalog\Controller\Product\View" type="Sugarcode\Test\Controller\Product\View" />
</config>

Ensuite, j'ai créé le fichier de modèle dans /Model/Product.php

<?php
/**
 * Copyright © 2015 Magento. All rights reserved.
 * See COPYING.txt for license details.
 */
namespace Sugarcode\Test\Model;

class Product extends \Magento\Catalog\Model\Product
{
    /**
     * Get product name
     *
     * @return string
     * @codeCoverageIgnoreStart
     */
    public function getName()
    {
        return $this->_getData(self::NAME).'Local';
    }    
}

Puis j'ai créé le fichier Block dans /Block/Product/View.php

<?php
/**
 * Copyright © 2015 Magento. All rights reserved.
 * See COPYING.txt for license details.
 */
namespace Sugarcode\Test\Block\Product;
/**
 * Product View block
 * @SuppressWarnings(PHPMD.CouplingBetweenObjects)
 */
class View extends \Magento\Catalog\Block\Product\View
{


    /**
     * Retrieve current product model
     *
     * @return \Magento\Catalog\Model\Product
     */
    public function getProduct()
    {
       echo 'Local Block';
       if (!$this->_coreRegistry->registry('product') && $this->getProductId()) {
            $product = $this->productRepository->getById($this->getProductId());
            $this->_coreRegistry->register('product', $product);
        }
        return $this->_coreRegistry->registry('product');
    }


}

Maintenant, créez une vue de produit contrôleur / contrôleur / produit / vue.php

<?php
/**
 *
 * Copyright © 2015 Magento. All rights reserved.
 * See COPYING.txt for license details.
 */
namespace Sugarcode\Test\Controller\Product;

class View extends \Magento\Catalog\Controller\Product\View
{

    /**
     * Product view action
     *
     * @return \Magento\Framework\Controller\Result\Forward|\Magento\Framework\Controller\Result\Redirect
     */
    public function execute()
    {
        // Get initial data from request
       echo 'I Am in Local Controller';
       $categoryId = (int) $this->getRequest()->getParam('category', false);
        $productId = (int) $this->getRequest()->getParam('id');
        $specifyOptions = $this->getRequest()->getParam('options');

        if ($this->getRequest()->isPost() && $this->getRequest()->getParam(self::PARAM_NAME_URL_ENCODED)) {
            $product = $this->_initProduct();
            if (!$product) {
                return $this->noProductRedirect();
            }
            if ($specifyOptions) {
                $notice = $product->getTypeInstance()->getSpecifyOptionMessage();
                $this->messageManager->addNotice($notice);
            }
            if ($this->getRequest()->isAjax()) {
                $this->getResponse()->representJson(
                    $this->_objectManager->get('Magento\Framework\Json\Helper\Data')->jsonEncode([
                        'backUrl' => $this->_redirect->getRedirectUrl()
                    ])
                );
                return;
            }
            $resultRedirect = $this->resultRedirectFactory->create();
            $resultRedirect->setRefererOrBaseUrl();
            return $resultRedirect;
        }

        // Prepare helper and params
        $params = new \Magento\Framework\Object();
        $params->setCategoryId($categoryId);
        $params->setSpecifyOptions($specifyOptions);

        // Render page
        try {
            $page = $this->resultPageFactory->create(false, ['isIsolated' => true]);
            $this->viewHelper->prepareAndRender($page, $productId, $this, $params);
            return $page;
        } catch (\Magento\Framework\Exception\NoSuchEntityException $e) {
            return $this->noProductRedirect();
        } catch (\Exception $e) {
            $this->_objectManager->get('Psr\Log\LoggerInterface')->critical($e);
            $resultForward = $this->resultForwardFactory->create();
            $resultForward->forward('noroute');
            return $resultForward;
        }
    }
}

Cela fonctionne bien pour moi :-)


6

Il y a deux étapes pour remplacer le fichier Block, Model And Controller

1) Ajouter une préférence dans di.xml

2) Créer un bloc, un modèle et un fichier de contrôleur dans votre module

Espace de noms: Prince

Nom du module: Helloworld

Par exemple, pour remplacer le bloc de produit de catalogue ListProduct

1) Créer un fichier di.xml dans un dossierPrince/Helloworld/etc

<?xml version="1.0"?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:ObjectManager/etc/config.xsd">
 <preference for="Magento\Catalog\Model\Product" type="Prince\Helloworld\Model\Rewrite\Catalog\Product" />
</config>

2) Créer un fichier ListProduct.php dans un dossierPrince/Helloworld/Block/Rewrite/Product

<?php
    namespace Prince\Helloworld\Block\Rewrite\Product;

    class ListProduct extends \Magento\Catalog\Block\Product\ListProduct
    {
        public function _getProductCollection()
        {
            // Do your code here
        }
    }

Par exemple, pour remplacer le modèle de produit du catalogue.

1) Ajouter une préférence dans di.xml àPrince/Helloworld/etc

<preference for="Magento\Catalog\Model\Product" type="Prince\Helloworld\Model\Rewrite\Catalog\Product" /> 

2) Créer le fichier modèle Product.php dans un dossier Prince/Helloworld/Model/Rewrite/Catalog

<?php
namespace Prince\Helloworld\Model\Rewrite\Catalog;

class Product extends \Magento\Catalog\Model\Product
{
    public function isSalable()
    {
        // Do your code here

        return parent::isSalable();
    }

}

Contrôleur prioritaire

1) Ajouter une préférence dans di.xml àPrince/Helloworld/etc

<preference for="Magento\Catalog\Controller\Product\View" type="Prince\Helloworld\Controller\Rewrite\Product\View" />

2) Créer View.php dans un dossierPrince/Helloworld/Controller/Rewrite/Product

class View extends \Magento\Catalog\Controller\Product\View
{
    public function execute()
    {
        // Do your stuff here
        return parent::execute();
    }
}

Vous pouvez remplacer d'autres blocs, modèles et contrôleurs en utilisant la même approche.


Avons-nous besoin d'ajouter la réécriture après Controller, Model & Block? Pour moi sans ajouter réécrire a également travaillé.
sagar sapkota

@sagarsapkota Oui, vous pouvez utiliser Controller, Model & Block directement sans réécrire le dossier.
Prince Patel

4

Petite correction mais grosse utilité, nous n’avons pas besoin de créer un nombre n de fichier pour chaque fonction dans le concept de plugin. Pour un module, un seul fichier plug-in est suffisant pour pouvoir étendre tous les modules, tous les modèles, blocs et contrôleurs de Magento complet.

<?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="../../../../../lib/internal/Magento/Framework/ObjectManager/etc/config.xsd">

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

et dans le fichier php plugin

<?php
/**
 * Copyright © 2015 Magento. All rights reserved.
 * See COPYING.txt for license details.
 */
namespace Sugarcode\Test\Model\Plugin;

class Product
{        
    public function beforeSetName(\Magento\Catalog\Model\Product $subject, $name)
    {
        return array('(' . $name . ')');
    }

     public function afterGetName(\Magento\Catalog\Model\Product $subject, $result)
    {
        return '|' . $result . '|';
    } 
    public function aroundGetProduct(\Magento\Catalog\Block\Product\View $subject, \Closure $proceed)
    {

        echo 'Do Some Logic Before <br>';
        $returnValue = $proceed(); // it get you old function return value
        $name='#'.$returnValue->getName().'#';
        $returnValue->setName($name);
        echo 'Do Some Logic  After <br>';
        return $returnValue;// if its object make sure it return same object which you addition data
    }
    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
    }
}

Magento2 Rocks


Bonjour Pradeep - tu as posté trois réponses à cette question - il vaudrait peut-être la peine de les combiner en une seule réponse
Robbie Averill

J'ai essayé avec cette réponse, C'est une erreur de lecture qui se passe Uncaught Error: Call to undefined method Magento\\Backend\\Model\\View\\Result\\Redirect\\Interceptor::getEntityId()ici - \Clousure $proceedObéjct deMagento\\Backend\\Model\\View\\Result\\Redirect\\Interceptor
Praful Rajput

3

Vous pouvez directement étendre le bloc ou la classe de contrôleur de magento dans votre bloc ou votre contrôleur personnalisé.Par exemple, en étendant le modèle de facture PDF dans mon module personnalisé pour changer le logo de la facture générée PDF de la même manière, vous pouvez outrepasser le bloc ou le contrôleur. créer un fichier di.xml sans avoir à définir de préférences.

class Invoice extends \Magento\Sales\Model\Order\Pdf\Invoice
{


    /**
     * Return PDF document
     *
     * @param array|Collection $invoices
     * @return \Zend_Pdf
     */
    public function getPdf($invoices = [])
    {

        $this->_beforeGetPdf();
        $this->_initRenderer('invoice');

        $pdf = new \Zend_Pdf();
        $this->_setPdf($pdf);
        $style = new \Zend_Pdf_Style();
        $this->_setFontBold($style, 10);

        foreach ($invoices as $invoice) {
            if ($invoice->getStoreId()) {
                $this->_localeResolver->emulate($invoice->getStoreId());
                $this->_storeManager->setCurrentStore($invoice->getStoreId());
            }
            $page = $this->newPage();
            $order = $invoice->getOrder();
            /* Add image */
            $this->insertCustomLogo($page, $invoice->getStore());
            /* Add address */
            $this->insertCustomAddress($page, $invoice->getStore());
            /* Add head */

            $this->insertOrder(
                $page,
                $order,
                $this->_scopeConfig->isSetFlag(
                    self::XML_PATH_SALES_PDF_INVOICE_PUT_ORDER_ID,
                    \Magento\Store\Model\ScopeInterface::SCOPE_STORE,
                    $order->getStoreId()

                )
            );

            /* Add document text and number */
            $this->insertDocumentNumber($page, __('Invoice # ') . $invoice->getIncrementId());
            /* Add table */

            $this->_drawHeader($page);
            /* Add body */

            foreach ($invoice->getAllItems() as $item) {
                if ($item->getOrderItem()->getParentItem()) {
                    continue;
                }

                /* Draw item */
                $this->_drawItem($item, $page, $order);

                $page = end($pdf->pages);
            }

            /* Add totals */
            $this->insertTotals($page, $invoice);
            if ($invoice->getStoreId()) {
                $this->_localeResolver->revert();
            }
        }

        $this->_afterGetPdf();
        return $pdf;
    } 

   protected function insertCustomLogo(&$page, $store = null)
   {

     $image='demo.png'

     if ($image) {
        $imagePath = '/logo/' . $image;
        if ($this->_mediaDirectory->isFile($imagePath)) {
            $image = \Zend_Pdf_Image::imageWithPath($this->_mediaDirectory->getAbsolutePath($imagePath));
            $top = 830;
            //top border of the page
            $widthLimit = 270;
            //half of the page width
            $heightLimit = 270;
            //assuming the image is not a "skyscraper"
            $width = $image->getPixelWidth();
            $height = $image->getPixelHeight();

            //preserving aspect ratio (proportions)
            $ratio = $width / $height;
            if ($ratio > 1 && $width > $widthLimit) {
                $width = $widthLimit;
                $height = $width / $ratio;
            } elseif ($ratio < 1 && $height > $heightLimit) {
                $height = $heightLimit;
                $width = $height * $ratio;
            } elseif ($ratio == 1 && $height > $heightLimit) {
                $height = $heightLimit;
                $width = $widthLimit;
            }

            $y1 = $top - $height;
            $y2 = $top;
            $x1 = 25;
            $x2 = $x1 + $width;

            //coordinates after transformation are rounded by Zend
            $page->drawImage($image, $x1, $y1, $x2, $y2);

            $this->y = $y1 - 10;
        }
    }
}

}


Est-ce vraiment la voie à suivre en M2?
Max

Le truc dans Magento 2 est de définir une préférence dans le fichier di.xml. Il me manque cette partie assez essentielle de votre réponse ...
7ochem

3
  • Développeur / Helloworld / registration.php

    
    \Magento\Framework\Component\ComponentRegistrar::register(
        \Magento\Framework\Component\ComponentRegistrar::MODULE,
        'Developer_Helloworld',
        __DIR__
    );
  • Développeur / Helloworld / etc / module.xml

    <config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:Module/etc/module.xsd">
        <module name="Developer_Helloworld" setup_version="1.0.0">
        </module>
    </config>

  • Développeur / Helloworld / etc / di.xml

<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:ObjectManager/etc/config.xsd">    
    <preference for="Magento\Catalog\Controller\Product\View" type="Developer\Helloworld\Controller\Catalog\Product\View" />
</config>

  • Développeur / Helloworld / Contrôleur / Catalogue / Produit / View.php

    namespace Developer\Helloworld\Controller\Catalog\Product;
    class View extends \Magento\Catalog\Controller\Product\View
    {
        public function execute(){
            echo '__TEST__';exit;
        }
    }
espérons que cela vous aidera

2

Une classe d'actions peut être réécrite de la même manière que dans Magento 1. Dans Magento 1, nous avions un beforeattribut autour des balises.<routers>..<args><modules><... before="Mage_Catalog">Namespace_MyModule ..

Dans [module path]/etc/[nothing|adminhtml|frontend]/routes.xml:

<config>
    <router id="[admin|standard|]">
        <route id="catalog" frontName="catalog">
            <module name="Namespace_MyModule" before="Magento_Catalog"/>
        </route>
    </router>
</config>

Et la classe d'action \Namespace\MyModule\Controller\[same path of action as in core module]\SameActionName.phpclass SameActionName.php extends \Magento\Catalog\...\SameActionName

Ceci est le module Magento_Catalog, fichier Magento\Catalog\etc\adminhtml\routes.xmlenregistrant une nouvelle route dans admin:

<router id="admin">
    <route id="catalog" frontName="catalog">
        <module name="Magento_Catalog" before="Magento_Backend" />
    </route>
</router>

http://devdocs.magento.com/guides/v2.1/extension-dev-guide/routing.html

Pour remplacer l'action du contrôleur dans une route par une commande personnalisée, ajoutez la classe de contrôleur personnalisé avant le contrôleur d'origine.

Le contrôleur et l'action personnalisés doivent partager les mêmes noms avec les noms d'origine.

Le système traite le contrôleur personnalisé avant l’original, alors que la route reste la même.

Si vous devez réinitialiser un itinéraire et une conception, transférez le traitement de la demande vers un autre itinéraire:

$this->_forward('other/controller/action')

Pour supprimer l'action du contrôleur, transférez-la vers noroute, par exemple, dans app / code / Company / SomeExtension / Controller / Account.php:

Je ne crois pas que les préférences ou les plug-ins des classes d'action soient une bonne idée selon les meilleures pratiques de Magento. Et il y a peut-être plus que cela.


0

Pour remplacer directement une classe, vous devez utiliser les préférences. En savoir plus sur les documents de développement: https://devdocs.magento.com/guides/v2.0/extension-dev-guide/build/di-xml-file.html#abstraction-implementation-mappings
Nous utilisons généralement Interceptors (plugins) car c’est la meilleure pratique pour réécrire ou ajouter une partie de vos modifications. Voir dev docs: https://devdocs.magento.com/guides/v2.0/extension-dev-guide/plugins.html

En conservant votre exemple de tri des éléments de la liste en ajoutant un nouvel ordre de tri "Les plus populaires" que je vous fournis la meilleure façon de modifier le résultat.
Créez un module personnalisé et créez une configuration app/code/Arsal/SortOption/etc/module.xml:

<?xml version="1.0" ?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"  xsi:noNamespaceSchemaLocation="urn:magento:framework:Module/etc/module.xsd">
   <module name="Arsal_SortOption" setup_version="1.0.0" />
</config> 

Enregistrez maintenant votre module app/code/Arsal/SortOption/registration.php:

<?php
 \Magento\Framework\Component\ComponentRegistrar::register(
     \Magento\Framework\Component\ComponentRegistrar::MODULE,
     'Arsal_SortOption',
      __DIR__
 );

Maintenant, créez di.xml app/code/Arsal/SortOption/etc/di.xml:

<?xml version="1.0" ?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:ObjectManager/etc/config.xsd">
    <type name="Magento\Catalog\Block\Product\ProductList\Toolbar">
       <plugin name="toolbar_instance" type="Arsal\SortOption\Block\Product\ProductList\Toolbar" />
    </type>
</config>

Maintenant, créez une classe de bloc Arsal\SortOption\Block\Product\ProductListToolbar.php:

<?php
namespace Arsal\SortOption\Block\Product\ProductList;

class Toolbar {

    public function afterGetAvailableOrders (
        \Magento\Catalog\Block\Product\ProductList\Toolbar $subject, $result
    ) {
        $result ['most_popular'] = 'most popular';
        return $result;
    }

Cela ajoutera une option d'ordre de tri personnalisé pour trier la liste des ordres. entrez la description de l'image ici }

En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.