MVC Framework – Content Management with Admin Panel in PHP

content-managementdesign-patternsmvcPHP

I've lately been developing my own MVC content management system using PHP and, at least in my mind, am a little stuck with the system design. I believe this would apply to building a content management system with an existing MVC framework as well.

This is going to be a little difficult to explain, so sorry in advance for the lengthy dilemma.

A little intro to the system:

Currently my routes look a little like this (stored as JSON):

{
    "/admin/:controller/:action/:params":"",
    "/admin/:controller/:params":"AdminController",
    "/admin":"AdminController",
    "/:page?/:subpage?":"IndexController"
}

The routes are the keys, the default controllers are the values. If there isn't a default controller the router falls through to the next rule. I've done this to separate the front end of the site from the admin panel.

The controllers are all in one directory for the time being, although this is destined to change. They either return a template that's been populated with data from their respective model or simply modify the request they were instantiated with.

The problem:

My problem is with deciding how to implement separate controllers that concern the same model for the front end and the back end in a modular way.

For example, I have a page in the admin panel that allows an administrator to enter some private information that's intended only to be accessible on the front end with a username and password. Imagine this is handled by an InfoController in the back end, for editing the private information, matched by the route /admin/info.

What if I wanted to create a route for the front end, for accessing the private information, with the same name as in the admin panel (/info)?

The problem makes more sense in context with the solutions I've considered, I think.

Solutions I've considered:

  1. My first thought was to append all admin-related controllers with
    Admin – so AdminInfoController and InfoController – but I'm
    interested in eventually having a modular system where all the routes,
    controllers and views (and CSS/JavaScript if needed) pertaining to the Info model would be in their own directory structure (something like /modules/info).
  2. With the desire for modularity in mind, I thought about matching routes a bit like /:module/:controller/:action, but this would then imply that the admin panel is itself a module, which would need access to all the modules the front end can use. Would that make sense?
  3. The design I've thought about the most is to have the admin and front end as two distinguished, core concepts of the framework. They would share modules that contain controllers and views for both.

Ultimately I'm looking for input on the best approach here, any alternatives, and whether I'm totally over-thinking this.

It feels a bit like I've driven myself crazy with the pursuit of my ideal system design that keeps with the MVC pattern (is it even the right thing for a system like this?). Thanks for reading, I hope it made sense.

Best Answer

I solved this when I started using service providers with a dependency injection container to implement a module system.

Treating modules as service providers for the application is what worked best, whether they are providing new services or providing to data to existing services, like routes.

The admin panel has itself become a module that simply provides admin related routes and services to the container. Any other modules can do the same thing.

Default routes in the config look like this in JSON format:

{
    "/:controller/:action/:params": {
        "namespace": "Darya\\Core\\Controllers"
    },
    "/:controller/:params": {
        "namespace": "Darya\\Core\\Controllers"
    },
    "/:page?/:subpage?": "Darya\\Core\\Controllers\\IndexController"
}

Module routes can look like this when defined in a module class (a service provider):

// Route path to namespace prefixes:
// "/admin/info" would become "Darya\Module\Admin\Controllers\InfoController"
$router->add(array(
    '/admin/:controller/:action/:params'  => 'Darya\Module\Admin\Controllers',
    '/admin/:controller/:params'          => 'Darya\Module\Admin\Controllers',
    '/:controller/:action/:params'        => 'Darya\Module\Controllers'
    '/:controller/:params'                => 'Darya\Module\Controllers'
));

This way all the URLs of the application are nice and extensible. The next problem is deciding on route priorities, but that becomes off topic.

Dependency injection is your friend. :)

Related Topic