
Сегодня мы разберем интересную и очень актуальную тему: взаимодействие Kohana 3.3.x и Ajax при помощи jQuery. Мы научимся отправлять данные из формы при помощи Ajax, делать валидацию данных, добавлять запись в БД, выводить обновленную информацию, удалять запись из Базы Данных – и все это будет без перезагрузки страницы.
Итак, сначала определим какие нам для этого понадобятся файлы:
- Контроллеры
- Articles - имеет 3 метода:
- Вывод списка статей
- Добавление новых статей, при удачном добавлении возвращает список статей (возвращает json обьект)
- Удаление статьи
- Articles - имеет 3 метода:
- Виды
- articles – список статей и форма добавления статьи
- main – наш базовый шаблон, в который мы будем вставлять все второстепенные виды
- Модель
- Articles – имеет 3 метода:
- Получение всех статей
- Добавление записи в БД
- Удалении записи из БД
- Articles – имеет 3 метода:
SQL
Для начала работы нам понадобится таблица articles в БД с данной структурой:
CREATE TABLE IF NOT EXISTS `articles` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(255) NOT NULL,
`description` text NOT NULL,
PRIMARY KEY (`id`)
)
Views
Теперь сделаем наш главнй шаблон main.php, в нем бует костяк нашей страницы:
<!DOCTYPE html>
<html lang="ru">
<head>
<title>Ajax в Kohana 3.3.x</title>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=0;">
<link href="/css/bootstrap.css" rel="stylesheet">
<link href="/css/bootstrap-responsive.css" rel="stylesheet">
<script src="http://code.jquery.com/jquery-latest.min.js" type="text/javascript"></script>
<script src="/js/script.js" type="text/javascript"></script>
</head>
<body>
<div id="wrap">
<div class="push"></div>
<div class="container">
<div class="page-header">
<h1><a href="/">Ajax в Kohana 3.3.x</a></h1>
</div>
</div>
<div class="container">
<?php print $content;?>
</div>
</div>
</body>
</html>
Теперь сделам шаблон для вывода списка новостей и форму добавления статьи articles.php:
<table class="table articles">
<thead>
<th>ID</th>
<th>Заголовок</th>
<th>Текст</th>
<th>Действия</th>
</thead>
<tbody>
<?php if($data): ?>
<?php foreach($data as $item): ?>
<tr>
<td><?php print $item['id']?></td>
<td><?php print $item['name']?></td>
<td><?php print $item['description']?></td>
<td><a class="delete btn btn-danger" href="/articles/delete/<?php print $item['id']?>">Удалить</a></td>
</tr>
<?php endforeach; ?>
<?php else: ?>
<td colspan="4"><center>Добавьте статью</center></td>
<?php endif; ?>
</tbody>
</table>
<div class="alert alert-error" id="error" style="display:none"></div>
<form action="/articles/add" method="POST" id="form_article">
<div class="form-item">
<label>Название</label>
<input name="name" type="text" class="span5 input-medium " placeholder="Название статьи" />
</div>
<div class="form-item">
<label>Текст</label>
<textarea name="description" rows="5" class="span5" placeholder="Текст статьи"></textarea>
</div>
<div class="form-item">
<button type="submit" class="btn btn-primary">Добавить статью!</button>
</div>
</form>
jQuery
Также добавим обработчик на отправку формы, для валидации на стороне клиента и отправку данных посредтсвом ajax на сервер используя jQuery:
$("#form_article").submit(function(){ // при отправке формы проводим валидацию на заполненые поля и отправляем форму
var form = $(this);
$("[type=submit]",form).attr('disabled','disabled'); // делаем кнопку недоступной, чтобы избежать повторных нажатий
$("#error").empty().hide(); // Очищаем блок с ошибкой и скрываем его
var name = $('[name=name]',form).val(); // берем имя статьи из формы
var description = $('[name=description]',form).val(); // берем текст из формы
/** Если не заполнены поля - то выводим ошибку */
if(name == '' || description == ''){
$("#error").html('Ошибка валидации формы!').slideDown();
$("[type=submit]",form).removeAttr('disabled'); // делаем кнопку снова доступной
return false;
}
$.ajax({ // описываем наш запрос
type: "POST", // будем передавать данные через POST
url: form.attr('action'), // берем адрес отправки формы и передаем туда наши данные аяксом
data: form.serialize(), // серриализируем данные
dataType: "json", // указываем, что нам вернется JSON
beforeSend: function(){
$("#loading").slideDown(); // показываем индикатор загрузки
},
success: function(data) { // когда получаем ответ
if(!data.error){ // Если ошибки нет, то выводим список статей
// Если есть статьи - то будем их выводить
if(data.content){
var html = '';
for(var A in data.content){
var item = data.content[A];
html += '<tr><td>'+item.id+'</td><td>'+item.name+'</td><td>'+item.description+'</td><td><a class="delete btn btn-danger"href="/articles/delete/'+item.id+'">Удалить</a></td></tr>';
}
$('table.articles tbody').html(html);
}
form.trigger('reset');
}else{ // Если сервер вернул ошибку то выводим текст ошибки
$("#error").html(data.message).slideDown();
}
/** Делаем кнопку отправки снова активной и убираем индикатор загрузки */
$("[type=submit]",form).removeAttr('disabled');
$("#loading").slideUp();
},
error: function(){ // Если сервер вернул ошибку, 4хх, 5хх
/** Выводим ошибку, делаем кнопку отправки снова активной и убираем индикатор загрузки */
$("#error").html('Произошла ошибка').slideDown();
$("[type=submit]",form).removeAttr('disabled');
$("#loading").slideUp();
}
});
return false;
});
Добавим еще один обработчик события для удаления статей:
/** Функция удаления статьи */
$('body').on('click','.delete',function(){
var link = $(this);
if(confirm('Вы действительно хотете удалить?')){
$.ajax({
type: "POST",
url: link.attr('href'), // берем адрес из ссылки
dataType: "json",
success: function(data) { // когда получаем ответ
if(!data.error){ // Если ошибки нет, то удаляем строку
link.closest('tr').hide(function(){
$(this).remove();
})
}else{ // Если сервер вернул ошибку то выводим текст ошибки
$("#error").html(data.message).slideDown();
}
}
});
}
return false;
});
Model
Создадим модель articles.php для работы с записями в БД:
<?php
class Model_articles extends Model_Database
{
static $table_articles = "articles";
/** Выбор записей */
public function findBy() {
return DB::select()->from(self::$table_articles)->execute()->as_array();
}
/** Сохранение записи */
public function save($data){
if(!$data) return false;
foreach($data as $k=>$v){
$key[] = $k;
$value[] = $v;
}
$id = DB::insert(self::$table_articles, $key)->values($value)->execute();
return $id;
}
/** Удаление записи */
public function delete($id){
if($id){
return (bool) DB::delete(self::$table_articles)->where('id', '=', $id)->execute();
}
return false;
}
}
Controller
И на последок создадим контролер, который будет обрабатывать наши запросы:
<?php defined('SYSPATH') or die('No direct script access.');
class Controller_Articles extends Controller_Template {
public $template = "main";
public function action_index()
{
$data = array();
$modelArticles = new Model_articles;
$data = $modelArticles->findBy(); // выбираем список статей из БД
$this->template->content = View::factory('articles',array('data'=>$data)); // выводим список статей и форму для добавления статей
}
public function action_add()
{
$error = true;
$id= null;
$modelArticles = new Model_articles;
if($post = $this->request->post())
{
$data = array(
'name' => $post['name'],
'description' => $post['description'],
);
$validate = Validation::factory($data); // готовимся к проведению валидации
$validate -> rule(TRUE, 'not_empty'); // Проверяем на наличие пустых строк
if($validate -> check()) // проводим валидацию
{
$id = $modelArticles->save($data); //добавляем в БД запись
if ($id){
$error = false;
}
}
}
if (Request::initial()->is_ajax()){ // выполняем только если запрос был через Ajax
if($error){
$result = array('error'=>true,'message'=>'Ошибка валидации формы!'); // по умолчанию возвращаем код с ошибкой
}else{
// если валидация прошла успешно и запись в БД новой статьи прошла успешно
$result['error'] = false; // возвращаем код успеха!
$data = $modelArticles->findBy(); // выбираем список статей из БД и формируем масив
if($data){
foreach($data as $v){
$result['content'][] = array(
'id' => $v['id'],
'name' => $v['name'],
'description' => $v['description']
);
}
}
}
header('Content-Type: text/json; charset=utf-8'); // Устанавоиваем правильный заголовок
echo json_encode($result); // на выходе отдаем код в формате JSON
exit;
}else{
$this->redirect('/articles'); // если запрос был не Аяксом, то редиректим на страницу списка статей
}
}
public function action_delete()
{
$error = true;
$modelArticles = new Model_articles;
$id = (int) $this->request->param('id');
if($id)
{
$error = !$modelArticles->delete($id); //Удаляем статью
}
if (Request::initial()->is_ajax()){ // выполняем только если запрос был через Ajax
if($error){
$result = array('error'=>true,'message'=>'Ошибка при удалении'); // по умолчанию возвращаем код с ошибкой
}else{
$result['error'] = false; // возвращаем код успеха!
}
header('Content-Type: text/json; charset=utf-8'); // Устанавоиваем правильный заголовок
echo json_encode($result); // на выходе отдаем код в формате JSON
exit;
}else{
$this->redirect('/articles'); // если запрос был не Аяксом, то редиректим на страницу списка статей
}
}
}
Тут стоит отметить, что благодаря проверке Request::initial()->is_ajax() мы проверяем как нам передали данные, если передача была обычным методом - то мы просто редиректим на страницу со списком статей, если запросы был Аяксом, то выдаем список статей в JSON.
Готово, пробуем запустить http://localhost/articles/. Только в рабочем приложении не забудьте добавить дополнительные проверки входных данных, а также – авторизованный доступ.
Frameworks.su Шпаргалка вебмастера
Благодарю Вас за труды!
Очень помогло в освоении kohana.
Особенно версии 3.3 в русскоязычном пространстве.
Было бы здорово если бы Вы добавили в пример функцию редактирования статьи и запись ее в БД.
И еще хотелось бы увидеть реализацию этого примера через ORM.
Надеюсь, что мою просьбу не оставите без внимания.