[aur-dev] [PATCH 2/2] Added simple hook framework in preperation to solve FS#30109. Signed-off-by: Mario (xenji) Mueller <mario at xenji.com>

Mario Mueller mario at xenji.com
Tue Sep 18 17:05:31 EDT 2012


Simple function call would be enough to solve the exact need at every
single point of extension, so there is no need to defend my proposal. I
this is the way you want to expand this, there is no need for my patch. It
will make contributions even harder as they are now, because everybody
needs to understand every piece of the code, wich is - please don't get me
wrong - pretty hard without enough of documentation. Hooks make your life
easier, as you enable contributions on a very low level with mostly defined
APIs.

The need really depends on how you want to mangage the existing code. If
you want to touch it as little as possible, hooks are *one* of the ways
that you can possibly go.

I hope I pointed out the advantages.

2012/9/18 Lukas Fleischer <archlinux at cryptocrack.de>

> On Mon, Sep 17, 2012 at 02:11:43PM +0200, mario at xenji.com wrote:
> > From: "Mario (xenji) Mueller" <mario at xenji.com>
> >
> > Signed-off-by: Mario (xenji) Mueller <mario at xenji.com>
> > ---
> >  web/lib/acctfuncs.inc.php |   5 ++
> >  web/lib/aur.inc.php       |   4 ++
> >  web/lib/hookdef.php       | 113
> ++++++++++++++++++++++++++++++++++++++++++++++
> >  web/lib/hooks/account.php |   4 ++
> >  4 files changed, 126 insertions(+)
> >  create mode 100644 web/lib/hookdef.php
> >  create mode 100644 web/lib/hooks/account.php
>
> Before reviewing this, could you please explain why hooks are
> advantageous here? Hooks are nice if you want to change entry points of
> a function invocation dynamically, such as in extensions or complex
> configurations, but I don't see how a hook framework is supposed to be
> superior to a simple function call here.
>
> >
> > diff --git a/web/lib/acctfuncs.inc.php b/web/lib/acctfuncs.inc.php
> > index 6f7c98a..0ccd235 100644
> > --- a/web/lib/acctfuncs.inc.php
> > +++ b/web/lib/acctfuncs.inc.php
> > @@ -188,6 +188,11 @@ function
> process_account_form($UTYPE,$TYPE,$A,$U="",$T="",$S="",$E="",
> >                       } else {
> >                               # account created/modified, tell them so.
> >                               #
> > +
> > +                // trigger hook and pass the fully escaped array to it.
> > +                // see lib/hookdef.php for details.
> > +                trigger_hook('newAccount', $escaped);
> > +
> >                               print __("The account, %s%s%s, has been
> successfully created.",
> >                                               "<b>",
> htmlspecialchars($U,ENT_QUOTES), "</b>");
> >                               print "<p>\n";
> > diff --git a/web/lib/aur.inc.php b/web/lib/aur.inc.php
> > index 6dcbb34..50c4bce 100644
> > --- a/web/lib/aur.inc.php
> > +++ b/web/lib/aur.inc.php
> > @@ -11,6 +11,10 @@ include_once('translator.inc.php');
> >  set_lang();
> >
> >  include_once("config.inc.php");
> > +
> > +include_once("hookdef.php");
> > +include_once("hooks/account.php");
> > +
> >  include_once("routing.inc.php");
> >  include_once("version.inc.php");
> >  include_once("acctfuncs.inc.php");
> > diff --git a/web/lib/hookdef.php b/web/lib/hookdef.php
> > new file mode 100644
> > index 0000000..19d93d5
> > --- /dev/null
> > +++ b/web/lib/hookdef.php
> > @@ -0,0 +1,113 @@
> > +<?php
> > +/*
> > + * This hook system is similar to the ones in wordpress or durpal.
> > + *
> > + * It is meant to be simple and effective, whithout any overengineered
> stuff.
> > + * If you think about making it "better" by creating a OOP version with
> > + * interfaces, please take a look at the rest of the system and ask
> yourself
> > + * if this really fits in here.
> > + */
> > +
> > +// LIST OF EXISTING HOOKS
> > +/*
> > + * USE THIS PATTERN:
> > + *
> > + * filename.php hookname (payload1, payload2, ...)
> > + *
> > + * acctfuncs.inc.php newAccount (array($U, $E, $P, $salt, $R, $L, $I,
> $K))
> > + */
> > +
> > +/**
> > + * Triggers the hook by it's name and passes the given payload to the
> hook.
> > + *
> > + * The trigger does not return anything as they must be used in a
> fire-and-
> > + * forget manner.
> > + *
> > + * The functions for the hooks must follow a naming convention to be
> triggered
> > + * by this function. Keep in mind that the weight goes from 1 (lowest)
> to
> > + * PHP_INT_MAX (highest). The higher the number the earlier it will be
> executed.
> > + *
> > + * The pattern is:
> > + *
> > + * <code>hook_$hookname_$weight_uniqueId</code>
> > + *
> > + * @example <code>
> > + *          function hook_registerUser_15_SendmailOnReg($sUsername) {
> do something }
> > + * // or
> > + *          function hook_updatePackage_1_SendmailOnUpdt($sPkgName,
> $sUsername) {
> > + *          do something
> > + * }
> > + * </code>
> > + *
> > + * @param string $sHookName The hook name to be triggered
> > + * @param mixed  $mPayload  A nullable payload to pass to the hook.
> > + *
> > + * @return void
> > + * @author  xenji <mario at xenji.com>
> > + * @since   2012-09-17
> > + */
> > +function trigger_hook($sHookName, $mPayload)
> > +{
> > +    error_log('Started ' . __FUNCTION__);
> > +    $aUserDefFunctions   = get_defined_functions()['user'];
> > +    error_log('Got defined fncs: ' . implode(', ', $aUserDefFunctions));
> > +
> > +    // We just want to process the relevant hooks, no other hooks or
> fnc.
> > +    $oFilter = new \CallbackFilterIterator(
> > +        new \ArrayIterator($aUserDefFunctions),
> > +        function ($mCurr, $iKey, $oIter) use ($sHookName)
> > +        {
> > +            // keep this with three eq. signs, it is needed!
> > +            if (
> > +                strpos($mCurr, 'hook_') !== false
> > +                && strpos(strtolower($mCurr), strtolower($sHookName))
> !== false
> > +            )
> > +            {
> > +                error_log('Hookname OK: '. $sHookName . ' in ' .
> $mCurr);
> > +                return true;
> > +            }
> > +            return false;
> > +        });
> > +
> > +
> > +    $oHookQueue = new \HookQueue();
> > +
> > +    foreach ($oFilter as $sFunction)
> > +    {
> > +        // $_ => unused declaration, borrowed from scala's convention
> > +        list($_, $_, $iWeight, $_) = explode('_', $sFunction);
> > +        error_log("Inserting $sFunction into Queue with weight
> $iWeight");
> > +        $oHookQueue->insert($sFunction, (int)$iWeight);
> > +    }
> > +
> > +    // We just want to have the function name, not the prio
> > +    $oHookQueue->setExtractFlags(\SplPriorityQueue::EXTR_DATA);
> > +    if ($oHookQueue->count() > 0)
> > +    {
> > +        $oHookQueue->top();
> > +
> > +        foreach ($oHookQueue as $sFunction)
> > +        {
> > +            call_user_func($sFunction, $mPayload);
> > +        }
> > +    }
> > +}
> > +
> > +/**
> > + * This is an implementation of the prio queue, which fits perfectly
> for our
> > + * need to sort the hooks in relation to their weight.
> > + *
> > + * Taken from the example on php.net, because I was too lazy to type
> the text.
> > + *
> > + * @see http://php.net/manual/de/class.splpriorityqueue.php
> > + * @author xenji <mario at xenji.com>
> > + * @since 2012-09-17
> > + */
> > +class HookQueue extends SplPriorityQueue
> > +{
> > +    public function compare($priority1, $priority2)
> > +    {
> > +        if ($priority1 === $priority2) return 0;
> > +        return $priority1 < $priority2 ? -1 : 1;
> > +    }
> > +}
> > diff --git a/web/lib/hooks/account.php b/web/lib/hooks/account.php
> > new file mode 100644
> > index 0000000..aea57b5
> > --- /dev/null
> > +++ b/web/lib/hooks/account.php
> > @@ -0,0 +1,4 @@
> > +<?php
> > +function hook_newAccount_1_SendMailForNewAccount($aAccountData) {
> > +    // send a mail if you want to...
> > +}
> > \ No newline at end of file
> > --
> > 1.7.12
>


More information about the aur-dev mailing list