Laravel 博客开发|导入 md 博客文章
我的早期博客采用 Hugo 和 GitHub 开发,并创作了超过 50 篇早期博文。现采用 Laravel 与 Bulma 进行重构。A new blog 的内容存储在数据库中,而 my old blogs were in Markdown format.我想保留我的 previously written blog posts,但 without manually importing each file individually,所以我因此要求一个程序化的解决方案来实现将这些文件导入并保存到数据库中。
md 文件示例:
欢迎来到从零开发个人博客日志的第 6 天,这个系列涵盖了我在公众场合从零开发个人博客应用的旅程,这是一个大胆的尝试。如果你错过了第 5 天,可以在[这里查看](https://www.sevdot.com/post/blog-development-from-zero-five-day)。
## 进度
目前整个博客应用的功能已经开发完,接下来打算整理整理发布上线,这一刻还是挺开心的,在业余时间开发了一个小项目,并且全程写博客记录。
能够清楚看出,在博客文章中,标题、日期以及分类信息位于两个 -- 之间作为 YAML 格式的标记语言内容;而外部的部分则是博客文章正文的主要内容。
现在的文本已经按照要求进行了同义改写
- 将所有的.md文件打包成一个.zip文件。
2. 将zip文件上传至平台,并完成解压操作。
3. 解析解压后生成的所有.md文件内容。
4. 对每一个解压得到的.md文件进行详细解析。
5. 根据解析结果生成相应的文章内容。
上传 zip 文件
1. 添加表单
运行如下命令创建上传文件表单:
php artisan admin:form ImportArticleForm
替换为如下内容:
app/Admin/Forms/ImportArticleForm.php
<?php namespace App\Admin\Forms;
use Dcat\Admin\Widgets\Form;
class ImportArticleForm extends Form
{
public function handle(array $input)
{
return $this->response()->success('导入成功')->refresh();
}
public function form()
{
$this->file('zip','压缩包')->required();
}
}
3. 添加动作
运行如下命令添加动作:
php artisan admin:action
Which type of action would you like to make?:
[0] default
[1] grid-batch
[2] grid-row
[3] grid-tool
[4] form-tool
[5] show-tool
[6] tree-row
[7] tree-tool
从选项中选择 grid-tool(选项),然后在名称字段中填入 ImportArticleAction ,替换为以下路径:import_article_action_path = `app/Admin/Actions/Grid/ImportArticleAction.php;`
<?php namespace App\Admin\Actions\Grid;
use App\Admin\Forms\ImportArticleForm;
use Dcat\Admin\Grid\RowAction;
use Dcat\Admin\Widgets\Modal;
class ImportArticle extends RowAction
{
/** * @return string
*/
protected $title = '导入文章';
public function render()
{
$form = ImportArticleForm::make();
return Modal::make()
->lg()
->title($this->title)
->body($form)
->button('<button class="btn btn-primary">导入文章</button>');
}
}
3. 修改控制器
修改管理后台文章控制器,在 grid方法添加如下内容:
app/Admin/Controllers/ArticlesController.php
$grid->tools(function ($tools) {
$tools->append(new ImportArticleAction());
});
在打开文章管理界面时,你会注意到出现了一个导入新文章的按钮。单击该按钮将触发显示一个新的对话框。

完成文件选择后, 点击上传按钮将被成功地上传到指定目录 storage/app/public/files 下.
解压 zip 文件
在 ImportArticleForm.php$import_form 中注册一个名为 extract 的新方法。
.
.
.
public function extract($file){
$zipper= new \ZipArchive();
$zipper->open($file);
$targetPath=storage_path('app/public/blog');
$zipper->extractTo($targetPath);
$zipper->close();
return $targetPath;
}
.
.
.
上面的代码是将指定的压缩文件解压到指定的目录。
在 handle 方法中调用:
.
.
.
public function handle(array $input)
{
$file=Arr::last(explode(',',$input['zip']));
$filePath=storage_path('app/public/').$file;
$blogPath=$this->extract($filePath);
return $this->response()->success('导入成功')->refresh();
}
.
.
.
批量创建文章
运行如下命令安装扩展:
composer require symfony/yaml
为 $ImportArticleForm.php$ 表单新增一个 $batchAddArticle$ 方法
public function batchAddArticle($path){
$files = File::files($path);
foreach ($files as $key=>$file){
$content = $file->getContents();
preg_match_all('/---\n(.*?)---\n/s',$content,$yamlArr);
$yaml = $yamlArr[1][0];
$meta=Yaml::parse($yaml);
$datetime=date('Y-m-d H:i:s',$meta['date']);
$category=Arr::last($meta['categories']);
$column = Column::firstOrCreate(['name'=>$category]);
$articleContent=str_replace($yamlArr[0],'',$content);
Article::create([
'column_id'=>$column->id,
'title'=>$meta['title'],
'content'=>$articleContent,
'created_at'=>$datetime,
'updated_at'=>$datetime,
]);
}
}
上面的代码逻辑:
上文已将 zip 压缩包解压至指定路径。通过调用 File::files() 函数可检索该目录下的所有文件,并以数组形式返回。
$files = File::files($blogPath);
- 遍历文件数组,使用
getContents方法得到文件内容。
$content = $file->getContents();
- 获取两个
---里面的 YAML 格式的内容。
preg_match_all('/---\n(.*?)---\n/s',$content,$yamlArr);
$yaml = $yamlArr[1][0];
- 使用
symfony/yaml扩展解析 YAML 格式的内容。
$meta=Yaml::parse($yaml);
解析后会返回一个数组,如下所示:
array:4 [
"title" => "Laravel 博客开发|Laravel 项目中安装和使用 Bulma"
"date" => 1650565800
"lastmod" => 1650565800
"categories" => array:1 [
0 => "开发日志"
]
]
- 组装数据并创建博客文章:
Article::create([
'column_id'=>$column->id,
'title'=>$meta['title'],
'content'=>$articleContent,
'created_at'=>$datetime,
'updated_at'=>$datetime,
]);
在 handle 方法中调用:
public function handle(array $input)
{
$file=Arr::last(explode(',',$input['zip']));
$filePath=storage_path('app/public/').$file;
// 解压
$blogPath=$this->extract($filePath);
// 批量创建文章
$this->batchAddArticle($blogPath);
return $this->response()->success('导入成功')->refresh();
}
经过上面的处理过程,我们能够轻而易举地将之前的Markdown文件中的文章导入到现有的博客环境中
