基于模块化CMS的动态菜单模块的最佳实践

Jos*_*ndo 7 php laravel laravel-5.2

好吧,我知道标题可能有点奇怪.但我不知道怎么说.基本上它归结为一些简单的东西,但有时候只是一个开发人员让你质疑并让你想与其他开发人员讨论它.

快速介绍问题:我将基于流行的PHP框架重新开始我的CMS(Fyi:Laravel是我的选择).CMS将是模块化的(博客,用户,页面,表格等),但我也希望网站所有者可以管理网站导航.这是我开始考虑这样做的最佳实践的地方.

到目前为止,我所想的是创建一个接口"使用MenuBuilder",它定义了需要已知产生一个给定模块菜单链接的方法.所以,假设我的BlogModule有一个类BlogMenuBuilder.

MenuBuilder类将有一个方法来构建基于none或一些参数(如记录ID)的链接,生成所有链接的方法,为下拉列表生成选项数组的方法等.

然后MenuModule将类名和可选参数保存到表中,连同菜单位置(顶部,页脚,侧边栏等),我可以调用MenuModule::build('top'),此函数将找到所有链接,按顺序排序,并通过调用构建链接BlogMenuBuilder::link('type', $optional_parameters);.在这种情况下,类型将是Laravel框架中的命名路由.最终,MenuModule :: build()方法将缓存,而不是每次都必须再次构建它.

我是否接近最佳做法?我觉得我正朝着正确的方向前进,但由于我没有其他开发人员认为这件事我希望从SO获得一些可用的反馈.

谢谢你的时间!

Ste*_*e O 6

我认为你在结构方面几乎就是这样.基于我对你的问题的理解(以及你正在使用Laravel),我会这样做:


数据库

Name:    menus
Columns: id | builder | created_at          | updated_at          | deleted_at
         ---------------------------------------------------------------------
     eg. 1  | NULL    | 1985-10-26 01:20:00 | 1985-10-26 01:21:00 | NULL
         2  | blog    | 1985-10-26 01:20:00 | 1985-10-26 01:21:00 | NULL


Name:    links
Columns: id | menu_id | type  | resource_type | resource_id | url                       | created_at          | updated_at          | deleted_at
         -------------------------------------------------------------------------------------------------------------------------------
     eg. 1  | 1       | url   | NULL          | NULL        | http://example.com/blog/1 | 1985-10-26 01:20:00 | 1985-10-26 01:21:00 | NULL
         1  | 2       | route | blog          | 1           | NULL                      | 1985-10-26 01:20:00 | 1985-10-26 01:21:00 | NULL


Name:    meta (or options)
Columns: id | resource_type | resource_id | name     | value
         ---------------------------------------------------
     eg. 1  | menu          | 1           | bg_color | 000000
         2  | link          | 1           | target   | _blank
Run Code Online (Sandbox Code Playgroud)

使用此表设置,您可以存储菜单,链接(在相关构建器或URL中定义的路径)和菜单或链接的元/选项数据.

注意:如果要重新使用多个菜单中的链接,可以menu_idlinks表中删除menu_links为菜单和链接之间的ManyToMany关系添加一个表


楷模

很简单,你想要每个表的模型,即.Menu,LinkMeta


建设者

app项目的目录中,我会放置一个Builders文件夹,并且可能MenuBuilders在其中放置一个文件夹.使用该结构,您可以为每个Builder类命名App\Builders\MenuBuilders.

对于每个Builder类,你可以那么可以扩展主MenuBuilder类,或者取决于你有多少的每个变化Builder,你可以implementinterface.这是一个使用a的简单示例interface(如果你不熟悉接口,我建议你看看Laracasts PHP Bootcamp):

MenuBuilderInterface.php

namespace App\Builders\MenuBuilders;

interface MenuBuilderInterface{
    /* 
     * Build function
     *
     * @param object $menu
     */
    public build($menu);
}
Run Code Online (Sandbox Code Playgroud)

BlogMenuBuilder.php

namespace App\Builders\MenuBuilders;

class BlogMenuBuilder implements MenuBuilderInterface {
    /* 
     * Build function
     *
     * @param object $menu
     */
    public build($menu)
    {
        // Here you can now build your menu using
        // the menu instance passed through
    }
}
Run Code Online (Sandbox Code Playgroud)

如果你不想有创造合同的所有方法interface,那么也许延伸的主MenuBuilder类的工作对你更好,这真的取决于你如何看到不同的菜单是和您是否可以重新使用了大量的方法一个主要的MenuBuilder.


在实践中

那么你将如何使用上述设置?就像你在问题中所说的那样,每个人都menu在数据库中定义了它的构建器,所以我们可以在Menu模型中创建一个简单的构建函数来调用正确的Builder类:

Menu.php

namespace App;

use Illuminate\Database\Eloquent\Model;

class Menu extends Model
{
    /**
     * Get the user's first name.
     *
     * @param  string  $value
     * @return string
     */
    public function build()
    {
        // First we define our namespace and get the builder based on the menu data
        $namespace = 'App\\Builders\\MenuBuilders\\';
        $builder   = !empty($this->builder)? $namespace.ucfirst($this->builder).'MenuBuilder' : $namespace.'MenuBuilder';

        // Then check the builder class defined definitely exists
        // If no, replace with main menu builder class
        $builder = class_exists($builder)? $builder : $namespace.'MenuBuilder';

        // Lastly we call the build method on a new instance of our builder
        // passing in our menu instance
        return new $builder()->build($this);
    }
}
Run Code Online (Sandbox Code Playgroud)

现在我们在视图中需要做的就是在菜单实例上调用build函数:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Example Site</title>
</head>
<body>
    <div id="menu">

        <?php
        // Get our blog menu
        // - you would obviously more likely do this in your controller
        $menu = Menu::find(2);
        ?>
        {!! $menu->build() !!}

    </div>
</body>
</html>
Run Code Online (Sandbox Code Playgroud)

总有一些不同的方法可以构建这种东西.根据你所追求的每个结果的具体要求,你不可避免地会找出最适合自己的东西,但我希望有所帮助!