Please upgrade here. These earlier versions are no longer being updated and have security issues.
HackerOne users: Testing against this community violates our program's Terms of Service and will result in your bounty being denied.

Trying to hook into CategoryWatch

edited January 2013 in Vanilla 2.0 - 2.8

The CategoryModel::CategoryWatch() method handles category privileges, allowing posts that match certain categories to be suppressed. This is how category permissions applies to the core.

Now, I an trying to hook into that method so that I can apply a further layer of category filters in certain circumstances (I'm actually filtering by the user's locale, where each category has a specified locale).

In my plugin I am attempting to catch the event, so I can adjust the allowed category IDs using this method:

public function CategoryModel_CategoryWatch_Handler($Sender) {...}

But that is not working. Looking at the pluggable class, I suspect it may be because the event is fired from a statically-invoked method in the search and summary queries, i.e. CategoryModel::CategoryWatch() above.

This method does work, however:

public function Gdn_PluginManager_CategoryWatch_Handler($Sender) {...}

So, any potential problems with using this event handler? Is this actually a bug in Gdn_Pluggable class? It should be able to get the caller class name through late static binding, I believe, but it needs to check a different way. And, of course, __construct() doesn't get executed when called statically so the caller class name cannot be caught there.

Any thoughts? I'm just going to use the second method for now, but it feels a little cludgy. I'm using Vanilla 2.0.18, so would also like to think about future-proofing this for 2.1.0

-- Jason


  • Options
    x00x00 MVP
    edited January 2013

    This is worth opening an issue on github. I think you got it in one it is a static method.

    In my view the it should detect the controller/model CategoryWatch is being used.

    Then you could go

     public function Base_CategoryWatch_Handler($Sender) {...}


     public function DiscussionModel_CategoryWatch_Handler($Sender) {...}

    grep is your friend.

  • Options

    Thanks, I'll raise it later today. In my plugin, I'll create both handlers, and have one pass control over to the other. That way if an update fixes this, the plugin should still work.

    The weird thing is, get_called_class() (PHP5.3 only) should give the correct class name, as it handles late static binding. However, it gives the same result - it says Gdn_Pluggable::FireEvent() is being called in the Gdn_PluginManager class, and not CategoryModel where the event is being fired in CategoryWatch(), which is in turn being called statically. I'm not sure what is going on there.

  • Options

    Not sure I follow, the called class is Gdn_PluginManager not CategoryModel in that case.

    it is not being extended.

    I think you are confusing the static method of CategoryWatch with the event line which is called from Gdn_PluginManager.

    It doesn't matter is something is called in a method, if it called from some other class. The two things are not related.

    grep is your friend.

  • Options

    CategoryModel contains this line of code:


    So the calling class is CategoryModel - it is that class which fires the event. That is where the event line is - where the event is being fired - not Gdn_PluginManager.

  • Options

    CategoryModel contains this line of code:


    So the calling class is CategoryModel - it is that class which fires the event. That is where the event line is - where the event is being fired - not Gdn_PluginManager.

    Hmm, looking at it again, it is the fact that it is Gdn::PluginManager() firing the event and not $this, which is the problem. I guess it needs to be called up statically like this because there is no "$this". Perhaps it should look more like this (which would be PHP 5.3 only):


    That would mean FireEvent would need to be statically callable too, leading on to other complications.

    Maybe (and I am clutching at straws here) Gdn::PluginManager() could take a parameter of the actual source class name, so that could be passed down the line:


    Anyway, what I have now works, and luckily I don't need to distinguish between the several different places that the event is fired from. If I did need to know, then things could get tricky. So I have this one event handler for now:


    Instead of two different handlers that could be used to distinguish between the sources:

    function DiscussionModel_CategoryWatch_Handler($Sender) {...}
    function VanillaSearchModel_CategoryWatch_Handler($Sender) {...}

    -- Jason

  • Options

    Gdn::PluginManager() instanceof Gdn_PluginManager

    is true

    Gnd_Model extends Gdn_Pluggable that is where the FireEvent method is located
    Gdn_PluginManager also extends Gdn_Pluggable.


    class B { 
      public static function Check(){ 
          $Self = self; 
          if($Self instanceof B)
               echo "Instance of B";
               echo "Not an Instance at all!"
    php > B::Check();
    Not an Instance at all!
    php > $B = new B();
    php > if($B instanceof B) echo "Instance of B";
    Instance of B

    In other words you have a static method being called and an instance of Gdn_Pluggable, the two thing are not related except that Gdn::PluginManager() is in that method.

    grep is your friend.

  • Options

    Okay, fair enough. I've got code that works now at least (as detailed above), and that's cool.

Sign In or Register to comment.