rougin/staticka

又一款基于PHP的静态站点生成器。

dev-master / 1.0.x-dev 2024-08-25 07:13 UTC

This package is auto-updated.

Last update: 2024-09-25 07:18:03 UTC


README

Latest Version on Packagist Software License Build Status Coverage Status Total Downloads

这是一款基于PHP的静态站点生成器。它可以将Markdown内容和PHP文件转换为静态HTML。它受到了流行的静态站点生成器如HugoJekyll的启发。

安装

通过Composer安装Staticka

$ composer require rougin/staticka

基本用法

从字符串生成简单的HTML

Staticka可以将简单的Markdown内容从字符串转换为HTML

// index.php

use Rougin\Staticka\Page;
use Rougin\Staticka\Parser;

// Creates a new page with the specified body ---------
$page = new Page;

$page->setName('Hello world!');
$page->setBody("# {NAME}\nThis is a sample template.");
// ----------------------------------------------------

// Converts the page into an HTML ---
$parser = new Parser;

echo $parser->parsePage($page);
// ----------------------------------
$ php index.php

<h1>Hello world!</h1>
<p>This is a sample template.</p>

注意

这里的{NAME}只是一个占位符,用于将name值从Page类插入到主体中。

使用.md文件

Staticka还支持通过将指定.md文件的路径添加到Page类来转换基于Markdown的文件(.md文件)

<!-- app/pages/hello-world.md -->

# Hello World!

This is a sample **Markdown** file!
// index.php

// ...

// Specify the path of the Markdown file -----
$file = __DIR__ . '/app/pages/hello-world.md';

$page = new Page($file);
// -------------------------------------------

// ...
$ php index.php

<h1>Hello World!</h1>

<p>This is a sample <strong>Markdown</strong> file!</p>

添加Front Matter,额外数据

Staticka支持Front Matter,可以在特定内容中添加预定义变量。默认情况下,还会生成特殊的变量,如pathlinkname,但可以在内容内部覆盖这些变量。

<!-- app/pages/hello-world.md -->

---
link: hello-world
---

# Hello World!

The link is **{LINK}**.
$ php index.php

<h1>Hello World!</h1>

<p>The link is <strong>hello-world</strong>.</p>

构建HTML页面

可以使用Site类将多个Page实例转换为具有相应目录名称的.html文件

// index.pp

// ...

use Rougin\Staticka\Site;

// ...

// Builds the site with its pages ------------
$site = new Site($parser);

$file = __DIR__ . '/app/pages/hello-world.md';
$site->addPage(new Page((string) $file));

$site->build(__DIR__ . '/app/web');
// -------------------------------------------
$ php index.php
<!-- app/web/hello-world/index.html -->

<h1>Hello World!</h1>
<p>The link is <strong>hello-world</strong>.</p>

Site类还可以清空指定目录或复制具有其文件的目录。如果输出目录需要CSS和JS文件,则此功能很有用。

app/
├─ web/
│  ├─ index.html
styles/
├─ index.css
// ...

// Empty the "output" directory ---
$output = __DIR__ . '/app/web';
$site->emptyDir($output);
// --------------------------------

// Copy the "styles" directory to "output" ---
$styles = __DIR__ . '/styles';
$site->copyDir($styles, $output);
// -------------------------------------------

// ...

在指定场景中,可以在同一个Site类中添加适用于所有生成页面的数据。

// ...

$data = array('ga_code' => '12345678');
$data['website'] = 'https://roug.in';

$site->setData($data);

// ...

警告

如果在Site类中添加包含Page类保留属性名称(例如,linkplate等)的数据,将覆盖页面中定义的数据。

添加模板引擎

仅从Markdown文件构建HTML页面只会返回内容本身。通过添加第三方模板引擎,可以更容易地添加部分(例如,布局)或为每个页面提供额外的样式。要添加模板引擎,必须在Parser类内部使用Render

<!-- app/pages/hello-world.md -->

---
name: Hello world!
link: hello-world
plate: main.php
---

# This is a hello world!

The link is **{LINK}**. And this is to get started...

注意

plate属性指定了解析页面时使用的布局文件。在这个例子中,main.php是用于hello-world.md文件的布局。

<!-- app/plates/main.php -->

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title><?php echo $name; ?></title>
</head>
<body>
  <?php echo $html; ?>
</body>
</html>

注意

$html变量是从解析的页面返回内容的预定义变量。预定义变量也基于页面的属性及其使用$page->getData()方法的数据。

// index.php

// ...

use Rougin\Staticka\Parser;
use Rougin\Staticka\Render;

// ...

// Sets the Render and Parser ----------
$paths = array(__DIR__ . '/app/plates');

$render = new Render($paths);

$parser = new Parser($render);
// -------------------------------------

// Render may be added to Parser after ---
$parser->setRender($render);
// ---------------------------------------

// ...

注意

要找到前面示例中指定的main.php文件,必须在Render类中包含要搜索的路径。

$ php index.php
<!-- app/web/hello-world/index.html -->

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Hello world!</title>
</head>
<body>
  <h1>This is a hello world!</h1>
  <p>The link is <strong>hello-world</strong>. And this is to get started...</p></body>
</html>

要为Staticka实现自定义模板引擎,必须实现该引擎到RenderInterface

namespace Rougin\Staticka\Render;

interface RenderInterface
{
    /**
     * Renders a file from a specified template.
     *
     * @param string               $name
     * @param array<string, mixed> $data
     *
     * @return string
     * @throws \InvalidArgumentException
     */
    public function render($name, $data = array());
}

设置布局

Staticka中,一个Layout类允许页面使用过滤器和辅助工具。它也可以作为class-string传递到.md文件中

// index.php

use Rougin\Staticka\Layout;

// ...

$pages = __DIR__ . '/app/pages';

// Define the layout with the name "main.php" ---
$layout = new Layout;

$layout->setName('main.php');
// ----------------------------------------------

// ...

// Set the layout into the page -------------
$page = new Page($pages . '/hello-world.md');

$site->addPage($page->setLayout($layout));
// ------------------------------------------

注意

使用这种方法,不需要从指定的.md文件中指定plate属性。

还可以在Front Matter详细信息中指定扩展了Layout的类

namespace App\Layouts;

use Rougin\Staticka\Layout;

class HomeLayout extends Layout
{
    /**
     * Specifies the plate to be used as the layout.
     *
     * @var string
     */
    protected $name = 'home.php';
}

注意

必须指定指定的plate的目录,在Render实例中(例如,app/plates)。

<!-- app/pages/hello-world.md -->

---
name: Hello world!
link: hello-world
plate: App\Layouts\HomeLayout
---

# This is a hello world!

The link is **{LINK}**. And this is to get started...

扩展和定制

使用过滤器修改

Filter允许在解析后修改页面

// index.php

use Rougin\Staticka\Filter\HtmlMinifier;

// ...

// Set the layout class for "main.php" ---
$layout = new Layout;

$layout->setName('main.php');
// ---------------------------------------

// Minifies the HTML after parsing the page ---
$layout->addFilter(new HtmlMinifier)
// --------------------------------------------

// ...
$ php index.php
<!-- app/web/hello-world/index.html -->

<!DOCTYPE html><html lang="en"><head><meta charset="UTF-8"><title>Hello world!</title></head><body><h1>This is a hello world!</h1><p>The link is <strong>hello-world</strong>. And this is to get started...</p></body></html>

要创建自定义过滤器,请使用FilterInterface实现。

namespace Rougin\Staticka\Filter;

interface FilterInterface
{
    /**
     * Filters the specified code.
     *
     * @param string $code
     *
     * @return string
     */
    public function filter($code);
}

使用辅助器的方法

Helper在模板文件中提供了额外的功能方法。

// index.php

use Rougin\Staticka\Helper\LinkHelper;

// ...

// Set the layout class for "main.php" ---
$layout = new Layout;

$layout->setName('main.php');
// ---------------------------------------

// Add a "$url" variable in templates ---
$url = new LinkHelper('https://roug.in');

$layout->addHelper($url);
// --------------------------------------

// ...
<!-- app/plates/main.php -->

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title><?php echo $name; ?></title>
</head>
<body>
  <?php echo $html; ?>
  <a href="<?php echo $url->set($link); ?>"><?php echo $name; ?></a>
</body>
</html>
$ php index.php
<!-- app/web/hello-world/index.html -->

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Hello world!</title>
</head>
<body>
  <h1>This is a hello world!</h1>
  <p>The link is <strong>hello-world</strong>. And this is to get started...</p>
  <a href="https://roug.in/hello-world">Hello world!</a>
</body>
</html>

要创建模板辅助器,请在HelperInterface中实现相关代码。

namespace Rougin\Staticka\Helper;

interface HelperInterface
{
    /**
     * Returns the name of the helper.
     *
     * @return string
     */
    public function name();
}

将过滤器添加到解析器

按照设计,FilterInterface下的过滤器应在解析器完成解析后执行。然而,在某些情况下,页面内容必须在解析前经过过滤器处理。

namespace App\Filters;

use Rougin\Staticka\Filter\FilterInterface;

class WorldFilter implements FilterInterface
{
    public function filter($code)
    {
        return str_replace('Hello', 'World', $code);
    }
}
// index.php

use App\Filters\WorldFilter;

// ...

// Replaces "Hello" string to "World" ---
$parser->addFilter(new WorldFilter);
// --------------------------------------

// ...

更新日志

有关最近变更的详细信息,请参阅更新日志

测试

$ composer test

致谢

许可证

MIT许可证(MIT)。有关更多信息,请参阅许可证