Как быстро сделать сайт визитку на Yii или разбираемся и дорабатываем модуль YCM
В этой статье я покажу как можно создать простой сайт-визитку на основе связки Yii Framework + YCM.
Немного предыстории
Вообще впервые YCM мы опробовали на проекте ka73.ru. По началу лично меня немного коробило это расширение - оно прямо-таки заставляет тебя размещать всю логику в моделях, что в конечном итоге оказалось довольно таки удобно.
Главный недостаток этого модуля в том, что он работает только с фиксированными виджетами - только посмотрите на этот метод.
Уже целых 360 СТРОК ДЛЯ КОНСТРУКЦИИ switch!!!
И это далеко не предел - как только становятся нужны кастомные виджеты, этот свитч будет расти и расти и расти. Лично мое терпение лопнуло, когда после внедрения виджета мультиаплоадинга, мне понадобилось добавить в админку еще парочку виджетов. Именно по этой причине я и форкнул этот модуль и добавил туда возможность создавать свои кастомные виджеты.
Однако это тянет на отдельную публикацию, в этом же материале, давайте сосредоточимся на главном - как быстро сделать сайт визитку?
Так как сайт будет максимально простым, я буду использовать для его разработки оригинальный модуль YCM от Jani Mikkonen.
Шаг 1. Подготовка.
Сперва стоит спроектировать базу данных для проекта. Для примера я возьму наипростейшую схему:
у нас будут такие сущности - Страница, Меню, Пользователь.
С помощью mysql workbench рисуем простую er-диаграмму (либо создаем в phpMyAdmin напрямую):
Далее преобразуем все это в сущности базы данных с помощью synchronize model, либо выгрузки и импортирования sql кода.
Затем нам понадобится Yii Framework (процесс установки и настройки см. на их сайте), и соответствено модуль YCM (ссылки см. выше).
Как только приложение будет сгенерировано и настроено можно приступать к разработке.
Шаг 2. Подключение YCM.
С помощью инструмента Gii генерируем необходимые модели для приложения:
Как только сгенерились все необходимые модели, можно приступать к подключению YCM.
Для этого в файле protected/config/main.php, в разделе modules надо добавить следующие строчки:
'ycm'=>array(
'username'=>'YOUR USERNAME', // логин администратора
'password'=>'YOUR PASSWORD', // пароль администратора
'registerModels'=>array(
// пути к моделям с которыми будет работать YCM
'application.models.Page',
'application.models.MenuItem'
)
),
После этой нехитрой операции на сайте станет доступен адрес http://<sitename>/ index.php/ycm.
На этом этап подключения YCM завершен, и можно приступить к разработке моделей.
Шаг 3. Модели
Вообще YCM по умолчанию пытается добавить виджеты исходя из типа столбца, т.е. если у нас в таблице title это varchar, то будет генерироваться виджет TextField, а если content это text, то генериться будет wysiwyg редактор текста.
Тут в принципе все понятно, но в нашем случае для модели Page будут также создаваться поля Date Create и Date Update, что не всегда желательно.
Поэтому стоит озадачиться ручной настройкой виджетов.
Page
Для этого нужно в класс модели Page (protected/models/Page.php) добавить метод attributeWidgets:
// метод возвращает хэшмассив с настройками виджетов для каждого поля
public function attributeWidgets() {
return array(
array('id_page', 'hide'), // скрывает поле
array('title', 'text'), // текстовая строка
array('description', 'wysiwyg'), // редактор текста
array('content', 'wysiwyg'),
array('date_create', 'hide'),
array('date_update', 'hide')
);
}
Модифицировав таким образом модель мы получаем такое представление:
Создаем страницу с помощью этой формы и видим такую фигу:
Так происходит потому что в модели нет данных для списка. Чтобы исправить положение сделаем следующие добавления в модель Page:
public function adminSearch() {
return array(
'columns'=>array(
'id_page',
'title',
'date_create',
'date_update'
),
);
}
Метод adminSearch дает модулю YCM понять какие поля нужно выводить в списке материалов. В нашем случае будут выводиться поля - ид, заголовок, дата создания, дата редактирования.
Дата создания/сохранения будут пустыми, т.к. мы не создали автозаполнение для этих полей.
Для решения этой проблемы можно пойти двумя путями - использовать для этого встроенный класс поведения CTimestampBehavior, или реализовать это в методе beforeSave руками.
Вот как это делается с CTimestampBehavior:
public function behaviors() {
return array(
'CTimestampBehavior' => array(
'class' => 'zii.behaviors.CTimestampBehavior',
'updateAttribute' => 'date_update',
'createAttribute' => 'date_create',
'timestampExpression' => 'date("Y-m-d H:i:s")'
)
);
}
Теперь попробуем отредактировать страницу, добавить еще одну и посмотрим что получится:
Ну и напоследок, думаю, не лишним будет метод getUrl(), который бы возвращал фиксированный url для страниц:
// возвращает абсолютный или относительный url в зависимости от параметра $absolute
public function getUrl($absolute = false) {
if($absolute == true)
return Yii::app()->createAbsoluteUrl('page/view', array('id' => $this->id_page));
return Yii::app()->createUrl('page/view', array('id' => $this->id_page));
}
Соответственно неплохо бы также расширить метод adminSearch, чтобы сразу выводить ссылки на эти страницы:
array(
'type' => 'raw',
'value'=> 'CHtml::link("Открыть",$data->getUrl(true), array("target" => "_blank")'
)
MenuItem
В принципе, тут все тоже самое, и единственное, что мы попробуем сделать, так это не ручное указание url для элементов меню, а выбор страницы из выпадающего списка.
Для этого нужно создать уже знакомый нам метод attributeWidgets :
public function attributeWidgets() {
return array(
array('id_menu_item', 'hide'),
array('menu_title', 'text'),
array('menu_url', 'chosen') // тот самый выпадающий список
);
}
Помимо этого, список menu_url нужно еще чем-то заполнить, поэтому нужно добавить метод menu_itemChoices :
// в YCM для насыщения chosen данными нужно реализовывать метод названиеАттрибутаChoices
public function menu_urlChoices() {
$pages = Page::model()->findAll();
$urls = array();
foreach($pages as $page) {
$urls[$page->getUrl()] = $page->title;
}
return $urls;
}
Таким образом мы получаем список всех страниц сайта и возвращаем их в виде хэш-массива url_страницы => заголовок_страницы.
Шаг 4. Frontend
Для разработки фронтенда будем использовать стандартные возможности Yii Framework, а именно контроллеры(controller) и вьюхи(view).
Вообще для этого можно использовать инструмент Gii, но так как большинство генерируемых вьюх и экшенов(action) для этого сайта нам не понадобятся, предлагаю просто написать все это вручную. (тем меньше кода придется выпиливать)
Сперва набросаем простейший контроллер (protected/controllers/PageController.php):
// контроллер страниц
class PageController extends Controller {
// шаблон для вьюх
public $layout = 'main';
// основной экшен
public function actionView($id = null) {
$model = $this->loadModel($id);
// установим заголовок страницы
$this->pageTitle = $model->title;
$this->render('view', array(
'model' => $model
));
}
// загружает модель из бд, либо бросает ошибку 404
private function loadModel($id) {
$model = Page::model()->findByPk($id);
if($model == null)
throw new CHttpException(404);
return $model;
}
}
Тут ничего сверх-естественного нет - когда пользователь запрашивает такой адрес http://sitename.ru/page/view/id/2, то получает страницу 2, а если, допустим страницы с id_page = 2 не существует, то получает "от ворот поворот" в виде 404 ошибки.
Теперь нужно создать шаблон для вьюх. Я не стану приводить полный html, но покажу основные моменты.
В общем виде layout представляет собой нечно вроде такого (protected/views/layouts/main.php):
<!DOCTYPE html>
<html lang="ru">
<head>
<meta charset="UTF-8">
<title><?php echo $this->pageTitle; ?></title>
<!-- тут стили и скрипты -->
</head>
<body>
<div id="header">
<?php echo CHtml::link("Сайт-визитка", Yii::app()->getBaseUrl()); ?>
</div>
<div id="content">
<?php echo $content; ?>
</div>
<div id="footer">
<p>Сайт визитка, разработанный за час!</p>
</div>
</body>
</html>
Так вот, основной момент в лэйауте - переменная $content, в ней содержится отрендеренная вьюха. Переменная $this в любой вьюхе обычно является экземпляром текущего контроллера.
Теперь набросаем простую верстку для вьюхи (protected/views/page/view.php) :
<h1><?php echo $model->title; ?></h1>
<p><?php echo $model->description; ?></p>
<p><?php echo $model->content; ?></p>
Вот и весь процесс! Теперь перейдя по ссылке http://sitename.ru/page/view/1 вы увидите нечто вроде такого:
Навигация
Да, чуть не забыл - у любого уважающего себя сайта всегда есть навигация. В Yii это реализуется достаточно просто - мы можем использовать встроенный класс CMenu для этой цели, однако придется добавить еще один метод в модель MenuItem.
// подгонка под формат CMenu
public static function getItems() {
$menuItems = self::model()->findAll();
$items = array();
foreach($menuItems as $menuItem) {
$items[] = array(
'label' => $menuItem->menu_title,
'url' => $menuItem->menu_url
);
}
return $items;
}
Соответственно теперь можно использовать виджет CMenu в любом удобном месте, например, в лэйауте:
<div id="header">
<?php echo CHtml::link("Сайт-визитка", Yii::app()->getBaseUrl()); ?>
<?php $this->widget('zii.widgets.CMenu', array(
'items' => MenuItem::getItems()
)); ?>
</div>
А вот и результат, которого мы добились:
В принципе на этом можно и закончить, дальше остается только внедрить верстку и подключить css и js файлы, и очередной сайт визитка будет готов!