📜 ⬆️ ⬇️

Kohana 3.0 - simplify your life

The framework is good, it's great, this is an opportunity to save a lot of time on thinking about the architecture of the future application, but ... The framework itself is a frame. And, using Kohana 3.0 as an example, which will be discussed in this article, this framework should be finished to one degree or another.
Now let's take a look at what we are going to do now:

So, let's begin…

It is assumed that we have already done a couple of simple actions - we created the .htaccess file in the image and example of example.htaccess, setting the necessary path to our working directory in it; changed the initialization parameters in the Kohana :: init method (they also set the path to the working directory and set (to taste) 'index_file' => FALSE; we connected the modules necessary for the subsequent work ...
Now we’re looking at the end of bootstrap.php where the default route is set - how many ordinarily are the routes? Ten? Twenty? In my last application on Ko3.0 there were about 30 of them. Dofig, in general, for storage right here, mixed with the data that is actually stored in bootstrap.php. Output? We take them all to a separate file and enable it. Suppose so:
Create a new file in the application folder with the name of routes.php and transfer the entire Route :: set ('default') there ... and in its former location in the bootstrap.php just write require_once APPPATH.'routes.php ';
Now let's remember that the controller class (that Kohana_Controller) has wonderful methods before () and after (), which are executed, respectively, before and after the “body” of the controller. Now let's remember that in most applications we will connect an auth module (auth) - at least for administrative login. Why am I doing this?
And let's rewrite the base Kohana_Controller and start working with the (possible) user right there.
<?php class Controller extends Kohana_Controller { /** * @var auth property with instance of "Auth" module */ public $auth = NULL; /** * @var user property with object of user */ public $user = FALSE; public function before() { parent::before(); $this->auth = Auth::instance(); $this->user = $this->auth->get_user(); } public function after() { parent::after(); } } 

And we save this stuff in the application / classes folder under the name controller.php
Now we will think, what else can we need in absolutely any place of any controller in the future? Redirect! Even two! Actually - redirect to home and redirect back. I will not describe the possible situations of necessity, simply if you agree with the necessity of redirects - we read further about them:
A redirect to the main one implies a redirect of the user to the address that corresponds to the default route without parameters. A redirect back implies a redirect to the address from the referrer line, if it is a link at all. If not, we redirect to the main page using the redirect described above. We can also have 2 types of redirects (so far this has never been useful to me, but the opportunity, it seems to me, is useful) is the redirect of the current request (HMVC and all that ...) and the redirect of the main request. By default, we will perform the redirect of the main request. Actually, I suggest the following implementation of the above (we write everything in the same application / classes / controller.php after the before () method):
  public function go_home($current_request_only = FALSE) { $url = Route::url('default', NULL, TRUE); $this->go($url, $current_request_only); } public function go_back($current_request_only = FALSE) { Validate::url(Request::$referrer) OR $this->go_home($current_request_only); $this->go(Request::$referrer, $current_request_only); } private function go($url, $current_request_only) { $request = ($current_request_only) ? $this->request : Request::instance(); $request->redirect($url); } 

I will explain a little methods:
in the go_home () method we get the URL of the default route and call the go () method
in the go_back () method, we check the validity of the URL from Request :: $ referrer and if it fails the check, we run the go_home () method on which execution is interrupted
in the go () method, we determine which request to redirect (by default, Request :: instance () is the main request, but you can also $ this-> request)

Now, since we are talking about various possible requests (HMVC / simple) - let's eliminate a small omission in the class Request. The omission is that in Kohana 3.0, in contrast to Kohana 3.1, there is no method for determining the belonging of a request - only Request :: $ is_ajax.
Create an application / classes / request.php file and write:
 class Request extends Kohana_Request { public function is_initial() { return $this === Request::instance(); } } 

Since Request :: current () returns an instance of the main request (Singletone), it suffices to check whether the current Request object is such as $ this. This method is useful to us in the future.
Next on the queue we have an extension of a simple controller - a controller that will not only perform some actions, but also work with View. Let's call it Controller_Front (although Kohana offers something remotely similar called Controller_Template - it's a matter of taste, nothing depends on the name - just what class you will inherit from the rest of the controllers).
Controller_Front will split the entire View into a “wrapper” and “content”. A wrapper is a standard markup, characteristic of all pages of our project - there will be a doctype, a connection of styles and everything, everything, everything that should be on all pages. Content is the result of a particular controller. Let's digress a bit from our Controller_Front and create them right away in order to understand what we are talking about:
 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en"> <head> <meta http-equiv="content-type" content="text/html; charset=utf-8" /> <meta name="author" content="Roman Chvanikoff" /> <title><?php echo $title; ?></title> </head> <body> <?php echo $content; ?> </body> </html> 

Here we will have a wrapper in which the content ($ content), obtained as a result of the controller, will be invested.
Save it as application / views / index.php
Now let's create a content view for the default Kohana route, welcome / index
 <h1>Welcome!</h1> 

and save it as application / views / welcome / index.php
Actually, by this line of the article you should already understand if for some reason it did not work out earlier what is the wrapper and what is the content.
But back to our Controller_Front. Let's default render everything into a wrapper index if the wrapper name has not been redefined in the controller (what little is the logic of your application).
 class Controller_Front extends Controller { /** * @var layout wrapper of content for final output */ public $layout = 'index'; /** * @var content controller-generated output */ public $content; /** * @var errors all logic errors (including Validate errors) should be stored here */ public $errors; /** * @var post Validate object of _POST */ public $post; /** * @var view_path define what folder should be used to generate Views * values: * NULL - View::path will be generated as name of called controller * FALSE - View::path will not affect views generation * string - View::path will have value of the view_path property */ public $view_path = NULL; public function before() { parent::before(); $this->layout = View::factory($this->layout); $this->layout->set_global('user', $this->user); $this->post = Validate::factory($_POST); // Doubts? Look at view_path property definition if (is_null($this->view_path)) { View::$view_path = $this->request->controller; } elseif ($this->view_path) { View::$view_path = $this->view_path; } } public function after() { /** * Clear View "environment" */ View::$view_path = NULL; if ( ! Validate::not_empty($this->errors)) { $this->errors = NULL; } else { // $this->errors should be an array to pass it as argument to View. is_array($this->errors) OR $this->errors = array($this->errors); // $this->errors is a View now $this->errors = View::factory('errors', array('errors' => $this->errors)); } // $this->content can be a simple string or something like that so we check if it is a View file if ($this->content instanceof View) { // Append post-data $this->content->post = $this->post; // Append errors $this->content->errors = $this->errors; } // If request is initial - return layout with attached content if ($this->request->is_initial() AND ! Request::$is_ajax) { // Append content to layout $this->layout->content = $this->content; // Set response $this->request->response = $this->layout; } else { // Set response as controller-generated output $this->request->response = $this->content; } parent::after(); } } 

In this controller, I hope everything is clear from the comments, except for working with some View :: $ view_path - what is it? This is what will allow us not to write strings like $ this-> content = View :: factory ('user / edit') within the same controller in different actions; and replace them with more compact $ this-> content = View :: factory ('edit');
By the way, let's expand the View itself - otherwise how do we implement it?
 class View extends Kohana_View { /** * @staticvar view_path a directory that will be used to generate views */ public static $view_path = NULL; /** * Sets the view filename. * * $view->set_filename($file); * * @param string view filename * @return View * @throws Kohana_View_Exception */ public function set_filename($file) { $directory = 'views'; if ( ! is_null(View::$view_path)) { $directory .= DIRECTORY_SEPARATOR.View::$view_path; } if (($path = Kohana::find_file($directory, $file)) === FALSE) { throw new Kohana_View_Exception('The requested view :file could not be found in :directory', array( ':file' => $file, ':directory' => $directory, )); } // Store the file path locally $this->_file = $path; return $this; } } 

I think that after working with this modified class from Controller_Front has been scheduled, it will be unnecessary to stop here, so we save this file as application / classes / view.php, save Controller_Front as application / classes / controller / front.php and " go further. "

Open the welcome controller (application / classes / controller / welcome.php) and change the extends Controller to extends Controller_Front, and in the index method, replace the line $ this-> request-> response = 'hello, world!'; at $ this-> content = View :: factory ('index');
')
Now, if everything is done correctly, open the browser, go to the project address and see our Views / welcome / index.php View file, framed by the Views / index.php layout.

Afterword

The article lay in the “add and publish” folder for almost a month, but finally my hands reached at least somehow sort the information in it and, in fact, publish it. If you read it and some moments were not clear to you, or I made mistakes in the code, or you did everything on the article, but it didn’t work - write in the comments immediately, I will answer as soon as possible. ;)

PS: I think someday I will get my hands on the rest of the articles from the “add and publish” folder, so ... This article is just the beginning, then we will make a simple application (write your wishes in the comments) based on what we managed to do in This article - this will assess the convenience that we have just created.

UPD:
The view file views / errors.php can be like this:
 <ul class="errors"> <?php foreach ($errors as $error) : ?> <li><?php echo $error; ?></li> <?php endforeach; ?> </ul> 

Source: https://habr.com/ru/post/115009/


All Articles