Skip to content
This repository has been archived by the owner on Apr 3, 2020. It is now read-only.

Template hook system #303

Open
euantorano opened this issue Sep 30, 2017 · 12 comments
Open

Template hook system #303

euantorano opened this issue Sep 30, 2017 · 12 comments

Comments

@euantorano
Copy link
Member

Template hook system, allowing plugins and modules to easily output and modify template content without requiring edits to templates (removing the requirement for find_replace_templatesets). This should be less prone to error and make managing themes much easier (installing a new theme should mean that plugins just work).

@1e4
Copy link
Contributor

1e4 commented Dec 4, 2017

Is this still required? I'm willing to put something together if needed?

@euantorano
Copy link
Member Author

euantorano commented Dec 4, 2017 via email

@1e4
Copy link
Contributor

1e4 commented Dec 6, 2017

I built a hook system a few months back, pretty simple so I can create a PR when I get a chance.

@euantorano
Copy link
Member Author

Sounds awesome, I'll quickly outline the kind of thing I'm hoping for 😄

  • A Twig function that can be used in any view, something like the following (each hook has a name - the header_welcomeblock_member_end hook is just an example here):
{{ hook('header-welcomeblock_member_end') }}
  • A central TemplateHookManager (or something) where plugins and modules can register functions to run at a given hook. These functions should return a string that contains HTML content to be displayed (this string could be a rendered Twig view or just raw HTML):
$hookManager = app('template_hooks;); // Example of the hook manager's registered name in the DI
$hookManager->addHook('header-welcomeblock_member_end', function(\Twig_Environment $twig) {
    // do some stuff and return a rendered view here
    return $twig->render('foo');
});
  • Hooked functions should have priorities, to decide which one runs first. This would be an optional third parameter to TemplateHookManager::addHook().
  • It would be awesome if there were implicit hooks at the start/end of each view. I don't know if this is possible as I haven't looked into it at all, but it would be great to add code to the start or end of any view without there being an explicit hook there.

I can't think of anything else at the moment - perhaps @Eric-Jackson or @justinsoltesz have some items on their wishlist (or anybody else out there - feel free to chime in with your wishes!). THe naming of things is always the hardest part I find, so feel free to use names other than TemplateHookManager and such 😄

@1e4
Copy link
Contributor

1e4 commented Dec 7, 2017

Sounds good, below is what I hacked together a few months ago for a project, with a little tweaking and exposing the methods to Twig it should be golden. I need to add priority, basically just sort the array. I'll write a checklist at the end, if you can confirm then I can put it in MyBB

<?php

class HookContainer {

    /**
     * Object container all hooks that are enabled
     *
     * @var array
     */
    private $hooks;

    public function __construct()
    {

        // Get all the hooks and store them
        $this->hooks = Hooks::enabled();
    }


    /**
     * Run the hooks
     *
     * @param $location
     * @param array ...$args
     */
    public function run($location, ...$args)
    {

        $this->execute('hook_before', $args);
        $this->execute($location, $args);
        $this->execute('hook_after', $args);

    }

    /**
     * Wrapper for blade directives so we can show visible hooks
     *
     * @param $location
     * @param array ...$args
     */
    public function display($location, ...$args)
    {

        if(($debug = app('settings')->where('key', '=', 'debug')->first()) !== null)
        {
            if($debug->value === "1")
                echo view('partials.hook', [
                    'location'  =>  $location
                ]);
        }

        $this->execute('hook_before', $args);
        $this->execute($location, $args);
        $this->execute('hook_after', $args);
    }

    /**
     * Execute the hook location
     *
     * @param $location
     * @param array ...$args
     */
    public function execute($location, ...$args)
    {

        // Get hooks based on the location
        $hooks = $this->hooks;

        logDebug("Hook Location: {$location}");
        

        if(count($hooks) > 0) {
            // Loop through and execute each one
            foreach ($hooks as $hook) {
                foreach($hook->locations as $loc)
                {
                    if($loc->location !== $location)
                        continue;

                    $className = $loc->namespace;

                    // Find the class
                    $class = new $className(...$args);

                    // Add some friendly debug
                    logDebug([
                        "hook"=>[
                            "name"      =>  $hook->name,
                            "class"     =>  $className,
                            "location"  =>  $location,
                            "args"      =>  $args
                        ]
                    ], 'hooks');
                    $func = $loc->method;

                    // Allow the plugin to return a view or text or whatever
                    echo $class->$func();
                }


            }
        }
    }

}

I named it HookContainer as it contains all the hooks - this isn't limited to templates, I exposed it via IoC then wrapped a helper method so I could essentially do hook()->display('header') for example.

  • Add priorities

  • Integrate into twig

  • Add a helper method into MyBB to easily call hooks

  • Admin section to handle hooks?

  • Migrations

Is that correct?

@1e4
Copy link
Contributor

1e4 commented Dec 14, 2017

@euantorano Hope you don't mind the little bump

@euantorano
Copy link
Member Author

Sorry, I somehow missed the notification for your reply @1e4!

Looks good to me. The only points I see are:

  • I'm not a big fan of facades for loading hooks - a repository injecting into the constructor would be nice 😄
  • An admin section would be nice, but shouldn't be a priority. Very little work has been done on the ACP, so it can always get added later on.

@1e4
Copy link
Contributor

1e4 commented Dec 17, 2017

No problem @euantorano, there are also no Facades. The Hooks::enabled() is a model with a static method. The hook() function simply get's the Hook instance from the Container. I'll try and carve some time out and get this in this week :)

@1e4
Copy link
Contributor

1e4 commented Jan 2, 2018

Afternoon @euantorano Christmas & New Year were busier than I expected, I'll look at making progress on it this week and keep you posted.

@euantorano
Copy link
Member Author

euantorano commented Jan 2, 2018 via email

@1e4
Copy link
Contributor

1e4 commented Jan 2, 2018

Happy New Year @euantorano I hope MyBB 2 gets a BETA this year ^_^, hoping to contribute as much as I can to make this happen

@euantorano
Copy link
Member Author

euantorano commented Jan 2, 2018 via email

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

No branches or pull requests

2 participants