Вывод статей по ид

Комментарии: 44  Просмотры: 20 894

В прошлом уроке у нас была теория, а в этом немного попрактикуемся. Будем дорабатывать наш блог.
Мы уже сделали выборку всех статей из базы данных и вывели их на главной странице. Теперь нам нужно вывести не все статьи, а только одну. Для этого нужно знать ее идентификатор. Добавим ссылку «Подробнее» в файл Вида 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; ?>

Вот теперь все готово. Загружаем сайт, жмем на «Подробнее» у любой статьи, смотрим. Должна получиться вот такая красота:
Вывод одной статьи в Kohana v3.2
Если внимательно посмотреть, можно заметить, что комментарии к статьям перестали выводиться. Чтобы это исправить, все, что нужно сделать — это поменять article1 и article2 на 1 и 2 в проверке switch-case файла comments.php. Теперь все работает:
Вывод одной статьи в Kohana v3.2

Сами комментарии правда пока добавлять нельзя, но это мы исправим, когда будем изучать Query Builder. Успехов!

<< Назад | Вперед >> | Обсудить на форуме


К записи оставлено 44 коммент.

Что делается в
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 = »)

А зачем там три точки ?

"Теперь пришла очередь Модели. Добавим в класс Model_Article еще один метод."

вы хотя бы прочтите прежде чем воспользоваться ctrl+c - ctrl+v
 :)

Такой вопрос — у меня запрос мускл в модели работает только с кавычками типа «, с такими уже не работает » , скажите можно ли как нибудь сделать чтобы запрос принимался с такими кавычками как последний? А то не удобно каждый раз копировать их, а на клавиатуре таких нет

А зачем в ссылке подробнее передавать $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



Оставить комментарий или два

Пожалуйста, зарегистрируйтесь для комментирования.