mickey / mkyengine
PHP 模板引擎
Requires
- php: >=8.1
README
该模板引擎使用块和扩展系统来定义视图的不同部分。
// 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']
如果属性存在或存在属性获取器,例如 postcode
或 getPostcode()
或存在魔术方法,则所有属性和嵌套属性均可用。
字符串
组件可能需要对象或数组作为参数(如用户列表中的一个用户),为此您可以在参数中设置当前迭代数据的名称。
// 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