Jump to content

Failing to hook from one custom module into another


Ovi
 Share

Recommended Posts

Hello everyone.


My problem today: 

  • i have a custom module built by Antti Peisa which hooks into the comments module that comes with PW and adds a ratings field.
  • Antti did an awesome job with it, except i'm not able to sort pages by their average rating.
  • that happens because the average rating is not stored into any db field, it's just calculated at runtime, on request.
  • since Antti unfortunately doesn't have any time to help me with this beyond a quick pointer, i'm posting here.
  • please see the bottom of this post for Antti's comment ratings module.

My attempted solution:

  • build a module that stores the average rating for a comments field in another field, as an integer or float:
  • i built the module lke this
class PageAverageRating extends WireData implements Module {

    public static function getModuleInfo() {
        return array(
           // bla bla, removed for brevity
        );
    }

    public function init() {
       $this->addHookAfter(CommentRatings::processRatingInput, $this, 'copyAverageRating');
    }

    public function copyAverageRating($event) {
        $page = $event->arguments[0];

        // we're interested in product pages only
        if($page->template->name != 'product') return;

        // copy the average rating into another field, if there is a rating
        if(count($page->product_comments) > 0) {
            $page->average_rating = $page->product_comments->averageRating;
        } else {
            $page->average_rating = 0;
        }

    }
}
  • i obviously had to hook it to the moment a comment gets added. Didn't really know how to do that.
  • Antti said:
    try making CommentFormWithRatings::processRatingInput hookable (by adding ___)
  • so i turned processRatingInput into ___processRatingInput to make it hookable -  i doesn't seem to have worked, see below

Where i'm stuck:

when i run the module above with the hook:

$this->addHookAfter(CommentRatings::processRatingInput, $this, 'copyAverageRating'); 

 i get an error saying: 

Error: Undefined class constant 'processRatingInput' (line 16 of ..../public_html/site/modules/PageAverageRating.module) 

Other things i've tried:

Since this should be a method and not a property, i tried:

$this->addHookAfter(CommentRatings::processRatingInput(), $this, 'copyAverageRating'); 

 i get an error saying: 

Error: Undefined class method 'processRatingInput' (line 16 of ..../public_html/site/modules/PageAverageRating.module)

Also i've tried hooking into the CommentFormWithRatings class which extends the CommentForm class and actually contains the processRatingInput() method:

$this->addHookAfter(CommentFormWithRatings::processRatingInput, $this, 'copyAverageRating');
Error: Class 'CommentFormWithRatings' not found (line 16 of ..../public_html/site/modules/PageAverageRating.module) 

I'm attaching the module that Antti built here - it's going to be public anyway.

CommentFormWithRatings.php

CommentRatings.module

Can anybody please help me out ? I feel like the village idiot for not managing to figure this out.

How do i make this hook work?

Big thanks!

Link to comment
Share on other sites

Ovi,

not much time, but when Anttis code isn't a module and "class CommentFormWithRatings extends CommentForm" why do you doesn't extend Anttis class?

class OvisCommentFormWithSorting extends CommentFormWithRatings

and then you have there a public function processRatingInput() { that call parent::processRatingInput(); and then do your stuff ?

So, completely untested, but its like I understand the OOP System from PHP 5x, what is relative new to me, so- maybe I'm wrong.

Link to comment
Share on other sites

Try adding quotes and hooking into CommentFormWithRatings:

$this->addHookAfter("CommentFormWithRatings::processRatingInput", $this, 'copyAverageRating');

Edit: speed bonus goes to Soma.

Link to comment
Share on other sites

Thanks, can't believe i missed that. But the problem's still here, it just that the error's gone.


i tried all i could think of but i'm certain now that 

$this->addHookAfter("CommentRatings::processRatingInput", $this, 'copyAverageRating');

is not triggering like it should. So my module's not working. (even though i have ___processRatingInput() in Antti's code)

Basically i need a hook that would execute the copyAverageRating function each time a comment is added. 

There's no hook in PW for when a comment is added, as far as i know. 

@horst

Thanks for the suggestion, but it's a little hard for me to do since i don't understand Antti's module. If i did, i would have written it myself :) Everything's a confusing mess for me and each time i try to follow the code i get lost. Besides, all i need is to "do something" after a comment has been added. It looks like a module might be the simplest solution to that, if i can get a working hook, that is.

Halp? :undecided:

Link to comment
Share on other sites

@Ovi: did you try what I've suggested above, ie. hooking into "CommentFormWithRatings::processRatingInput"? That actually worked for me (at least to the point that a die() statement placed in copyAverageRating() was getting executed), so I'm pretty sure it should work for you too :)

Any chance that your method is getting executed but it doesn't work properly? Try doing something very obvious (like a die("foo")) in your copyAverageRating() and see if that gets executed. Whether it does or doesn't, you'll have narrowed the problem quite a bit already.

Another thing you could try is doing something similar in init() method of your module. Try putting a die() statement there; if your page still gets rendered, whole module isn't getting executed properly. (You've omitted module settings, but just to make sure: that module is set as "autoload", right?)

  • Like 1
Link to comment
Share on other sites

public function init() {        die("foo");       $this->addHookAfter("CommentFormWithRatings::processRatingInput", $this, 'copyAverageRating');    }

displays foo when viewing any page, so the module loads properly.

public function copyAverageRating($event) {
        die("foo");
        $page = $event->arguments[0];
 
        // we're interested in product pages only
        if($page->template->name != 'product') return;
 
        // copy the average rating into a field called average_rating
        $page->average_rating = $page->product_comments->averageRating;
       
    } 

The above does nothing when adding a comment. die() never gets called. I double checked all my naming, i don't know where the issue is.

Any idea where to look next?

Link to comment
Share on other sites

This must work, only thing would be if your module isn't autoload.

It is definitely autoload: 

public static function getModuleInfo() {
        return array(
            'title' => 'Copy average rating into hidden field',
            'version' => 100,
            'summary' => 'Copies the average rating to another field',
            'singular' => true,
            'autoload' => true,
        );
    }
Link to comment
Share on other sites

No idea, but it works for me. I use same code as yours, can you post your complete module?

sure: 

<?php

class PageAverageRating extends WireData implements Module {

    public static function getModuleInfo() {
        return array(
            'title' => 'Copy average rating into hidden field',
            'version' => 100,
            'summary' => 'Copies the average rating to another field',
            'singular' => true,
            'autoload' => true,
        );
    }

    public function init() {
        die("foo");
       $this->addHookAfter("CommentFormWithRatings::processRatingInput", $this, 'copyAverageRating');

    }

    public function copyAverageRating($event) {
        die("foo");
        $page = $event->arguments[0];

        // we're interested in product pages only
        if($page->template->name != 'product') return;

        // copy the average rating into a field called average_rating
        $page->average_rating = $page->product_comments->averageRating;
    }
}
Link to comment
Share on other sites

I just took your code and tested (removed the die() in the init) and it works the "foo" gets displayed after submitting. No idea what problem you got, but there's nothing special about it really. Does the comments and rating work at all for you? Caching?

Link to comment
Share on other sites

I have cache set to 0 on the product template. not using any other caching method.

The comments module and the ratings module are working fine. I can add comments and ratings and the they get displayed properly. Everything is perfect except this hook won't work.

I'm really starting to think we've stumbled onto some weird PW bug here. But maybe i'm jumping to conclusions...

Link to comment
Share on other sites

Have you at some point added the autoload true when the module was already installed?

There's no bug as far as I know as PW wouldn't work at all with all those hooks used in core.

Link to comment
Share on other sites

Well the class you hook on is a little special in that it's extending CommentForm, but since it works for all of us except for you. What PW version do you use and PHP version?

Can you try hooking page render?

$this->addHookAfter("Page::render", $this, 'copyAverageRating');

Works?

Link to comment
Share on other sites

Currently I can't see any reason why this wouldn't work. But a few things you might try:

1. Clear your opcode (APC?) cache. I do this whenever I encounter something odd that doesn't add up. 

2. Clear your modules cache. You can do this by clicking "check for new modules" on the Modules tab.

3. Check your Comments field settings. Is it set to redirect after post? Try disabling that option, temporarily, to see if it makes any difference.

4. While I'm not aware of any issues related to this in PW 2.3.0, maybe try switching to the dev branch (2.3.1) just to change things up. 



Also: Uninstall your module. Then click "check for new modules", then re-install it. I'm wondering if it maybe started out as NOT autoload, and that setting got cached in the DB. PW doesn't load all the module settings at runtime, as it caches some of them, especially autoload status. 

Link to comment
Share on other sites

Thanks for the suggestions Ryan, but none of them helped, unfortunately.

1. i do not use opcode cache on that server

2. i cleared the modules cache - no dice

3. the comment field was never set to redirect

4. I'm afraid to upgrade to 2.3.1 straight off the bat for fear of creating more bugs, i have to create a copy of the site on another account and try it there. Will let you know how it goes.

5. i uninstalled and reinstalled the module - no improvement.

Not to whine, but I'm really getting to the end of my rope here, i have to turn in the site soon and this is holding things up terribly.

Any help would be appreciated, although i'm beginning to think this can't be fixed for my site.

Link to comment
Share on other sites

We might have to look further, like what's going on in the template file. But one problem that I can spot in taking a closer look at the code is that the definition of your processRatingInput() method in CommentFormWithRatings.php has no arguments sent to it, but your hook function is assuming arguments[0] is a $page, when in fact it would be null. This doesn't indicate why the hook isn't getting called but it seems like you would get a PHP error in your hook function. I would fix that just in case it is causing the strange behavior or hiding some other error. 

Link to comment
Share on other sites

Hello guys, I apologize for not responding for a while, i was ( still am ) in a middle of a nightmare situation with one of my older clients and his MODx site, i barely had time to sleep. So happy i moved away from MODx, wish i'd found PW earlier.

Your offer is very generous Soma, of course i'll give you access!

I will PM you right now with the login details for the site and also the FTP to it.

Thanks so much,

Ovi


PS: the fact that you haven't given up on me and my problem yet shows what an awesome community this is. Best one i've seen so far.

  • Like 3
Link to comment
Share on other sites

Hello Ovi

Thanks for the info. I could connect and checked it out. I haven't done anything and it works. I only clicked "Check for new modules" once. The hook is getting executed and the output is shown in the review box after I submit the comment. Not sure what's about it, maybe you didn't look close enough but it's working as it should. I tested on this product /adaptasun-sea-and-tropics-spf-30/.

Now I first looked also at what modules are installed, and the only strange thing is that you have 2 FieldtypeComments module, the one in core and one by Apeisa in site/modules ... ? Can they coexist like this? Well if it works, but I'm not sure if it would cause troubles or isn't needed. At least the core one can be deinstalled?

Well so far, happy hacking.

  • Like 3
Link to comment
Share on other sites

Wow, I don't know what's went on there. i'm seeing the same thing now. I'm sorry for all the trouble i put you through, it definitely wasn't working for me before - the full page was getting displayed. 

I'll move on to seeing why the field isn't getting populated.

Will keep you posted.

Thanks so much!

Link to comment
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

  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...