I decided to use the HMVC opportunity to more clearly divide the site into blocks. I thought about this structure. In the files of the form where necessary, I display the menu.

echo Request::factory('/blocks/menu/topmenu')->execute(); 

Where do you need a sidebar.

 echo Request::factory('/blocks/sidebar/rightsidebar')->execute(); 

To display other information such as a news list is the same.

 echo Request::factory('/blocks/widget/news')->execute(); 

The controllers are located in Controller/Blocks/<тип_блока>/<имя_контроллера> . The route has the corresponding Blocks/<тип_блока>/<имя_контроллера> view Blocks/<тип_блока>/<имя_контроллера>

Controller example

 <?php defined('SYSPATH') or die('No direct script access.'); class Controller_Blocks_Menu_Topmenu extends Controller { public function action_index() { $content=View::factory('/blocks/menu/topmenu'); $this->response->body($content); } } // End Menu (HMVC) 

How to create a universal route for all of them, and so that there is a check that the request was executed only internal, that is, the user cannot directly enter the data of the route into the address?

Tried it turned out cumbersome and did not work, and it seems tugovato, for a long time with the framework did not really work.

    2 answers 2

    As an option, you can do a trace. in the following way:

    bootstrap.php:

     Route::set('widget', 'widget(/<controller>(/<param>))', array( 'param' => '.+' )) ->defaults(array( 'directory' => 'widget', 'action' => 'index', )); 

    application / classes / Widget.php:

     class Widget { protected $_route_name = 'widget'; // Название файла конфигураций виджетов по умолчанию protected $_params = array(); // Массив передаваемых параметров protected $_widget_name; // Название виждета (контроллер) /* * Вызов виджета Widget::load('widget_name', array('param' => 'val'), 'route_name'); * @param string Название виджета * @param array Массив передаваемых параметров * @param string Название роута данного виджета */ public static function load($widget_name, array $params = NULL, $route_name = NULL) { $widget = new Widget($widget_name, $params, $route_name); return $widget->render(); } public function __construct($widget_name, array $params = NULL, $route_name = NULL) { if ($params != NULL) { $this->_params = $params; } if ($route_name != NULL) { $this->_route_name = $route_name; } $this->_widget_name = $widget_name; } public function render() { $this->_params['controller'] = $this->_widget_name; $url = Route::get($this->_route_name)->uri($this->_params); return Request::factory($url)->execute(); } } 

    You put the widgets in the application / classes / Controller / Wisget / folder

    For example:

     class Controller_Widget_MainMenu extends Controller_Widget { public $template = 'widget/mainmenu'; public function action_index() { $this->template->pages = Site::Instance()->getPages(); } } 

    So that the user could not directly access the widget via the url of the http://site.com/widget/MainMenu type, just put a condition in before:

     class Controller_Widget extends Controller_Template { public function before() { parent::before(); if (Request::current()->is_initial()) { $this->auto_render = FALSE; } } } 

    I think you realized that displaying widgets is very simple: <? = Widget :: load ('MainMenu')?>

    I hope to help out =)

    • Thanks a lot, it's really a lot easier) - Danis92
    • Only Error got out ErrorException [Recoverable Error]: Argument 2 passed to Widget :: __ construct () must be an array, given APPPATH \ classes \ Widget.php [26] $ 21 widget = new Widget ($ widget_name, $ params, $ route_name); public function __construct ($ widget_name, array $ params = NULL, $ route_name = NULL) I can not figure out what's wrong. - Danis92
    • Well, read what is written) the constructor is waiting for the array with the second parameter. You give him the object - Vitaly Kustov

    So that the user could not directly access the widget via the url of the http://site.com/widget/MainMenu type

    This chip should either be removed altogether or made optional. embedding widgets in other sites is very common - http://www.webasyst.ru/widgets/ . It is also easier to immediately throw an exception instead of $ this-> auto_render = FALSE; because the action action in the case of an external call will still cause an error with $ this-> template-> pages since $ this-> template will contain not a View object, but a string.

    I use this helper method to call widget controllers.

     /** * Wrapper for request to widget controller * * @param string $uri Request uri(widget name) * @param array $data Send data * @param string $method Request method * @param boolean $auto_render Execute request and return body? * @return mixed * @uses Request::factory * @uses HTML::chars * @throws Request_Exception */ public static function widget($uri, array $data = NULL, $method = Request::GET, $auto_render = TRUE) { // Create request if ( ! $widget = Request::factory('widget'.DIRECTORY_SEPARATOR.$uri)) { throw new Request_Exception('Request to widget :uri failed', array(':uri' => $uri)); } // Set data switch ($method) { case Request::GET: $widget->query($data); break; case Request::POST: $widget->post($data); break; default: throw new Request_Exception('Unknown method :method of widget :uri', array(':method' => $method, ':uri' => $uri)); } // Set data sending method $widget->method($method); // Return request body or object return ($auto_render ? $widget->execute()->body() : $widget); }