В прошлом уроке у нас была теория, а в этом немного попрактикуемся. Будем дорабатывать наш блог.
Мы уже сделали выборку всех статей из базы данных и вывели их на главной странице. Теперь нам нужно вывести не все статьи, а только одну. Для этого нужно знать ее идентификатор. Добавим ссылку «Подробнее» в файл Вида show.php:
<h3>Это главная страница</h3> <br /> <?php foreach($articles as $article): ?> <div style="padding:10px; margin-bottom:10px; border-bottom:#333 2px solid;"> <strong><?php echo $article['title']; ?></strong><br /> <i>Автор: <?php echo $article['author']; ?></i> / <i>Дата публикации: <?php echo $article['date']; ?></i><br /><br /> <p><?php echo $article['content_short']; ?></p> <p style="text-align:right; text-decoration:underline;"> <a href="<?php echo URL::site('articles/'. $article['id'] .'-'. $article['alt_title']); ?>">Подробнее</a> </p> </div> <?php endforeach; ?>
А также немного изменим нашу таблицу articles и добавим туда два поля.
ALTER TABLE `articles` ADD `alt_title` VARCHAR(250) NOT NULL COMMENT 'Название в урл' AFTER `title`; ALTER TABLE `articles` ADD `content_full` TEXT NOT NULL COMMENT 'Полный текст статьи';
Поле «alt_title» будет отвечать за название статьи в адресной строке. Заполните его значениями «about_framework», «yii_framework» и «symfony_framework». Поле «content_full» будет отвечать за полный текст статьи, который пользователь увидит при нажатии на кнопку «Подробнее». Продублируйте текст из поля «content_short» — это сейчас не принципиально.
Если сейчас зайти на главную страницу и посмотреть на ссылки в «Подробнее», то они будут иметь вид http://kohana/articles/1-about_framework, что и выглядит красиво, а также корректно с точки зрения SEO. Ссылки в принципе вполне рабочие и совпадают с роутом, но во-первых, роут пропускает и ссылки вида http://kohana-new/articles/about_framework, а во-вторых, в переменную $id у нас попадет не число, а вся часть 1-about_framework. Конечно число можно отсечь с помощью регулярных выражений в контроллере, но делать так — глупо. Проще переписать роут. Замените в файле bootstrap.php роут:
Route::set('articles', '<articles>(/<id>)', array('id' => '.+')) ->defaults(array( 'controller' => 'articles', 'action' => 'index', ));
на
Route::set('articles', '<articles>/<id>-<artname>', array('id' => '[0-9]+'), array('artname' => '.+')) ->defaults(array( 'controller' => 'articles', 'action' => 'article', ));
Теперь роут будет искать в адресе совпадение «число-любые символы», т.е. как раз то, что нам нужно. Обратите внимание, что в новом роуте изменился action. Это сделано для того, чтобы за вывод всех статей отвечал один action-метод, а за вывод одной статьи — другой. Если вы плохо помните, о чем речь, перечитайте этот урок. Следовательно теперь нам нужно видоизменить наш Контроллер Controller_Articles. Он станет таким:
<?php defined('SYSPATH') or die('No direct script access.'); class Controller_Articles extends Controller_Common { public function action_index() { $content = View::factory('/pages/articles'); $this->template->content = $content; } public function action_article() { $id = $this->request->param('id'); $content = View::factory('/pages/article') ->bind('article', $article) ->bind('comments', $comments); $article = Model::factory('Article')->get_article($id); $comments_url = 'comments/' . $id; $comments = Request::factory($comments_url)->execute(); $this->template->content = $content; } } // Articles
Теперь пришла очередь Модели. Добавим в класс Model_Article еще один метод, который как раз и будет извлекать статью по ее идентификатору:
<?php defined('SYSPATH') or die('No direct script access.'); class Model_Article extends Model { protected $_tableArticles = 'articles'; ... /** * Get article * @return array */ public function get_article($id = '') { $sql = "SELECT * FROM ". $this->_tableArticles ." WHERE `id` = :id"; $query = DB::query(Database::SELECT, $sql, FALSE) ->param(':id', (int)$id) ->execute(); $result = $query->as_array(); if($result) return $result[0]; else return FALSE; } }
И наконец финальный штрих — реализация страницы со статьей, которая лежит в Видах в файле article.php:
<?php if($article): ?> <div style="padding:10px; margin-bottom:10px; border-bottom:#333 2px solid;"> <strong><?php echo $article['title']; ?></strong><br /> <i>Автор: <?php echo $article['author']; ?></i> / <i>Дата публикации: <?php echo $article['date']; ?></i><br /><br /> <p><?php echo $article['content_full']; ?></p> </div> <?php echo $comments; ?> <?php else: ?> <div style="padding:10px; margin-bottom:10px;"> Статья не найдена или не существует </div> <?php endif; ?>
Вот теперь все готово. Загружаем сайт, жмем на «Подробнее» у любой статьи, смотрим. Должна получиться вот такая красота:
Если внимательно посмотреть, можно заметить, что комментарии к статьям перестали выводиться. Чтобы это исправить, все, что нужно сделать — это поменять article1 и article2 на 1 и 2 в проверке switch-case файла comments.php. Теперь все работает:
Сами комментарии правда пока добавлять нельзя, но это мы исправим, когда будем изучать Query Builder. Успехов!
<< Назад | Вперед >> |
Пожалуйста, зарегистрируйтесь для комментирования.
Что делается в
public function action_index()
??))
Упс. Дада, это лишнее, не обращайте внимание. Кусок от пагинатора затесался. Убрал, спасибо.
Я так понял, у нас статьи все постятся на главной, а сам «раздел» articles будет служить только для вывода конкретной стати?
Да, как на блогах. На главной список статей в виде превью в порядке их добавления (последняя находится вверху), а при нажатии на «подробнее» попадаем на саму статью. Вообще правильнее всего action_index из контроллера Page засунуть в контроллер Articles, Page вообще удалить и в бутстрапе поменять.
Да кстати, так и сделал))
Ну и правильно
Вообще думаю потом сделать цикл уроков «Делаем блог», где будет без ошибок и без воды.
Да, хорошо бы, можно отдельным изданием сделать в виде брошюрки pdf в купе со справочным материалом, и в массы по 30р за штучку отпускать — думаю будет пользоваться спросом))
Ага..и сразу на торренты выложат. Торренты хороши до тех пор, пока сам не начинаешь что-то создавать и матюгаться на пиратов
за 30 рублей народ брать будет! А за 30 баксов качать с торента будет!
>>$query = DB::query(Database::SELECT, $sql, FALSE)
>> ->param(‘:id’, (int)$id)
(int)$id) — это способ определения типа параметра?
Округление до числа. Хотя тут в принципе кроме числа ничего и быть не может )
Я подумал, что это как бы доп, защита от SQL инъекций))
Так и есть ) Там еще такая штука бывает, что число обрамляется кавычками, т.е. определяется как строка. С int такого не происходит. Да и такую запись в англоязычных учебниках по кохане видел. Зря наверное бы не писали.
хотя туплю)) там же регулярки у нас в ботстрапе))
Да, регулярка не пропустит ничего кроме числа. Причина-то, что я написал выше.
Такой вопрос.
После изменения модели у меня выходит ошибка в этом месте: protected $_tableArticles = ‘articles’;
…
ругается на эти три точки,после того как их убираю показывает ошибки в page.php : get_all();
или в модели get_article($id = »)
А зачем там три точки ?
Такой вопрос — у меня запрос мускл в модели работает только с кавычками типа «, с такими уже не работает » , скажите можно ли как нибудь сделать чтобы запрос принимался с такими кавычками как последний? А то не удобно каждый раз копировать их, а на клавиатуре таких нет
А зачем в ссылке подробнее передавать $article['alt_title'] ? Можно же передать content_full, а в контроллере в модель передавать 2 параметра: $article = Model::factory(‘Article’)->get_article($id, $artname); Тогда в модели будет запрос:
$sql = «SELECT :artname FROM «. $this->_tableArticles .» WHERE `id` = :id» И в результате выборке будет только одна статья.
Для красоты alt_title — это название статьи транслитом. Тогда ссылка выглядит как
kohana/articles/1-about_framework.
Красивее же, чем просто
kohana/articles/1.
Оно нигде не используется.
А, ясно ) Ну тогда можно в модели просто прописать SELECT content_full вместо SELECT * Чтобы бд просто так не гонять. Да и загрузка быстрее будет )
Ну мы же не только content_full (текст) выводим, а еще и автора, дату публикации, название, а это собственно уже фактически вся таблица.
Но вообще да, указывать конкретные поля в селекте — хороший тон. И я вас наверное огорчу, если скажу, что орм всегда вытаскивает ВСЕ поля
Можно вытащить определенные, но придется переписывать модуль под себя.
Тогда лучше использовать PDO написать отдельный модуль, т.к. встроенного я не видел и использовать его. Я вот, например сейчас пишу инсталяцию cms и мне нужно чтобы скриптом создавались таблицы в указанной пользователем БД, но метод query требует указать первый параметр, который или SELECT или INSERT в общем всё что угодно, только не CREATE. А вообще фреймворк очень хороший. Выбирал между zend framework и codeigniter, но у них у каждого свои существенные недостатки, а этот то что нужно.
пропало условие , что при отсутствии id , выводим articles.php , после чего он перестал выводится при переходе по ссылке «статьи» или я что-то не понял?
Да. Поправил, спасибо.
Здравствуйте, зачем мы используем $result = $query->as_array(); если все работает и так:
$query = DB::query(Database::SELECT, $sql, FALSE)
->param(‘:id’, (int)$id)
->execute();
if($query)
return $query[0];
else
return FALSE;
Здравствуйте. Работает потому, что по умолчанию и выдает как массив.
Используем видимо по той же причине, по которой люди пишут ORDER BY `id` ASC….для наглядности.
Здравствуйте! У меня почему-то выводит «Статья не найдена или не существует» на все три статьи. то есть не выполняется условие если я правильно поняла. подскажите пожалуйста, в чем могла быть ошибка? проверила, id берет правильно, может быть ошибка в модели? вот мой код модели:
_tableArticles;
return DB::query(Database::SELECT, $sql)
->execute();
}
public function get_article($id = »)
{
$sql = «SELECT * FROM «. $this->_tableArticles .» WHERE ‘id’ = :id»;
$query = DB::query(Database::SELECT, $sql, FALSE)
->param(‘:id’, (int)$id)
->execute();
$result = $query->as_array();
if($result)
return $result[0];
else
return FALSE;
}
}
Посмотрите, что находится в $result