Jump to content


Photo

Stop execution of a function via hook


  • Please log in to reply
11 replies to this topic

#1 Nico Knoll

Nico Knoll

    The Boss.

  • Members
  • PipPipPipPipPip
  • 644 posts
  • 234

  • LocationBerlin, Germany

Posted 14 January 2012 - 05:17 PM

Hi,
is there a way to stop the execution of a function via hook?

/ Nico

#2 Pete

Pete

    Administrator

  • Administrators
  • 1,756 posts
  • 658

  • LocationChester, England

Posted 15 January 2012 - 08:32 AM

Hi Nico

Do you have a more detailed description or a code example of what you're trying to do? Specifically which function you're trying to stop?

#3 ryan

ryan

    Hero Member

  • Administrators
  • 5,773 posts
  • 3116

  • LocationAtlanta, GA

Posted 16 January 2012 - 02:15 PM

Nico, this is something that is technically possible with the way the hook system is designed, but I've not implemented it yet. The idea behind it was that there would be a 'replace' hook, where you can have your own function completely replace the functionality of a core function, so that the core one is never called. I haven't implemented this because it's not so friendly in an environment where there may be multiple modules hooked to a given function. If one module completely takes over a core function, it alters program flow and the behavior that other modules may be expecting. So I've left it out because I think it's a bit too unpredictable, though may still add it in if there's interest. However, you can achieve the same effect by using an 'after' hook and completely replacing the $event->return value with your own. Not as efficient as replacing the execution too, but much more predictable.

#4 Nico Knoll

Nico Knoll

    The Boss.

  • Members
  • PipPipPipPipPip
  • 644 posts
  • 234

  • LocationBerlin, Germany

Posted 16 January 2012 - 07:05 PM

@Ryan: I'm using the $event->return way right now, but the problem is that the original function throws a 404 header. (It's because I'm changing the URLs with my module).

#5 ryan

ryan

    Hero Member

  • Administrators
  • 5,773 posts
  • 3116

  • LocationAtlanta, GA

Posted 17 January 2012 - 10:46 AM

I understand -- I think that's a good reason for us to add a replace hook. For my own testing when implementing this, can you tell me which function it is that you are hooking into?

#6 Nico Knoll

Nico Knoll

    The Boss.

  • Members
  • PipPipPipPipPip
  • 644 posts
  • 234

  • LocationBerlin, Germany

Posted 17 January 2012 - 03:26 PM

$this->addHook('ProcessPageView::execute', $this, 'getPage');

(See the rest of my code at GitHub if you need it ;))

#7 ryan

ryan

    Hero Member

  • Administrators
  • 5,773 posts
  • 3116

  • LocationAtlanta, GA

Posted 18 January 2012 - 11:55 AM

Thanks, I'll add this capability to the hooks API.

#8 ryan

ryan

    Hero Member

  • Administrators
  • 5,773 posts
  • 3116

  • LocationAtlanta, GA

Posted 24 January 2012 - 01:50 PM

Nico, this has been added in the latest commit of 2.2. To make use of it, have your hooked function (getPage in your case) do this:

$event->replace = true; // now original function won't be called
$event->return = 'you are now providing the return value';

Also your hook obviously must be a 'before' hook in order to replace the original. So you'd init the hook like this:

$this->addHookBefore('ProcessPageView::execute', $this, 'getPage');


Unrelated to the above, but another cool addition: I upgraded the hook system so that it will let you set or get hooked function arguments by name rather than just by position. So if you'd hooked into Pages::save, and you wanted to refer to the 'page' argument, you can now do this:

$page = $event->arguments('page');


Before you could only do this, having to know what position the argument was in:

$page = $event->arguments[0];

You can also set arguments back to the event by name if you want to, i.e.

$event->arguments('page', $mypage);


#9 Soma

Soma

    Hero Member

  • Moderators
  • 3,188 posts
  • 1745

  • LocationSH, Switzerland

Posted 24 January 2012 - 02:47 PM

That's really great to have the arguments by name and not position! Thanks Ryan for the update.

But I'm not quite getting the last one. Maybe a little example could make it more clear?

@somartist | modules created | support me, flattr my work flattr.com


#10 apeisa

apeisa

    Hero Member

  • Moderators
  • 2,525 posts
  • 851

  • LocationVihti, Finland

Posted 24 January 2012 - 02:54 PM

Yes, great additions.

Soma, in the example Ryan is changing original page with different/modified one.

#11 ryan

ryan

    Hero Member

  • Administrators
  • 5,773 posts
  • 3116

  • LocationAtlanta, GA

Posted 24 January 2012 - 04:00 PM

But I'm not quite getting the last one. Maybe a little example could make it more clear?


Antti's right about what that example is doing, but let me do another. Lets say we've hooked in before $session->redirect(). If I go look at the function definition in /wire/core/Session.php, I can see it has two arguments: $url and $http301. So lets say I want to hook into that and automatically add a GET variable to every redirected URL, like "url.com/path/?is_redirected=1", I'd do this:

public function hookSessionRedirect(HookEvent $event) {
    $url = $event->arguments('url'); // get the existing value 
    $url .= (strpos($url, '?') === false ? "?" : "&") . "is_redirected=1";
    $event->arguments('url', $url); // set the new value that gets sent to $session->redirect
}

Btw, there is some overhead in using the argument names as opposed to the position (it involves using Reflection), so in most cases I think it's still better to use the argument position rather than the name. But have wanted to make both options available because I think some people will find it more straightforward to to use the argument names... and it no doubt makes code examples more readable.

#12 Nico Knoll

Nico Knoll

    The Boss.

  • Members
  • PipPipPipPipPip
  • 644 posts
  • 234

  • LocationBerlin, Germany

Posted 25 January 2012 - 09:42 AM

Wow, looks nice. Have to try PW 2.2 in the next days. I didn't do it until now because I thought I could wait for the final release :)




0 user(s) are reading this topic

0 members, 0 guests, 0 anonymous users