Кохана 3.0 – Упрощаем Вашу Жизнь

Фреймворк — это хорошо, это здорово, это возможность сэкономить кучу времени на обдумывании архитектуры будущего приложения, но… Фреймворк как таковой — это фреймворк.

И, на примере Kohana 3.0, о котором пойдет речь в этой статье, этот фреймворк должен в той или иной степени быть завершенным.

Теперь давайте посмотрим, что мы собираемся делать сейчас:

  • -Расширим базовый контроллер, добавив жизненно важные методы и работу с пользователями (что присутствует в 99% проектов, по крайней мере, на уровне административного входа)
  • -Создадим свой фронт-контроллер для более удобной и красивой работы с файлами просмотра
  • -Реализуем вывод ошибок валидации через фронт-контроллер
  • -Улучшение базового класса View.
  • -Ну и еще некоторые полезные мелочи.

Итак, начнем… Предполагается, что мы уже сделали пару простых шагов — создали файл .

htaccess по образу и подобию example.htaccess, прописав в него необходимый путь к нашему рабочему каталогу; изменили параметры инициализации в методе Kohana::init (также мы указали путь к рабочей директории и установили (по вкусу) 'index_file' => FALSE; подключили необходимые для последующей работы модули.

Теперь посмотрите на конец файла bootstrap.php, где установлен маршрут по умолчанию — сколько маршрутов обычно имеется в приложении? Десять? Двадцать? В моем последнем приложении на Ко3.0 их было около 30. В общем, многие из них нужно хранить прямо здесь, вперемешку с данными, которые на самом деле хранятся в bootstrap.php. Выход? Мы поместили их все в отдельный файл и включили.

Скажем так: Создаем в папке приложения новый файл с именем router.php и перемещаем туда весь Route::set('default').

и на прежнем месте в bootstrap.php просто пишем require_once APPPATH.'routes.php' ; Теперь давайте вспомним, что класс контроллера (то есть Kohana_Controller) имеет замечательные методы before() и after(), которые выполняются до и после тела контроллера соответственно.

Теперь помните, что в большинстве приложений мы будем подключать модуль авторизации (auth) — как минимум для административного входа.

О чем я говорю? Давайте переопределим базовый Kohana_Controller и прямо здесь начнем работать с (возможным) пользователем.

  
  
  
  
  
  
  
   

<Э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(); } }

И сохраняем все это в папке application/classes под именем контроллер.

php А теперь давайте подумаем, что еще нам может понадобиться в абсолютно любом месте любого контроллера в будущем? Перенаправление! Даже два! Собственно — редирект на главную страницу и редирект обратно.

Я не буду описывать возможные ситуации необходимости, просто если вы согласны с необходимостью редиректов, читайте о них дальше: Перенаправление на главную страницу подразумевает перенаправление пользователя на адрес, соответствующий маршруту по умолчанию без параметров.

Редирект обратно означает перенаправление на адрес из реферерной строки, если это вообще ссылка.

Если нет, то перенаправляем на главную страницу, используя редирект, описанный выше.

Еще у нас может быть 2 типа редиректа (я этим еще ни разу не пользовался, но думаю функция полезная) — редирект текущего запроса (HMVC и все такое.

) и редирект основного запроса.

По умолчанию мы перенаправим основной запрос.

Собственно, я предлагаю следующую реализацию вышеизложенного (пишем всё в том же application/classes/controller.php после метода before()):

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

Немного поясню методы: в методе go_home() мы получаем URL-адрес маршрута по умолчанию и вызываем метод go() в методе go_back() мы проверяем валидность URL-адреса из Request::$referrer, и если проверка не проходит, мы выполняем метод go_home(), где выполнение прерывается в методе go() определяем, какой запрос перенаправить (по умолчанию — Request::instance() — основной запрос, но возможен и $this-> request) Теперь, раз уж мы говорим о различных возможных запросах (HMVC/simple), давайте исправим небольшое упущение в классе Request. Упущение в том, что в Kohana 3.0, в отличие от Kohana 3.1, нет метода определения принадлежности запроса — только Request::$is_ajax. Создайте файл application/classes/request.php и напишите:

class Request extends Kohana_Request { public function is_initial() { return $this === Request::instance(); } }

Поскольку Request::current() возвращает экземпляр основного запроса (Singletone), достаточно проверить, является ли текущий объект запроса $this таковым.

Этот метод нам пригодится позже.

На очереди у нас расширение простого контроллера — контроллер, который будет не только выполнять какие-то действия, но и работать с Представлением.

Назовем его Controller_Front (хотя Kohana предлагает нечто отдалённо похожее под названием Controller_Template — это дело вкуса, от названия ничего не зависит — только от какого класса вы унаследуете остальные контроллеры).

Наш Controller_Front обеспечит разделение всего View на «обертку» и «контент».

Обертка представляет собой стандартную разметку, типичную для всех страниц нашего проекта — там будет доктайп, включенные стили и все-все, что должно быть на всех страницах.

Контент является результатом работы конкретного контроллера.

Давайте немного отдохнем от наших Controller_Front и сразу создадим их, чтобы понять, о чем мы на самом деле говорим:

<!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="текст/html; кодировка = utf-8" /> <meta name="author" content="Роман Чваников" /> <title><Эphp echo $title; ?></title> </head> <body> <Эphp echo $content; ?> </body> </html>

Это то, что у нас будет в качестве обертки, в которой будет находиться контент ($content), полученный в результате работы контроллера.

Давайте сохраним это как application/views/index.php. Теперь давайте создадим представление контента для маршрута по умолчанию, предлагаемого Kohana, Welcome/index.

<h1>Welcome!</h1>

и сохраните это как application/views/welcome/index.php. Собственно, по этой строчке статьи вы уже должны понимать, если раньше по каким-то причинам не получилось, что такое обертка и что такое контент. Но вернемся к нашему Controller_Front. Давайте отрендерим все в индексную обертку по умолчанию, если имя обертки не было переопределено в контроллере (мало ли какова логика вашего приложения).



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(); } }

В этом контроллере, надеюсь, из комментариев всё понятно, кроме работы с каким-то View::$view_path — что это такое? Это то, что позволит нам не писать строки типа $this-> content = View::factory('user/edit'); и замените их более компактными $this-> content = View::factory('edit'); Кстати, расширим сам View — иначе как мы это реализуем?

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

Думаю, что после работы с этим модифицированным классом из Controller_Front ненужно будет на этом останавливаться, поэтому сохраните этот файл как application/classes/view.php, сохраните Controller_Front как application/classes/controller/front.php и "Двигаемся дальше" .

" Откройте контроллер приветствия (application/classes/controller/welcome.php) и измените расширение Controller на расширение Controller_Front, а в индексном методе замените строку $this-> request-> response = 'hello, world!'; в $this-> content = View::factory('index'); Теперь, если все сделано правильно, открываем браузер, переходим по адресу проекта и видим наш файл представления Views/welcome/index.php, обрамленный макетом Views/index.php.

Послесловие
Статья пролежала в папке «дописать и опубликовать» почти месяц, но наконец я дошел до того, чтобы как-то систематизировать содержащуюся в ней информацию и, собственно, опубликовать ее.

Если вы прочитали и какие-то моменты вам остались непонятны, или я допустил ошибки в коде, или вы сделали все по статье, но ничего не помогло — пишите сразу в комментариях, отвечу как можно скорее.

;) P.S.: Думаю, когда-нибудь доберусь до остальных статей из папки «дописать и опубликовать», так что.

та статья — это только начало, потом сделаем простую заявку (пожелания напишите в комментарии) на основе того, что мы уже сделали в этой статье — это позволит вам оценить те удобства, которые мы только что создали.

УПД: Файл представленияviews/errors.php может выглядеть так:

<ul class="errors"> <Эphp foreach ($errors as $error) : ?> <li><Эphp echo $error; ?></li> <Эphp endforeach; ?> </ul>

Теги: #кохана 3 #кохана

Вместе с данным постом часто просматривают:

Автор Статьи


Зарегистрирован: 2019-12-10 15:07:06
Баллов опыта: 0
Всего постов на сайте: 0
Всего комментарий на сайте: 0
Dima Manisha

Dima Manisha

Эксперт Wmlog. Профессиональный веб-мастер, SEO-специалист, дизайнер, маркетолог и интернет-предприниматель.