kaiwessela / blog
我的个人博客系统。
Requires
- kaiwessela/astronauth: dev-master
- kaiwessela/parsedownforblog: v1.0.0
This package is auto-updated.
Last update: 2024-09-12 13:27:19 UTC
README
Mein persönliches Blog-System
简介
Blog是为谁制作的?
Blog是一个小型、轻量级的博客管理系统,适合那些已有HTML和CSS经验,并希望充分利用这些语言在页面设计上的自由度和功能的人。另一方面,他们又不希望放弃通过一个正规的CMS来管理内容。
目前,大多数内容管理系统都过于复杂。如果你想用WordPress创建一个网站,你需要在现有的主题之间进行选择,不幸的是,这些主题几乎总是看起来一样——如果你有经验,通常一眼就能认出是一个WordPress页面——而且往往质量也不尽如人意。或者你可以创建自己的主题,然后深入研究一个复杂且难以理解的模板语言——最终这些模板语言也只会生成HTML。为什么不直接使用HTML和CSS呢?
基于这个愿望,我创造了Blog。我的目标始终是开发一个系统,你可以用它结合少量学习和熟悉的工具来创建一个带有功能性强、易于使用的内容管理的自定义网站。
原则
逻辑和展示分离
Blog基于已知和成熟的 Model-View-Controller 模型构建。该模型将程序分为三个层次:数据库层 (Model),负责与数据库通信;逻辑层 (Controller),执行实际计算;展示层 (View),仅负责展示。
在Blog中,展示层由模板组成。逻辑和展示的分离意味着模板中不再编写任何代码,而只插入控制器计算的内容和变量。因此,模板保持整洁且易于理解。
使用已知技术
Blog不会强迫用户学习任何不必要的新的模板语言或深入研究复杂的文本编辑器,只需具备HTML、CSS、Markdown和基本的PHP知识(如果有疑问,可以在半小时内学会)。
你可以简单地用Markdown或HTML写新的博客条目,或者选择用HTML编写,而不需要适应一个复杂的WYSIWYG编辑器,在编辑器中,你往往无法得到你看到的内容(或者至少不是你想要的内容)。
模板使用经典的HTML和内联PHP。由于逻辑和展示的分离,你不需要掌握比简单的单行 if 查询、foreach 循环、include 指令(用于子模板)和内联输出语法 <?= $variable ?> 更多的PHP知识来输出变量的值。这就是全部。
基本结构
对象和类
数据集,例如博客条目、页面和事件,作为对象存储。存在各种对象类,例如用于博客条目的 」Post「 类、用于静态页面的 」Page「 类和用于事件的 」Event「 类。
一个对象总是有多个属性。有些属性,例如ID,属于所有对象,无论属于哪个类,其他属性,例如属性 title,是特定类的,因此仅由特定类的对象使用,在这个例子中是 」Post「。
通用属性
属性 id 和 longid 是通用的,也就是说,它们可以被所有类别的对象使用。以下我将更详细地解释这两个重要的属性。
id
在创建对象时,例如创建一个新的页面或撰写一个新的博客条目时,会自动生成一个唯一的 id 并分配给新对象。它是随机的、不可修改的,由 8 个十六进制字符组成。
id 可以很好地用于短链接,例如,可以通过 https://example.org/a/9ac4fb1e 访问 我的第一篇文章。
longid
longid 和 id 一样,具有唯一标识对象的功能。但是,对象创建者,比如博客条目的作者,可以自行设置 longid。longid 的目的是成为一个唯一且易于阅读的对象标识符。因此,它通常用于在 URL 列表中调用对象。例如,URL https://example.org/artikel/mein-erster-artikel 比 https://example.org/artikel/9ac4fb1e 更好地表明了内容。
longid 必须至少有 9 个字符长(最多 60 个字符),且只能由拉丁字母 (a-z/A-Z)、数字 0-9 和连字符 (-) 组成。一旦设置,它就不能再修改。这会违反网络标准,即资源应该始终可以通过相同的地址访问。
路由
博客允许用户自由设置其页面 URL 的结构。因此,存在路由配置 »routes.json«。它确保特定的路径(例如,/artikel/mein-erster-artikel)被分配给正确的页面。
此外,用户可以决定页面应该如何构建,例如加载哪些模板和控制台。
路径表示法
一个路由始终以相关路径的表示法开始。例如,当调用 artikel 时,应显示博客条目的列表,而当调用 artikel/mein-erster-artikel 时,则显示具有 longid mein-erster-artikel 的单个文章。
静态形式
因此,在 simplest case 下,可以这样写:
{
"artikel": {
…
},
"artikel/mein-erster-artikel": {
…
},
…
}
这样,已经为这两个路由指定了有效的路径。但是,将每个新文章单独添加到路由表中将非常繁琐且不实用。因此,可以在路径表示法中插入各种占位符。
通配符
以下通配符是有效的路径表示法:/ 和 *。
在这里,/ 表示一个空路径,因此当用户调用 https://example.org/ 时将被调用。通常,这将显示主页。
* 表示所有可能的路径。因此,它是一个 Catch-All 表示法,当所有先前路由的路由表示法都不适用时将被调用。因此,应将带有此通配符的路线放在路由文件的最末尾,否则后续路由可能无法被调用。
路径模式
路径模式是一种路径表示法,它允许使用简单的占位符。因此,我们上面的示例 artikel/mein-erster-artikel 更适合用路径模式 artikel/* 来描述。此路径模式适用于所有文章,例如 artikel/urlaubsgruesse、artikel/meine-lebensgeschichte 和 artikel/zum-geburtstag。以下我将更详细地描述此表示法。
检查内容:一个有效的PathPattern通过以下正则表达式定义:^([A-Za-z0-9-]+|[\*#]({[0-9]+,?[0-9]*})?)(\/([A-Za-z0-9-]+|[\*#]({[0-9]+,?[0-9]*})?))*([\*#]*\??)?$
片段
一个路径由多个片段组成。在我们的示例 artikel/urlaubsgruesse 中,artikel 和 urlaubsgruesse 分别是各自的片段。片段通过斜杠 (/) 连接。顺便说一句,开头和结尾没有斜杠。
占位符
现在可以在PathPattern中使用占位符符号替换片段
*表示片段内的任意字符。#表示任意大小的数字。
注意:对于每个片段只能有一个占位符,绝不能在同一个片段中有多个占位符,占位符与其他字符在同一个片段中,或者一个占位符用于多个片段。
因此,PathPattern artikel/* 如上所示,将匹配所有任意的路径 artikel/[artikel-longid],而PathPattern artikel/# 只匹配路径 artikel/1、artikel/2、artikel/3 等。后者通常用于文章列表,例如,文章列表可以通过URL https://example.org/artikel 访问,但由于文章数量庞大,需要分多页显示,第二页、第三页、第四页等可以通过附加数字(例如 https://example.org/artikel/2)来访问。
限定符
但在先前的示例中,我们遇到了一个问题:如果我们使用PathPattern artikel/# 来处理文章列表,那么没有数字的https://example.org/artikel(没有数字)将返回空。我们现在需要设置两个路由,带有路径标记 artikel 和 artikel/#,尽管它们实际上具有相同的目标(或者几乎相同,但我们会稍后讨论)。
为了解决这个问题,存在限定符。它们位于占位符之后,并确定占位符应该用于多少个字母、数字或字符。
以下是一些限定符:
{n},即{1}、{2}等,表示前面的占位符只能有 n 个字符,因此artikel/#{1}将匹配 artikel/1、artikel/2 或 artikel/3,但不匹配 artikel/11 或 artikel/123。{n,m},即{1,2}、{2,4}等,表示前面的占位符只能有 n 到 m 个字符。因此artikel/#{2,4}将匹配 artikel/12、artikel/567 或 artikel/9999,但不匹配 artikel/2 或 artikel/12345。{n,}:第二个参数 m 可以省略。在这种情况下,这个限定符表示至少 n 个字符。然而,省略逗号前(即 n)的数字是不允许的。?是一个特殊的情况。这个限定符只能位于最后一个片段的末尾。它使最后一个片段的占位符可选。因此artikel/#?将匹配URL https://example.org/artikel 以及 https://example.org/artikel/2。
注意:限定符只能位于占位符之后,绝不能位于之前,单独存在或位于其他字符之后。
正则表达式(RegEx)
正则表达式是路径标记中最复杂但也是最强大的形式。初学者可能不需要它,但对于有经验的用户来说,它几乎可以提供设计路径配置的绝对自由度。它以 /^ 开头,表示路径的开始,以 $/ 结尾,表示路径的结束。中间可以使用所有已知的RegEx搜索模式。
检查时仅使用URL路径部分,而不是主机、查询字符串(?xy=z)或片段(#abc)。此外,还将删除开头和结尾可能存在的斜杠。正则表达式从URL https://example.org/artikel/mein-erster-artikel/?queryString=true#kapitel-2 中检查的只是段 artikel/mein-erster-artikel。在正则表达式路径表示时应注意这一点。
重要:分隔路径段的斜杠(/)必须使用反斜杠(\)进行双重转义,一方面因为它们将通过JSON解析器,另一方面,因为否则会被误解释为正则表达式的结束标记。
博客内部仅使用正则表达式,因此将静态表示、通配符和PathPatterns转换为正则表达式。因此,PathPatterns的某些部分可能对正则表达式专家来说已经很熟悉,它们只是简单地被采用。内部重写的示例包括
artikel/mein-erster-artikel转换为/^artikel\/mein-erster-artikel$/artikel/*转换为/^artikel\/[^\/]+$/artikel/*{0,8}转换为/^artikel\/[^\/]{0,8}$/artikel/#?转换为/^artikel(\/[0-9]+)?$//(通配符)转换为/^$/*(通配符)转换为/^.*$/
替换字符
在我们的示例中,具有路径表示 artikel/#? 的路由与URL https://example.org/artikel 以及URL https://example.org/artikel/2 相匹配。这是预期的结果。然而,我们希望当调用第二个URL时显示不同的文章列表,因为第一个URL指向第一页,而第二个URL指向第二页。
我们已经了解到,我们可以通过向控制器传递page属性来告诉它我们想要获取列表的哪个页面。但是,我们到目前为止只能静态地这样做,因此我们只能输入1、2、3、…、n等值。在这种情况下,必须动态确定page属性,因为相同的路由与多个页面匹配。
如果我们再次查看路径,我们会看到在第二个段中实际上已经说明了我们想要调用哪个页面。我们只需要通知路由器将此URL段用于page属性。为此,我们有替换字符。
一个替换字符对应于模式?n,因此是一个跟在数字后面的问号。数字指定替换字符与哪个路径段相关。在我们的示例路径表示artikel/#?中,我们因此写"page": "?2",因为第二个路径段包含我们想要放入page属性的信息。路由器现在会识别这个替换字符并将路径段的内容放入属性中。
替换字符不能在所有地方使用,而目前只能在template、identifier、page属性以及作为控制器名称(见第几章)中使用。但是,它也可以在其它字符之间,"template": "seite-?2" 也是有效的。
顺便说一句:在 https://example.org/artikel 的情况下,第二路径段缺失并不成问题。路由器会自动将1作为值放入page属性,如果路径段为空。
模板化
正如之前所述,博客仅使用HTML和内联PHP来创建模板。没有必要学习新的和复杂的模板化语言,最终这些语言将被解析为HTML。
基本规则是”一个路由 - 一个模板”。对于每个路由(即每个不同的页面结构),都应该有一个对应的模板。一个简单的模板可能看起来像这样
<!DOCTYPE html>
<html lang="de">
<head>
<meta charset="utf-8">
<title><?= $site->title ?></title>
<link rel="stylesheet" type="text/css" href="<?= $server->url ?>/resources/css/style.css">
</head>
<body>
<header>
…
</header>
<main>
<h1>Herzlich Willkommen</h1>
<section>
<h2>Neueste Blogeinträge</h2>
<?php foreach($Post->objects as $post){ ?>
<article>
<h3><?= $post->headline ?></h3>
<p><?= $post->author ?></p>
<p><?= $post->teaser ?></p>
<a href="<?= $server->url ?>/posts/<?= $post->longid ?>">weiterlesen</a>
</article>
<?php } ?>
</section>
</main>
<footer>
…
</footer>
</body>
</html>
此模板可能是展示最新博客文章的首页。您已经看到,博客模板其实并不复杂。