Post by alexmitev » Wed Sep 18, 2024 10:53 pm

Hello,
I have a problem with methods which are being called from another method in the same model not firing events registered for them.

Example:
I have registered an event for the catalog/model/chekcout/addOrderHistory() method, which works as expected.
However, I have created another method in the same model which calls addOrderHistory:

Code: Select all

	
public function verifyOrder($order_id) {
	$this->addOrderHistory($order_id, 29);
}
And this call does not trigger the registered event.

I digged a little further and decided the cause was not binding the closure in the model proxy.
So, I modified the Loader class as follows:

Code: Select all

$proxy = new \Opencart\System\Engine\Proxy();

foreach (get_class_methods($model) as $method) {
	if ((substr($method, 0, 2) != '__') && is_callable($class, $method)) {
		$closure = function (mixed &...$args) use ($route, $model, $method): mixed {
			...
		};
		
		$closure = $closure->bindTo($proxy, $proxy);
		
		$proxy->{$method}  = $closure;
	}
}

$this->registry->set($key, $proxy);
However the event is still not fired.
Any help would be appreciated.

Regards,
Alex

New member

Posts

Joined
Wed Jan 19, 2011 10:38 pm

Post by halfhope » Thu Sep 19, 2024 4:54 am

Hi!

It would be nice to see the code of the first event handler. If it has any return values, using return, then all events after it will not be fired.

My FREE extensions in marketplace. [ security | flexibility | speedup ]


User avatar
Active Member

Posts

Joined
Tue Dec 10, 2013 9:44 pm
Location - San Diego

Post by alexmitev » Thu Sep 19, 2024 9:58 pm

It would be nice to see the code of the first event handler. If it has any return values, using return, then all events after it will not be fired.
It is just the standard OpenCart code in catalog/model/checkout/order/addOrderHistory()
not returning anything

OK, I've created a testcase which is a little easier to track:

Code: Select all

<?php
/* the standard OC Proxy class*/
class Proxy {
	public function __get($key) {
		return $this->{$key};
	}
	
	public function __set($key, $value) {
		 $this->{$key} = $value;
	}
	
	public function __call(string $method, array $args) {
		// Hack for pass-by-reference
		foreach ($args as $key => &$value);

		if (isset($this->{$method})) {
			return call_user_func_array($this->{$method}, $args);
		} else {
			$trace = debug_backtrace();

			throw new \Exception('<b>Notice</b>:  Undefined property: Proxy::' . $method . ' in <b>' . $trace[0]['file'] . '</b> on line <b>' . $trace[0]['line'] . '</b>');
		}
	}
}

class MyClass {
	public function a() {
		echo 'in method a <br>';
	}
	
	public function b() {	
		echo 'in method b <br>';
		$this->a();
	}
}

$proxy = new Proxy();
$my_class = new MyClass();

foreach (get_class_methods('MyClass') as $method) {
	$closure = function (&...$args) use ($method, $my_class) {
		echo 'call proxy ' . $method . ' <br/>';
		call_user_func_array([$my_class, $method], []);
	};
	
	$closure = $closure->bindTo($proxy, $proxy);
	
	$proxy->{$method} = $closure;
}

$proxy->b();
Expected result:

Code: Select all

call proxy b 
in method b
call proxy a 
in method a
Actual result:

Code: Select all

call proxy b 
in method b
in method a
And if I do

Code: Select all

var_dump($this);
inside method b(), it outputs

Code: Select all

object(MyClass)
instead of

Code: Select all

object(Proxy)

New member

Posts

Joined
Wed Jan 19, 2011 10:38 pm

Post by softmonke » Sat Sep 21, 2024 3:46 am

If you're using OpenCart 4, isn't it "addHistory" rather than "addOrderHistory"?

Anyway, maybe in your "verifyOrder" function, you can just load the model, and call it via the loaded model rather than calling it as an internal function, like below:

Code: Select all

public function verifyOrder($order_id) {
	$this->load->model('checkout/order');
	$this->model_checkout_order->addOrderHistory($order_id, 29);
}
I believe this should trigger the event registered for "addOrderHistory".

Update:
Tested on my own installation of OpenCart v4.0.2.3 and loading the model then calling addHistory via the loaded model will trigger the event. But calling the addHistory function internally does not trigger the event.
Last edited by softmonke on Sun Sep 22, 2024 7:51 am, edited 1 time in total.

Check out our ever-growing list of extensions for OpenCart here.
Some useful extensions for a better admin experience: Image File Manager ProDrag & Drop Sort Order

Reach out to us at hello@softmonke.com for your OpenCart web development needs or feedback for our extensions.


User avatar
Active Member
Online

Posts

Joined
Tue May 23, 2023 4:42 am


Post by halfhope » Sat Sep 21, 2024 7:31 am

Code: Select all

In addition to changing data through arguments, event handlers can also return values using return. For example, if the controller/common/home/before event handler returns the generated html code via return, then the entire output of the common/header controller will be replaced by it, and the common/header controller itself will not be executed, but the after event will be fired. Those. it is possible to replace the execution data of functions without executing them.
From here
viewtopic.php?t=227710&start=20#p839606

My FREE extensions in marketplace. [ security | flexibility | speedup ]


User avatar
Active Member

Posts

Joined
Tue Dec 10, 2013 9:44 pm
Location - San Diego

Post by softmonke » Sun Sep 22, 2024 7:56 am

halfhope wrote:
Sat Sep 21, 2024 7:31 am

Code: Select all

In addition to changing data through arguments, event handlers can also return values using return. For example, if the controller/common/home/before event handler returns the generated html code via return, then the entire output of the common/header controller will be replaced by it, and the common/header controller itself will not be executed, but the after event will be fired. Those. it is possible to replace the execution data of functions without executing them.
From here
viewtopic.php?t=227710&start=20#p839606
I might be wrong but I think what OP is saying is that calling the addHistory function internally like "$this->addHistory" in "model/checkout/order.php" does not trigger any events registered for "model/checkout/order.addHistory". This doesn't seem to address the issue they are facing as it's not an issue whether the event is firing since OP already mentioned that the event is firing correctly.

Based on my testing for OpenCart v4.0.2.3, loading the model in the custom function in "model/checkout/order.php" like below will trigger the event registered for "model/checkout/order.addHistory" but calling it internally by performing "$this->addHistory(...);" doesn't trigger the event:

Code: Select all

class Order extends \Opencart\System\Engine\Model {
	...
	public function customFunction() {
		$this->load->model('checkout/order');
		$this->model_checkout_order->addHistory(...); // this will trigger events registered under "model/checkout/order.addHistory"
	}
	
	public function anotherCustomFunction() {
		$this->addHistory(...); // this will not trigger any events registered under "model/checkout/order.addHistory"
	}
	...
}

Check out our ever-growing list of extensions for OpenCart here.
Some useful extensions for a better admin experience: Image File Manager ProDrag & Drop Sort Order

Reach out to us at hello@softmonke.com for your OpenCart web development needs or feedback for our extensions.


User avatar
Active Member
Online

Posts

Joined
Tue May 23, 2023 4:42 am

Who is online

Users browsing this forum: No registered users and 0 guests