Статьи

Transphporm — другой вид шаблонного движка

Если есть одна вещь, которая нужна миру, это определенно другой движок шаблонов PHP! Но подождите, этот другой!

Многие движки шаблонов PHP ( Smarty , Blade , Twig …) — это не просто абстрагированный PHP-код, что облегчает написание циклов, блоков if / then / else и отображает переменные с меньшей детализацией, чем ванильный PHP. Эти традиционные движки шаблонов требуют, чтобы у дизайнера было понимание особого синтаксиса. Механизм шаблонов также должен быть в рабочем состоянии, чтобы анализировать данные и, таким образом, полностью отображать окончательный проект. Ничего плохого в этом нет.

Журнал, флаер, брошюра, дизайн макета обложки, печать шаблона

Transphporm следует другому подходу, который обычно известен как «шаблонная анимация». Это означает, что веб-дизайнер создает всю страницу HTML / CSS / JS, включая контент-заполнитель, такой как «Lorem Ipsum», затем появляется шаблонный движок и заменяет части DOM новыми данными перед окончательным рендерингом.

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

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

По сути, дизайнер может работать с этим:

< h1 > A Good Title Here </ h1 > < p > A subtitle </ p > < p > Some awesome text for clients to see. </ p > 

Вместо этого:

 < h1 > {$futuretitle|upper} </ h1 > < p > {$futuresubtitle|capitalize:true|default:'Default Text'} </ p > < p > {$futureawesometext} </ p > 

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

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

Примечание. Серверная часть может по-прежнему создавать приемлемые теги HTML, например, созданные с помощью редактора WYSIWYG. т.е. img, a, p, strong, em и т. д., но никогда не блокируйте уровень, если все сделано правильно.

Посмотрим, как это работает. Если вы хотите следовать, подготовьте новую среду .

Установка Transphporm

В public папке нашего проекта мы установим пакет через Composer.

 composer require level-2/transphporm:dev-master 

Затем мы создаем новый файл index.php с содержимым:

 <?php require 'vendor/autoload.php' ; 

Примечание. Часто запускайте composer update поскольку Transphporm является активным проектом. Он обновлялся несколько раз во время написания этой статьи.

Создайте свои страницы

Transphporm не требует интерфейсного синтаксиса или специального кода на уровне разработки. Мы будем использовать CSS-подобный язык выбора, чтобы находить и заменять контент перед отображением вывода в браузере.

По природе шаблонной анимации я теоретически могу получить любой готовый шаблон из Интернета, если он действителен в XHTML . Это означает <meta charset='utf-8' /> а не <meta charset='utf-8'> как в текущем HTML5. Современная практика состоит в том, чтобы не использовать самозакрывающиеся теги, но чтобы быть XML-допустимыми, мы должны это сделать. Обратите внимание, что ваш окончательный рендер может быть HTML5, но шаблоны, которые вы создаете для Transphporm, должны быть XHTML. Это просто природа использования XML-методов PHP.

Объект Transphporm требует двух значений. Одна — действительная разметка XHTML, которая представляет шаблон дизайнера. Это может быть целая страница или просто фрагменты XHTML для использования в большой теме. Другая — это директивы TSS (Transphporm Style Sheet), которые содержат логику замены.

Обратитесь к странице github для полной документации, поскольку я могу быть настолько многословным в пределах длины этой статьи.

Добавьте это в файл index.php :

 $page = 'home.xml' ; $tss = 'home.tss' ; $template = new \ Transphporm \ Builder ( $page , $tss ) ; echo $template - > output ( ) - > body ; 

Теперь создайте файл home.xml с помощью этого базового шаблона XHTML:

 <!DOCTYPE html> < html lang = " en " > < head > < meta charset = " utf-8 " /> < title > HTML5 TEMPLATE </ title > < style > body { padding : 20 px ; font-size : 1 em ; } header nav { background-color : #ACEAD0 ; padding : 15 px 10 px ; } header nav ul { padding : 0 ; } header nav li { display : inline ; list-style : none ; margin-right : 15 px ; } header nav a { text-decoration : none ; } article header h1 { margin-bottom : 4 px ; color : #34769E ; font-size : 2 em ; } article header h2 { margin : 0 ; font-size : .8 em ; color : #555 ; } article p { font-family : Arial, sans ; color : #444 ; line-height : 1.4 em ; } footer { background-color : #444 ; padding : 10 px ; } footer p { color : #E2E2E2 ; } </ style > </ head > < body > < header > < nav > < ul > < li > < a href = " # " > Home </ a > </ li > < li > < a href = " # " > The Goods </ a > </ li > < li > < a href = " # " > Favorites </ a > </ li > < li > < a href = " # " > Media </ a > </ li > < li > < a href = " # " > Contact </ a > </ li > </ ul > </ nav > </ header > < main > < article > < header > < h1 > Page Title </ h1 > < h2 > By Jehoshaphat on Jan 1, 2015 </ h2 > </ header > < p > Lorem ipsum dolor sit amet, consectetur adipisicing elit. Ut voluptas deserunt in quam itaque consequatur at recusandae, veritatis placeat porro cum magni eos iure vero, obcaecati est molestiae quos enim. </ p > < p data-p = " yes " > Lorem ipsum dolor sit amet, consectetur adipisicing elit. Commodi sed asperiores cum explicabo praesentium, mollitia possimus nam. Aperiam autem doloribus hic. Ex quae quia fugiat, fugit eaque quam adipisci nemo. </ p > < ul > < li > A list item 1 </ li > </ ul > </ article > </ main > < footer > < p > footer stuff </ p > </ footer > </ body > </ html > 

Теперь создайте файл home.tss с этим:

 article h1 { content : "My New Page Title" } 

Директива TSS «выбирает» h1 с использованием CSS-подобного синтаксиса. «Найдите h1, который является потомком тега статьи». Обратите внимание, что специфичность имеет значение. Если бы у вас было много тегов статьи или много тегов h1, все они были бы выбраны и изменены!

Это особенно верно для повторяющихся узлов, таких как <li> . Если в нашем шаблоне их было больше одного, каждый отдельный элемент списка будет заменен всем повторяющимся набором данных!

Если ваши файлы index.php , home.xml и home.tss были созданы правильно, вы сможете открыть веб-сайт и увидеть шаблон. Шаблон имеет <h1>Page Title</h1> но вы должны увидеть «My New Page Title» при отображении в браузере.

Transphporm поддерживает общий синтаксис CSS, включая:

  • .classname
  • tagname.classname
  • direct > descendant
  • #id
  • element[attribute="value"] ИЛИ просто element[attribute]

Не поддерживаемые методы включают ~ и + .

Помимо этих селекторов, Transphporm поддерживает псевдоэлементы, включая:

  • element:before
  • element:after
  • element:nth-child(n)
  • element:even
  • element:odd

Вы можете связать селекторы вместе, как в CSS.

 article header > p { content : "First paragraph after the article header section" } 

Это простая штука и, надеюсь, прямолинейная.

В этот момент вы наверняка думаете: «Но я не хочу жестко кодировать текст в директиве TSS!»

Ну вот и начинается самое интересное.

Обработка данных

Давайте представим, что этот проект немного сложнее. Вы вряд ли будете иметь новый контент <h1> жестко запрограммированный в файле TSS! И вам, скорее всего, придется обновить более одного контента.

Я собираюсь создать объект с именем $data и присвоить ему некоторые значения.

Обновите index.php к этому:

 require 'vendor/autoload.php' ; // Some fancy routing to setup the page. $page = 'home.xml' ; $tss = 'home.tss' ; // Some fancy controller/model action to get data. $data = new stdClass ; $data - > pagetitle = "Awesome Page" ; $data - > title = "Article Title" ; $data - > subtitle = "By Zack" ; $template = new \ Transphporm \ Builder ( $page , $tss ) ; echo $template - > output ( $data ) - > body ; 

Теперь у нас есть $data как объект. Мы также добавили $data в метод output() .

Теперь файл home.tss можно обновить до следующего:

 title { content : data (pagetitle) } article h1 { content : data (title) } article h1 > h2 { content : data (subtitle) } 

Атрибут, который мы называем content принимает значение, называемое data() . Это похоже на то, как в CSS вы можете указать rgba() в качестве значения color .

На данный момент мы можем заменить любой контент, используя синтаксис CSS. Обратите внимание, как мы даже заменили контент в разделе <head> .

DOM Concerns

В этот момент вы можете подумать, что дизайнеру и программисту не нужно разговаривать друг с другом; но на каком-то уровне они делают. Разработчик должен использовать правильный XHTML, иначе движок зависнет (обработка ошибок может со временем улучшиться).

Вам может быть интересно, что произойдет, если разработчик изменит DOM и тем самым нарушит выбор TSS. Это может произойти, особенно если вы больше полагаетесь на дерево DOM, чем на хорошо продуманные идентификаторы и классы. Я бы предпочел использовать id="posttitle" чем полагаться на main article header > h1 который не всегда может быть задан в камне.

Несколько частичных

Мы также можем использовать более одного файла XML для сборки окончательного шаблона.

Вот пример файла TSS:

 @import 'another.tss' ; aside { content : template ( "sidebar.xml" ) } 

Мы можем использовать @import для включения других файлов TSS. Мы также можем использовать template() чтобы назначить частичный XML выбранному узлу, как показано выше. Любые директивы TSS, которые идут после этой строки, могут влиять на включаемый файл XML.

Таким образом, вы можете тщательно составить импорт XML-партиалов и директив TSS для сборки конечной страницы. Как и CSS, все компилируется сверху вниз.

Не только это, но вы можете заменить содержимое частичным содержимым включенного шаблона. В приведенном выше примере я sidebar.xml весь файл sidebar.xml . Но что, если я хочу только <aside> в этом файле? Просто сделай это:

 aside { content : template ( "sidebar.xml" , "#extra aside" ) } 

Это только вытянет <aside> из-под элемента с идентификатором «extra». Преимущество этого заключается в том, что дизайнер может по-прежнему работать с полными шаблонами, если он этого хочет, даже если вы можете извлечь только определенные элементы. Это также означает, что так же, как вы можете объединять изображения в один файл и использовать CSS для их отображения по мере необходимости, вы можете комбинировать элементы шаблона в одном файле и просто извлекать нужные вам части.

Расширенные Директивы

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

Это связано с тем, что шаблон «master» по-прежнему содержит полный макет дизайнера. Там ничего не меняется. «Настоящая» окончательная разметка будет в пределах партиалов. Это делает работу дизайнера лишь немного более сложной, поскольку им придется визуально редактировать основной дизайн, а затем копировать и изменять элементы в рамках производства. Если они обновляют основную страницу, им, возможно, придется обновить частичные данные.

Если вы вернетесь к нашему базовому шаблону HTML, частичные фрагменты можно легко использовать для верхнего колонтитула, меню, основной области содержимого, нижнего колонтитула и т. Д. Но размещение их в частичных параметрах не влияет на возможность дизайнера покинуть основную базу. Шаблон полностью исправен и визуально завершен. Частицы просто заменят разметку заполнителя позже.

И, как мы только что видели, сами части могут быть частью большой сложной или полной страницы.

Повторяющиеся данные

Transphporm может обрабатывать повторяющиеся данные с помощью атрибута repeat() .

Наш шаблон имеет неупорядоченный список. Мы можем заполнить его, используя $data для передачи массива объектов. Давайте добавим массив фруктовых объектов в index.php .

 $fruits = [ ] ;  // Master array of all fruits $fruit = new stdClass ; $fruit - > name = 'Apple' ; $fruits [ ] = $fruit ; $fruit = new stdClass ; $fruit - > name = 'Pear' ; $fruits [ ] = $fruit ; $data - > fruits = $fruits ; 

Теперь в файле TSS:

 article ul li { repeat : data (fruits) ; content : iteration (name) } 

Если вы добавили данные в index.php и обновили файл TSS, теперь в неупорядоченном списке должны быть два узла <li> перечисляющие «Apple» и «Pear».

Перед:

 < ul > < li > A list item 1 </ li > </ ul > 

После:

 < ul > < li > Apple </ li > < li > Pear </ li > </ ul > 

Обратите внимание, как мы использовали два атрибута «repeat» и «content», разделенные точкой с запятой. Точно так же, как установка высоты, ширины, цвета и границы в CSS для одного узла, вы можете применить несколько преобразований, используя один выбор с Transphporm.

Мы передали data(fruits) в функцию repeat . Это будет повторять выбранный узел ( <li> ), включая его закрывающий тег. Затем мы используем iteration() чтобы сообщить, какие данные в каждом фруктовом объекте отображать.

Примечание: кроме data() и iteration() , существуют другие доступные преобразования, включая format который принимает значения «прописными», «строчными», «titlecase», «date», а также может работать с числами.

Атрибуты

Transphporm может делать забавные вещи с атрибутами.

Допустим, мы хотели скрыть <li> если оно равно «Apple». Для этого мы можем проверить текущую итерацию и выбрать на ее основе.

 article ul li :iteration [name='Apple'] { display : none ; } 

Обратите внимание, как он работает как элемент psuedo, используя двоеточие после <li> и в квадратных скобках, соответствующих паре name=value . Также обратите внимание, что Transphporm может так же легко скрывать элементы с помощью знакомой директивы CSS display:none (хотя в Transphporm элементы полностью удаляются из DOM, а не просто скрываются).

В нашем шаблоне второй абзац имеет data-p="yes" . Давайте скрыть это на основе этого значения.

 article p[data-p="yes"] { display : none } 

Обратите внимание, что здесь нет двоеточия после p как раньше, когда используется iteration , то есть функция Transphporm. Мы выбираем с обычным синтаксисом атрибутов CSS, который не использует двоеточие.

Вы также можете установить содержание самих атрибутов. Пример из документации использует ссылку «mailto», например:

 a :attr(href) { content : "mailto:" , iteration (email) } 

И снова attr — это функция Transphporm, поэтому используется двоеточие. Также обратите внимание, что «(href)» — это прямой выбор самого атрибута, значение не используется.

Здесь происходит что-то классное — контент устанавливается на «mailto:», но затем мы используем запятую и значение итерации. Transphporm объединит несколько значений при использовании запятой, например:

 p { content : "This " , "is " , "really " , "long" } 

Таким образом, в предыдущем примере href="mailto:[email protected]" будет собран правильный атрибут href="mailto:[email protected]" .

Заголовки

Transphporm не отправляет заголовки. Для этого вам придется использовать обычные функции PHP.

Метод output() возвращает объект с двумя атрибутами. Один — это body которое содержит отрендеренный HTML, другой — headers которые являются массивом заголовков.

Способ установить заголовок состоит в том, чтобы выбрать элемент <html> и использовать встроенный псевдоэлемент :header для его установки.

 html :header [location] { content : "/another-url" } 

Чтобы использовать заголовки, установленные таким образом, вам нужно прочитать массив, возвращенный Transphporm, взять эти значения и установить их с помощью функции header() PHP. Инструкции о том, как это сделать, находятся в документации.

Условные изменения

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

 class Security { public function LoggedIn ( ) {  // Some logic return false ; } } $data = new Security ;  // Be sure to pass $data to the output() method as usual 

Теперь вы можете прочитать это значение и определить соответствующее действие:

 #welcome :data [LoggedIn=""] { display : none } 

Это может быть очень удобно!

Следует отметить, что при анимации шаблона мы обычно начинаем с полного шаблона со всеми функциями, а затем удаляем части, которые не принадлежат. Мы построили бы шаблон с «вошедшими в систему» ​​функциями, а затем удалили бы их из DOM, если они не нужны.

Это описывается как подход «сверху вниз», а не «снизу вверх», где присутствует только минимальная разметка, и мы добавляем материал по мере необходимости.

Оба подхода работают с Transphporm.

Преимущества развязанного дисплея и логики

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

Одним из примеров этого является использование TSS для повторного заполнения форм. Один TSS может быть использован для повторного заполнения любого шаблона формы. Это будет выглядеть так:

 form textarea { content : data ( attr (name)) } form input[type="text"] :attr(value) { content : data ( attr (name)) } 

Функция attr(name) считывает атрибут «name» выбранного элемента. Если атрибут «name» элемента textarea был «comments», то он компилируется в:

 form textarea { content : data (comments) } 

data(comments) здесь ссылаются на переданный объект $data мы уже использовали ранее, но он будет работать так же хорошо, если вместо него будет передан сам $_POST .

Вторая строка в приведенном выше TSS выбирает все элементы ввода формы с типом «текст». Затем он специально выбирает сам атрибут value , в который вы помещаете контент при заполнении формы. Данные, опять же, поступают из data(xyz) где «xyz» — это атрибут имени выбранного элемента. В свою очередь, атрибут name будет соответствовать данным, поступающим из $_POST или объекта $data .

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

 import 'form-populate.tss' ; 

В качестве примера передачи $_POST вы можете сделать это на своем PHP:

 $data - > title = "Article Title" ; $data - > formData = $_POST ; 

Как только $_POST был передан через $data , функция привязки может специально связать formData со всеми TSS, используемыми в этом элементе формы.

 form { bind : data (formData) } /* Now that formData is bound to form, it can be accessed directly */ form input :attr(value) { content : data ( attr (name)) } 

Связывание просто означает, что я могу вызывать data(key) а не data(formData[key]) потому что контекст data() был изменен на ссылку на formData напрямую.

Языковая независимость

Следует отметить, что разделение означает, что любой язык может использоваться для обработки файлов TSS без каких-либо изменений в шаблонах. Автор построил родственный компилятор в Javascript, который на 100% совместим в отношении шаблонов TSS и XML. Найдите это на Github в Transjsform .

проблемы

Использование шаблонной анимации заботится как о дизайнере, так и о кодере. Дизайнер может создавать свои шаблоны и частичные компоненты без особой заботы о бэкенде или шаблонизаторе. Требуется только действительный XHTML. Программисту, с другой стороны, нужна только способность легко находить элементы DOM, которым необходимо заменить их содержимое.

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

Человек, о котором еще не совсем позаботились, — редактор / писатель.

Хорошо иметь шаблоны XHTML. Хорошо, что где-то есть логика TSS. Данные могут поступать из контроллера и быть собраны в один объект $data . Но где пишут писатели?

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

В какой-то форме метаданных потребуется сказать, что «этот абзац требует пользовательских данных, а этот нет». Программист также должен знать, какие разделы будут заменены частичными. Может даже быть несколько версий частичного в зависимости от некоторой другой логики приложения.

Из-за этого мы не можем утверждать, что существует 100% разделение между дизайнерами и программистами, поскольку им все еще требуется определенный уровень согласованности в отношении общей структуры вещей.

Заставить редактора узнать TSS?

Одна из причин для анимации шаблонов заключается в том, чтобы не позволить дизайнеру изучать язык шаблонов или синтаксис. Это бессмысленная цель, если вы просто заставляете писателя изучать синтаксис TSS! Скорее всего, дизайнеру будет гораздо легче выучить синтаксис шаблона, чем обучить синтаксис писателя CSS.

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

Части TSS предназначены для сборки страницы, другие части для назначения копии. Кроме того, редакторам нужен только доступ к некоторым из этих преобразований. Некоторые преобразования могут быть структурными по природе, в то время как другие ориентированы на содержание.

Истинное разделение интересов здесь должно включать редакторов, а также программиста и дизайнера. Ни одна из существующих CMS не сможет принять Transphporm как есть. Сложный шаблон может содержать сотни преобразований с множеством различных логических путей. Для редакторов контента нужен WYSIWYG.

Все вместе это представляет собой интересную проблему для того, чтобы сделать Transphporm удобным для всех.

Следует отметить, что в настоящее время автор работает над синтаксическим анализатором, где редактор может отправить Markdown в качестве содержимого, а Transphporm проанализирует его в HTML для вывода. Эта функция должна быть добавлена ​​очень скоро и приближает нас к интерфейсу редактирования.

Кэширование

Базовое кэширование реализуется как написано здесь . Без кеша PHP в настоящее время должен обходить XHTML и анализировать TSS для каждой загрузки страницы. В текущей итерации это может создать проблему с производительностью при использовании Transphporm.

Вывод

Использование CSS-подобного синтаксиса для выбора элементов DOM — очень интересная концепция. Дизайнеры могут найти облегчение в необходимости изучения нового синтаксиса, и они могут макетировать 100% законченных проектов, не беспокоясь о бэкэнде. Это также означает, что вы должны иметь возможность загружать любые готовые шаблоны XHTML и начать работу относительно быстро с минимальными изменениями DOM.

Будет интересно посмотреть, как этот проект созревает. Первый интерфейс CMS, который будет создан для управления преобразованиями TSS и редактирования контента, будет особенно интересным.

Если вам не нравится, как работают обычные шаблонизаторы, возможно, Transphporm лучше для вас? Посмотрите и дайте нам знать!