Best practice for a dynamic module module based on modular CMS

Well, I know the name may be a little strange. But I do not know how else to say it. Basically it comes down to something simple, but sometimes, being one developer, you ask questions and make you discuss it with other developers.

A quick introduction to the problem: I'm going to remake my CMS based on the popular PHP Framework (Fyi: Laravel is my choice). CMS will be modular (blog, users, pages, forms, etc.), but I also want the website to be managed by website owners. It was here that I began to think about best practice for this.

So far, I have been thinking about creating the "MenuBuilder" interface, which defines the methods that should be known for creating menu links for this module. So let's say my BlogModule has a BlogMenuBuilder class.

In the MenuBuilder classes, a method will be created for creating a link based on none or some parameters (for example, a record identifier), a method for generating all links, a method for generating an array of parameters for a drop-down list, etc.

Then the MenuModule will save the class name and optional parameters in the table along with the location of the menu (header, footer, sidebar, etc.) and I could call MenuModule::build('top') , this function will find all the links, sorted in order and build links by calling BlogMenuBuilder::link('type', $optional_parameters); . The type in this case will be a named route from the Laravel framework. In the end, the MenuModule :: build () method will cache, not create it again every time.

Am I somewhere close to best practice? I feel like I'm heading in the right direction, but since I don't have other developers to think about it, I was hoping to get useful feedback from SO.

Thank you for your time!

+6
source share
2 answers

I think you're pretty much where the structure is. Based on what I understand from your question (and if you use Laravel), I would approach it like this:


Database

 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 

Using this table, you can store menus, links (or a route defined in the corresponding builder or URL), as well as meta / options data for menus or links.

Note. . If you want to reuse links in several menus, you can remove menu_id from the links table, add the menu_links table for ManyToMany the relationship between menus and links


Models

Simple enough, you need a model for each table, i.e. Menu , Link and Meta


Builders

In the app directory of your project, I would place the Builders folder, and possibly the MenuBuilders folder inside it. Using this structure, you should skip the space in each Builder class under App\Builders\MenuBuilders .

With each Builder class, you can either extend the main MenuBuilder class, or, depending on how much you change for each Builder , you could implement a interface . Here is a quick example using interface (if you are not familiar with interfaces, I would suggest looking at Laracasts PHP Bootcamp ):

MenuBuilderInterface.php

 namespace App\Builders\MenuBuilders; interface MenuBuilderInterface{ /* * Build function * * @param object $menu */ public build($menu); } 

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 } } 

If you do not want to create all the methods enclosed in the interface , then perhaps the extension of the main MenuBuilder class will work better for you, it really depends on how different you see the menu and whether you use it and can reuse many methods in the main MenuBuilder .


On practice

So how would you use the above setting? As you said in your question, each Menu defines its constructor in the database, so we could create a simple build function in our Menu model to call the correct Builder class:

menu.php

 namespace App; use Illuminate\Database\Eloquent\Model; class Menu extends Model { /** * Get the user 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); } } 

Now all we need in our view is to call the build function in our menu instance:

 <!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> 

There are always several different ways to structure these kinds of things. Inevitably, you will understand what is best for you, based on the specific requirements of each result that you are after, but I hope this helps!

+5
source

Well, as everyone said, do what the other big cms did.

So, in the user interface: - have a selection box for existing menus - there is a button for creating a new menu

  • when creating or adding a menu
  • you will have a button to add a new item
  • when a field with all pages is clicked on a new element →

this part can be complicated, like your site: - contain static pages: /, / about, / contact - contain dynamic pages (e.g. wordpress) - contain dynamic messages (e.g. wordpress) - contain dynamic categories, tags independently (like WordPress ) - free input unit

+2
source

All Articles