Skip to content

Latest commit

 

History

History
312 lines (237 loc) · 10.7 KB

File metadata and controls

312 lines (237 loc) · 10.7 KB

扩展插件

根据事件扩展

插件主要使用事件服务进行扩展,以注入或修改核心类和其他插件的功能。

订阅事件

订阅事件最常见的地方是插件注册文件boot方法。 例如,当用户首次注册时,您可能希望将它们添加到第三方邮件列表,这可以通过订阅rainlab.user.register全局事件来实现。

public function boot()
{
    Event::listen('rainlab.user.register', function($user) {
        // Code to register $user->email to mailing list
    });
}

通过扩展模型的构造函数和使用本地事件可以实现相同的目的。

User::extend(function($model) {
    $model->bindEvent('user.register', function() use ($model) {
        // Code to register $model->email to mailing list
    });
});

声明事件

您可以在全局或本地声明事件,下面是声明全局事件的示例:

Event::fire('acme.blog.beforePost', ['first parameter', 'second parameter']);

本地等效项要求代码位于调用对象的上下文中。

$this->fireEvent('blog.beforePost', ['first parameter', 'second parameter']);

注意: 将本地事件放在全局事件之前是一种好习惯,所以本地事件优先。

订阅此事件后,参数在处理程序方法中可用。 例如:

// Global
Event::listen('acme.blog.beforePost', function($param1, $param2) {
    echo 'Parameters: ' . $param1 . ' ' . $param2;
});

// Local
$this->bindEvent('blog.beforePost', function($param1, $param2) {
    echo 'Parameters: ' . $param1 . ' ' . $param2;
});

扩展后端视图

有时您可能希望允许后端视图文件或部分扩展,例如工具栏。 这可以使用所有后端控制器中的fireViewEvent方法。

将此代码放在您的视图文件中:

<div class="footer-area-extension">
    <?= $this->fireViewEvent('backend.auth.extendSigninView') ?>
</div>

这将允许其他插件通过挂钩事件并返回所需的标记来将HTML注入此区域。

Event::listen('backend.auth.extendSigninView', function($controller) {
    return '<a href="#">Sign in with Google!</a>';
});

注意: 事件处理程序中的第一个参数将始终是调用对象(控制器)。

上面的示例将输出以下标记:

<div class="footer-area-extension">
    <a href="#">Sign in with Google!</a>
</div>

用法示例

这些是如何使用事件的一些实际示例。

扩展用户模型

此示例将通过绑定到其本地事件来修改User模型的model.getAttribute事件。 这是在插件注册文件boot方法内执行的。 在两种情况下,当访问$model-> foo属性时,它将返回值bar

class Plugin extends PluginBase
{
    [...]

    public function boot()
    {
        // Local event hook that affects all users
        User::extend(function($model) {
            $model->bindEvent('model.getAttribute', function($attribute, $value) {
                if ($attribute == 'foo') {
                    return 'bar';
                }
            });
        });

        // Double event hook that affects user #2 only
        User::extend(function($model) {
            $model->bindEvent('model.afterFetch', function() use ($model) {
                if ($model->id != 2) {
                    return;
                }

                $model->bindEvent('model.getAttribute', function($attribute, $value) {
                    if ($attribute == 'foo') {
                        return 'bar';
                    }
                });
            });
        });
    }
}

扩展后端表单

此示例将修改Backend\Widget\Form类的backend.form.extendFields全局事件,并在表单用于修改用户的条件下注入一些额外的字段值。 此事件也在插件注册文件boot方法内订阅。

class Plugin extends PluginBase
{
    [...]

    public function boot()
    {
        // Extend all backend form usage
        Event::listen('backend.form.extendFields', function($widget) {

            // Only for the User controller
            if (!$widget->getController() instanceof \RainLab\User\Controllers\Users) {
                return;
            }

            // Only for the User model
            if (!$widget->model instanceof \RainLab\User\Models\User) {
                return;
            }

            // Add an extra birthday field
            $widget->addFields([
                'birthday' => [
                    'label'   => 'Birthday',
                    'comment' => 'Select the users birthday',
                    'type'    => 'datepicker'
                ]
            ]);

            // Remove a Surname field
            $widget->removeField('surname');
        });
    }
}

如果您需要扩展后端表单并同时添加对翻译这些新字段的支持,则必须在呈现实际表单之前添加字段。 这可以通过backend.form.extendFieldsBefore事件来完成。

    public function boot()
    {
        Event::listen('backend.form.extendFieldsBefore', function($widget) {
            
            // You should always check to see if you're extending correct model/controller
            if(!$widget->model instanceof \Foo\Example\Models\Bar) {
                return;
            }
            
            // Here you can't use addFields() because it will throw you an exception because form is not yet created 
            // and it does not have tabs and fields
            // For this example we will pretend that we want to add a new field named example_field
            $widget->fields['example_field'] = [
                'label' => 'Example field',
                'comment' => 'Your example field',
                'type' => 'text',
            ];
            
            // Ok that's it about adding field inside form, now we need to tell our model that this field is translatable
        });
        
        // We will pretend that our model already implements RainLab Translatable behavior and $translatable property, 
        // if it does not you'll have to add it with addDynamicProperty()
        \Foo\Example\Models\Bar::extend(function($model) {
            $model->translatable[] = 'example_field';
        });
    }

请记住在类文件的顶部添加use Event以使用全局事件。

扩展后端列表

此示例将修改Backend\Widget\Lists类的backend.list.extendColumns全局事件,并在使用列表修改用户的条件下注入一些额外的列值。 此事件也在插件注册文件boot方法内订阅。

class Plugin extends PluginBase
{
    [...]

    public function boot()
    {
        // Extend all backend list usage
        Event::listen('backend.list.extendColumns', function($widget) {

            // Only for the User controller
            if (!$widget->getController() instanceof \RainLab\User\Controllers\Users) {
                return;
            }

            // Only for the User model
            if (!$widget->model instanceof \RainLab\User\Models\User) {
                return;
            }

            // Add an extra birthday column
            $widget->addColumns([
                'birthday' => [
                    'label' => 'Birthday'
                ]
            ]);

            // Remove a Surname column
            $widget->removeColumn('surname');
        });
    }
}

请记住在类文件的顶部添加use Event以使用全局事件。

扩展组件

这个例子将在Topic组件中声明一个新的全局事件rainlab.forum.topic.post和名为topic.post的本地事件。 这在Component class definition中执行。

class Topic extends ComponentBase
{
    public function onPost()
    {
        [...]

        /*
         * Extensibility
         */
        Event::fire('rainlab.forum.topic.post', [$this, $post, $postUrl]);
        $this->fireEvent('topic.post', [$post, $postUrl]);
    }
}

接下来,这将演示如何从页面执行生命周期中挂钩这个新事件。 当在Topic组件(上面)中调用onPost事件处理程序时,这将写入跟踪日志。

[topic]
slug = "{{ :slug }}"
==
function onInit()
{
    $this['topic']->bindEvent('topic.post', function($post, $postUrl) {
        trace_log('A post has been submitted at '.$postUrl);
    });
}

扩展后端菜单

此示例将使用 ... 替换后端中CMS和Pages的标签。

class Plugin extends PluginBase
{
    [...]

    public function boot()
    {
        Event::listen('backend.menu.extendItems', function($manager) {

            $manager->addMainMenuItems('October.Cms', [
                'cms' => [
                    'label' => '...'
                ]
            ]);

            $manager->addSideMenuItems('October.Cms', 'cms', [
                'pages' => [
                    'label' => '...'
                ]
            ]);

        });
    }
}

同样,我们可以删除具有相同事件的菜单项:

Event::listen('backend.menu.extendItems', function($manager) {

    $manager->removeMainMenuItem('October.Cms', 'cms');
    $manager->removeSideMenuItem('October.Cms', 'cms', 'pages');

});