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.

What's the best way to invoke one plugin from another?

rbrahmsonrbrahmson ✭✭✭
edited March 2016 in Vanilla 2.0 - 2.8

Since I run an intranet forum I cannot use the real use case, so here is a made up use case:
I have a plugin that adds a "status" field to discussions. When users change the "status" to specific values I want to invoke another plugin (for example, the Discussion Note plugin to add a post-it note to the discussion based on the changed status).

I can think of two ways, not sure they are good choices, and there probably are better ways:
1. Have the called plugin setup a mini controller and invoke it via URL.
2. Create an event in the calling plugin (fireevent?). Not yet sure how to do that, whether plugins can do that, and whether this would interfere with anything else.

Appreciate your advice.

Comments

  • R_JR_J Admin

    The fireEvent would be the best way. If you are not sure, it is always a good start to search in existing code. If you search the plugins for "fireevent" you would find several examples. So in the plugin that changes the status, add lines like that

    $this->EventArguments['PluginName'] = $this->PluginInfo['Index'];
    $this->EventArguments['DiscussionID'] = $discussionID;
    $this->EventArguments['Status'] = $status;
    $this->fireEvent('AfterAddStatus');
    

    The discussion note plugin must contain a function like that:

    public function pluginController_afterAddStatus_handler($sender, $args) {
        // Some other plugins might have implemented an event like "AfterAddStatus"
        if ($args['PluginName'] != 'StatusPlugin') {
            return;
        }
    
        // do what you want to do
    }
    

    I'm really unsure about the public function pluginController, though. Maybe you can use/must use the classname of your status plugin. You have to test it...

  • rbrahmsonrbrahmson ✭✭✭

    Thanks, Always insightful!

  • First things first, I would add the other plugin as a dependency in the Plugin Info array.

    You can get instances of existing plugin classes via the plugin manager. Since all hooks are public members, you can directly call the hooks in other plugins.

    $plugin = Gdn::pluginManager()->getPluginInstance('classname');
    $plugin->classMember();
    

    That said, I would still probably use an event like RJ described. I would only use this method if you cannot (or will not) modify the "parent" plugin.

    Search first

    Check out the Documentation! We are always looking for new content and pull requests.

    Click on insightful, awesome, and funny reactions to thank community volunteers for their valuable posts.

  • rbrahmsonrbrahmson ✭✭✭

    Thanks, @hgtonight ! Very helpful as well. I think that what you mean is that I can call functions within the parent plugin, right? That's awesome! How would parameters be passed? (I can see they they are prepared via EventArguments in the case of fireevent)

    Also, you seem to favor the fireevent method. Why?

    I also deduce from your method that I can probably invoke the dashboard setup of any "parent" plugin from my plugin. Interesting...

  • hgtonighthgtonight MVP
    edited March 2016

    @rbrahmson said:

    Also, you seem to favor the fireevent method. Why?

    Given your stated use case, you want to hand control off to a different plugin when something happens. This is a perfect use of the event system provided by the framework. If you are writing both plugins, this is good.

    I just put the instance method out there in case you cannot, or will not, modify one of the plugins.

    Search first

    Check out the Documentation! We are always looking for new content and pull requests.

    Click on insightful, awesome, and funny reactions to thank community volunteers for their valuable posts.

  • R_JR_J Admin

    @rbrahmson said:
    Also, you seem to favor the fireevent method. Why?

    You didn't asked me, but i tell you anyway ;)

    You've created plugin A and then plugin B. Then you've thought that it would be great if plugin A could invoke some functionality of plugin B.
    Now imagine you or me or someone else creates plugin C and that plugin should invoke some functionality of plugin A, too. Plugin A must be changed again. That's tedious and not really easy to handle.

    If you add a fireEvent() to your plugin A, everybody could simply use that to let his own action follow on what is done in plugin A. You never have to touch that plugin again.

  • @R_J said:

    If you add a fireEvent() to your plugin A, everybody could simply use that to let his own action follow on what is done in plugin A. You never have to touch that plugin again.

    Also, what he said.

    Search first

    Check out the Documentation! We are always looking for new content and pull requests.

    Click on insightful, awesome, and funny reactions to thank community volunteers for their valuable posts.

  • rbrahmsonrbrahmson ✭✭✭
    edited March 2016

    OK, got it. Thank you @R_J and @hgtonight
    Now to the drawing board =)

  • So many wisdoms being dropped!

  • rbrahmsonrbrahmson ✭✭✭

    Indeed, many thanks to my mentors!

  • @Linc said:
    So many wisdoms being dropped!

    Yes, I wish I could get the code to invoke Baal and his 9900 slave labor daemonds so my hard drive was not on an eminent death list .... :(

  • rbrahmsonrbrahmson ✭✭✭

    @R_J , @hgtonight: I am trying to apply fireevent and the hooked function does not seem to get control.
    I inserted the following code into the FilterDiscussion plugin:

            $Urlparms = $_GET;
            //Allow other plugins pass the filters (which need to be in the same format as those passed through the url)
            $this->EventArguments['PluginName'] = $this->PluginInfo['Index'];
            $this->EventArguments['Filter'] = $Urlparms;
            $this->fireEvent('UsingFilter');
    

    With the clear intention of allowing other plugins to set the filtering parameter (instead of getting it from the url).

    I turned on eventi and verified that the event is indeed fired. It is.

    Then I insesrted the following code into another plugin:

        public function pluginController_UsingFilter_handler($Sender, $Args) {
            $Plugin = $Args['PluginName'];
            $Filter = $Args['Filter'];
            echo '<BR>'.__LINE__.' Plugin:'.$Plugin.' <br>Filter:'.$Filter;
    

    Unfortunately I do not see that echoed line... I don't think it gets control.

    Have I misunderstood the mechanism, misapplied the sample code, or perhaps I am the victim of Baal and his 9900 slave labor daemons;-)

  • You aren't using the right event name. You called $this->fireEvent() which fires the event off as your class name. You will need to use the hook FilterDiscussion_UsingFilter_Handler.

    Search first

    Check out the Documentation! We are always looking for new content and pull requests.

    Click on insightful, awesome, and funny reactions to thank community volunteers for their valuable posts.

  • rbrahmsonrbrahmson ✭✭✭

    Thanks! That works. I was using the code example @R_J showed above...

Sign In or Register to comment.