magento2 – How to use 2 observer in same event in Magento 2?

I want to use 2 observer on ‘sales_order_place_after’ this observer as i have checked if i place one observer it works fine but how can i run 2 observer with one event.

<event name="sales_order_place_after">
    <observer name="sales_order_place_after"
              instance="HlSendEmailObserverCustomerNewOrderObserver"/>
    <observer name="hl_sales_order_place_after" instance="HlSendEmailObserverAfterOrderObserver" />
</event>

here oage got stuck on checkout and nothing happens.

Any idea how to do that?

Magento2 Product Collection Observer only changes one page at a time

In ListProduct block Magento is using initializeProductCollection() to initialize the collection.

While initializing it dispatches event catalog_block_product_list_collection as follows.

$this->_eventManager->dispatch(
    'catalog_block_product_list_collection',
    ('collection' => $collection)
);

Using the event catalog_block_product_list_collection I am trying to filter a list of products:

$_collection = $observer->getCollection();
$_collection->addAttributeToFilter('sku', ('nin' => $invalidSkus));

however instead of limiting the category from 50 products to 49 products, it is limiting the page results of 12 products to 11 products. If I have a list of 12 invalid skus that all coincide to be on page 1, then page 1 returns no products.

How do I filter the entire product list for a category, not just the product list for a single category page?

magento2.3 – How to get the option label for a custom customer variable in an observer in Magento 2

I am trying to build an observer to catch the form submissions during customer account registration that sends an email copy to our stores address letting us know a customer has registered and what information they filled out. The below code is working, however if the custom variable is of the dropdown type it will return the option ID, and not the value/label located in the eav_attribute_option_value table. Either the label for the front end or admin will work here (store view 1 and 0 respectively) for my purposes.

example: ‘account_level’ will return as “5” instead of “Wholesale”

How can I get the labels for these options in my observer?

...
protected $_customerRepositoryInterface;
...


public function __construct(
...
    MagentoCustomerApiCustomerRepositoryInterface $customerRepositoryInterface
) {
...
    $this->_customerRepositoryInterface = $customerRepositoryInterface;
}

public function getCustomer($customerId)
{   
    return $this->_customerRepositoryInterface->getById($customerId);
}

public function execute(MagentoFrameworkEventObserver $observer)
{
    
    $customer = $observer->getEvent()->getCustomer();
    $custId = $customer->getId();
    $custInfo = $this->getCustomer($custId);
    $CustData = $custInfo->getCustomAttributes();
    
    $aboutThem = '';
    $accountLevel = '';
    $web = '';
    $volume = '';
    $normalPurchase = '';
    $primeAct = '';
    $primeName = '';
    $primePos = '';
    $primeEmail = '';
    $registerAs = '';
    $years = '';
    
    if (array_key_exists('about_them', $CustData)) {$aboutThem = $CustData('about_them')->getValue();}
    if (array_key_exists('account_level', $CustData)) {$accountLevel = $CustData('account_level')->getValue();}
    if (array_key_exists('company_website', $CustData)) {$web = $CustData('company_website')->getValue();}
    if (array_key_exists('estimated_volume', $CustData)) {$volume = $CustData('estimated_volume')->getValue();}
    if (array_key_exists('normal_purchase', $CustData)) {$normalPurchase = $CustData('normal_purchase')->getValue();}
    if (array_key_exists('primary_activity', $CustData)) {$primeAct = $CustData('primary_activity')->getValue();}
    if (array_key_exists('primary_contact_name', $CustData)) {$primeName = $CustData('primary_contact_name')->getValue();}
    if (array_key_exists('primary_contact_position', $CustData)) {$primePos = $CustData('primary_contact_position')->getValue();}
    if (array_key_exists('primary_contact_email', $CustData)) {$primeEmail = $CustData('primary_contact_email')->getValue();}
    if (array_key_exists('register_as', $CustData)) {$registerAs = $CustData('register_as')->getValue();}
    if (array_key_exists('years_in_business', $CustData)) {$years = $CustData('years_in_business')->getValue();}

...
}

php – Adjusting variables on change of status attribute of my Order Laravel model on the updated event in observer

Nine status combinations

Status can either be 0, 1, or 2, so there are 8 possible changes in status.

There are nine (three states multiplied by three states) possible “changes” (state combinations). Although three of them are to stay the same. This is why you need seven if statements (and actually you don’t, the last could be a simple else): six to cover the possible changes and one to cover the three possible ways to stay the same. If there were only two statuses, this would be four (two times two) and three (one plus two times one). If four, then sixteen (four times four) and thirteen (one plus four times three).

In general if there are $n$ states, then there will be $n^2$ combinations and $1 + n(n – 1) = n^2 -n + 1$ conditions. There are $n$ combinations that stay the same. So the total number of combinations minus the number where the status stays the same plus one for all those where the status stays the same.

Naming

    $unchanged_order = $order->getOriginal();

I would find $original_order clearer.

        // skip if status wasn't changed. I use this skip so that we don't have to check all of the following. 

Rather than commenting, it would be simpler just to return in that case. As there is no reason to update the client if nothing has changed.

        // Nothing changed; nothing to do.  

Alternatively, this comment is shorter and better explains what’s happening.

Alternative

    if ($original_order->state === $order->state) {
        return;
    }

    if ($original_order->state === 1) {
        $order->client->total_generated_revenue -= $order->total;
        $order->client->orders_got -= 1;
    } elseif ($original_order->state === 2) {
        $order->client->orders_cancelled -= 1;
    }

    if ($order->state === 1) {
        $order->client->total_generated_revenue += $order->total;
        $order->client->orders_got += 1;
    } elseif ($order->state === 2) {
        $order->client->orders_cancelled += 1;
    }

If you work it out, this will have all the same results but with only five comparisons rather than the seven that you used.

It doesn’t make much difference with two states, but you could also use two switch statements instead of two if/elseif structures.

Status objects

A more advanced form would be to use objects or classes as the states rather than primitive integers. Then you could replace both structures (not the first if) with something like

    $original_order->status->leave($order);
    $order->status->enter($order);

Then you could make simpler methods, like

namespace OrderStatus;

class Cancelled implements OrderStatus
{

    public function enter($order)
    {
        $order->client->orders_cancelled++;
    }

No if/else scaffolding.

That would make it easier to add a status, as you’d just have to create one file and implement the required methods. This makes the update code simpler at the cost of making the status more complex.

How to modify product data on observer pre cache?

My problem would be the following:

I need to modify the product data on load after the product page was cached.

Everytime I load a product I need to request some data to an api and overwrite certain product attribute, even after it was cached.

I tried intercepting these events, but the code on my observers only gets executed the first time, then it gets cached:

catalog_product_load_after

catalog_controller_product_view

I’m open to any alternative solution btw!
Thanks

event observer – Magento 2 origData null in customer_save_before

I have created an observer on the customer_save_before event. Surprisingly
$observer->getEvent()->getCustomer()->getOrigData() is null. Is my expectation wrong?

This is also happening for customer_save_commit_after.

I am looking for an event for which the customer data (new and original) is available, that ideally takes place after the new data was persisted in the db, independent of the area from which it is called frontend or adminhtml.

I have logged all the events that are being dispatched throughout my save customer process and the two events mentioned above made the most sense.

Is there such an event?

Thanks!

magento2 – Magento 2.3 – Why observer triggers multiple times on ‘newsletter_subscriber_save_after’ event?

I am trying to send email when customer subscribes/unsubscribes from newsletter, however, my observer is triggering three times for some odd reason. Any ideas why or how to prevent it?

The following code logs “Test” three times in the log files…

Observer:

<?php
namespace VENDORMODULEObserver;

use MagentoFrameworkEventObserver as EventObserver;
use MagentoFrameworkEventObserverInterface;
use PsrLogLoggerInterface as Logger;

class NotifyAdmin implements ObserverInterface
{
    public function __construct(
        Logger $logger
    ) {
        $this->_logger = $logger;
    }

    public function execute(EventObserver $observer)
    {
        $this->_logger->info('Test');
    }
}

reinventing the wheel – Observer pattern in Rust

A simple implementation of the Observer pattern in rust. The Observable constructor (::new) is called with a subscription function which will be called every time an observer subscribes.

The subscription function must return a cleanup function which is defined by the using code.

An observer subscribed to the Observable either by:

  • passing a simple next function
  • providing an Observer which provide a next, complete and error function
  • providing a FullObserver which, in addition to the aforementioned function, provide also a start function which allows the Observer to be called before the processing start.
use std::error::Error;
use std::rc::Rc;

struct Observer<T, E> {
    next: Box<dyn Fn(T)>,
    complete: Box<dyn Fn()>,
    error: Box<dyn Fn(E)>,
}

struct FullObserver<T, E> {
    start: Box<dyn Fn(&mut Subscription)>,
    next: Box<dyn Fn(T)>,
    complete: Box<dyn Fn()>,
    error: Box<dyn Fn(E)>,
}

struct Observable<T, E> {
    subscription_fn: Rc<dyn Fn(&FullObserver<T, E>) -> Box<dyn Fn()>>,
}

struct Subscription {
    cleanup: Option<Box<dyn Fn()>>,
    closed: bool,
}

impl Subscription {
    fn new<T, E, F: Fn() + 'static>(
        observer: FullObserver<T, E>,
        subscription_fn: Rc<dyn Fn(&FullObserver<T, E>) -> F>,
    ) -> Subscription {
        let mut subscription = Subscription {
            cleanup: None,
            closed: false,
        };

        (observer.start)(&mut subscription);
        if !subscription.closed {
            let cleanup = Box::new((subscription_fn)(&observer));
            subscription.cleanup = Some(cleanup);
        }

        return subscription;
    }

    fn unsubscribe(&mut self) {
        if let Some(cleanup) = &self.cleanup {
            (cleanup)();
        }
        self.closed = true;
    }
}

impl<T, E> Observable<T, E> {
    fn new<F: Fn() + 'static>(
        subscription_fn: impl (Fn(&FullObserver<T, E>) -> F) + 'static,
    ) -> Self {
        Observable {
            subscription_fn: Rc::new(move |observer| Box::new(subscription_fn(observer))),
        }
    }

    fn subscribe(&self, next: impl Fn(T) + 'static) -> Subscription {
        Subscription::new(
            FullObserver {
                start: Box::new(|_s| {}),
                next: Box::new(next),
                complete: Box::new(|| {}),
                error: Box::new(|_err| {}),
            },
            self.subscription_fn.clone(),
        )
    }

    fn subscribe_observer(&self, observer: Observer<T, E>) -> Subscription {
        Subscription::new(
            FullObserver {
                start: Box::new(|_s| {}),
                next: observer.next,
                complete: observer.complete,
                error: observer.error,
            },
            self.subscription_fn.clone(),
        )
    }

    fn subscribe_full_observer(&self, observer: FullObserver<T, E>) -> Subscription {
        Subscription::new(observer, self.subscription_fn.clone())
    }
}

fn main() {
    let observable = Observable::<i32, Box<dyn Error>>::new(|observer| {
        (observer.next)(42);
        (observer.next)(666);
        (observer.complete)();
        return || {
            println!("cleanup");
        };
    });

    let mut subscription = observable.subscribe(|value| {
        println!("next {}", value);
    });
    subscription.unsubscribe();

    let some_closure = "yo!";
    observable.subscribe_full_observer(FullObserver {
        start: Box::new(|_subscription| println!("start")),
        next: Box::new(|value| println!("next {}", value)),
        complete: Box::new(move || println!("complete {}", some_closure)),
        error: Box::new(|error| eprintln!("error {:?}", error)),
    });
}
```