Magento2でコアモデルのブロックとコントローラーをオーバーライドすることにこだわっています。誰でもこれを助けることができますか?
リストツールバーを例として、sort by most popularという新しいソートオプションを追加する必要があります。どうすれば追加できますか?このために、ブロックレベルでオプションを追加し、List.php
コレクションレベルで条件を追加する必要があると思います。
Magento2でコアモデルのブロックとコントローラーをオーバーライドすることにこだわっています。誰でもこれを助けることができますか?
リストツールバーを例として、sort by most popularという新しいソートオプションを追加する必要があります。どうすれば追加できますか?このために、ブロックレベルでオプションを追加し、List.php
コレクションレベルで条件を追加する必要があると思います。
回答:
Magento2はプラグインと呼ばれる非常に良いコンセプトを与えました
コア関数の前後に何でもできます。また、すべての情報をカバーするコードが前後に実行されるもう1つの呼び出しがあります
Mymodule / etc / di.xmlにファイル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>
この中で、製品モデルと製品ビューブロックの例を取り上げました
私は周りのすべての機能を利用する接頭辞です製品ビューブロックの周りに使用し、最初の1がある2パラメータがあるべきことを確認してくださいあなたの使用して第二のオブジェクトされた閉鎖古いリターン情報を保持しています
<?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
}
}
モデルiでは、その前後に使用されます
<?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 . '|';
}
}
この方法で古いコードを保持できるため、明日Magentoコアコードが更新された場合、新しい更新コードとカスタムロジックの両方を直接オーバーライドすると、その関数またはファイルの新しい更新コードが失われます:-)
http://devdocs.magento.com/guides/v2.0/extension-dev-guide/plugins.html
ついにできた !!!!
以下の手順に従って、ブロック、コントローラー、およびモデルをオーバーライドします製品モデルと製品ビューのブロックとビューコントローラー/アクションの例
/etc/di.xmlに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>
次に、/ 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';
}
}
次に、/ 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');
}
}
Product View Controller /Controller/Product/View.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;
}
}
}
私にとってはうまくいく:-)
ブロック、モデル、コントローラーファイルをオーバーライドするには、2つのステップがあります
1)di.xmlに設定を追加します
2)モジュールにブロック、モデル、コントローラーファイルを作成する
名前空間:プリンス
モジュール名:Helloworld
たとえば、カタログ製品のListProductブロックをオーバーライドするには
1)フォルダにdi.xmlファイルを作成しますPrince/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)フォルダーにListProduct.phpを作成しますPrince/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
}
}
たとえば、カタログ製品モデルをオーバーライドします。
1)di.xmlで設定を追加しますPrince/Helloworld/etc
<preference for="Magento\Catalog\Model\Product" type="Prince\Helloworld\Model\Rewrite\Catalog\Product" />
2)フォルダーにProduct.phpモデルファイルを作成する 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();
}
}
オーバーライドコントローラー
1)di.xmlで設定を追加しますPrince/Helloworld/etc
<preference for="Magento\Catalog\Controller\Product\View" type="Prince\Helloworld\Controller\Rewrite\Product\View" />
2)フォルダにView.phpを作成しますPrince/Helloworld/Controller/Rewrite/Product
class View extends \Magento\Catalog\Controller\Product\View
{
public function execute()
{
// Do your stuff here
return parent::execute();
}
}
同じアプローチを使用して、他のブロック、モデル、およびコントローラーをオーバーライドできます。
小さな修正ですが、大きな有用性があり、プラグインの概念で各関数に対してn個のファイルを作成する必要はありません。1つのモジュールには、すべてのモジュール、すべてのモデル、ブロック、および完全なMagentoのコントローラーを拡張してコードの下で自己チェックできるという点で、1つのプラグインファイルで十分です。
<?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>
およびプラグインのPHPファイルで
<?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
Uncaught Error: Call to undefined method Magento\\Backend\\Model\\View\\Result\\Redirect\\Interceptor::getEntityId()
。ここ\Clousure $proceed
からobejct取得Magento\\Backend\\Model\\View\\Result\\Redirect\\Interceptor
カスタムブロックまたはコントローラーでmagentoのブロックまたはコントローラークラスを直接拡張できます。たとえば、カスタムモジュールでPDF請求書モデルを拡張して請求書PDFのロゴを変更すると、ブロックまたはコントローラーをオーバーライドできるのと同じ方法で生成できます。 di.xmlファイルを作成し、プリファレンスを設定する必要はありません。
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;
}
}
}
}
di.xml
です。あなたの答えにはこのかなり重要な部分が欠けています
Developer / Helloworld / registration.php
\Magento\Framework\Component\ComponentRegistrar::register(
\Magento\Framework\Component\ComponentRegistrar::MODULE,
'Developer_Helloworld',
__DIR__
);
Developer / 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>
Developer / 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>
namespace Developer\Helloworld\Controller\Catalog\Product;
class View extends \Magento\Catalog\Controller\Product\View
{
public function execute(){
echo '__TEST__';exit;
}
}
これが役立つことを願って
アクションクラスは、Magento 1と同じ方法で書き換えることができます。Magento1ではbefore
、タグの周りに属性がありました。<routers>..<args><modules><... before="Mage_Catalog">Namespace_MyModule ..
で[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>
そしてアクションクラス\Namespace\MyModule\Controller\[same path of action as in core module]\SameActionName.php
はclass SameActionName.php extends \Magento\Catalog\...\SameActionName
これは、Magento_Catalogモジュールで、Magento\Catalog\etc\adminhtml\routes.xml
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
ルート内のコントローラーアクションをカスタムアクションに置き換えるには、元のコントローラーの前にカスタムコントローラークラスを追加します。
カスタムコントローラとアクションは、元のコントローラと同じ名前を共有する必要があります。
システムは元の前にカスタムコントローラーを処理しますが、ルートは同じままです。
ルートとデザインをリセットする必要がある場合、リクエスト処理を別のルートに転送します。
$this->_forward('other/controller/action')
コントローラーアクションを削除するには、たとえばapp / code / Company / SomeExtension / Controller / Account.phpでnorouteに転送します。
Magentoのベストプラクティスでは、Actionクラスの設定やプラグインが良い考えだとは思いません。そして、それ以上のものがあるかもしれません。
クラスを直接オーバーライドするには、設定を使用する必要があります。開発者
向けドキュメントの詳細を参照してください:https : //devdocs.magento.com/guides/v2.0/extension-dev-guide/build/di-xml-file.html#abstraction-implementation-mappingsほとんどの場合、インターセプターを使用します(プラグイン)方法。これは、変更の一部を書き換えたり追加したりするためのベストプラクティスであるためです。
開発者向けドキュメントを参照してください:https : //devdocs.magento.com/guides/v2.0/extension-dev-guide/plugins.html
新しい並べ替え順序「最も人気のある」を追加してリストアイテムの並べ替えの例を維持する結果を変更する最良の方法。
カスタムモジュールを作成し、構成を作成します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>
モジュールを登録します app/code/Arsal/SortOption/registration.php
:
<?php
\Magento\Framework\Component\ComponentRegistrar::register(
\Magento\Framework\Component\ComponentRegistrar::MODULE,
'Arsal_SortOption',
__DIR__
);
次に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>
次に、ブロッククラスを作成します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;
}