Page 1 of 16

[RELEASED] Override Engine for OpenCart

Posted: Fri Oct 05, 2012 12:50 am
by JNeuhoff
The Override Engine provides a replacement system engine for OpenCart. It uses the same MVC architecture as the standard OpenCart framework.

All instances of controller, model, or library classes are created by a special factory class.

An additional override feature is supported. This allows 3rd party addons to do changes to the OpenCart core classes, templates, and language files. Core controller, model and library classes can be extended and their methods be overridden in a normal object oriented programming manner.

VQmod is supported, too, but I think this new Override Engine allows the modifications of OpenCart core files to be done in an easier way. The Override Engine uses object oriented programming techniques to modify OpenCart core classes, whereas VQmod uses dynamic search and replace operations for this.

Re: [RELEASED] Override Engine for OpenCart

Posted: Wed Oct 10, 2012 4:59 pm
by qahar
I'm not test it yet but from what I read, it's sound interesting!

The only concern is conflict possibility and performance of the chain-class.
Well, I think I will found an answer after test it :)

Re: [RELEASED] Override Engine for OpenCart

Posted: Wed Oct 10, 2012 8:18 pm
by dunks
very interesting,, appreciated thankU ,, will test it too :)

Re: [RELEASED] Override Engine for OpenCart

Posted: Thu Oct 11, 2012 1:23 am
by JNeuhoff
qahar wrote:I'm not test it yet but from what I read, it's sound interesting!

The only concern is conflict possibility and performance of the chain-class.
Well, I think I will found an answer after test it :)
I have it already running on 2 new live sites in the UK:

http://www.ion.uk.com
http://www.madeinharwich.com

And it has no performance degradation, to the contrary, it is slighly faster. Of course, I'd only know for sure if I do some precise performance measurement with and without the override engine. I am planning to port another 5 websites over to the latest OpenCart with this new override engine.

Re: [RELEASED] Override Engine for OpenCart

Posted: Thu Oct 11, 2012 1:56 am
by Qphoria
Ah.. Great to see something finally came from the old 0.x discussions! Looks like you guys have done a nice job with this. I haven't tried it yet but it sounds great the way you got the automatic subclassing system working for multiple mods. I will have to try this.

Nice Work!

Re: [RELEASED] Override Engine for OpenCart

Posted: Thu Oct 11, 2012 2:41 am
by JNeuhoff
Qphoria wrote:Ah.. Great to see something finally came from the old 0.x discussions! Looks like you guys have done a nice job with this. I haven't tried it yet but it sounds great the way you got the automatic subclassing system working for multiple mods. I will have to try this.

Nice Work!
Let me know how your testing goes. I already have some addons where each one of them extends the same header.php, amongst other classes, and the automatic chaining of class extensions works just fine.

Re: [RELEASED] Override Engine for OpenCart

Posted: Wed Oct 24, 2012 6:46 am
by 3rdcorner
Something like this is what I've built in-house. The only problem I have is it replacing the core files. Right now I use VQMod to modify the core files and keep my override system separated.

How's the upgrade process with this system?

Looks great, I'll see for my next project what the options are for using this with VQMod, although it might not be worth the trouble.

Re: [RELEASED] Override Engine for OpenCart

Posted: Wed Oct 24, 2012 4:50 pm
by JNeuhoff
3rdcorner wrote:Something like this is what I've built in-house. The only problem I have is it replacing the core files. Right now I use VQMod to modify the core files and keep my override system separated.

How's the upgrade process with this system?

Looks great, I'll see for my next project what the options are for using this with VQMod, although it might not be worth the trouble.
I don't use VQmod at all anymore for new OpenCart projects 8)

You can easily modify OpenCart core classes, language files and even templates with the new Override Engine.

Upgrading to newer future OpenCart versions should be a lot easier with this Override Engine, compared to VQmod, because all your overrides (e.g. extended core classes with their overriden methods) are in a separate 'override' folder. VQmod's dynamic XML search and replace operations get more easily broken in OpenCart upgrades.

Re: [RELEASED] Override Engine for OpenCart

Posted: Wed Oct 24, 2012 10:11 pm
by Qphoria
So how do you do small changes with this?

Lets say I want to change this line in the catalog/model/account/customer.php file:

INSTEAD OF THIS:
$this->db->query("UPDATE " . DB_PREFIX . "customer SET address_id = '" . (int)$address_id . "' WHERE customer_id = '" . (int)$customer_id . "'");
I WANT THIS:
$this->db->query("UPDATE " . DB_PREFIX . "customer SET address_id = '" . (int)$address_id . "', newfield = 1 WHERE customer_id = '" . (int)$customer_id . "'");
I assume I need to subclass the function

Code: Select all

 public function addCustomer($data) 
But when this function is called, it uses the last_insert_id which if called in the child and then called in the parent, what will be the end result of that? Seems like it would generate duplicate insert records.

Re: [RELEASED] Override Engine for OpenCart

Posted: Wed Oct 24, 2012 11:22 pm
by JNeuhoff
That's an easy one. 8) Call the parent method first (you should always call the parent method somewhere in your overriden method, so as to not to break the chain of class extensions). Then, in the overridden method, find the newly added customer record by email, and add the newfield, for example:

Code: Select all

<?php
class myaddon_ModelAccountCustomer extends ModelAccountCustomer {

	public function addCustomer($data) {
		parent::addCustomer($data);

		// also add the newfield to the customer record
		$sql  = "UPDATE `".DB_PREFIX."customer` SET newfield = '".$data['newfield']."' ";
		$sql .= "WHERE email = '".$data['email']."'";
		$this->db->query( $sql );
	}
}
....
?>

Re: [RELEASED] Override Engine for OpenCart

Posted: Thu Oct 25, 2012 9:37 am
by Qphoria
Ah ok.. so there is an active logical understanding is needed there. Since I have to knowledgeably know to switch the WHERE clause to use another appropriate qualifier like email instead of last_insert_id.

But then how would you do the same thing for an order? You can "cheat" by using the email field for a customer because that is also unique per customer. But the order table has only one unique field.

Re: [RELEASED] Override Engine for OpenCart

Posted: Thu Oct 25, 2012 4:54 pm
by JNeuhoff
Qphoria wrote: But then how would you do the same thing for an order? You can "cheat" by using the email field for a customer because that is also unique per customer. But the order table has only one unique field.
Easy enough again :)

Code: Select all

<?php
class myaddon_ModelCheckoutOrder extends ModelCheckoutOrder {

	// override function
	public function addOrder($data) {
		$order_id = parent::addOrder($data);

		// add new field into order record
		$sql  = "UPDATE `".DB_PREFIX."order` SET newfield='".$data['newfield']."' ";
		$sql .= "WHERE order_id = '".(int)$order_id."'";
		$this->db->query( $sql );
		return $order_id;
	}
}
?>
You have to think differently here. This is object oriented programming, in particular, extending classes and overrding methods to get an additional and/or modified behavior for the method. I have a few live sites now using this new Override Engine, with lots of modifications, no problems so far.

Re: [RELEASED] Override Engine for OpenCart

Posted: Fri Oct 26, 2012 1:40 pm
by Qphoria
JNeuhoff wrote:
Qphoria wrote: But then how would you do the same thing for an order? You can "cheat" by using the email field for a customer because that is also unique per customer. But the order table has only one unique field.
Easy enough again :)

Code: Select all

<?php
class myaddon_ModelCheckoutOrder extends ModelCheckoutOrder {

	// override function
	public function addOrder($data) {
		$order_id = parent::addOrder($data);

		// add new field into order record
		$sql  = "UPDATE `".DB_PREFIX."order` SET newfield='".$data['newfield']."' ";
		$sql .= "WHERE order_id = '".(int)$order_id."'";
		$this->db->query( $sql );
		return $order_id;
	}
}
?>
You have to think differently here. This is object oriented programming, in particular, extending classes and overrding methods to get an additional and/or modified behavior for the method. I have a few live sites now using this new Override Engine, with lots of modifications, no problems so far.
Yea i get what it is doing.. just wasn't sure where it comes in. I guess it depends on where you call the parent. In this case you are fortunate that addOrder returns the order_id, so I'll try something more difficult...

In the catalog/model/checkout/order.php
in the confirm() function
I want to change

Code: Select all

$order_download_query = $this->db->query("SELECT * FROM " . DB_PREFIX . "order_download WHERE order_id = '" . (int)$order_id . "'");
to

Code: Select all

$order_download_query = $this->db->query("SELECT * FROM " . DB_PREFIX . "order_download LEFT JOIN order_download_master odm WHERE order_id = '" . (int)$order_id . "'");

[RELEASED] Override Engine for OpenCart

Posted: Fri Oct 26, 2012 2:02 pm
by madimar
Just to say... Really interesting topic... I will try to check the new override system soon. Thanks for your work jneuhoff.
M

Re: [RELEASED] Override Engine for OpenCart

Posted: Fri Oct 26, 2012 11:15 pm
by JNeuhoff
Qphoria wrote: Yea i get what it is doing.. just wasn't sure where it comes in. I guess it depends on where you call the parent. In this case you are fortunate that addOrder returns the order_id, so I'll try something more difficult...

In the catalog/model/checkout/order.php
in the confirm() function
I want to change

Code: Select all

$order_download_query = $this->db->query("SELECT * FROM " . DB_PREFIX . "order_download WHERE order_id = '" . (int)$order_id . "'");
to

Code: Select all

$order_download_query = $this->db->query("SELECT * FROM " . DB_PREFIX . "order_download LEFT JOIN order_download_master odm WHERE order_id = '" . (int)$order_id . "'");
You are really trying to make my life miserable here ???

Well, Rome wasn't built in a day. :) My Override Engine may need some more refinement to cater for all these crazy cases, you got me there ;D

I must admit the catalog/model/checkout/order.php is a real mess here because it has some non-model code in it, such as sending a mail message. It should have been splitted up between the model, and a sendMail. It is usually called from a payment controller's callback function. I'd probably use my own confirm method altogether (e.g. a confirmPayment), and override the payment controller's callback function, which then would invoke the model's new confirmPayment and sendMail functions.

Or even better: Maybe in the next version of the Override Engine, I'll add a non-chained bugfix folder, replacing some of the buggy or messy core methods, which can then be overridden for addons.

I noticed there are still some OpenCart classes such as Mail, Pagination, or Template whose instances aren't yet created through the override engine's Factory class. I'll correct that one in the next version of the Override Engine.

Your order_download_query is probably used in 2 places within method confirm:

Code: Select all

			$template = new Template();
			if ($order_download_query->num_rows) {
				$template->data['download'] = $order_info['store_url'] . 'index.php?route=account/download';
			} else {
				$template->data['download'] = '';
			}
			...
			$html = $template->fetch('default/template/mail/order.tpl');
			...

Code: Select all

			if ($order_download_query->num_rows) {
				$text .= $language->get('text_new_download') . "\n";
				$text .= $order_info['store_url'] . 'index.php?route=account/download' . "\n\n";
			}
$text and $html are then used later in the Mail class, for sending a mail:

Code: Select all

			$mail = new Mail(); 
			...
			$mail->setHtml($html);
			$mail->setText(html_entity_decode($text, ENT_QUOTES, 'UTF-8'));
			$mail->send();

I think in the next version of the override engine I will make sure it uses the Factory class for creating instances of Template and Mail, e.g.:

Code: Select all

			$template = $this->factory->newTemplate();
			...
			$mail = $this->factory->newMail();
			...
instead of the current

Code: Select all

			$template = new Template();
			...
			$mail = new Mail();
			...
Then I can extend these classes and override their methods more easily, such as:

Code: Select all

class myaddon_Mail extends Mail {

	// override method
	function setText( $text ) {
		parent::setText( $text );
		// run the modified order_download_query
		// change $this->text accordingly
		...
	}

	// override method
	function setHtml( $html ) {
		parent::setHtml( $html );
		// run the modified order_download_query
		// change $this->html accordingly	
		...
	}
}	

Re: [RELEASED] Override Engine for OpenCart

Posted: Fri Oct 26, 2012 11:34 pm
by JNeuhoff
madimar wrote:Just to say... Really interesting topic... I will try to check the new override system soon. Thanks for your work jneuhoff.
M
As you may have noticed from this forum thread, there is still some room for improvements for the Override Engine. That's why I am always grateful for some feedback.

I noticed there are a few classes such as Mail, Pagination, or Template whose instances aren't created like the model or controller classes. So I think the next version of the Override Engine will make sure that any instance creation of these remaining few classes will go through the Factory class, too, as is already the case for controller or model classes. This way they'll become extendable, too.

Re: [RELEASED] Override Engine for OpenCart

Posted: Sun Oct 28, 2012 11:47 pm
by Qphoria
JNeuhoff wrote: You are really trying to make my life miserable here ???

Well, Rome wasn't built in a day. :) My Override Engine may need some more refinement to cater for all these crazy cases, you got me there ;D
LOL I just wanted to press a little... maybe for being a bit dismissive of vQmod :)
Granted your way is indeed a much better programmatic way of proper modification. vQmod is just that little hack engine that could.

I'd still like to see your override engine in the core for larger mods, leaving vQmod for the smaller one line changes like this.

Re: [RELEASED] Override Engine for OpenCart

Posted: Mon Oct 29, 2012 4:30 am
by JNeuhoff
Qphoria wrote: LOL I just wanted to press a little... maybe for being a bit dismissive of vQmod :)
Granted your way is indeed a much better programmatic way of proper modification. vQmod is just that little hack engine that could.

I'd still like to see your override engine in the core for larger mods, leaving vQmod for the smaller one line changes like this.
I appreciate your comments. I am already working on some larger addons, have about 50 VQmods scripts to be converted to this override engine.

BTW.: For your specific example, with the existing Override Engine, depending on what you were trying to accomplish, I'd probaly do something like this:

Code: Select all

<?php
class myaddon_ModelCheckoutOrder extends ModelCheckoutOrder {

	// override function
	public function confirm($order_id, $order_status_id, $comment = '', $notify = false) { 

		// prevent parent function from sending mail, because we need some modifications
		$saved_mail_protocol = $this->config->get('config_mail_protocol');
		$this->config->set( 'config_mail_protocol', '' );

		// call parent method`
		parent::confirm( $order_id, $order_status_id, $comment, $notify );

		// let's use our modifified download_order_query
		$order_download_query = $this->db->query("SELECT * FROM " . DB_PREFIX . "order_download LEFT JOIN order_download_master odm WHERE order_id = '" . (int)$order_id . "'");
		$has_downloads = ($order_download_query->num_rows > 0);

		// use the modified order downloads query data for populating the mail message body, 
		// then send the confirmation mail
		$this->config->set( 'config_mail_protocol', $saved_mail_protocol );
		$mail = new Mail();
		// .....
		$mail->send();
	}
}
?>
There will be cases where VQmod is shorter (as in your last example). Or for other cases where the Override Engine offers an easier approach. The two are just different technologies, available to solve the problem where addons need to modify the OpenCart core.

I think many PHP programmers will find it easier to use the object oriented way of extending classes and overriding methods, rather than having to specify core changes in XML search and replace operations. However, the Override Engine does support VQmod, too!

I hope that future releases of OpenCart can also introduce some hook functions into its MVC framwork, the Override Eingine can easily support them. I have already introduced one hook: Method preRender in class Controller, to give the addon the chance to add its own variables, and to modify the template before rendering it.

Re: [RELEASED] Override Engine for OpenCart

Posted: Thu Nov 01, 2012 3:54 am
by straightlight
@JNeuhoff:

Exactly as I pointed out from one of the topics last year; to use overrides.

This override system seem to be exactly what I was looking for which could definitely replace the XML utility in OpenCart. If all works well as demonstrated from your ZIP file, I will modify my contributions based on this engine instead. :)

Edit: One aspect I did encountered is that preRender uses the same template buffer name whether it comes from the same or different author. It would be great to have an override system for template files as well.

Re: [RELEASED] Override Engine for OpenCart

Posted: Thu Nov 01, 2012 4:25 am
by JNeuhoff
straightlight wrote: Exactly as I pointed out from one of the topics last year; to use overrides.
Except this Override Engine is more than that: It can also handle the case where multple addons happen to extend the same class and override the same method, in which case it uses a dynamic chain of class extensions. That's why an overridden method always has to call the parent method, too, so as not to break the chain.

Let us know how you get on with your testing.