-
Notifications
You must be signed in to change notification settings - Fork 74
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Support for Plugins #39
Comments
I'm going to move plugins into beta because the current version seems pretty stable and we could benefit from not worrying so much about semver just yet. (As they say, move quickly and break things! 😖) In 7a7c2ca, I added a few basic methods to handle events. I envision them working a lot like jQuery's To listen for events// Without a namespace
Postleaf::on('post.save', function($event) {
// Do stuff
});
// With a namespace
Postleaf::on('post.save/yourNamespace', function($event) {
// Do stuff
}); Namespacing is useful so you can stop listening to a specific event without breaking all of its other listeners. By convention, they're separated by a slash. To stop listening for events// Stop all listeners for a specific event
Postleaf::off('post.save');
// Stop all listeners for a specific event with a specific namespace
Postleaf::off('post.save/yourNamespace')
// Stop all listeners for all events with a specific namespace
Postleaf::off('/yourNamespace'); Dispatching EventsThe app will dispatch events like this: // Dispatch the post.save event
Postleaf::dispatchEvent('post.save', $event_data);
// Dispatch the user.delete event
Postleaf::dispatchEvent('user.delete', $event_data); I'm thinking that event data should be passed to this method by reference so callbacks can make necessary changes that feed back to the app. More info
I think this is a good start, but I'd like some feedback before proceeding. The next step is to add event hooks to various parts of the app and expose some additional functionality (such as the ability to add routes). |
This looks great. Adding an eventpublic static function on($event, $callback) {
$options = explode('/', $event, 2);
// my suggestion
$resource = explode('.', $options[0], 2);
// Attach the listener
self::$listeners[$resource[0]][] = [
'event' => $resource[1],
'namespace' => $options[1] ?: null,
'callback' => $callback
]; Dispatch an eventpublic static function dispatchEvent($event, $data = null) {
// my suggestion
$resource = explode('.', $options[0], 2);
// Loop through all listeners
foreach((array) self::$listeners[$resource[0]] as $listener) { If we do so, the loop doesn't need to iterate over perhaps 1000 items, it only needs to iterate over the $resource[0] items. What do you think? |
The loop could definitely be optimized, possibly so it only loops over the event name (without the namespace). I'll play around with it. |
I benchmarked event dispatching to compare a few different solutions. The results were:
Thinking a bit more about this, I decided to take @karsasmus' approach and store each event type like this: self::$listeners[$event] = [
'namespace' => $namespace ?: null,
'callback' => $callback
]; Which allows us to iterate over just the events we're targeting in I also changed the namespace delimiter to |
I added some post events to experiment with in 5d434ed. For now, you can test listeners by adding them in Here are a couple examples that append the save time to posts when adding/updating: Postleaf::on('post.update', function(&$event) {
$event['post']['content'] .= '<p>Post updated on ' . date('Y-m-d H:i:s') . '</p>';
});
Postleaf::on('post.add', function(&$event) {
$event['post']['content'] .= '<p>Post created on ' . date('Y-m-d H:i:s') . '</p>';
}); Note that Any thoughts on this before proceeding with other events? |
I reviewed 5d434ed. You fire an event before and after an action. So we should name the event resource.beforeFunctionName and resource.afterFunctionName. Example: If we do so, we avoid confusion about the data an event returns. Example: If we follow my suggestion, the events would be called "post.afterGet" and "post.afterGetMany" Should we also add an event for startup and shutdown? Postleaf::dispatch('postleaf.startup', $eventData);
Postleaf::dispatch('postleaf.shutdown', $eventData); |
The events use present tense and past tense verbs:
The present tense is dispatched as soon as possible and the past tense fires after the operation completes. This is less verbose and similar to the convention Bootstrap uses for their events.
Definitely. TODO updated. |
Ok, present and past tense are fine. How can I support you? |
I suggest using |
@karsasmus if you want to get started on tags/users/navigation/settings that would be great. Just follow my lead on posts. 😀 Will we need to be able to prevent an event from firing? If so, we should think about how to handle that too. |
Ok, I'll begin tomorrow 😁 I think, the events should always get fired, except we implement a cli. |
I believe the events should be fired. No matter whether it is cli or web. |
I agree, any event that happens should dispatch an event. In the case of alternate interfaces, they may want to register their own listeners separate from those of plugins. But yeah, one thing at a time. 😎 |
A proposal for the plugins database table. DROP TABLE IF EXISTS `__plugins`;
CREATE TABLE IF NOT EXISTS `__plugins` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(51) NOT NULL,
`author` varchar(51) NOT NULL,
`version` varchar(8) NOT NULL,
`install_date` datetime NOT NULL,
`enabled` tinyint(4) NOT NULL,
`enabled_date` datetime NOT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `id` (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 AUTO_INCREMENT=1 ; Should we also save the plugin config (from plugin.json) to database? I know, we haven't implemented yet the event system, but if this proposal is ok for you, we could check off the todo. 😇 |
This issue is for plugin planning and development.
TODO
default.database.sql
INSTALL.md
content/plugins
(similar toTheme::getAll()
)The text was updated successfully, but these errors were encountered: