Yii PHP framework: создаём игровой сайт. Часть 8. Создаём виджеты.

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

yii_game_site_widgets

В этой части мы поговорим о том, какие средства предоставляет Yii для создания виджетов. Если верить википедии, виджет (widget) – это «контент модуль, который встраивается в веб-страницу или браузер» (вообще, это не совсем точно, в википедии есть несколько определений).

Правда здесь может возникнуть небольшая путаница в терминологии. Дело в том, что некоторые CMS (WordPress, например) используют термин виджет для обозначения особых плагинов, которые предназначены для отображения блоков с информацией в сайдбаре. Но сейчас нас интересует Yii PHP framework, поэтому мы будем считать виджетами объекты, которые наследуют класс CWidget.

Обычно виджеты используют для отображения какого-нибудь контента, который не зависит от основного содержимого страницы. Например, это может быть форма входа, перечень жанров игр, блок со случайными скриншотами, ссылки на страницы архива и т.п.

Для нас важно, что CWidget имеет особенность. Он является потомком класса CComponent, и, следовательно, является компонентом.

Рассмотрим, как создаются компоненты в фреймворке Yii.

Шаг 1. В папке protected/components создаём файл с классом компонента. Этот класс выполняет инициализацию компонента и подготовку данных (например, чтение из БД).

Шаг 2. В папке protected/components/views создаём файл с представлением компонента. По-сути это шаблон, который используется для отображения содержимого компонента.

Шаг 3. Добавляем компонент в макет (layout) нужных страниц сайта. Макеты находятся в папке protected/views/layouts.

Теперь рассмотрим конкретный пример. Создадим виджет, содержащий ссылки на страницы жанров игр.

Назовём класс TypesMenu.

Создаём файл protected/components/TypesMenu.php.

class TypesMenu extends CWidget {
	public function run() {
		$types = Types::model()->findAll();
		
		$this->render('typesMenu',array('types'=>$types));
	}
}

Как видите, класс содержит один метод (run), который будет вызван фреймворком при создании виджета.

В этом методе мы получаем список всех жанров игр (строка 3) и результат передаём представлению (строка 5).

Создаём представление (файл protected/components/views/typesMenu.php).

<h2>Жанры</h2>
<ul>
<?php
foreach ($types as $type) {
	//каждый пункт списка - ссылка на страницу с играми данного жанра
	//жанр указывается с помощью параметра в get запросе - type_id
	echo '<li>'.CHtml::link($type->t_name, array('games/list', 'type_id'=>$type->t_id)).'</li>';
}
?>
</ul>

Обратите внимание, у нас доступна переменная $types. (её название мы указали при загрузке представления, метод render).

Сами ссылки создаём с помощью метода CHtml::link. В первом параметре указываем текст ссылки, а во втором – массив с параметрами. В данном случае будут созданы url вида
http://yiigame.domen/index.php?r=games/list&type_id=1
где type_id – id соответствующего жанра.

Вставляем виджет в макет страницы. Для этого в файл protected/views/layouts/main.php добавляем следующий код.

<div class="menu">
<?php $this->widget('application.components.TypesMenu'); ?>
</div><!-- menu -->

Посмотрите, как указано имя виджета. Перед названием файла виджета (без расширения) мы добавляем application.components, проще говоря, указываем путь к виджету.

Всё, мы получили работающий виджет, правда, самый примитивный. Давайте рассмотрим вариант немного посложнее.

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

Популярность игры мы можем определить, используя поле g_rate (таблица ygs_games), т.е. нам нужно будет при поиске игр в базе просто отсортировать их по этому полю.

Показывать виджет нам нужно на страницах с общим перечнем игр и страницах отдельных жанров. И те, и другие страницы формирует метод actionList (класс GamesController). Но на страницах жанров мы будем показывать топ игр, которые относятся к данному жанру, а не все подряд, т.е. в наш запрос нужно будет добавить дополнительное условие.

Если задача ясна, приступаем.

Создаём файл виджета protected/components/TopGames.php.

class TopGames extends CWidget {
	
	public $title = 'Популярные игры';
	public $showOn = array();
	public $count = 10;
	
	public function run() {
		//определяем название контроллера и метода (action)
		$controller = Yii::app()->controller->id;
		$action = Yii::app()->controller->action->id;
		//проверяем нужно ли показывать виджет
		if (!in_array($controller.'/'.$action, $this->showOn)) {
			return;
		}
		//проверяем, нужно ли выводить игры только данного жанра
		if (isset($_GET['type_id'])) {
			$id = $_GET['type_id'];
			$params = array('limit'=>$this->count,'order'=>'g_rate DESC'
				,'condition'=>'t_id=:id'
				,'params'=>array(':id'=>$id));
			//ищем игры
			$games = Games::model()->getTopGames($params)->published()->with('ygs_types')->findAll();
		} else {
			$params = array('limit'=>$this->count,'order'=>'g_rate DESC');
			//ищем игры
			$games = Games::model()->getTopGames($params)->published()->findAll();
		}
		
		//заполняем массивы с жанрами игр для каждой найденной игры
		//для этого раскодируем поле g_type
		foreach ($games as $key=>$game) {
			$games[$key]->g_types = Yii::app()->controller->_decodeTypes($game->g_type);
		}
		//показываем виджет
		$this->render('topGames'
			, array('title'=>$this->title, 'games'=>$games));
	}
}

Прежде всего, обратите внимание на три свойства класса $title, $showOn и $count. Фреймворк позволяет указывать значения для всех отрытых (public) свойств виджета при его создании, т.е. в макете (layout) мы можем задать значения для этих свойств. Таким образом, появляется возможность изменять вид виджета, не трогая его код.

В данном случае в свойстве $title мы указываем заголовок виджета, в свойстве $showOn – массив с перечнем страниц, на которых он должен отображаться, а в свойстве $count – количество игр.

Рассмотрим метод run.

Прежде всего, определяем название контроллера и метода (action) (строки 9, 10). И проверяем, нужно ли показывать виджет. Страницы, на которых нужно отображать виджет указываются в формате «название_контроллера/название_метода». Если массив $showOn не содержит подходящего элемента, мы завершаем работу виджета.

В противном случае, мы:

1) Проверяем, является ли эта страница, страницей жанра (получен параметр $_GET['type_id'] или нет). Если получен, формируем запрос, при этом в его параметрах мы указываем, что нам нужны игры только текущего жанра.

2) Если мы находимся на странице с общим перечнем игр, то просто получаем игры, отсортированные по полю g_rate.

Обратите внимание на метод getTopGames($params). Он объявлен в модели (Games) и нужен только для того, чтобы немного сократить запись запроса.

public function getTopGames($params) {
	$this->getDbCriteria()->mergeWith($params);
	return $this;
}

Примечание. Использовать его не обязательно. Можно было просто создать объект CDbCriteria, как мы и делали в предыдущих частях, но я хотел попробовать разные варианты работы.

3) Расшифровываем поле с перечнем жанров (эту операцию мы рассматривали в предыдущих частях).

4) Показываем представление при этом передаём ему заголовок виджета и данные игр.

Само представление выглядит так (файл protected/components/view/topGames.php).

<h1><?php echo $title; ?></h1>

<?php
$i = 0;
foreach($games as $n=>$model) {
	//шаблон для вывода игры находится в views/games/_short_desc.php
	$this->controller->renderPartial('_short_desc', array('game'=>$model));
	if ($i % 2 !== 0) {
		echo '<div class="clear"></div>';
	}
	$i++;
}
?>

Как видите, для вывода игры мы использовали представление, которое относится к контроллеру Games (views/games/_short_desc.php).

Последний шаг – подключение шаблона в макете (файл protected/views/layouts/main.php)

<div id="top_games" class="grid_9">
<?php $this->widget('application.components.TopGames'
	, array('title'=>'Популярные игры'
		,'showOn'=>array('games/list','types/show')
		,'count'=>4)); ?>
</div><!-- top_games -->

Тут стоит отметить передачу параметров виджету. Они должны быть записаны в виде массива. При этом, ключ элемента должен совпадать с именем соответствующего свойства класса.

На этом мы остановимся. Думаю, общее представление о виджетах у вас появилось. Но в этой статье рассмотрены далеко не все их возможности, поэтому очень советую почитать соответствующий раздел справки.

Продолжение следует 😉

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

  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. Архив с исходниками
  • Когда же будет продолжение то?

  • Когда же будет продолжение то?

  • Delancer

    foreach($games as $n=>$model) {
    $this->controller->renderPartial('_short_desc', array('game'=>$model));
    if ($n % 2 !== 0) {
    echo »;
    }
    }
    также будет даже проще

    • Сейчас сравниваю ваш вариант со своим и думаю: «Зачем я это счетчик добавил?» 🙂

    • Сейчас сравниваю ваш вариант со своим и думаю: «Зачем я это счетчик добавил?» 🙂

  • $_GET параметры не очень хорошо использовать в коде виджета,
    параметры лучше передовать при вызове

    • Согласен.
      Но в данном случае GET параметр используется для основной странице и содержимое виджета также зависит от содержимого страницы. Т.е. виджет получился узкоспециализированный.

  • mr Rabbit

    сферический быдлокод в вакууме

  • Джер

    Браво!! Автор, Браво!
    Ты молодчина, что создал пошаговое описание разрабоtки на YII для новичков. Для старта самое то!!!!