torbenkoehn/php-xtpl

PHP 模板引擎

dev-master 2020-06-26 19:59 UTC

This package is auto-updated.

Last update: 2024-09-10 08:20:57 UTC


README

XTPL 是一个 PHP 的模板系统,它不使用任何花哨的新语法,而是使用普通的旧 HTML,或者说 XML。

它是如何工作的?

XTPL 解析器 解析 XTPL 文件并处理找到的特定节点。节点插件是动态加载的,这意味着像将整个扩展映射到你的 HTML 代码上以处理新和现有 HTML 元素等功能是很容易实现的。

你得到的是 PHTML,你可以将其包含在 PHP 中。PHTML 只是 PHP 与 HTML 的结合,它渲染一个动态的服务器端处理的 HTML 页面。

如果你不想自己处理 PHTML 的事情,XTPL 包含了一个渲染器,如果你喜欢,它还会为你缓存。

如何安装?

你可以通过下载 GitHub 上的 ZIP 文件 或使用 Composer 来安装。

要使用 Composer 安装,你需要在你的 composer.json 中添加以下信息

{
    "minimum-stability": "dev",
    "require": {
        "php": ">=5.3.0",
        "torbenkoehn/php-xtpl": "*"
    }
}

之后,只需运行

$ composer install

即可安装 XTPL 库并使其可供使用。

如何使用?

你可以让 XTPL 渲染器处理所有工作,或者你可以动手使用原始 API 来处理。

最简单的方法

    $xtpl = new Xtpl\Renderer;

    $xtpl->displayFile( 'your/path/to/the/xtpl/file', array(
        'title' => 'My Page Title',
        'posts' => array(
            0 => array(
                'title' => 'Some post title',
                'content' => 'bla bla bla bla bla'
            )
        )
    ) );

无论你是否使用 .xtpl 扩展,都没有关系。

使用类似显示的方式将执行 eval() 代码,众所周知,eval 是邪恶的。你最好将缓存目录作为第一个参数传递给渲染器

    $xtpl = new Xtpl\Renderer( __DIR__.'/cache' );

当然,这个目录需要可写,但这将大大提高系统的性能。

使用这种方式,渲染器将自动处理所有缓存,你不需要做任何事情。

如果你想深入了解,你还可以以更原始的方式使用该系统,如下所示

    $xtpl = $xtpl->renderFileToFile( 'your/xtpl', './phtml/your/xtpl.phtml' );
    extract( $yourTemplateArgs );
    include './phtml/your/xtpl.phtml';

注意: 对于其他任何内容,请查看上面的代码和下面的文档。

基本功能

你可以定义一个块,并让其他块在其中添加或替换内容。这是递归的,这意味着你可以在布局模板中定义块,从它扩展并仅定义块内容。你还可以定义块,然后包含指定块内容的模板。

my-page.xtpl

<?xml version="1.0" encoding="utf-8" ?>
<xtpl>

	<html version="5">
	    <head>
	        <title>XTPL is awesome!</title>
	
	        <block name="scripts">
	            <script src="jquery.js" />
	        </block>
	
	        <block name="styles">
	            <link rel="stylesheet" href="style.css" />
	        </block>
	    </head>
	    <body>
	
	        <block name="content">
	            I'm some placeholder content, I won't stay here.
	        </block>
	    </body>
	</html>



	<block name="scripts" mode="append">
        <script src="bootstrap.js" />
    </block>

    <block name="styles" mode="prepend">
        <link rel="stylesheet" href="bootstrap.css" />
    </block>

    <block name="content">

        <h1>My current content</h1>
        <p>
            This might be some static or dynamic content, whatever you prefer.
        </p>
        
        <p>
        	It actually doesn't matter what's in here, you can include stuff, you can have sub-blocks and sub-sub-blocks, XTPL can handle all of it.
        </p>

    </block>

</xtpl>

注意: 实际上,你不再需要关闭脚本元素了。

生成的 HTML 将是这样的

<!doctype html>
<html>
    <head>
        <title>XTPL is awesome!</title>

        <script src="jquery.js"></script>
        <script src="bootstrap.js"></script>

        <link rel="stylesheet" href="bootstrap.css">
        <link rel="stylesheet" href="style.css">
    </head>
    <body>

        <h1>My current content</h1>
        <p>
            This might be some static or dynamic content, whatever you prefer.
        </p>
        
        <p>
        	It actually doesn't matter what's in here, you can include stuff, you can have sub-blocks and sub-sub-blocks, XTPL can handle all of it.
        </p>

    </body>
</html>

请注意,脚本块被附加,样式块被预先插入,内容块替换了先前的内容。

目标块总是解析器找到的第一个具有该名称的块,其他块将添加到它(或不会添加)

那些玩过 Jade 的人应该知道这种模板机制。

扩展

模板可以扩展其他模板。如果你来自 Jade,你应该已经知道了工作方式。这并没有做什么比将你的当前模板 DOM 放入扩展的模板 DOM 中更多,但它允许递归块使用,全局布局和类似的东西。

想象一下,你有一个非常好的主布局

layout.xtpl

<?xml version="1.0" encoding="utf-8" ?>
<xtpl>

	<html version="5">
	    <head>
	        <title>XTPL is awesome!</title>
	
	        <block name="scripts">
	            <script src="jquery.js" />
	        </block>
	
	        <block name="styles">
	            <link rel="stylesheet" href="style.css" />
	        </block>
	    </head>
	    <body>
	
	        <block name="content">
	            I'm some placeholder content, I won't stay here.
	        </block>
	    </body>
	</html>

</xtpl>

并且你渲染了一个扩展它的模板

my-page.xtpl

<?xml version="1.0" encoding="utf-8" ?>
<xtpl extends="layout">

    <block name="scripts" mode="append">
        <script src="bootstrap.js" />
    </block>

    <block name="styles" mode="prepend">
        <link rel="stylesheet" href="bootstrap.css" />
    </block>

    <block name="content">

        <h1>My current content</h1>
        <p>
            This might be some static or dynamic content, whatever you prefer.
        </p>
        
        <p>
        	It actually doesn't matter what's in here, you can include stuff, you can have sub-blocks and sub-sub-blocks, XTPL can handle all of it.
        </p>

    </block>
</xtpl>

生成的 HTML 将是这样的

<!doctype html>
<html>
    <head>
        <title>XTPL is awesome!</title>

        <script src="jquery.js"></script>
        <script src="bootstrap.js"></script>

        <link rel="stylesheet" href="bootstrap.css">
        <link rel="stylesheet" href="style.css">
    </head>
    <body>

        <h1>My current content</h1>
        <p>
            This might be some static or dynamic content, whatever you prefer.
        </p>
        
        <p>
        	It actually doesn't matter what's in here, you can include stuff, you can have sub-blocks and sub-sub-blocks, XTPL can handle all of it.
        </p>

    </body>
</html>

实际上,在扩展层级、块的数量等方面没有任何编程限制。你可以根据需要深入扩展布局,即使在包含的 XTPL 中也是如此。

尽量避免递归

注意实际上,递归现在可能会把一切搞砸。

包含

包含子模板。在子模板中,你可以访问模板变量以及包含元素的属性。

my-page.xtpl

<?xml version="1.0" encoding="utf-8"?>
<xtpl>

    <body>

		<block name="page-header" />
        <header>

            <include file="navigation" orientation="vertical" />
            
        </header>
    </body>
    
</xtpl>

navigaton.xtpl

<?xml version="1.0" encoding="utf-8"?>
<xtpl>

    <nav class="nav nav-[[orientation]]">
        <ul>
            <li><a href="#home">Home</a></li>
            <li><a href="#about-me">About me</a></li>
            <li><a href="#blog">Blog</a></li>
            <li><a href="#portfolio">Portfolio</a></li>
        </ul>
    </nav>
    
    <block name="page-header">
    	My Page Header
    </block>
    
</xtpl>

要在包含的模板(或任何扩展模板)中使用 orientation 属性,你可以在任何属性或文本节点中使用 [[orientation]],看看 <nav> 元素的 class="" 属性。这也适用于扩展了包含模板的模板。orientation 只是一个例子,你可以使用任何你喜欢的属性名或值(你甚至可以加载 file 属性的值)

[[attributeName]] 的插值在属性值和纯文本节点上工作。

变量

还有什么,这是最重要的部分之一。在模板中使用变量有两种方式,有一个 <var> 元素,并且你可以使用插值。

<var> 元素

    <var name="my.variable.name" />

是相同的

    <?php echo $my->variable->name; ?>

你还可以设置

    <var name="my.variable.name" value="New Value!" />

如果变量未设置,则可以使用默认值(这会自动进行 !empty() 检查)

    <var name="title" default="My Website Title!" />

但这使用了官方的 <var> 标签,不是吗?

是的,但它不会以任何方式影响它。VarElement 仅在存在至少一个 name 属性时才会响应(在正常的 <var> 元素上设置一个没有任何理由)。其余的仍然是纯 HTML。

插值

变量插值在属性值和文本节点上工作。类似于 <{{var.name}}> 的东西是不可能的,可能永远不会。

    <nav class="nav nav-{{orientation}}">
    
		Hey, this is some text and I don't want to use a tag now so I just {{output}} my variable named "output" here.
		
    </nav>

注意如果你认为在 <php> 节点中使用插值是有意义的,你可以这样做,但说实话,这没有意义。你无论如何都可以通过简单的 $varName 访问变量。尽管如此,在某些情况下可能是有意义的,所以它也工作。

至于属性,如果变量是属性值中唯一的东西,并且变量为 null 或 false,则不会渲染该属性。这对于可选类很有用

    <a href="my-link.html" class="{{link.active}}">My link!</a>

如果 $link->activenullfalse,这将渲染

    <a href="my-link.html">My link!</a>

实际上,这是一个谎言,现在它不会这样做,但很快就会。

你还可以在表达式的调用方式中使用默认值和回调/过滤器。

	<p>
		HEY, THE NEXT TEXT SHOULD ALSO BE {{someText(I dont have a Text):strtoupper:SomeClass.doSomeStaticStuff}}
	</p>

循环

现在有 for 和 foreach 循环。两者都使用 <for> 元素。

一个简单的 foreach 循环工作如下

    <for each="my.posts" as="post">

        <article>
            <header>
                <h1>{{post.title}}</h1>
            </header>
            <p>
                {{item.content}}
            </p>
        </article>
    </for>

你也可以通过

<for each="my.posts" as="post" key="currentIndex">

for 循环目前只是一个计数器,你可以多次执行某项操作并指定一个起点。现在这非常没有用,因为你不能为 times 属性使用插值,但将来这肯定会被改变。

for 循环工作如下

<for times="5" as="i">
    ({{i}}): Hey, this should happen 5 times! 
</for>

条件

是的,它们现在有了!XTPL 支持 <if><else><elseif> 块。后两个始终需要位于它们引用的 if 元素内部。

通过属性进行的可能检查有 emptynot-emptysetnot-setcondnot-cond

condnot-cond 只翻译成纯 PHP,它就像在 PHP 中定义 if 语句中的 (...) 之间的内容。

<if not-empty="myVar">
    Heeey, we made sure that {{myVar}} is not empty!
</if>
<if cond="!empty( $myVar ) and $myVar > 0">
    This gets printed if the condition is true
</if>
<if not-set="myVar">
    myVar is not set
    <else>
        myVar is set!
    </else>
</if>

else/else-if 标签在节点中的位置无关紧要,它们总是会自动在末尾渲染。如果你想在大型 if 块的顶部放置 else 块以提高可读性,这很有用。

<if not-set="myVar">
    myVar is not set
    <else>
        myVar is set!
    </else>
    and here is some more content<br>
    but this will only be rendered, if the if-block is true!
</if>
<if not-set="myVar">
    myVar is not set
    <elseif set="myVar">
        myVar is set
    </elseif>
    <else>
        This won't ever be printed.
    </else>
</if>

尝试使用它,感受它,它实际上真的可以工作!

行内PHP

您可以使用PHP-HTML标签在模板中使用纯PHP。通过XML限制,您必须将复杂代码放入<![CDATA[ ... ]]>标签中。

	<php>echo $someVariable;</php>
	
	<php>while( $i < 10 ):</php>
		<span>{{i}}</span>
		<php>$++;</php>
	<php>endwhile;</php>

	<php><![CDATA[
	
		//Here you can use any kind of complex PHP code
		
		class SomeClass {}
		
		$instance = new SomeClass;
		$instance->something = 'SomeValue';
		
		var_dump( $instance );
	
	]]></php>

处理指令

您已经看到可以使用标签进行行内PHP。实际上,您还可以在任何XTPL文件中使用<?php ... ?>语法。这些被处理为处理指令,并直接转换为元素。

以下是一些可用的处理指令

<?php [您的PHP代码] ?> 转换为<php>元素,在PHTML文件中渲染实际的PHP代码块。

<?css [您的CSS] ?> 转换为有效的<style>元素

<?js [您的JavaScript] ?> 转换为有效的<script>元素

扩展

XTPL可以通过非常简单的方式扩展。

解析器从特定的命名空间获取节点。您可以为解析器添加任何喜欢的命名空间,以提供新的或现有的、重工作的元素。

假设您在XTPL文件中使用了<my-custom-tag>标签。

解析器会查找其扩展命名空间中的My\Custom\TagElement类,如果找到,则处理它并将其渲染为有效的XTPL节点。

由于新添加的命名空间始终首先被读取,因此可以很容易地通过这种方式删除整个元素命名空间。下一章中提到的Bootstrap扩展将给出一个很好的例子。

默认命名空间如下

Xtpl\Nodes Xtpl\Extensions

要包含一个新命名空间,您可以在Xtpl\Renderer上调用$renderer->addExtension( 'Your\\Extension\\Namespace' );$parser->addElementNamespace( 'Your\\Extension\\Namespace' );Xtpl\Parser上。

要启用XTPL扩展,您可以在Xtpl\Renderer上调用$renderer->addXtplExtension( 'ExtensionName' )$parser->addElementNamespace( 'Xtpl\\Extensions\\ExtensionName' );Xtpl\Parser上。

通常您应该与Xtpl\Renderer一起工作,了解一下。

默认扩展

虽然您当然可以轻松地自己开发扩展,但您不必这样做。XTPL实际上带来了一整套新的HTML元素。

您可以通过它们的完整命名空间激活它们,或者包含单个命名空间将它们映射到现有的HTML上。

单个扩展(Xtpl\Extensions

单个扩展是简单的单个元素,仅提供一些实用功能。

电子邮件

标签<email>someone@example.com</email>将被转换为<a href="mailto:someone@example.com">someone@example.com</a>

HTML

<html>标签有一个新属性叫做version。目前它只支持值5,这会使它自动在<html>标签前添加<!doctype html>

头部

<head>扩展实际上只是默认添加UTF-8字符集,如果您没有手动添加。

换行

<br>标签提供了一个新的属性repeat,它确实如您所想的那样工作。<br repeat="5" />将渲染为<br><br><br><br><br>

这在布局中比人们想象的更有用。

Bootstrap扩展(Xtpl\Extensions\Bootstrap

Bootstrap扩展是一套新的HTML元素,它们提供了Twitter的Bootstrap框架的全部功能,具有您见过的最简单的标记。

注意: 您不必自己加载bootstrap!XTPL实际上负责这件事,并自动处理bootstrap的脚本和CSS需求。这意味着,一旦您的代码中有Bootstrap元素,您也就有了jQuery。看看生成的DOM吧!

使用bootstrap扩展有两种方法。

直接调用

您可以通过使用它们的命名空间直接调用Bootstrap扩展。记住,Xtpl\Extensions命名空间始终被加载。使用<bootstrap-button theme="primary">我的闪亮按钮!</bootstrap-button>,您将获得一个完全工作的Bootstrap-Button,它会自动处理您对它的所有操作。

扩展映射

如果您无论如何都在整个项目中使用Bootstrap,您也可以将整个扩展命名空间映射到您的XTPL文件上。您可以通过启用Bootstrap扩展来实现这一点。只需在您的Xtpl\Renderer上调用$renderer->addXtplExtension( 'Bootstrap' );即可。

Bootstrap扩展将78个新元素引入您的XTPL模板。要了解它们的功能,您最好查看以下XTPL模板:

[Bootstrap扩展示例模板](https://github.com/TorbenKoehn/php-xtpl/tree/master/templates/bootstrap-extension)

开发您自己的扩展

目前实际上没有关于扩展元素如何工作的文档。您只需查看现有的Bootstrap-Extension,以全面了解它们是如何制作的。

Boostrap扩展PHP文件

计划中的功能和修复

  • Less和CoffeeScript集成
  • Markdown集成
  • 更多动态处理指令
  • 在节点中改进DOM管理
  • 改进固定值属性的插值(例如,<boostrap-button theme="{{theme}}" />目前无法正常工作)
  • Twitter Bootstrap折叠(手风琴)、轮播和固定
  • 更多文档类型
  • 更智能的编码检测和自动生成
  • 更智能和巧妙的单扩展元素

为什么叫XTPL?

老实说,因为我还没有找到任何花哨、合适的名字。也许它将永远被称为XTPL,也许我会在某个时候改变它,我不知道。

XTPL来自XML和Template (TPL),这使得它成为XTPL。很酷,我知道。

我欢迎名字建议。

我有反馈,我很感兴趣,我想贡献力量,我给这个项目起了个新名字?

请发送电子邮件到torben@devmonks.net并告知我。

我期待与感兴趣的人交谈 :)