mattferris/staccato

原生PHP模板的最简模板库

v1.1.1 2023-08-17 21:40 UTC

This package is auto-updated.

Last update: 2024-08-29 23:33:32 UTC


README

Staccato 是一个用于原生PHP模板的最简模板系统。

它借鉴了令人尊敬的 Twig 的基础思想,主要是继承模型。因此,它建立在通过 扩展模板的概念之上。提供缓存作为一等特性(尽管不是必需的),支持 动态 缓存,允许缓存的模板包含动态内容。简单的插件设施确保 Staccato 可以按需扩展。Staccato 内置了一个 markdown 插件,它使用 Parsedown

继承

你有想倾诉的事情吗?创建一个博客!从编写一个简单的网站模板 base.tmpl.php 开始。

<!doctype html>
<html>
  <head>
    <meta charset="utf-8">
    <title>The Frivolous Fancies of Feral Foxes</title>
    <link rel="stylesheet" type="text/css" href="blog.css">
  </head>
  <body>
    <header><h1>The Frivolous Fancies of Foxes</h1</header>
    <article>
      <!-- content goes here -->
    </article>
  </body>
</html>

太棒了!现在让我们考虑如何包含内容。在渲染时,模板可以传递变量。这让我们可以使用变量向模板提供内容。我们只需要在模板中的 <article> 标签中输出变量。

    <article>
      <header><h1><?= $title ?></h1></header>
      <?= $body ?>
    </article>

有一个内置变量叫做 $_,它指的是代表当前模板的 Template 实例。它的使用将在后面介绍。

现在我们可以渲染模板了。

use MattFerris\Staccato\Staccato;

$vars = [
    'title' => 'Are Foxes Funny or Frightening?',
    'body' => '...';
];

echo (new Staccato())->render('base.tmpl.php', $vars);

当然,我们到目前为止所做的一切都是标准的PHP模板,不需要模板引擎。所以让我们让事情变得有趣。

随着读者群体的增长,你开始注意到对特定类型内容的需求,如评论和更正式的文章,除了当前的非正式帖子。是时候扩展你的模板以为每种类型的内容创建独特的样式了。 使这一点变得相当容易。

<?php namespace MattFerris\Staccato ?>
<!doctype html>
<html>
  <head>
    <meta charset="utf-8">
    <title>The Frivolous Fancies of Feral Foxes</title>
    <link rel="stylesheet" type="text/css" href="blog.css">
  </head>
  <body>
    <header><h1>The Frivolous Fancies of Foxes</h1</header>
    <article>
      <?php begin($_, 'content') ?>
      <?php end($_) ?>
    </article>
  </body>
</html>

首先,我们使用 Staccato 函数 begin() 定义了一个名为 content 的块。所有 Staccato 函数都需要你传递模板实例作为它们的第一个参数。实例作为 $this 或我们之前介绍的更简单的 $_ 可用。 begin() 还需要你传递一个块名称,在这种情况下为 content。最后,块通过 end() 终止。

那些细心的读者也会注意到我们为这个模板指定了一个命名空间 MattFerris\Staccato。这是为了提供方便访问模板函数。否则,您将不得不指定完全限定的函数名称(例如 <?php MattFerris\Staccato\begin($_, 'content') ?>)。谢谢!

接下来,我们可以定义一个名为 article.tmpl.php 的模板,它将扩展我们的基本模板。

<?php namespace MattFerris\Staccato ?>
<?php extend($_, 'base.tmpl.php') ?>

<?php begin($_, 'content') ?>
  <header><h1><?= $title ?></h1></header>
  <?= $body ?>
<?php end($_) ?>

我们可以使用 extend() 函数扩展 base.tmpl.php。通过这样做,我们可以访问在 base.tmpl.php 中定义的块。扩展是通过修改父模板中块的内容来完成的。在扩展块中定义的任何内容都将覆盖父模板中定义的内容。

文章需要自己的样式表。所以让我们在 base.tmpl.php 中定义一个用于样式表的块,并将现有的样式表添加到其中。

  <head>
    <meta charset="utf8">
    <title>The Frivolous Fancies of Feral Foxes</title>
    <?php block($_, 'css') ?>
      <link rel="stylesheet" type="text/css" href="blog.css">
    <?php end($_) ?>
  </head>

现在我们可以在 article.tmpl.php 中访问 css 块。

<?php block($_, 'css') ?>
  <link rel="stylesheet" type="text/css" href="article.css">
<?php end($_) ?>

但是,一旦我们扩展了 css 块,我们将覆盖父模板并丢失 base.css 样式表。幸运的是,我们可以使用 parent() 访问父块的内容。

<?php block($_, 'css') ?>
  <?= parent($_) ?>
  <link rel="stylesheet" type="text/css" href="article.css">
<?php end($_) ?>

然而,因为我们只是向块中追加样式表,我们可以使用快捷方式。

<?php append($_, 'css) ?>
  <link rel="stylesheet" type="text/css" href="article.css">
<?php end($_) ?>

append() 函数将扩展一个块,使其内部定义的所有内容都追加到父内容中。同样,prepend() 可以用于将内容追加到父块中。

模板包含

时不时地,你会发布一系列相关的博客文章、评论或文章。为了提高可用性,你希望在组成系列的页面中添加一些系列导航元素。这意味着你不能简单地将导航元素添加到你的基本模板中。你也不希望为每个子模板(例如article.tmpl.php)分别实现。这时就出现了incl()函数,它允许你将一个模板的渲染内容包含到另一个模板中。我们可以创建一个名为series-nav.tmpl.php的模板,内容如下。

<?php namespace MattFerris\Staccato ?>
<nav>
  <ul>
    <li><a href="<?= $prev ?>">Previous</a></li>
    <li><a href="<?= $next ?>">Next</a></li>
  </ul>
</nav>

现在我们可以在article.tmpl.php中包含这个模板。

<?php begin($_, 'content') ?>
  <?= incl($_, 'series-nav.tpl.php', [ 'prev' => '...', 'next' => '...' ]) ?>
  <header><h1><?= $title ?></h1></header>
  <?= $body ?>
<?php end($_) ?>`

注意,incl()函数返回模板内容作为字符串,因此必须手动输出。

缓存

虽然模板原生支持缓存,但直到你启用缓存插件,你才能利用这一功能。

use MattFerris\Staccato\Staccato;
use MattFerris\Staccato\Plugins\Cache\FileCache;
use MattFerris\Staccato\Plugins\Cache\CachePlugin;

$path = 'cache/dir'; // path to a directory to store cache entries
$ttl = 3600; // keep cache entries for one hour
$cache = new FileCache('path/to/cache/dir', $ttl);

$staccato = (new Staccato())
    ->addPlugin(new CachePlugin($cache));

一旦启用,模板将自动缓存其渲染内容。所有后续对模板的请求将返回缓存的模板,直到缓存条目过期或被删除。

可以使用set()函数禁用模板的缓存。

<?php namespace MattFerris\Staccato ?>
<?php set($_, 'cachemode', 'disabled') ?>

cachemode可以是static(默认)、dynamic(见下文)或disabled

缓存块

当模板被渲染时,cache块将缓存其内容。即使模板被重新渲染,它也会使用缓存块,直到它过期或被删除。这对于计算成本高昂的内容非常有用。

<?php cache($_, 'myblock', $ttl) ?>
  <?= some_expensive_operation() ?>
<?php end($_) ?>

cache接受一个第三个参数,指定缓存数据有效的时长(以秒为单位)。为了最大限度地利用缓存块,TTL应该设置得大于模板的TTL。TTL默认为1小时(3,600秒),而缓存块可以设置为1天(86,400秒),甚至1周(604,800秒)。

注意,可以使用begin()append()prepend()扩展缓存块。但是,不能使用cache()扩展标准块。当然,任何扩展缓存块的块都将缓存扩展块的内容。

无论模板的缓存模式设置为何,cache()都会缓存块的内容。

缓存包含

可以使用cincl()包含模板,这将返回包含模板的缓存内容。与cache()一样,cincl()也接受TTL作为第三个参数。并且与cache()一样,cincl()提供了对渲染成本高昂的模板进行缓存的另一选项。

<?= cincl($_, 'template.tmpl.php', $ttl) ?>

无论当前模板和包含模板的缓存模式设置为何,cincl()都会缓存包含模板的内容。

缓存获取的内容

从远程URL获取内容可能既昂贵又耗时。在远程内容不经常变化的情况下,可以使用cfetch()来缓存获取的内容。cfetch()使用file_get_contents()执行请求,因此你可以使用它支持的任何协议。

<?= cfetch($_, 'https://example.com/expensive/api/call', $ttl) ?>

非缓存获取

ncfetch()允许你在缓存模板中包含动态获取的内容。使用ncfetch()将自动将模板的缓存模式设置为dynamic。使用动态缓存的模板实际上是编译的。编译的模板包含指示解析器如何获取远程内容的标签。远程内容替换标签,并返回结果。虽然动态缓存的模板仍然经历少量处理,但这种权衡使得可以最大限度地利用模板。

<?= ncfetch($_, 'https://example.com/feed') ?>

Markdown

Markdown功能通过Markdown插件提供。该插件引入了一个markdown块,它在模板渲染时将内容解析为markdown,以及一个md()函数,它将字符串解析为markdown。

添加插件。

use MattFerris\Staccato\Staccato;
use MattFerris\Staccato\Plugins\Markdown\MarkdownPlugin;

$staccato = (new Staccato())
    ->addPlugin(new MarkdownPlugin());

然后在模板中开始解析Markdown。

<?php namespace MattFerris\Staccato ?>

<?php markdown($_, 'body') ?>
Article Title
=============

This is an *article* about *stuff*!
<?php end($_) ?>

<?= md($_, 'You shall not *pass*!') ?>