RE: Simple HMVC - Martin7483 - 09-25-2015
In my opinion if you can direct route to a module it is MVC and not HMVC. It's a request that goes from top to bottom. If you can direct route to a module, why not just make it a regular controller with a bunch of libraries, models and views etc.
As for packages, it may look like packages. But if i'm not mistaken, you can load only one package at a time. And as many say, call it what you want. If a packages, containing independent classes (models, views, libraries etc.), would be controlled through a controller request, isn't that then still HMVC?
RE: Simple HMVC - Martin7483 - 10-15-2015
When I started this thread I stated that it would not be possible to directly route a request to a module. But when using the _remap() method in, for example MY_Controller, you can map a request to a module.
I needed this as my CMS is fully module based and I don't want to create a “main” admin controller for every module used in my CMS.
Here is what I have done:
I created a MY_Controller file with two classes defined within this file. The classes are WEBSITE_Controller and ADMIN_Controller. The ADMIN_Controller has the following _remap() method
PHP Code: class ADMIN_Controller extends CI_Controller { /** * Holds all the available params extraxted from the uri * @var array */ public $params = array(); public $language; public $page_cache_title; public $module; public $controller; public $method; public $value; public $slug; public $level; public $segments; public function __construct() { log_message('info', "Class ADMIN_Controller initialized."); parent::__construct(); $this->params = $this->uri->get_params(); foreach($this->params as $key => $value) { $this->$key = $value; } } public function _remap($method) { $output = NULL; // First we check if a module has been requested $module = $this->load->module($this->module); // If this is a object, a valid module has been loaded if(is_object($module) ) { /* If the method is index and the controller != module * then controller is the value to be passed in * e.g. uri = /some-module/some-article.html */ if( $this->controller !== $this->module && $this->method === 'index' ) { $this->value = $this->controller; $this->controller = $this->module; } else /* * e.g. uri = /some-module/a-method/some-article.html */ if( method_exists($module, $this->controller) ) { // The value = the method $this->value = $this->method; // It's a method, the method = the controller $this->method = $this->controller; $this->controller = $this->module; } else // controller was not a method of module, see if it is a sub controller if( is_object($subcontroller = $this->load->module($this->module.'/'.$this->controller)) ) { // Check if the set method exists in the sub controller if( ! method_exists($subcontroller, $this->method) ) { $this->value = $this->method; $this->method = 'index'; } $module = $subcontroller; } // Check if the final set module has the requested method if( method_exists($module, $this->method) ) { // Execute the method of the loaded module and controller $output = $module->{$this->method}($this->value); } else { $output = 'The module request could not be routed to an existing method within the module.'; } } // Continue with regular _remapping if( method_exists($this, $method) ) { $this->{$method}(); } else { // Method is your arg value for the $this->index($output); } }
}
This will now try and find a matching module/controller and method/value based on the URI and execute it if found. The output is then passed to the index method of my admin controller.
The params I use are gathered in a MY_URI class. See code below:
PHP Code: <?php if ( ! defined('BASEPATH')) exit('No direct script access allowed');
class MY_Uri extends CI_URI { /** * The current language of the website * @var string */ protected $language = 'nl'; /** * The available languages for the website * @var array */ protected $languages = array('nl'=>'Nederlands'); /** * Any param values found in the url are stored here * and removed from the (r)segments array * @var array */ protected $params = array(); /** * The level the current DB page is at * @var integer */ protected $level = 1; /** * The DB page slug * @var string */ protected $slug = NULL; public function __construct() { log_message('debug', "Class MY_URI initialized."); parent::__construct(); $this->_set_language(); $this->_set_params(); } //------------------------------------------------------------------- /** * Method to extract and set available data from the uri * This method must be called from the _set_routing() method in the Router * class. Create a MY_Router for this */ public function _setup_page_request() { $this->level = count($this->segments); // Set a hashed cache title for page caching if(count($this->segments) > 0) { $this->slug = $this->segments[$this->level]; $str = str_replace('-', '_', implode('_', $this->segments)); $page_cache_title = substr(md5($str), 0, 15); } else { $page_cache_title = substr(md5('homepage'), 0, 15); } $this->params['page_cache_title'] = $page_cache_title; // Used for module routing, sets module, controller, method and arg if available if( array_key_exists(1, $this->segments) ) { // We will set the module and controller to the same value $this->params['module'] = str_replace('-', '_', $this->segments[1]); $this->params['controller'] = $this->params['module']; } // Set the default method $this->params['method'] = 'index'; if( array_key_exists(2, $this->segments) ) { $this->params['controller'] = str_replace('-', '_', $this->segments[2]); } if( array_key_exists(3, $this->segments) ) { $this->params['method'] = str_replace('-', '_', $this->segments[3]); } if( array_key_exists(4, $this->segments) ) { $this->params['value'] = str_replace('-', '_', $this->segments[4]); } // Set the slug, mainly used on frontend $this->params['slug'] = $this->slug; $this->params['level'] = $this->level; $this->params['segments'] = $this->segments; } //------------------------------------------------------------------- /** * Method to extract the language form the URI */ private function _set_language() { if(count($this->segments) > 0) { // Check if we in the CMS or on front end if($this->segments[1] === 'crossfire') { // Crossfire CMS language if(array_key_exists($this->segments[2], $this->languages)) { $this->language = $this->segments[2]; $this->_unset(2); } } else if(array_key_exists($this->segments[1], $this->languages)) { // Front end language $this->language = $this->segments[1]; $this->_unset(1); } } $this->params['language'] = $this->language; } //------------------------------------------------------------------- /** * Method to extract key:value params from the url */ private function _set_params() { if(count($this->segments) > 0) { foreach($this->segments as $key => $segment) { if( strpos($segment, ':') ) { list($key_name, $value) = explode(':', $segment); if(is_numeric($value)) { $this->params[$key_name] = (int)$value; } else { $this->params[$key_name] = $value; } $this->_unset($key); } } } } //------------------------------------------------------------------- /** * Method to reindex the segments array after any unset() */ private function _unset($key) { // Check if the key exists in the segments array if( array_key_exists($key, $this->segments) ) { // Unset the passed key unset($this->segments[$key]); // re-index the segments array $nkey = 1; $segments = $this->segments; $this->segments = array(); foreach($segments as $segment) { $this->segments[$nkey] = $segment; $nkey++; } } } //------------------------------------------------------------------- /** * Return the set params */ public function get_params() { return $this->params; } }
I only use this for my CMS. My WEBSITE_Controller uses a page builder to render the content of a DB page and will execute any module that is found on the requested page. For more info on routing DB pages check out my other thread
RE: Simple HMVC - nasser.man - 10-15-2015
interesting, do you want to create an repository for this and some guidelines for it?
RE: Simple HMVC - Martin7483 - 10-16-2015
(10-15-2015, 12:13 PM)nasser.man Wrote: interesting, do you want to create an repository for this and some guidelines for it?
At the moment I'm still working on some things that together will form a simple base project. The project will include the Simple HMVC and all the latest tweaks and some nice extras that are missing in the default CI.
The project will contain:- CI 3.x.x
- Simple HMVC
With direct module routing for CMS setup.
Needed MY_xxx.php files will be included
- Extended router class for the use of a catchall controller for easy DB page routing
- Honey pot form extension
- A form builder for easy form creation and validation handling, including jQuery Form validation
- Ion Auth, will make use of the form builder for the required forms
- An assets loader for CSS and JS assets
- An assets path controller handler.
This will allow for easy use of assets. No need for you to know the complete path of an asset.
- Mobile detection, checks if a visitor is on desktop, tablet or mobile
This project is not a CMS. I will be using this to build my own CMS and will share created modules that easily plug in to this base project.
No designs will be included. So you will be free to use your own images/CSS/JS and design framework.
Once the base project is completed I will create a GitHub repo for it. I will also create a new thread for the base project.
RE: Simple HMVC - Sentro - 10-30-2015
One thing i came upon is in "MY_Loader.php" when you require the "base_module.php" file.
On linux systems the file could not be located so either had to change the file name to lowercase
or change the require to "Base_module.php" Line 62.
RE: Simple HMVC - Martin7483 - 10-30-2015
(10-30-2015, 01:37 AM)Sentro Wrote: One thing i came upon is in "MY_Loader.php" when you require the "base_module.php" file.
On linux systems the file could not be located so either had to change the file name to lowercase
or change the require to "Base_module.php" Line 62.
Thanks for the heads up on that! Will add the fix later today.
How is it working out for you?
RE: Simple HMVC - Sentro - 10-30-2015
(10-30-2015, 01:48 AM)Martin7483 Wrote: Thanks for the heads up on that! Will add the fix later today.
How is it working out for you?
Awesome, pretty much what i was looking for. Simple and straight forward. I'll let you know if i think of any improvements or stuff to add.
RE: Simple HMVC - Martin7483 - 10-30-2015
(10-30-2015, 02:10 AM)Sentro Wrote: Awesome, pretty much what i was looking for. Simple and straight forward. I'll let you know if i think of any improvements or stuff to add.
Nice to hear that
Here is a little extra method for the MY_Loader class
PHP Code: /** * Set a custom path for view files * * @param string $path * @param bool $view_cascade */ public function custom_view_path($path, $view_cascade = TRUE) { if( ! array_key_exists($path, $this->_ci_view_paths) ) { $this->_ci_view_paths = array($path => $view_cascade) + $this->_ci_view_paths; } }
It's almost the same as the library_view method, only the difference is that you pass an absolute path to this method. So now any location within your project could hold view files
|