ryunosuke/php-excelate

ryunosuke PHP 模板库

v1.0.7 2023-09-24 13:23 UTC

This package is auto-updated.

Last update: 2024-09-04 14:36:07 UTC


README

描述

这是一个使 PHPSpreadsheet 支持在表格内嵌入代码的库。

  • 通过 roweach/coleach 进行行列操作
  • 通过 rowshift/colshift 进行行列位移
  • 通过 eval 进行类似 PHP 的嵌入标签

安装

{
    "require": {
        "ryunosuke/php-excelate": "dev-master"
    }
}

演示

php /path/to/excelate/demo/run.php

Template

$renderer = new Renderer();

// ブック全体をレンダリング(拡張子に応じて reader/writer が決まり、一時ファイルに書き出される)
$renderer->renderBook(__DIR__ . '/template.xlsx', [
    0       => [ // 基本はシート番号
        'title' => 'example',
        'rows'  => [
            ['no' => 1, 'name' => 'hoge', 'attrs' => ['attr1', 'attr2']],
            ['no' => 2, 'name' => 'fuga', 'attrs' => ['attr1', 'attr2', 'attr3']],
        ],
    ],
    'sheet' => [], // シート名でもよい
    ''      => [], // 空文字はアクティブシートを意味する
]);

// あるいはシートを個別にレンダリング
$book = IOFactory::load(__DIR__ . '/template.xlsx');
$renderer->renderSheet($book->getSheet(0), [
    'title' => 'example',
    'rows'  => [
        ['no' => 1, 'name' => 'hoge', 'attrs' => ['attr1', 'attr2']],
        ['no' => 2, 'name' => 'fuga', 'attrs' => ['attr1', 'attr2', 'attr3']],
    ],
]);
IOFactory::createWriter($book, 'Xlsx')->save(__DIR__ . '/template-out.xlsx');

Rendered

用法

基本上以 demo 为基础进行说明。

标签

可用的语法如下。

template

A1 单元格允许写操作。这个标签可以明确指定渲染范围。例如,写 {template A1:C12} 则除了 A1:C12 外,其他都不会渲染。

不写也行,但默认范围是“有数据的范围”。有时明确指定会更快。

此外,渲染范围是模板原始状态的范围。如果渲染后行和列增加,则会相应扩展。 (“增加多少行”不需要关心)。

row

直接嵌入数组。不能使用任何嵌入语法,需要调用方 PHP 预先整理数组值,但速度会更快。

  • {row $array} 如果 $array 是 A, B, C 则展开为 3 列 A B C

rowcol

直接嵌入数组的数组。不能使用任何嵌入语法,需要调用方 PHP 预先整理数组值,但速度会更快。常用于直接嵌入从数据库检索的记录数组等。

  • {rowcol $records:true} 在最前面添加键数组
  • {rowcol $records:false} 不嵌入键数组

rowif

{rowif $condition} ~ {/rowif} 可以根据 $condition 的真假来跳过渲染。$condition 可以使用变量,也可以使用 PHP 表达式。也就是说可以使用 {rowif $flag1 && !$flag2} 这样的逻辑运算或 {rowif strpos($name, 'hoge') === false} 这样的表达式。

当 $condition 为真时,表现得就像没有 if 标签一样。当为假时,会丢弃标签块,将其视为不存在。当为假时,rowif, /rowif 的位置会有以下行为。

  • 左右正好符合模板范围时
    • 整行会被删除。在 Excel 中相当于选择单元格后选择删除,然后菜单中的“整行”
  • 左右不符合模板范围时
    • 块会被向上移动。在 Excel 中相当于选择单元格后选择删除,然后菜单中的“向上移动”

基本上应该正好符合范围使用。因为移动会导致列错位,所以使用起来不方便(或者说实际上没什么用)。

{if} 会被当作“强制符合范围的 {rowif}”处理。这是为了允许像 {roweach $items}{if $flag}...{/if}{/roweach} 这样的常见结构。

但将来计划实现“根据 col/row 的上下文自动判断”的实现。 ({coleach $items}{if $flag}...{/if}{/coleach} 中的 if 会被认为是 colif)。也就是说,“{if} 总是 row 模式”的假设可能会被打破,所以请注意。但通常使用的话不需要担心。简单来说,“没有被循环包围的纯 {if} 不要使用”。

colif

rowif 的列版本。用法完全相同,但“正好”的定义是上下而不是左右。

基本上不正好匹配使用。因为列添加会影响到所有行,所以使用起来不方便(或者说实际上没什么用)。

实际上很难想象需要用 col 来 if 的情况,所以只是作为 rowif 的对应来实现的。

roweach

循环元素直到 /roweach,并复制单元格范围进行渲染。

有几个语法

  • {roweach $Values} 循环 $Values。元素的引用方法将在后面说明
  • {roweach $Values $Value} 循环 $Values。将元素值分配给 $Value
  • {roweach $Values $Key:$Value} 循环 $Values。将键分配给 $Key,将元素值分配给 $Value

如上所述,可以仅指定循环变量。在这种情况下,键被视为 $k,值被视为 $v。它不会嵌套进入循环,所以请注意不要在嵌套的循环中跟踪父级的 $k 或 $v。

此外,每个循环都会声明 {$index} {$first} {$last}。依次是“基于 0 的循环序列”、“是否是第一个循环的布尔值”、“是否是最后一个循环的布尔值”。这些名称听起来很常见,容易冲突,所以请注意。

循环值(上面所说的 $Values)必须是变量。不能使用直接值({roweach [1, 2, 3]})或表达式({roweach array_filter($Values)})。

元素是类似数组的东西,常见的例子是从数据库 fetchAll 来的数组数组。当循环这样的数组时,其子元素会在循环上下文中展开。

{roweach $rows $row} {$row['name']} でもいいし {$name} でも全く同じです {/roweach}

coleach

roweach 的列版本。

我想几乎不会用到。

rowshift

roweach 是增加行数的结构,但 rowshift 不增加减少,而是进行位移。也就是说,周围的单元格会产生错位。在 Excel 中,相当于选择单元格后选择插入,然后菜单中的“整行”是 roweach,“向下移动”是 rowshift。

实际上很少使用 rowshift。colshift 的使用可能更多。

colshift

rowshift 的列版本。

我想这里会有动态列位移的需求,所以使用频率可能更高。

值填充

上述所有 {} 都被视为值填充,并将其内容作为 PHP 表达式进行解释和执行。以下都是有效的描述。

  • {$value}
  • {"{$value}hoge"}
  • {var_export($value, 1)}
  • {implode(',', $values)}

可能的话,可以将其视为类似于 <?= ?> 短标签。

效果器

一些处理默认嵌入到上下文中,以局部闭包的形式运行。

このセルはシート!セルへリンクが貼られます{$Link('シート!セル')}
このセルは http://example.com が貼られます{$HyperLink('http://example.com', 'link text')}
このセルは文字色が赤になります{$Color('FF0000')}
このセルは罫線がつきます{$Border([['medium','FF0000']])}
このセルはリスト入力規則になります{$ValidationList(['選択肢A', '選択肢B', '選択肢C'])}
このセルを基準にして画像が埋め込まれます{$Image('path/to/image.png')}
このセルを基準にして画像が埋め込まれます{$Image(['path' => 'path/to/image.png', 'width' => 100, 'description' => '配列で属性が指定できます'])}

也可以不使用此机制,而是分配闭包并调用它。几乎相同。只是效果器有一个“第一个参数是单元格”的特点。这部分的行为,包括 Image 效果器的属性等,最好查看源代码。

效果器可以通过 registerEffector 注册。

注意点

关于单元格遍历

为了搜索嵌入标签,会遍历所有单元格,但遍历是行向的。

coleach       coleach

/coleach      /coleach

这个模板不能工作。因为它是行向的,所以判断左上和右下·右上和左下是成对的。

关于速度和安全性

最初是为了内部使用,并且是简单应用中使用的,所以没有过多考虑。最好不要在太关键的用途中使用。

关于语法解析器

没有做解析。只是尽力使用正则表达式(将来会替换)。所以如果做了太复杂的事情,可能会很快死掉。用于资料制作或内部使用等可能更安全。