0

Currently I'm building off of a previous question I asked which involved displaying prices to 4 decimals points. The solution I was given worked great, but I actually only need it to run on a specific product. I'm unsure of how to conditionally call my plugins or for the plugins to conditionally run a specific way based on the product information.

My plugin is something like this (you can reference my question to see the unabridged answer)

# File: {Vendor}/{Extension}/Plugin/Framework/Pricing/Render/Amount.php
public function beforeConvertAndRound( $subject, ... ){
    return [$amount, $includeContainer, 4];
}

Using my IDE, I can see that the information I need is visible in the scope of the above function call:

$subject->price->product->_data->type_id; //-> 'customtype'

The more experienced probably recognized right away that the following code block doesn't work, but it shows the logic I'm looking for.

public function beforeFormatCurrency( $subject, ..., $currentproduct ){
    if (  $subject->price->product->_data->type_id == "customtype" ){
        return [$amount, $includeContainer, 4];
    }
    else {
        return [$amount, $includeContainer, 2];
    }
}

So my question is: What is the recommended strategy to get current page or product information inside of a Plugin?* My question is specifically about getting the product info inside my plugin, but I imagine the approach would very similar in any scope and inside of my template files as well.

Using Magento 2.1.2 CE*

0

I've edited this question after realizing the problem was specific to my use of a Plugin, and without that info, it probably sounded even more ignorant than it is. The question has been answered a few times, but the solutions did not fit my specific needs.

My solution, whether or not it is the best way to go about this, was to extend the class rather than simply use a Plugin. These two links were invaluable to figuring this out: Magento 2 Object Manager Plugin System and Magento 2 Object Manager Preferences. Lastly, this answer came close to what I needed.

So, what I ended up doing was extending the classes using object preference. This allowed me to tap into the __construct method and add a class to determine the current product, which isn't possible with Plugins/Interceptors. If there is another way to do this with just Plugins, it has escaped me.

# File {Vendor}/{Extension}/Plugin/Directory/Model/CustomPriceCurrency.php

namespace {Vendor}\{Extension}Plugin\Directory\Model;

use Magento\Store\Model\StoreManagerInterface;
use Psr\Log\LoggerInterface as Logger;
use Magento\Directory\Model\CurrencyFactory;
use Magento\Framework\Registry;
use Magento\Directory\Model\PriceCurrency; //copied these from original PriceCurrency definition
use Magento\Framework\Registry;

class CustomPriceCurrency extends PriceCurrency{
    public $registry;
    public function __construct(
        # [original arguments copied from original class...],
        Registry $registry //inject the Magento\Framework\Registry object
    ) {
        parent::__construct([original arguments...]);
        $this->registry = $registry; // now it will be available in the plugin
    }
}

The above is the pattern I used to make Magento\Framework\Registry available to my Plugin, which allows me to see what product is displaying. Rather than rewrite the functions that plugin ties into, I decided to keep the plugin pretty much in tact, however I had to add the logic for determining the product type and then return the correct decimal precision, like so:

# File {Vendor}/{Extension}/Plugin/Framework/Pricing/Render/Amount/Plugin.php
public function beforeConvertAndRound(
    $subject,
    $amount,
    $scope = null,
    $currency = null,
    $precision = \Magento\Directory\Model\PriceCurrency::DEFAULT_PRECISION
) {
    $registry = $subject->registry;
    $product = $registry->registry('current_product');
    $type_id = $product !== null ? $product->getTypeId() : null;
    if ( $type_id == 'customtype'){
        $precision = 4;
    }
    return [$amount, $scope, $currency, $precision];
}

I could have probably rewritten PriceCurrency ::convertAndRound() but decided to do it this way. The reason is partly that it didn't work when I first attempted it, but I don't see why it wouldn't. Using the before and after methods are also less intrusive and my hope was there is less chance for me to break some other functionality.

I copied this pattern for Magento\Framework\Locale\Format and the methods I plugged into there. Extending Magento\Framework\Pricing\Render\Amount was not necessary because I found out that the product info is already available. Here is the final plugin for that.

# File : {Vendor}/{Extension}/Plugin/Framework/Pricing/Render/Amount/Plugin.php
namespace {Vendor}\{Extension}\Plugin\Framework\Pricing\Render\Amount;
use Magento\Framework\Pricing\PriceCurrencyInterface;
//use Magento\Framework\Registry;

class Plugin
{
    public function beforeFormatCurrency(
        $subject,
        $amount,
        $includeContainer = true,
        $precision = PriceCurrencyInterface::DEFAULT_PRECISION
    ) {
        $price = $subject->getPrice();
        $product = $price->getProduct();
        $type_id = $product !== null ? $product->getTypeId() : null;
        if ( $type_id == 'customtype'){
            $precision = 4;
        }
        return [$amount, $includeContainer, $precision];
    }
}

That's about it. I had another extension causing a conflict but so far things seem to be working. More testing is definitely needed.

I'm hoping this helps someone, but either way this is how I solidify what I learned. If someone has a better solution or one that improves upon mine, I will happily accept it as correct.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.