3. Программирование
3.1 Главная страница, новости.
Новости должны располагаться в виде ленты на главной странице. Для начала сделаем обычный вывод тех шаблонов, которые мы только что сформировали. Создадим контроллер новостей и как действие по умолчанию впишем это отображение (Информация по контроллерам - http://docs.kohanaphp.com/general/controllers и работе с отображениями - http://docs.kohanaphp.com/general/views).
PHP код:
class News_Controller extends Controller {
public function index() {
// Обрабатываем все шаблоны
$view = new View('index');
// Переменный header, menu и footer
$view->header = new View('header');
$view->menu = new View('menu');
$view->footer = new View('footer');
// Показываем
$view->render(true);
}
}
Сохраните контроллер в соответствующей папке и обратитесь по ссылке http://kohana/news/. Вы должны увидеть пустой шаблон со словом "text" вместо основного контента.
Из за того что на главной странице всегда должна отображаться лента новостей мы сделаем её контроллер контроллером по умолчанию. Для этого откройте файл /system/config/routes.php и единственную настройку установите в значение "news"
После этого обращения к корню сайта будут автоматически вызывать контроллер новостей.
Вернёмся к коду. Сейчас нам нужно вывести все имеющиеся новости на экран. Они находятся в базе и надо их оттуда достать. Для этого создадим новую модель (http://docs.kohanaphp.com/general/models) News_Model в файле /application/models/news.php. В неё поместим конструктор создающий объект БД для этой модели и пустой метод который будет получать список новостей. Назовём его "newsList"
PHP код:
class News_model extends Model {
public function __construct() {
parent::__construct();
// Создаём новый объект БД
$this->db = new Database();
}
public function newsList() {
}
}
Этот метод должен будет возвратить массив новостей. Для их получения из базы мы воспользуемся конструктором запросов (http://docs.kohanaphp.com/libraries/database/builder). На данный момент нам пригодятся лишь 3 метода - from (указывает из какой таблицы взять данные), orderby (указание сортировки данных) и get (получение данных). Выполним их по очереди, а результат работы метода get вернём в качестве результата функции.
PHP код:
$this->db->from("news");
$this->db->orderby("id","DESC");
return $this->db->get();
Это эквивалентно запросу "SELECT * FROM `news` ORDER BY `id` DESC". В контроллере нам нужно вызвать вышеописанный метод и передать то что он вернёт в отображение. Там с помощью foreach-цикла мы обойдём массив новостей и отобразим всё одной лентой. Назовём параметр шаблонизатора, содержащий список новостей, newsList, по аналогии с методом модели. Сразу после обработки шаблона "index" добавьте вызов метода модели.
PHP код:
$view->newsList = $this->news->newsList();
Параллельно с этим нам нужно создать конструктор у контроллера новостей, в котором модель будет автоматически подгружаться что бы в дальнейшем быть доступной из методов контроллера.
PHP код:
public function __construct() {
parent::__construct();
$this->news = new News_Model;
}
Не забывайте в конструкторах прописывать вызовы конструктора класса-предка, иначе за место сайта получите горы ошибок. Откройте шаблон "index.php" и за место слова text добавьте следующий код.
Код:
<?foreach ($newsList as $news):?>
<h1 class="title"><a href="/news/view/<?=$news->id?>"><?=$news->title?></a></h1>
<p class="meta"><small><?=date('d-m-Y',$news->pub_date)?></small></p>
<div class="entry">
<!-- Показываем анонс - 200 символов от всего текста -->
<p><?=substr($news->text,0,200)?>...</p>
</div>
<?endforeach;?>
Теперь на главной странице отображаются все 4 новости которые находятся в базе.
Отойдём от основной темы и вернёмся к модели новостей. Формируя запрос в методе newsList мы написали 3 строки кода. Но конструктор запросов к БД в Kohana имеет одну интересную особенность. Вызываемые методы конструктора возвращают в качестве результата свой же объект (в нашем случае $this->db). То есть мы из вызова одного метода можем вызывать другие методы, выстраивая так называемую "цепочку". Вот пример такого вызова. Этот код можно поставить за место тех трёх строк.
PHP код:
return $this->db->from("news")->orderby("id","DESC")->get();
Результат работы от этого не изменится, но кода стало значительно меньше. Такой подход сильно облегчает жизнь при разработке больших проектов.
В начале статьи я писал про разбиение контента на страницы. У нас 4 новости, давайте разобьём их на 2 страницы, отображая 3 новости за раз. Воспользуемся классом "Pagination" (http://docs.kohanaphp.com/libraries/pagination). Перед тем как его задействовать нужно определится с настройками. При разбиении контента они передаются классу Pagination двумя способами - через специальный конфигурационный файл (/system/config/pagination.php) или же массивом прямо при создании объекта. Мне кажется что первый вариант лучше не использовать так как он является "центральным", а разбиение может понадобится не только в одном контроллере или методе. Пойдём по пути массива с настройками. Нам понадобится всего 4 опции
1. base_url - ссылка куда будет подставляться номер страницы. В нашем случае эта опция примет значение "/news/index/" потому что третьей частью адреса будет именно номер страницы.
2. total_items - общее количество объектов. В модель мы добавим метод который вернёт число новостей.
3. items_per_page - сколько объектов отображать на страницу. Мы отображаем по 3 новости.
4. style - стиль отображения ссылок. Здесь укажем "digg". На мой взгляд он выглядит приличнее остальных.
Метод возвращающий количество новостей в базе будет называться "newsCount" и содержать всего одну строку:
PHP код:
public function newsCount() {
return $this->db->count_records("news");
}
Поместите его в модель и вернёмся к контроллеру. Массив с настройками и их значениями можно объявить прямо в начале метода index:
PHP код:
// Настройки разбиения на страницы
$pagination_config = Array('base_url' => '/news/index/',
'total_items' => $this->news->newsCount(),
'items_per_page' => 3,
'style' => 'digg'
);
И сразу можно создать общедоступный объект класса Pagination, передав ему в конструктор массив с настройками.
PHP код:
$this->pagination = new Pagination($pagination_config);
Обратите внимание на то что объект имеет вид не локальной переменной ($pagination). Сделано это для того чтобы мы могли обращаться к нему из отображения без лишних проблем. Теперь в шаблоне "index.php" разместим код который вызовет отображение ссылок на страницы.
Код:
<center><?=$this->pagination->render()?></center>
Он должен идти сразу после foreach-цикла. Сохраните все изменения и обновите главную страницу. В низу покажется список страниц со ссылками на предыдущую и следующую страницы.
На очереди ограничение вывода новостей. Ссылка на вторую страницу имеет вид http://kohana/news/index/2, то есть номер страницы передаётся методу index как единственный параметр. Обозначим его, изменив объявление метода.
PHP код:
public function index($page = 0) {
Так как изначально параметр не передаётся (например, при обращении к главной странице) то мы указали его значение по умолчанию. Теперь значение переменной $page нужно передать в модель, в метод выборки новостей. Заменим код его вызова с
PHP код:
$view->newsList = $this->news->newsList();
на
PHP код:
$view->newsList = $this->news->newsList($page);
Ну и соответственно добавим методу newsList один параметр.
PHP код:
public function newsList($page) {
Вместе с этим вставим в формирование запроса вызов метода "limit", где укажем ограничение на выборку новостей
Здесь есть один важный момент. Так как отсчёт страниц у нас начинается ни с нуля (фактически нулевой страницы нет, как и ссылки на неё) то нам нужно постоянно уменьшать значение страницы на единицу. Если Вы сейчас попробуйте посмотреть новости то на главной странице у Вас покажутся 3 последние, а на второй новостей не будет вообще. Потому что при просмотре второй страницы, формируя лимит новостей, значение с которого нужно начать отбирать будет равно 6 ($page*3), а не 3. Поэтому в начало метода модели следует добавить строчку декремента параметра $page
А что бы при нулевом значении в первую границу limit не попадало число -3 (-1*3) мы изменим эту строку на
PHP код:
if($page > 0) $page--; else $page = 0;
Таким образом, после наших многочисленных манипуляций, полный код метода index, контроллера новостей становится следующий.
PHP код:
public function index($page = 0) {
// Настройки разбиения на страницы
$pagination_config = Array('base_url' => '/news/index/',
'total_items' => $this->news->newsCount(),
'items_per_page' => 3,
'style' => 'digg'
);
$this->pagination = new Pagination($pagination_config);
// Обрабатываем все шаблоны
$view = new View('index');
$view->header = new View('header');
$view->menu = new View('menu');
$view->footer = new View('footer');
$view->newsList = $this->news->newsList($page);
// Показываем
$view->render(true);
}
А два метода модели выглядят вот так.
PHP код:
public function newsList($page) {
if($page > 0) $page--; else $page = 0;
return $this->db->from("news")->limit(3,$page*3)->orderby("id","DESC")->get();
}
PHP код:
public function newsCount() {
return $this->db->count_records("news");
}
Единственное что осталось - написать метод просмотра полной новости. Как Вы могли заметить из кода главного шаблона, его имя "view".
Действие просмотра новости крайне простое. Нужно лишь взять информацию из базы и вывести её в шаблон. Ссылка показа новости имеет следующий вид: http://kohana/news/view/4. То есть в качестве идентификатора новости у нас передаётся её id. Он же является единственным параметром для нашего метода. Сначала создадим в модели функцию которая будет получать данные о новости по её id.
PHP код:
public function newsData($id) {
$result = $this->db->from("news")->where("id",(int) $id)->get();
return $result[0];
}
Теперь опишем метод view в контроллере.
PHP код:
public function view($id) {
$view = new View('./news/view');
$view->header = new View('header');
$view->menu = new View('menu');
$view->footer = new View('footer');
$view->news = $this->news->newsData($id);
$view->render(true);
}
Из кода видно что данные новости передаются в шаблон через переменную news. Сам код шаблона точно такой же как на главной странице, но с тремя отличиями. В нём нет цикла (мы же выводим одну новость), строки разбиения на страницы, и полный текст новости показывается целиком, а не первые 200 символов.
Код:
<?=$header?>
<body>
<?=$menu?>
<!-- start page -->
<div id="page">
<!-- start content -->
<div id="content">
<div class="post">
<h1 class="title"><a href="/news/view/<?=$news->id?>"><?=$news->title?></a></h1>
<p class="meta"><small><?=date('d-m-Y',$news->pub_date)?></small></p>
<div class="entry">
<p><?=$news->text?></p>
</div>
</div>
</div>
<!-- end content -->
<div style="clear: both;"> </div>
</div>
<!-- end page -->
<hr />
<?=$footer?>
Вот и всё. Новостная часть полностью готова. Идём дальше.