mickey/mkyengine

PHP 模板引擎

v1.1.0 2023-08-07 19:20 UTC

This package is auto-updated.

Last update: 2024-09-07 21:28:21 UTC


README

Micky-N 编写的 PHP 模板引擎
Latest Stable Version Generic badge

该模板引擎使用块和扩展系统来定义视图的不同部分。

// index.php
<?php $this->extends('layout') ?>

<?php $this->block('content') ?>
  <p>content</p>
<?php $this->endblock() ?>
// layout.php
<h4>Layout</h4>

<?= $this->section('content') ?>
  
<p>Footer</p>
// render
<h4>Layout</h4>

<p>content</p>

<p>Footer</p>

安装

composer require micky/mkyengine

用法

目录加载器

目录加载器为模板引擎注册视图目录

$loader = new \MkyEngine\DirectoryLoader('views_dir');

如果您想定义组件或布局子目录,请使用 setComponentDir 或 setLayoutDir

$loader->setComponentDir('components_dir')->setLayoutDir('layouts_dir');

组件目录将是 views_dir/components_dir,布局目录将是 views_dir/layouts_dir

环境

环境存储所有视图的命名空间和文件扩展名的目录,您可以可选地定义共享变量

$context = [] // Shared environment variables, optional

$environment = new \MkyEngine\Environment($loader, $context); 

默认情况下,第一个命名空间是根,您可以通过 addLoader() 方法添加另一个目录加载器和其命名空间

$environment->addLoader('ns2', $loader2);

// Check if loader exists
$environment->hasLoader('ns2'); // true

要从另一个命名空间使用视图、组件或布局,请使用 @namespace:view

<?= $this->component('form') ?> // From root namepsace
<?= $this->component('@ns2:form') ?> // From ns2 namespace

视图编译器

视图编译器通过检索块并在布局部分中显示它们来编译视图。第一个参数是环境,第二个是要显示的视图,第三个是视图变量。

$view = new \MkyEngine\ViewCompile($environment, 'index', [
   'name' => 'Micky'
]);

要渲染视图,请使用 render() 方法

echo $view->render();

模板化

布局

布局是视图的背景,您可以定义布局的哪些部分将被视图填充。

// layout.php
<h4>Layout</h4>
<?= $this->section('content') ?>
<p>Footer</p>

您可以在将要使用 'title' 块的地方定义默认值。

// layout.php
<?= $this->section('title', 'default') ?>

布局视图可以扩展另一个布局。

// layout.php
<?php $this->extends('great-layout') ?>

<?php $this->block('title', 'new Title') ?>

<?php $this->block('content2') ?>

   <h4>Layout</h4>
   <?= $this->section('content') ?>

<?php $this->endblock() ?>
// layout.php
<?= $this->section('title', 'title') ?>  
  
<h1>Layout2</h1>  
  
<?= $this->section('content2') ?>

扩展

扩展方法用于定义布局文件。

<?php $this->extends('layout') ?>

块是用于布局的视图的一部分。参数是块名称

<?php $this->extends('layout') ?>

<?php $this->block('content') ?>
  <p>content</p>
<?php $this->endblock() ?>

您可以使用第二个参数设置一个简单的块

<?php $this->extends('layout') ?>

<?php $this->block('title', 'MkyFramework') ?>

要显示此块,请使用布局中的 section() 方法,并指定要显示的块名称

// layout.php
<h4>Layout</h4>
<?= $this->section('content') ?>
<p>Footer</p>

您可以定义具有相同名称的多个块

<?php $this->block('content') ?>
  <p>content</p>
<?php $this->endblock() ?>
<?php $this->block('content') ?>
  <p>second part</p>
<?php $this->endblock() ?>

它将显示

<p>content</p>
<p>second part</p>

因此,块可以通过 if() 方法进行条件化

<?php $this->block('content')->if($condition) ?>
...
<?php $this->endblock() ?>

注入

多亏了注入方法 $this->inject,您可以将用于 HTML 模板的对象(如数字格式化器或表单生成器)作为视图属性设置

示例 FormBuilder

class FormBuilder
{
    public function open(array $attr): string
    {
        return "<form method='{$attr['method']}' action='{$attr['action']}'>";
    }

    public function input(string $type, string $name, string $value = ''): string
    {
        return "<input type='$type' name='$name' value='$value'>";
    }

    public function submit(string $message, string $name = ''): string
    {
        return "<button type='submit'" . ($name ? " name='$name'" : '') . ">$message</button>";
    }

    public function close(): string
    {
        return "</form>";
    }
}

在视图中

// view.php
<?php $this->inject('form', FormBuilder::class) ?>

第一个参数是要在视图实例中注册的属性名称,第二个是要实例化的类,您可以传递类实例或类名。您将能够通过 $this->nameOfProperty 使用类

<?php $this->inject('form', FormBuilder::class) ?>
<?= $this->form->open(['method' => 'POST', 'action' => '/create']) ?>
    <?= $this->form->input('text', 'firstname', 'Micky') ?>
    <?= $this->form->input('text', 'lastname', 'Ndinga') ?>
    <?= $this->form->submit('Save') ?>
<?= $this->form->close() ?>

HTML 渲染将如下所示

<!--Rendering-->
<form method="POST" action="/create">
    <input type="text" name="firstname" value="Micky">
    <input type="text" name="lastname" value="Ndinga">
    <button type="submit">Save</button>
</form>

组件

组件是视图的一部分,如果您想在多个视图中使用它,则非常有用。

<?= $this->component('form') ?>

您可以使用 bind() 方法向组件传递变量,第一个参数是组件变量,第二个是值。

<?= $this->component('form')->bind('name', 'Micky') ?>

您可以使用 binds() 方法向组件传递多个变量。

<?= $this->component('form')->multipleBind(['name' => 'Micky', 'lastname' => 'Ndinga']) ?>

与块类相同,组件可以通过 if() 方法进行条件化

<?= $this->component('form')->if($condition) ?>

您可以使用两种方法在循环中重复组件

  • for
  • each

循环

第一个参数是迭代次数,第二个是将在每次迭代中调用的回调。在回调中,第一个参数是视图参数,第二个是当前循环索引。

示例:在 name-input.php 组件中有一个名为 'name' 的变量用于输入,在每次迭代中,组件将具有当前用户的名称

// components/name-input.php
<input value="<?= $name ?>"/>
<?= $this->component('name-input')->for(3, function(array $params, int $index) use ($users){  
     $params['name'] = $users[$index]->name;  
     return $params;  
}) ?>

每个

使用 each() 方法,组件将遍历数组中的每个值。第一个参数是数组,第二个参数可以是回调函数、数组或字符串。

回调函数

each() 回调函数与 for() 回调函数相同,但多了一个第三个参数,即数组。

<?= $this->component('name-input')->each($users, function(array $params, int $index, array $users){
    $params['name'] = $users[$index]->name;  
    return $params;  
}) ?>
数组

您可以将变量与数组绑定,其中索引是组件变量,值是数据 $users 的对象属性或数组键。

<?= $this->component('name-input')->each($users, ['name']) ?> // 'name' => user->name
<?= $this->component('name-input')->each($users, ['name' => 'firstname']) ?> // 'name' => user->firstname

如果您需要传递嵌套值,可以通过连接 address.postcode 来实现,它等于

  • $user->{address | getAddress() | magic getter for "address"}->{postcode | getPostcode() | magic getter for "postcode"}

示例

  • $user->address->postcode
  • $user->getAddress()->postcode
  • $user->address['postcode']
  • $user->getAddress()['postcode']
  • $user['address']->postcode
  • $user['address']['postcode']

如果属性存在或存在属性获取器,例如 postcodegetPostcode() 或存在魔术方法,则所有属性和嵌套属性均可用。

字符串

组件可能需要对象或数组作为参数(如用户列表中的一个用户),为此您可以在参数中设置当前迭代数据的名称。

// components/user-input.php
<input value="<?= $user->name ?>"/>

// view
<?= $this->component('user-input2')->each($users, 'user') ?>
否则组件

如果数据 $users 为空,您可以将第三个参数设置为字符串来定义否则组件。

<?= $this->component('user-input')->each($users, 'user', 'empty-user') ?>
组件插槽

如果您有一个希望使主体动态的组件,例如

// components/alert.php
<div class="alert alert-<?= $type ?>">
    <div>
        <p><?= ucfirst($type) ?>:</p>
        <?= $this->slot('default') ?>
    </div>
    <?php if ($this->hasSlot('confirm')): ?>
        <button id="confirm"><?= $this->slot('confirm') ?></button>
    <?php endif ?>
    <?php if ($this->hasSlot('close')): ?>
        <button id="close"><?= $this->slot('close') ?></button>
    <?php endif ?>
</div>

一个简单的带条件按钮的警告组件,要在视图中使用此组件,您必须设置三个插槽:默认插槽、确认插槽和关闭插槽。

// view
<?php $this->component('alert')->bind('type', 'danger') ?>
    this is an alert
    <?php $this->addslot('confirm', 'confirm the alert') ?>
    // Or
    <?php $this->addslot('confirm') ?>
        <span>confirm</span> the alert
    <?php $this->endslot() ?>
    
    <?php $this->addslot('close', 'Close info') ?>

<?php $this->component('alert')->end() ?>

HTML 渲染将如下所示

<div class="alert alert-danger">
    <div>
        <p>Danger:</p>
        this is an alert
    </div>
    <button id="confirm"><span>confirm</span> the alert</button>
    <button id="close">Close info</button>
</div>

不在插槽中的所有文本都将放置在默认插槽中。插槽可以是条件性的。

<?php $this->addslot('close', 'Close info')->if($type == 'info') ?>

您还可以为空插槽设置默认值以避免错误消息。

<?= $this->slot('default', 'default text') ?>

许可证

MIT