Jump to content

[Solved] Another Override classes question - Definitive Answer on overriding core files


uddhava
 Share

Recommended Posts

Since there is not any piece of decent information available written by the PS team about overriding classes files i hope that someone here can give a fully qualified answer ;-).

If i want to override a class, for example FrontController.php in PS 1.4.x what do i need to do?
1) do i copy the classes/FrontController.php to /override/classes
2) do i create an empty file?

On the PS blog i found this bit of info , but as usual it leaves even more questions then answers.

So what do i need to do and what can be used as a skeleton code?

You can find the definitive answer in this post.
Or read below

  • Like 1

Share this post


Link to post
Share on other sites

So ok, thanks Angora for the brief intro on the overrides. Now i want to make it crystal clear to myself and to others on this forum. So will create an example.

Example (1) i want to introduce a new Hook. (favorite question on the forum).
Hookname : HOOK_HOMEBLOCK
The Hook declaration is part of the function : public function displayHeader()

So i would use the following code ??

class FrontController extends FrontControllerCore
{

  public function displayHeader()
   {
       parent::displayHeader();
   $this->smarty->assign('HOOK_HOMEBLOCK', Module::hookExec('homeblock'));
   }
}




I tried this code and it doesnt work. I get a server 500 error. When i deleted the Smarty assign code then the code works but the whole layout of the shop is messed up.

So do i need to copy the whole function displayHeader ?

Share this post


Link to post
Share on other sites

Finally after searching with google on overrides i found a nice post from Rocky about override.
You can read it here.

But when i try this out it doesnt work for me (see above example). So maybe something has changed in the configuration of override in 1.4.2?

ys

Share this post


Link to post
Share on other sites

I tried this code :

class FrontController extends FrontControllerCore
{

  public function displayHeader()
   {
       parent::displayHeader();
       self::$smarty->assign(array(
           'HOOK_HOMBLOCK' => Module::hookExec('homeblock')
       ));
   }
}



Also doesnt work, although now the layout is not messed up. Looks like i'm making progress...

Share this post


Link to post
Share on other sites

hello
you should change the order of processing as the tpl file is parsed in the parent function
put the smarty assign before calling parent::displayHeader();

if that does not work try to display the result of hookExec('homeblock') within something like die to see if the hook call works correctly, then we should work on some other solution

Share this post


Link to post
Share on other sites

On its personal website from Paul C he has an excellent article about using a plugin instead of working with Hooks to display modules anywhere in your template files by using a very simple smarty opcode.
(he! PS team! Read this and Implement!! pls)

> Thanks Paul C and good luck making this plugin work with Smarty v3 and PS1.4.2

In his example he is also overriding class files like this :

class FrontController extends FrontControllerCore
08    {
09     
10      function __construct()
11      {
12        parent::__construct();
13      }
14     
15      function init()
16      {
17        parent::init();
18     
19        global $smarty;
20     
21        $this->smarty = $smarty; // Not really sure why, but necessary.
22     
23        if (!Configuration::get('PS_FORCE_SMARTY_2'))
24        {
25          $this->smarty->registerPlugin('function', 'plugin', 'smartyEcartPlugin');
26        } else {
27          $this->smarty->register_function('plugin', 'smartyEcartPlugin');
28        }
29      }
30    }



So from this example it seems that we need a function __construct and parent::__construct ?

Share this post


Link to post
Share on other sites

Thanks Angora for your comments. Highly appreciated.


Have you INSERTed a row to the db hook table for your new hook, as instructed in that article?



Yes i did that of course. Thats why i included the extra informational post above for those readers that didnt get to that part.:-)
I already had the new hook working, but i just copied the whole FrontController file. When i read more about it on the forum i understood that you only need a small part of the file to override code.

So in summary you need this general code to override the FrontController and introduce a new Hook.

class FrontController extends FrontControllerCore
{

  public function displayHeader()
   {
     ORIGINAL FUNCTION CODE + EXTRA CODE FOR NEW HOOK        
   }
} 



Is the parent::displayHeader() then needed, and what is actually meant for?
(you can guess i am not a php programmer :o)

Share this post


Link to post
Share on other sites

(see the supplied classes/_Module.php for example. It omits the constructor)


I was wondering what those _files are for in the override/classes folder ?
The code seems totally different then the original file, for example the _FrontController.php .

Share this post


Link to post
Share on other sites

Ok, i tried all three examples. Here are the results :

1) whole controller -> That obviously will work
2) Original Function code + custom code -> That also works
3) Call to parent + just the code. -> first Errors --> Now Success

i used this code :

class FrontController extends FrontControllerCore
{

  public function displayHeader()
   {

       self::$smarty->assign(array('HOOK_HOMEBLOCK' => Module::hookExec('homeblock')));
       parent::displayHeader();

   }
}




I get these error messages :
Strict Standards: Accessing static property IndexController::$smarty as non static in D:\websites\presta142\override\classes\FrontController.php on line 34

Notice: Undefined property: IndexController::$smarty in D:\websites\presta142\override\classes\FrontController.php on line 34

Fatal error: Call to a member function assign() on a non-object in D:\websites\presta142\override\classes\FrontController.php on line 34


I figured it out. The parents needs to be called after the new hook has been assigned to the array. Duh.. makes sense.. I changed the code above to the correct one.

Share this post


Link to post
Share on other sites

[updated] changed text according to Angora's recommendations.
[updated 8 jun 2011] Corrected code due to Payment Method error

So after the excellent comments by Angora, which took some time to comprehend, this thread is solved for me at least. I hope that anybody looking for some good info on hooks will find this thread. To summarize this thread:

Overriding class files can be done by :
* create a folder with subfolders called: override/classes
/controllers
* copy the class or controller file you need to these folders.
(in 1.4.2 these folders are already created)

Then depending on your needs you can override :
1) Override entire class
2) Override individual functions (aka methods) of the class

When you copy the whole file from the /classes file to the /override/classes folder and add/change the code then you have completed (1). But you need to extend the class. For example the file FrontController.php; change the line

class FrontControllerCore


to

class FrontController extends FrontControllerCore




2) Just add your own code and call the parent function. Just be sure to watch the order.
In my example i added a custom hook to the displayHeader() function that resides in the FrontController Class. In this case i add the new hook and then call the rest of the function with a parent call.

class FrontController extends FrontControllerCore
{

  public function displayHeader()
   {
       if (!self::$initialized)
           $this->init();
       self::$smarty->assign(array('HOOK_HOMEBLOCK' => Module::hookExec('homeblock')));
       parent::displayHeader();

   }
}



The $this->init() code is needed otherwise an error will occur when selecting a payment method during Checkout.

  • Like 1

Share this post


Link to post
Share on other sites

  • 3 weeks later...
I hope that anybody looking for some good info on hooks will find this thread.


Well, be happy. This thread just saved my life !
I was desperatly seeking for a SIMPLE way to add a hook by using overides.

Your code works perfectly ! Thank you so much !

Share this post


Link to post
Share on other sites

My solution seems not to work when you try to choose a Payment Method. It then gives the error :

Fatal error: Call to a member function assign() on a non-object in 
D:\websites\142fin-afterupgrade\override\classes\FrontController.php on line 13



If i look at Line 13 (smarty assign)

class FrontController extends FrontControllerCore
{

  public function displayHeader()
   {

       self::$smarty->assign(array('HOOK_HOMEBLOCK' => Module::hookExec('homeblock')));
       parent::displayHeader();

   }
}



then something goes wrong. I have no idea what. When i include the whole displayHeader function in my override file then it works. So for now that will be my workaround.

Share this post


Link to post
Share on other sites

This doesn't seem to work on everything.

I'm trying to override _getPaymentMethods() from OrderOpcController.php

I just want to modify the text of an error message

if (!$this->isLogged)
           return '
'.Tools::displayError('Please sign in to see payment methods').'';



So I have created a OrderOpcController.php in override/controllers with the following code :

<?
class OrderOpcController extends OrderOpcControllerCore
{

  public function _getPaymentMethods()
   {
       if (!self::$initialized)
           $this->init();

   if (!$this->isLogged)
       return '
'.Tools::displayError('test').'';

       parent::_getPaymentMethods();

   }
}
?>



And then... nothing. Presta displays the regular warning message. I even tryed to just put a "exit;" in the function, but I didn't get the white page. Just the regular one.

I seek for hours, but I can't tell why it doesn't work.

Someone would have any idea ?

Thanks

Share this post


Link to post
Share on other sites

Thanks for the answer.

I tryed both things, but nothing happens.

As I told in my previous post, it seems that the override isn't even taken in consideration by Presta.

I even tryed this :

<?
class OrderOpcController extends OrderOpcControllerCore
{

  public function _getPaymentMethods()
   {

       exit;

   }
}
?>



I should get a white page, but I don't. The regular page is still displaying.

I tryed to remove the underscores in the function name (maybe they messed up the process) but no more success.

I checked and re-checked the names of my files and every other parameter. My code should work, but it doesn't, and I really don't understand why...

Could someone try on his side and tell me if the problem is the same ? Maybe it's a bug that we should report in the forge.

Share this post


Link to post
Share on other sites

Cache is disabled.
Force compile is on.
Full function copied in the override file.

I even deleted manually the files in the /smarty/compil folder, just to be sure to have a recompilation, but nothing changes.

Did you tryed on your side ?

Thank you for your help !

Share this post


Link to post
Share on other sites

Cant try it out at the moment. I am not at home. But you could try to use my example and see if that works.
I think the overriding of classes differs from overriding controllers. Just look closely at the dev guide from Rocky. (see above)

Share this post


Link to post
Share on other sites

Cant try it out at the moment. I am not at home. But you could try to use my example and see if that works.
I think the overriding of classes differs from overriding controllers. Just look closely at the dev guide from Rocky. (see above)


I tryed many things, but I can't get this to work.
I'm pretty sure that OrderOpcController.php is a controller and not a class, so this is not the issue.
I just don't understand why this is not working...

Share this post


Link to post
Share on other sites

Odjavel,

Firstly are you sure that you have placed the OrderOpcController.php override class in override/controllers ?


Another thought is that I'm pretty sure redeclaring a protected function as public will cause a problem. Try:

<?php
class OrderOpcController extends OrderOpcControllerCore
{

  protected function _getPaymentMethods()
   {

       exit;

   }
}



Paul

Share this post


Link to post
Share on other sites

Hi Paul.

This makes no difference.
Even when I copy/paste the whole exact original function.

And yes my file is in the godd place.

Try yourself ;-) Easy and quick to do. You will see : there's no way to override this controller.At least, no way that I found.

Share this post


Link to post
Share on other sites

Yes, I've had a look at the code and it doesn't look like you'll be able to override it. Whether it's a bug or not could probably be debated, but it's a good example to use when learning about overriding classes in PHP :D

The problem is that this function is only ever called from within a function defined in OrderOpcController, and the scope is limited by the "self" keyword (it's called from ::preProcess() and ::_assignPayment() in the parent OrderOpcController class using the self scope modifier).

Try the following:

class TestParent{

 protected function _getPaymentMethods()
 {
   echo '
Function called from Parent.';
 }

 public function testing()
 {
   echo 'Try self';
   self::_getPaymentMethods();
   echo 'Try $this';
   $this->_getPaymentMethods();
 }
}

class TestChild extends TestParent{

 protected function _getPaymentMethods()
 {
   echo '
Function called from Child.';
 }
}

$parent = new TestParent();
$child = new TestChild();

echo 'Parent Test';
$parent->testing();
echo 'Child Test';
$child->testing();



The output you get is:

Parent Test

Try self

Function called from Parent.

Try $this

Function called from Parent.

Child Test

Try self

Function called from Parent.

Try $this

Function called from Child.



The "self" keyword used with the scope operator means that the "parent" version of the function will always be called when the testing function uses "self::".

Now as to whether it's a bug or not.... I don't actually see why this function is called with the self:: scope modifier as the function calling it isn't declared "static", which is normally why you would use the self scope modifier. I suspect that if you replaced the "self::" with "$this->" in the preProcess and _assignPayment() functions it would work fine as you're expecting it to. Note that there are a couple of functions in that class that suffer from the same "problem"., not just this one.

Paul

Share this post


Link to post
Share on other sites

Hi Paul,

Well I tryed exactly your way and it works !

But then I made another test, and it appears that it works too just by copying preProcess() and _assignPayment() in the override. No need to change every self:: by $this->.

In fact, for what I want to do (editing 1 error message in _getPaymentMethods() function) it also works when you include only _assignPayment() in the override.

Anyway, you made this to work, and I'm thankful for that !
Thank you for your interest in my problem ! :-)

EDIT : there is still a problem. When you change a parameter like the carrier in the checkout page, the function is not overriden any more. So I'm back to your first method (the 3 functions and $this->), but the override still stops when the checkout page makes an ajax call.

I'll digg to try to find something about this...

Share this post


Link to post
Share on other sites

Yes, because by moving those two functions, "self" now refers to the child class not the parent class :)

Ideally you don't want to have to make copies of functions in your override, but in this case at least it gets it working (until maybe the PS developers change the Core class......). I think it would be worth reporting it to the bug tracker to be looked at, because I don't believe that the way this currently works is intentional.... as I said above, it isn't just that function that will suffer from the same problem either (and maybe there are other cases in other classes).

Paul

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
 Share

×
×
  • Create New...

Important Information

Cookies ensure the smooth running of our services. Using these, you accept the use of cookies. Learn More