Статьи

Создание интернационализированного блога с FigDice

В первой части этой серии, состоящей из двух частей, я начал изучать FigDice , систему шаблонов PHP, которая в большинстве своем использует немного другой подход.

Плоды инжира

Пока что мы создали очень простой пример сайта с использованием Figdice. Мы реализовали пару страниц, канал Twitter и некоторые шаблонные партиалы.

Во второй и последней части мы собираемся добавить простой блог на наш пример сайта, который позволит нам более подробно рассмотреть концепцию каналов данных в Figdice. Мы также рассмотрим интернационализацию, переведя часть содержимого сайта на несколько дополнительных языков.

Код

Я создал отдельный репозиторий для кода для этой второй части серии, которую вы найдете на Github . Он расширяет код, который мы написали в первой части .

Там также онлайн демо .

Создание простого блога

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

Сначала создайте другой класс фида — на этот раз для блога.

<?php namespace Sitepoint\Feed;

	use figdice\Feed;

	class BlogFeed extends Feed
	{

		public function run() {
			
			return array(
				array(
					'id'			=>	3,
					'slug'		=>	'post-three',
					'title' 	=> 	'Sample Blog Post Three',
					'body'		=>	'<p>Donec sed odio dui. Maecenas sed diam eget risus varius blandit sit amet non magna. Aenean lacinia bibendum nulla sed consectetur. Vestibulum id ligula porta felis euismod semper. Cras mattis consectetur purus sit amet fermentum. Duis mollis, est non commodo luctus, nisi erat porttitor ligula, eget lacinia odio sem nec elit. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus.</p>',
					'author'	=>	array(
						'id'		=>	1,
						'name'	=>	'Bob',
					),
					'created'	=>	12345,
				),
				
				// .. more posts here, omitted for brevity

			);
		}
	}

Опять же, мы подделываем данные, но извлечение сообщений из блогов — это то, что широко освещается в других местах и ​​должно быть относительно простым.

Теперь измените класс FeedFactory

 // ...
use Sitepoint\Feed\BlogFeed;

class FeedFactory implements \figdice\FeedFactory
{
	// ...
		
	public function create($className, array $attributes) {

		if ($className == 'BlogFeed') {			
			return new BlogFeed();
		}

		if ($className == 'TwitterFeed') {			
			return new TwitterFeed();
		}
		
		// ... 
		
	} 
}

Теперь создайте новый вид, который мы будем использовать в нашем блог-листинге:

 <!--  file: blog.html -->
<?xml version="1.0" encoding="utf-8"?>
<fig:template xmlns:fig="http://figdice.org/">

	<fig:dictionary file="menu.xml" name="menu" />

	<fig:feed class="BlogFeed" target="posts" />

	<fig:include file="layout.html" />

	<title fig:plug="docTitle"><fig:trans dict="menu" key="blog" /></title>

	<h1 fig:plug="pageTitle"><fig:trans dict="menu" key="blog" /></h1>

	<div fig:plug="pageContent">
		<article fig:walk="posts">
			<h2>			 					
				<a href="/blog/post/{slug}" fig:text="title"></a>
			</h2>
			<p class="author">By <span fig:text="author/name" /></p>
			<div fig:text="body"></div>
			<hr fig:auto="true" />
		</article>
	</div>

</fig:template>

Многое из этого мы уже видели, но давайте посмотрим на fig:walk На этот раз вместо создания простого элемента списка и внедрения одного свойства мы создаем дополнительную разметку; в этом случае для каждого поста мы создаем элемент <article>

Как только мы находимся в цикле «прогулки», который по сути является итератором, к свойствам можно обращаться по имени; см., например, <div fig:text="body"></body>

Внутри <h2>fig:text<a>{slug}

Ссылка внутри <h2> Он объединяет строку /blog/post/slug/blog/post/post-three

Вы также можете получить доступ к более глубоким свойствам, используя косую черту. Для информации об авторе мы хотим извлечь свойство nameauthor поэтому мы используем <span fig:text="author/name" /> Вы также можете использовать двойную точку ( ..

<fig:dictionary><fig:trans>

Ленты и атрибуты

Возможно, вы помните, что был второй, необязательный параметр для фабричного метода create Если вы добавите какие-либо дополнительные атрибуты к элементу fig:feedfigclasstarget

Например, вы можете изменить blog.html

 <fig:feed class="BlogFeed" target="posts" num-posts="5" sort="'date'" sort-direction="'asc'" />

Обратите внимание на одинарные кавычки внутри двойных кавычек; это потому, что значения оцениваются.

Затем на своей фабрике вы можете использовать getParameter()getParameterBool()getParameterInt()getParameterString() Каждый из этих методов принимает значение по умолчанию в качестве необязательного второго параметра.

Таким образом, для этого примера мы могли бы расширить фабрику следующим образом:

 // @file FeedFactory.php
	public function create($className, array $attributes) {
		
		$num_posts = $this->getParameterInt('num-posts', 10);
		$sort_by = $this->getParameterString('sort', 'date');
		$sort_dir = $this->getParameterString('sort-direction', 'desc');
		
		// now you can use these values, for example when you instantiate the feed

Для получения более подробной информации смотрите раздел «Каналы» в руководстве.

Завершение блога

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

Сначала давайте определим маршрут:

 // Individual blog posts.
	$app->get('/blog/post/{slug}', function($slug) use ($view) {

		$view->loadFile( '../templates/post.html' );

		// We use mount to "inject" the slug into the view, which it can then use to "pull" the appropriate post.
		$view->mount('slug', $slug);

		return $view->render();

	});

Обратите внимание, как мы внедряем слаг, который является параметром URL, в представление с помощью метода mount()

Теперь давайте создадим представление:

 // post.html
	<xml fig:mute="true"> <!-- Mute because this tag should not end up in the HTML document. But the FigDice template must have an XML root node. -->

		<fig:dictionary file="menu.xml" name="menu" />

		<!-- Load the page layout -->
		<fig:include file="layout.html" />

		<fig:feed class="BlogFeed" target="post" post-slug=" /slug " />

		<!-- Set the <title> tag -->
		<title fig:plug="docTitle"><fig:trans dict="menu" key="about" /></title>

		<!-- Set the <h1> tag -->
		<h1 fig:plug="pageTitle" fig:text="/post/title" />

		<!-- "Plug in" the page content -->
		<div fig:plug="pageContent">

			<p class="back"><a href="/blog">&laquo; <fig:trans dict="menu" key="blog" /></a></p>

			<p class="author">By <span fig:text="/post/author/name" /></p>
			<div fig:text="/post/body"></div>	
		</div>
	</xml>

Многое из этого должно быть знакомо, но давайте посмотрим на элемент <fig:feed>

 <fig:feed class="BlogFeed" target="post" post-slug=" /slug " />

Обратите внимание, как мы передаем переменную «slug», которую мы сделали доступной для представления с помощью метода mount()post-slug

Давайте изменим класс BlogFeed для получения одного сообщения в блоге. Поскольку мы определяем сообщения как простой массив, поместите его после того, как мы его создадим:

 $posts = array( .... );

// Get the slug, if provided
$slug = $this->getParameterString('post-slug');

if ($slug) {
			
	// Use a little Underscore magic to retrieve the appropriate post
	$post = Arrays::find($posts, function($post) use ($slug) {
		return ($post['slug'] == $slug);
	});

	return $post;

} else {

	// No slug, we want the lot.
	return $posts;	

}

Очевидно, что в «реальном» приложении вы будете выполнять поиск в базе данных, но этот пример должен дать вам представление о том, как настроить поток данных для ваших представлений.

условия

Небольшая заметка об условных выражениях, которую вы можете получить с помощью атрибута fig:cond

Например, для показа некоторого контента задано определенное условие:

 <span fig:cond="logged_in == true">You are logged in</span>

Чтобы добавить класс в <article>

 <article>
		<fig:attr fig:cond="status == 1" name="class">published</fig:attr>
		...
	</article>

Если статус установлен в единицу, результирующий HTML будет выглядеть следующим образом:

 <article class="published">
		...
	</article>

интернационализация

FigDice облегчает перевод текста в ваших шаблонах. Давайте начнем с создания некоторых языковых файлов для хранения наших переводимых строк. В большом приложении вы можете захотеть создать файл на модуль, упрощая их повторное использование в нескольких приложениях.

Типичная структура может выглядеть так:

 lang
		en
			menu.xml
			products.xml
			checkout.xml
		es
			menu.xml
			products.xml
			checkout.xml
		fr
			menu.xml
			products.xml
			checkout.xml

Давайте создадим конкретный пример, переведя меню нашего примера сайта:

 <!-- lang/en/menu.xml -->
<fig:dictionary xmlns:fig="http://www.figdice.org/" language="en">
	<entry key="home">Home</entry>
	<entry key="about">About</entry>
	<entry key="blog">Blog</entry>
</fig:dictionary>

Затем испанская версия этого файла:

 <!-- lang/es/menu.xml -->
<fig:dictionary xmlns:fig="http://www.figdice.org/" language="es">
		<entry key="home">Inicio</entry>
		<entry key="about">Acerca</entry>
	<entry key="blog">Blog</entry>	
</fig:dictionary>

Если вы хотите использовать переведенный текст, сначала обратитесь к файлу словаря и дайте ему идентификатор где-нибудь в вашем шаблоне:

 <fig:dictionary file="menu.xml" name="menu" />

Теперь вы можете вставить значение элемента, используя ключ словаря — взятый из атрибута namefig:dictionarykey

 // file: templates/menu.html
	<ul class="nav nav-pills pull-right">
		<li><a href="/"><fig:trans dict="menu" key="home" /></a></li>
		<li><a href="/about"><fig:trans dict="menu" key="about" /></a></li>
		<li><a href="/blog"><fig:trans dict="menu" key="blog" /></a></li>
	</ul>

Теперь, где-нибудь в коде вашего приложения, сообщите представлению, где найти ваши языковые файлы:

 $view->setTranslationPath('../lang');

Затем установите язык:

 $view->setLanguage('es');
	// or $view->setLanguage('en'), $view->setLanguage('fr'), etc

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

Сначала мы добавим несколько ссылок в заголовок макета ( templates/layout.html

 <a href="/lang/en"><img src="/img/en.png" width="16" height="16" /></a> | <a href="/lang/es"><img src="/img/es.png" width="16" height="16" /></a>

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

Теперь реализуйте соответствующий маршрут, который просто вставляет соответствующий код языка в переменную сеанса:

 $app->get('/lang/{lang}', function ($lang) use ($app) {

	$app['session']->set('lang', $lang);

	return $app->redirect('/');

});

Наконец, около вершины index.php

 // Get the language from the session, if it's set - default to English.
$language = $app['session']->get('lang', 'en');

// ...and set it.
$view->setLanguage($language);

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

Резюме

В этих двух статьях я представил FigDice, систему шаблонов, которая в большинстве своем использует совершенно другой подход. Это больше, чем я смог охватить, так что ознакомьтесь с руководством , учебными пособиями , примерами или ссылками .

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