earc/native-php-template-engine

本机面向对象的PHP模板引擎。

0.3 2021-04-10 14:07 UTC

This package is auto-updated.

Last update: 2024-09-29 05:29:08 UTC


README

轻量级、无依赖的模板组件,是earc框架的一部分,用于SOLID渲染方法。

利用面向对象编程的强大功能,使您的模板可重用且易于理解。

目录

安装

$ composer require earc/native-php-template-engine

引导

earc/native-php-template-engine不需要引导。

配置

earc/native-php-template-engine不需要配置。

基本使用

您可以渲染HTML、XML以及任何其他结构化或非结构化输出。

模板

模板是扩展AbstractTemplateModel的简单对象。您可以使用面向对象编程的全部功能,甚至依赖注入。

模板实现了template方法。在此方法内部输出的所有内容都是模板的渲染结果。您可以利用PHP将代码块外的代码视为纯输出的特性。

use eArc\NativePHPTemplateEngine\AbstractTemplateModel;

class MyTemplate extends AbstractTemplateModel
{
    /** @var object */
    protected $object;
    /** @var int */
    public $value;
    
    public function __construct(object $object, int $value)
    {
        $this->object = $object;
        $this->value = $value;    
    }

    public function template() : void
    { ?>
        <h1>Hello World</h1>
        <p>I have found a value `<?= $this->value ?>`.</p>
        <p>May be the object with the id `<?= $this->object->getId() ?>`
            can tell me what to do with it.</p>
    <?php }
}

提示:识别PHP的短输出语法(<?= .* ?>)。

最佳实践是只使用可以转换为字符串的属性。所有逻辑都必须外包到服务、实体、模型、转换器等中。即使是ifloop也不应出现在template方法内部,尽管它们可以通过底层的属性识别。

属性逻辑

即使从template方法中移除了所有逻辑,模板模型中仍需保留三个基本操作ifincludeloop。它们通过属性类型实现。

  1. IF:通过nullable属性实现。(null将转换为空字符串。)

  2. INCLUDE:可以通过模板内的模板实现复杂的树状结构。

    use eArc\NativePHPTemplateEngine\AbstractTemplateModel;
    
    class MyRootTemplate extends AbstractTemplateModel
    {
        /** @var AbstractTemplateModel */
        protected $head;
        /** @var AbstractTemplateModel */
        protected $body;
        
        public function __construct(AbstractTemplateModel $head, AbstractTemplateModel $body)
        {
            $this->head = $head;    
            $this->body = $body;
        }
    
        public function template() : void
        { ?><!DOCTYPE html>
    <html lang="en">
    <head>
        <title>I am fixed content.</title>
        <?= $this->head ?>
    </head>
    <body>
        <?= $this->body ?>
    </body>
        <?php }
    }
  3. LOOP:要将loop渲染为iterable,请将iterable注入到新的IteratorTemplateModel实例中。

    use eArc\NativePHPTemplateEngine\AbstractTemplateModel;
    use eArc\NativePHPTemplateEngine\IteratorTemplateModel;
    
    class MyTemplate extends AbstractTemplateModel
    {
        /** @var IteratorTemplateModel */
        protected $loop;
        
        public function __construct(iterable $iterable)
        {
            $this->loop = new IteratorTemplateModel($iterable);    
        }
    
        public function template() : void
        { ?>
            <div>
                The iterables items are cast to string on rendering:
                <?= $this->loop ?>
            </div>
        <?php }
    }

属性逻辑可以帮助您在模板中遵循单一职责原则。保持代码整洁,并使模板易于理解。

渲染

要渲染模板,只需将模板模型/对象转换为字符串。

$template = new MyTemplate($object, $value);

$renderedTemplate = (string) $template;

您可以直接输出类。PHP会隐式地进行转换。

echo new MyTemplate($object, $value);

渲染JSON对象

有时您不需要HTML,而是需要数据。json_encode将公共属性转换。这可以用于在一个输出数据模型中结合两个目的。

echo json_encode(new MyTemplate($object, $value);

如果您愿意,当然可以同时发送它们。

$template = new MyTemplate($object, $value);

echo json_encode(['data' => $template, 'html' => (string) $template]);

助手

为了使基本使用工作,earc/native-php-template-engine仅使用41行代码。

有时您可能需要一些额外的帮助来加速编码。earc/native-php-template-engine附带了许多助手。

模板模型接口

编写模板是关于增强数据输出。复杂的数据类型通常是对象,如果它们是可持久化的,则称为实体。如果它们可以直接转换为字符串,那岂不是很好?

使用__toString()方法有一些缺点

  1. 它可能已被用于其他目的。
  2. 一个对象可能存在多个模板。
  3. 构建模板可能需要一些额外的信息。

使用 TemplateModelInterface 提供了一种更加灵活的方式。类型转换足够简单

(string) $entity->getTemplate();

原则上,这是一个两步的类型转换。首先将实体对象转换成相关模板对象。然后,将模板对象转换成字符串。

如果有多个模板,提供模板的完全限定类名

(string) $entity->getTemplate(MyEntityTemplate::class);

如果模板需要构建一些额外的信息,则不应通过对象的模板工厂来构建。这样的工厂会超出转换的目的,因此违反了单一职责原则。使用传统方式

(string) new MyEntityTemplate($entity, $additionalParameter);

当然,您需要实现 TemplateModelInterface

use eArc\NativePHPTemplateEngine\helpers\TemplateModelInterface;

class SomeEntity implements TemplateModelInterface
{
    // ...
    
    public function getTemplate(?string $fQCN = null)
    {
        if (null === $fQCN) {
            return new SomeEntityDefaultTemplate($this);
        }

        return new $fQCN($this);
    }
}

集合模板模型

只要项目的类型转换能够得到期望的结果,IteratorTemplateModel 就可以正常工作。预处理是可能的,但这是一项足够愚蠢的任务

use eArc\NativePHPTemplateEngine\AbstractTemplateModel;
use eArc\NativePHPTemplateEngine\IteratorTemplateModel;

class MyTableTemplate extends AbstractTemplateModel
{
    // ...
    public function __construct($collection)
    {
        $tmplCollection = [];
        foreach ($collection as $entity) {
            $tmplCollection[] = new EntityDefaultTemplate($entity);
        }
        $this->collection = new IteratorTemplateModel($tmplCollection);
    }
    // ...
}

CollectionTemplateModel 会为您完成那些无聊的部分。

    use eArc\NativePHPTemplateEngine\helpers\CollectionTemplateModel;
    // ...
    $this->collection = new CollectionTemplateModel($collection, EntityDefaultTemplate::class);

如果您的集合实现了 TemplateModelInterface,则可以省略完全限定类名。

     use eArc\NativePHPTemplateEngine\helpers\CollectionTemplateModel;
    // ...
    $this->collection = new CollectionTemplateModel($collection);

甚至可以将参数传递给模板的构造函数。

     use eArc\NativePHPTemplateEngine\helpers\CollectionTemplateModel;
    // ...

    // calls internally: new EntityDefaultTemplate($collectionItem, $some, $arguments)
    $this->collection = new CollectionTemplateModel($collection, EntityDefaultTemplate::class, $some, $arguments);

    //...
    

HTML

属性

选择

发布

版本 1.0

  • 仅支持 PHP ^8.0
  • 简化了 API
  • 渲染属性的访问级别为 public
  • IteratorTemplateModel 的构造函数接受 iterable<string|TemplateInterface>
  • 通用 HTML 元素模板

版本 0.3

  • 支持 PHP ^8.0

版本 0.2

  • OptionTemplateModelOptGroupTemplateModel 添加了 callable 类型参数

版本 0.1

  • 添加了 TemplateInterfaceTemplateTrait

版本 0.0

  • 首次发布