Yii PHP framework: создаём игровой сайт. Часть 4. Работа с жанрами игр.

Владимир | | PHP, Web разработка, Yii.

yii game site

Сегодня мы продолжим разработку игрового сайта и напишем код необходимый для создания, удаления и изменения жанров.

Но вначале два небольших объявления.

1) Я как-то упустил, что есть русский перевод документации Yii, причём очень качественный.

2) Я решил выложить весь исходный код этого сайта, думаю так будет проще экспериментировать. Все-таки копировать куски кода из блога неудобно.

Source

Инструкция по установке.

1) В архиве находятся: папка public_html (в ней только исходные файлы сайта, без самого фреймворка), файл dump.sql (с дампом базы) и файл с инструкциями.

2) Распакуйте папку public_html так, чтобы DOCUMENT_ROOT вашего сервера указывал на ее содержимое (при желании, саму папку можно переименовать).

3) Откройте файл index.php и укажите путь к фреймворку Yii (строка 4).

4) Откройте файл \protected\config\main.php и укажите параметры подключения к базе данных (строки 45-47).

5) Импортируйте базу данных (файл dump.sql), например, с помощью phpMyAdmin.

6) Можно работать 🙂

7) Адрес входа в админку http://sitename.local/index.php?r=dashboard

Сразу хочу обратить ваше внимание, что это не окончательная версия сайта и, скорее всего, в ней есть баги и недоработки. Поэтому буду рад, если вы о них мне сообщите 😉

Возвращаемся к жанрам.

Открываем окно консоли и выполняем команды

>> yiic shell
>> model Types ygs_types
>> crud Types

В результате будут созданы:

1) Класс модели \protected\models\Types.php

2) Класс контроллера \protected\controllers\TypesController.php

3) Папка с представлениями \protected\views\types\

По-умолчанию, контроллер содержит 6 методов, которые предназначены для формирования страниц. Это:

actionShow (адрес types/show) – страница с выбранным жанром;
actionCreate (адрес types/create) – форма создания нового жанра;
actionUpdate (адрес types/update) – форма изменения жанра;
actionDelete (адрес types/delete) – удаление жанра;
actionList (адрес types/list) – список жанров;
actionAdmin (адрес types/admin) – список жанров с кнопками «Изменить» и «Удалить».

Тут я хочу обратить ваше внимание на один момент. Этот контроллер ничего не знает об играх. Поэтому на страницах show и list будут просто выведены отдельные жанры и их список, без игр.

Этот список мы оформим в виде виджета и поместим в сайдбаре, а для вывода игр, которые относятся к выбранному жанру, по-моему, будет логичнее использовать контроллер GamesController, который мы рассмотрим в следующий раз.

Я начинаю с жанров только потому, что они должны быть созданы до того как будет выполнен импорт игр из фида партнерки.

Т.е. методы actionShow и actionList нам не нужны, поэтому закроем к ним доступ. Чтобы не удалять эти методы из контроллера, я просто закомментировал первый элемент массива в методе accessRules. В результате при попытке доступа к ним посетитель увидит страницу с 403-ей ошибкой «У вас недостаточно прав для доступа к запрошенной странице».

Вносим небольшие изменения в методы actionCreate и actionUpdate. Нам нужно только изменить редирект. Посмотрите, например, на actionUpdate.

public function actionUpdate()
{
	$model=$this->loadTypes();
	//если запрос отправлен через форму изменения жанра
	if(isset($_POST['Types']))
	{
		$model->attributes=$_POST['Types'];
		//если жанр сохранен, переходим на страницу управления жанрами
		if($model->save())
			$this->redirect(array('admin'));
	}
	$this->render('update',array('model'=>$model));
}

Прежде всего, мы создаём модель. Для этого метод loadTypes читает $_GET['id'] и выполняет запрос к базе.

Затем проверяем, заполнял ли пользователь форму. Если нет – показываем страницу с формой (используется представление \protected\views\types\update.php), и в этом представлении мы можем получить данные из базы, используя переменную $model (об этом чуть позже).

Если пользователь заполнил и отправил форму, сохраняем модель и отправляем редирект на страницу types/admin.

Тут есть несколько интересных моментов.

Взгляните на строку

$model->attributes=$_POST['Types'];

При её выполнении используется метод setAttributes, который при присваивании элементов $_POST['Types'] будет использовать только безопасные атрибуты (safe attributes).

Определить список безопасных атрибутов можно с помощью метода модели safeAttributes

public function safeAttributes() {
	return array('t_id', 't_name');
}

Таким образом, фреймворк автоматически фильтрует все данные, которые не относятся к форме.

UPD. В версии 1.1 метод safeAttributes можно не использовать. Атрибуты считаются безопасными, если они упоминаются в правилах, которые возвращает метод rules(). При этом, правила должны относиться к данному сценарию (подробнее здесь). Спасибо, SAM!

При вызове $model->save() перед сохранением выполняется валидация данных. Правила валидации возвращает метод rules модели

public function rules()
{
	return array(
		array('t_name','length','max'=>45),
		array('t_id', 'required'),
		array('t_id', 'numerical', 'integerOnly'=>true),
	);
}

Как видите, по-умолчанию, для создания правил используются данные таблиц БД.

Переходим к работе с представлениями.

Как видите, для отображения представления используется метод render. В его первом параметре нужно указать имя файла представления (без расширения), а во втором – массив со всеми переменными к которым мы хотим получить доступ в представлении.

При этом если мы будем использовать встроенные библиотеки фреймворка, то в большинстве случаев будет достаточно передать экземпляр модели. Прежде всего, это касается класса CHtml.

Он содержит методы для создания различных элементов, причем для многих элементов есть по два метода. Например, CHtml::activeLabel() и CHtml::label(). Оба используются для создания тега label, но первый в качестве параметра получает экземпляр модели и использует её в качестве источника данных, а для второго метода нужно передать все данные явно.

Кстати, обратите внимание на метод attributeLabels модели

public function attributeLabels()
{
	return array(
		't_id' => 'Id жанра',
		't_name' => 'Жанр',
	);
}

Он возвращает массив с названиями полей, которые используются методами с приставкой active.

В качестве примера рассмотрим представление update.php

<?php
//страница "Изменить жанр"
//используется шаблон dashboard
$this->layout = 'dashboard'; ?>
<h2>Изменить жанр: <?php echo $model->t_name; ?></h2>

<div class="actionBar">
[<?php echo CHtml::link('Управление жанрами',array('admin')); ?>]
[<?php echo CHtml::link('Создать жанр',array('create')); ?>]
</div>

<?php echo $this->renderPartial('_form', array(
	'model'=>$model,
	'update'=>true,
)); ?>

Начнем со строки 4. В ней мы указываем, какой макет страницы нужно использовать. Дело в том, что Yii при создании страницы использует так называемый Two-Step View Pattern.

При этом для создания страницы используются минимум два файла. Первый – макет (layout) (может, есть более удачный перевод?), находится в папке \views\layuots\. Второй – файл представления, который указан в методе render.

Макет – это обычный php файл, содержащий строку
<?php echo $content; ?>
При обработке этого файла переменная $content будет содержать всю разметку представления.

В данном случае мы указываем, что нужно использовать макет dashboard, который я сделал для панели управления. Для остальных страниц сайта будет использоваться макет main.

В представлении для отображения формы используется метод renderPartial. Разница между render и renderPartial в том, что при вызове первого будет использован макет, а при вызове второго – нет. Т.е. мы просто вставляем форму (она находится в файле \views\types\_form.php).

Теперь давайте рассмотрим метод actionAdmin контроллера.

public function actionAdmin()
{
	//обработка команды удаления
	$this->processAdminCommand();
	//формируем запрос
	$criteria=new CDbCriteria;

	$pages=new CPagination(Types::model()->count($criteria));
	$pages->pageSize=self::PAGE_SIZE;
	$pages->applyLimit($criteria);
	//настраиваем сортировку
	$sort=new CSort('Types');
	$sort->applyOrder($criteria);
	//выполняем запрос
	$models=Types::model()->findAll($criteria);
	//показываем страницу
	$this->render('admin',array(
		'models'=>$models,
		'pages'=>$pages,
		'sort'=>$sort,
	));
}

Он создаёт таблицу с перечнем жанров. Напротив каждого жанра есть ссылки «Изменить» и «Удалить», а клик по заголовку столбца таблицы выполняет её сортировку.

Посмотрим, как работает этот метод.

Прежде всего, вызывается метод processAdminCommand. Он проверяет, был ли клик по ссылке «Удалить» и если был, удаляет соответствующую запись из базы.

Затем создаётся объект CDbCriteria. С его помощью можно изменять параметры запросов к БД. Например, можно указать список полей, которые должен вернуть запрос или ограничить количество строк.

Создаём объект CPagination, который используется для пагинации (разбивки записей на страницы). Обратите внимание, в качестве параметра конструктор получает общее количество записей. А это количество мы определяем с помощью метода count модели.

После этого, создаём объект CSort – сортировка записей. Этот объект использует параметр $_GET['sort'], который будет установлен при клике по заголовку столбца. С помощью метода applyOrder мы передаём параметры сортировки в объект CDbCriteria.

Таким образом, вызов Types::model()->findAll($criteria) возвращает записи таблицы, отсортированные в нужном порядке.

Заключительным этапом мы вызываем метод render. Ему передаём массив с найденными записями и объектами CPagination и CSort. CPagination используется для создания виджета с перечнем страниц, а CSort – для создания ссылок в заголовке таблицы.

На этом можно остановиться. Теперь вы можете зайти в админку и создать жанры.

Как видите, я не пытаюсь объяснить каждую строчку кода, да это и не реально 🙂 . Вместо этого, я попытался объяснить общий принцип. Поэтому, если что-то непонятно, спрашивайте в комментариях.

В следующий раз я планирую рассказать о работе с играми. Это самая объемная часть. И в ней мы подробнее рассмотрим работу с моделями и библиотекой для работы с БД.

Удачи!

Все разделы цикла.

  1. Yii PHP framework: создаём игровой сайт. Часть 1. Постановка задачи.
  2. Yii PHP framework: создаём игровой сайт. Часть 2. База данных и установка фреймворка.
  3. Yii PHP framework: создаём игровой сайт. Часть 3. Аутентификация.
  4. Yii PHP framework: создаём игровой сайт. Часть 4. Работа с жанрами игр.
  5. Yii PHP framework: создаём игровой сайт. Часть 5. Импорт игр.
  6. Yii PHP framework: создаём игровой сайт. Часть 6. Формируем страницы игр и жанров.
  7. Yii PHP framework: создаём игровой сайт. Часть 7. Работа с JavaScript и страницы игр.
  8. Yii PHP framework: создаём игровой сайт. Часть 8. Создаём виджеты.
  9. Yii PHP framework: создаём игровой сайт. Часть 9. Поиск ошибок.
  10. Yii PHP framework: создаём игровой сайт. Часть 10. Панель управления.
  11. Yii PHP framework: создаём игровой сайт. Часть 11. Человекопонятные URL.
  12. Архив с исходниками
  • Sam

    Стоит отметить, что safeAttributes в 1.1 задаётся в rules() как валидатор типа 'safe'.

  • Sam

    Стоит отметить, что safeAttributes в 1.1 задаётся в rules() как валидатор типа 'safe'.

  • Судя по виду шаблона, шаблонизатор очень похож на Zend_Layout + Zend_View с характерными плагинами, типа renderPartial().

  • Судя по виду шаблона, шаблонизатор очень похож на Zend_Layout + Zend_View с характерными плагинами, типа renderPartial().

  • Прикольно!)
    Так скоро сайтег по частям и соберёте!)

  • Прикольно!)
    Так скоро сайтег по частям и соберёте!)

  • Огромное вам спасибо! Особенно за архив

  • Огромное вам спасибо! Особенно за архив

  • Респект за русские доки!

  • Респект за русские доки!

  • alex

    а зачем при создании жанра вводить вручную id через админку?

    • Дело в том, что все игры импортируются из XML файла, который предоставляется партнерской программой, и в этих данных уже проставлены id категорий.

      Поэтому устанавливать id автоматически нельзя.

  • Никита

    А подскажите пожалуйста насчет кодировки… кириллицы.
    в html страницы кодировка стоит utf-8, а именно:
    но браузер все-равно хочет открывать страницу в windows-1251 8(в базе тоже все поля в utf8_general_ciНе первый раз уже создаю пример на Yii и наблюдаю такую непонятную ситуацию с кодировкой.

    • По большому счету Yii тут ни при чем. Браузер ничего не знает о том, как и с помощью каких средств формируется страница на сервере. Т.е. ему без разницы используется php, java, python или .net. Он видит заголовки страницы (headers) и содержимое страницы с мета тегами.
      Судя по вашему комментарию, мета теги установлены правильно. Поэтому проверяйте заголовки и кодировку страницы. Заодно нужно проверить в каких браузерах возникает проблема.

      • Никита

        Спасибо за наводку. Буду разбираться в чем дело.

    • в .htaccess (скорее всего, web-сервер — Apache) следует добавить строку указания кодировки «по умолчанию»:
      AddDefaultCharset utf8

      • Никита

        Да, действительно, дело в апаче. А именно в денвере была неточность.
        На хосте попробовал — все отлично.

      • Учитывая современные реалии, лучше указать utf-8 кодировкой по-умолчанию в httpd.conf.
        Обойтись без кириллицы вряд ли получится, без ajax — тоже, получается utf-8 нужна в 99% случаев.

        • Никита

          Целиком и полностью согласен в значимости кодировки utf-8

        • Kuntu

          izbenite 🙂 mojno Video urok po ustonobke 🙁 ochen nujno please 🙂

        • Простите, установке чего? этого примера? фреймворка? или кодировки в httpd.conf?

  • Юлия Серова

    a kak udalyat Журнал приложения :

  • Peter

    Привет. Вопрос. возможно, не по теме, но больше как к специалисту от новичка, который по Вашим (очень толковым статьям, кстати) постигает Yii.

    Собственно, на главной есть виджет NewsWidget (Новости). У каждой новости есть кнопка «Показать детали». Прикрутил к атрибуту кнопки «Показать детали» action=»SomeControllerName»; В контроллере описал какие данные нужно показать и вывести во view — тут все ок.

    Внимание, вопрос — как дать понять контроллеру, (по id новости, например) выводить подробную информацию именно этой одной новости, в зависимости от нажатия кнопки «Показать детали». Что нужно передать от виджета к контроллеру и как вобще это реализовывается. Заранее благодарен.

    • По-моему Вам достаточно использовать обычные ссылки в качестве кнопок «Показать детали». В атрибуте href должен быть указан соответствующий контроллер с id новости.

      <a href=".../id">Показать детали</a>

  • скопировал архив. в public_html по умолчанию у меня две папки yii (собственно фреймворк) и base (собственно приложение). по образу и подобию своего приложения указал ссылку на yii.php, указал данные для бд. после этого пришлось создать папку runtime и папку assets. ваше приложение загрузилось, но при нажатии на любую ссылку выкидывает The requested URL /game/games/show/363 was not found on this server. yii 1.1.16 . пожалуйста напишите ответ сюда и мне лично

    • Т.е. у вас загружается главная страница приложения, но не загружаются остальные страницы?

      Попробуйте в конфиге (config/main.php) отключить urlManager (просто закомментируйте строки). Приложение переключится в стандартный режим работы (с get параметрами). Обновите страницу и проверьте как работаю ссылки.
      Проблему это не исправит, но если страницы будут открываться, вы будете знать, что проблема в маршрутизации.