halestar / laravel-drop-in-cms
一个极其简单的内容管理系统,旨在直接集成到现有的laravel项目中。它不对用户和权限做出任何假设,并尽可能多地使用宿主项目的资源。它有插件来添加功能,但它的核心目的是构建页面。初始化
Requires
- php: ^8.2
- intervention/image: ^v3.7
- laravel/framework: ^11.0.0
- livewire/livewire: ^v3.5.4
Requires (Dev)
- phpunit/phpunit: ^11.2
README
DiCMS(简称)
DiCMS 是一个为程序员和需要简单 CMS 的人设计的 CMS,它不会干扰你的工作。大多数 CMS 的一个问题就是它们试图为你做所有的事情。每一个 CMS 都自带权限包、用户包或资产管理等。作为一个网络应用程序程序员,我们构建的大多数应用程序都是内部应用程序。它们带有漂亮的仪表板和可能的用户区域等,但前端通常留作空白,承诺“待填充”
因此,我构建了一个简单的 CMS,具有以下可扩展性目标
- 无用户:系统不会对用户产生困扰。
- 无权限:系统不会自带任何权限系统。
- 代码分离:CMS 应该是一个你可以导入、设置然后集中精力构建你的主页的包。
- 结构胜于形式:这不是一个全面的内容管理系统,让你可以做任何事并构建你梦想中的网页。如果你想要这些,请使用 Word Press,它们有惊人的界面和更多插件。这个 CMS 将是基本的,适用于网站的结构。
- 为程序员打造:这个 CMS 不是为最终用户设计的。它是为程序员设计的,以便他们可以在他们刚刚构建的全新的、令人惊叹的新应用程序的前端快速构建一些内容。
- 安全性是必需的:尽管我们不处理权限或用户,但这并不意味着它们不存在于系统中。系统应该能够通过权限、用户等来保护自己,但它们不应该妨碍你。
目录
功能
我构建这个包的原因是因为我的其他开发应用程序 FormativeLMS,我现在正在构建这个应用程序。这个应用程序主要是一个与已认证用户一起工作的应用程序,前端没有太多的事情发生。我想创建一个简单的博客,详细描述我构建这个框架的挑战和思考过程,并在我的 域名 上托管它。
然而,我遇到的问题是,在 laravel 应用程序中添加前端真的很困难。最简单的解决方案是制作几个静态 HTML 页面,但我想要构建一个博客,所以这就不适用了。我开始寻找博客软件和 CMS 软件,发现它们都带有附加的负担。我最大的不满是它们都有自己的用户或权限系统。我想使用自己的,而不是处理第三方。我只想有 5 个页面,我可以从某处下载一个设计,然后输入一些信息。一个小型博客,我可以输入我的想法,仅此而已。
但这显然太多。所以我开始构建自己的小东西,感觉就像是在重新发明轮子。我不想这么做,我想要一个可以“即插即用”到我的项目中的东西。因此,我列出了一些功能
- 无用户:但允许项目拥有用户。
- 内容管理系统(CMS)分为两部分:内部和外部,为每个部分分配路由,但让应用决定它们的位置。
- 我们需要确保安全性,所以我们使用策略来保护CMS的各个方面,但让应用根据自身需求覆盖它们。
- 一个插件系统来扩展它,第一个插件是博客插件。
- 一个内容编辑器,我可以用它来放置HTML元素。我选择了最优秀的GrapesJS。
- 一个文本编辑器,可以编辑富文本内容。我选择了CKEditor,但我还没有完全信服。
- 拥有多个站点,存档它们并在它们之间切换,在它们之间共享一些资产。
- 非常容易地导出和恢复一切。这需要通过文件、程序化地以及通过 artisan 命令来实现。
- 尽可能减少对宿主应用环境的依赖。加载我们自己的布局并“强制”用户使用它。这样就有了一个明显的应用分离,但可以通过视图编辑进行自定义。前端也是如此。宿主应用可以使用tailwind构建,但这个CMS使用bootstrap,而你正在使用的前端没有使用框架,而是来自俄罗斯网站的一个css,你真的很喜欢。
安装
安装假定你已经有一个Laravel应用,你已经构建或正在设计。也许它有一个认证部分,也许没有。也许你只是开始了一个新的应用,只是运行了ui/auth组件并有一个简单的管理员账户,或者有一个庞大的用户和守卫列表。这都没有关系,首先的事情是将包导入到你的Laravel应用中,执行以下操作:
composer require halestar/laravel-drop-in-cms
接下来,通过以下操作发布供应商文件:
php artisan vendor:publish --tag=dicms
迁移你的表
php artisan migrate
如果你想要使用你自己的策略,但想基于现有的策略,你可以通过以下操作导出所有DiCMS策略:
php artisan vendor:publish --tag=dicms-policies
开始之前要做的最后一件事是配置路由。前往你的主路由文件(在一个正常的Laravel安装中,这将是在routes/web.php
文件)并在文件末尾添加两个条目
Route::prefix('admin')->group(function() { \halestar\LaravelDropInCms\DiCMS::adminRoutes(); }); \halestar\LaravelDropInCms\DiCMS::publicRoutes();
了解这两个条目意味着什么以及如何正确配置它们非常重要。第一个条目设置所有管理路由,即所有管理CMS的路由,都从/admin
URL运行。如果你访问https://yoursite.com/admin
,你应该看到CMS管理的前页,要求你创建第一个新站点。
如果你想要从https://yoursite.com/cms
这样的URL运行它们,你会做如下条目
Route::prefix('cms')->group(function() { \halestar\LaravelDropInCms\DiCMS::adminRoutes(); });
如果你想确保只有认证用户才能访问这个管理站点,你可以将其更改为
Route::prefix('admin')->middleware('auth')->group(function() { \halestar\LaravelDropInCms\DiCMS::adminRoutes(); });
第二个条目告诉系统在哪里显示你构建的CMS网站。如果你没有将其包裹在任何前缀中,那么它将直接显示在网站根目录。这就是为什么要在路由文件末尾放置它,因为它将捕获它下面的所有路由。或者,如果你想让你的应用在https://yoursite.com/front
等URL上显示网站,你可以设置如下条目
Route::prefix('front')->group(function() { \halestar\LaravelDropInCms\DiCMS::publicRoutes(); });
设置好这两个路由后,系统就启动了。你应该首先登录到CMS的管理部分并创建一个新的站点。下面将有关于如何创建第一个新站点的说明。
构建你的第一个站点
您现在已经安装了CMS系统,并且可以访问CMS的管理部分。请注意,如果您尝试访问CMS的前端任何内容,将不会显示任何内容。这是因为我们还没有激活的站点!第一步是创建一个站点。从管理菜单中,点击“创建新站点”按钮,为您的站点输入一个名称以及在窗口中显示的标题。点击创建,让它带您进入新的站点。
这个CMS不是为了创意而设计的,也不允许您做任何想做的事情。如果您正在寻找这样的东西,请去WordPress或者编写自己的静态页面。这个CMS的目的是使内容结构化和逻辑化,以便您可以快速发布内容。
每个站点都附有一些组件,这些组件构成了整个站点。组件包括
- CSS文件:可以是文件、链接或您编写的实际CSS。
- JS文件:运行JavaScript代码的脚本文件。此外,您可以通过链接导入的库。
- 页眉:在每个页面顶部显示的页眉。
- 页脚:在每个页面底部显示的页脚。
- 页面:带有URL的页面列表,用于显示内容。
- 菜单:显示在网站顶部的菜单。
一个站点可以有多个这些组件,但只能有一个设置为“默认”。默认组件将在页面未设置特定组件时接管。创建一个页眉、页脚、菜单,并将一些CSS表单和JS脚本链接到一起以制作一个良好的站点轮廓,然后通过创建页面来填充内容。
一旦您设置了所有这些,请确保激活站点。这将使您的站点“上线”,您可以通过访问前端URL来查看结果。
保护您的CMS
保护您的CMS的关键是双重的,通过路由和通过策略对象。
通过路由保护
在某种程度上,当您安装项目时就已经完成了这一点。只需将管理路由包装在认证部分中,或应用权限中间件,即可保护所有CMS管理路由。您可以通过创建一个自定义中间件来进一步保护,该中间件在提供对管理路由的访问之前将检查权限或用户。这本质上为您提供了粗略的保护。
对于大多数项目,这将是足够的。然而,您可以通过使用策略来使保护更加细致。
通过策略保护
通过策略保护是您可以拥有的最细致的权限保护方法。本质上,CMS使用的每个模型都附有一个策略类,它定义了用户在操作该模型时拥有的权限。DiCMS中的所有模型都有策略,并且所有策略都可以在配置文件中重写。模型和策略的列表可以在config/dicms.php
配置文件中的$policies
数组中找到。它通常看起来像这样
'policies' => [ \halestar\LaravelDropInCms\Models\Site::class => env('DICMS_SITE_POLICY', \halestar\LaravelDropInCms\Policies\SitePolicy::class), \halestar\LaravelDropInCms\Models\Header::class => env('DICMS_HEADER_POLICY', \halestar\LaravelDropInCms\Policies\HeaderPolicy::class), \halestar\LaravelDropInCms\Models\Footer::class => env('DICMS_FOOTER_POLICY', \halestar\LaravelDropInCms\Policies\FooterPolicy::class), \halestar\LaravelDropInCms\Models\CssSheet::class => env('DICMS_CSS_SHEET_POLICY', \halestar\LaravelDropInCms\Policies\CssSheetPolicy::class), \halestar\LaravelDropInCms\Models\JsScript::class => env('DICMS_JS_SCRIPT_POLICY', \halestar\LaravelDropInCms\Policies\JsScriptPolicy::class), \halestar\LaravelDropInCms\Models\Page::class => env('DICMS_PAGE_POLICY', \halestar\LaravelDropInCms\Policies\PagePolicy::class), \halestar\LaravelDropInCms\Models\Menu::class => env('DICMS_MENU_POLICY', \halestar\LaravelDropInCms\Policies\MenuPolicy::class), ],
数组的左侧是模型,例如站点或页面,右侧是附加到其上的策略。默认策略非常宽容,允许用户做任何事情。然而,您可以通过创建自己的策略并覆盖它来更改这一点。
例如,让我们看看\halestar\LaravelDropInCms\Models\Site
模型。这个模型是站点的表示。我们看到它附加了类\halestar\LaravelDropInCms\Policies\SitePolicy
。查看这个类,定义很简单
class SitePolicy { /** * Determine whether the user can view any models. */ public function viewAny(User $user = null): bool { return true; } /** * Determine whether the user can view the model. */ public function view(User $user = null, Site $site = null): bool { return true; } /** * Determine whether the user can create models. */ public function create(User $user = null): bool { return true; } ...
您可以立即看到这个策略中的所有函数(实际上,所有策略)都返回true,这意味着权限被授予。因此,创建站点总是被所有人允许。但是,如果您想改变这一点怎么办?如果您想使站点的创建仅对具有特定权限的用户可用呢?我们可以扩展SitePolicy类并更改它为
class MySitePolicy extends \halestar\LaravelDropInCms\Policies\SitePolicy { public function create(User $user = null): bool { return $user->can('create sites'); } }
然后我们更改策略的配置
'policies' => [ \halestar\LaravelDropInCms\Models\Site::class => env('DICMS_SITE_POLICY', \App\Policies\MySitePolicy::class), ... ],
或者,我们可以在.env
文件中添加一个环境变量
DICMS_SITE_POLICY=\App\Policies\MySitePolicy::class
现在,只有正确的用户才能创建站点。
您可以在系统中发布所有策略,然后通过执行以下操作对它们进行随心所欲的调整:
php artisan vendor:publish --tag=dicms-policies
备份你的 CMS
有3种方式来备份您的CMS。备份意味着,从版本0.4.0开始,是数据库结构的字符串或文件表示,然后可以将其提供给恢复方法。
通过程序
可以通过实例化对象halestar\LaravelDropInCms\Models\SystemBackup
来以编程方式备份站点,如下所示:
// This will actually generate a backup instance. So long as // this object persist in memory, you have a snapshot of your // database at the time this command is executed. $backup = new SystemBackup(); // to access the backup data, get it by doing: $backupData = $backup->getBackupData(); // $backupData now has a string containing all the information // in your database
然后,您可以通过将其传递给halestar\LaravelDropInCms\Models\SystemBackup
作为静态函数来使用该数据以恢复它,如下所示:
SystemBackup::restore($backupData);
您的网站数据库现在已恢复。
通过Web
您可以通过访问DiCMS安装的CMS管理站点并选择备份菜单选项来在Web上备份和恢复您的网站。从那里,您将获得一个页面,允许您下载一个备份(命名为backup.json),或选择您之前导出的文件以恢复网站。
通过Artisan
您可以通过Artisan命令来备份和恢复网站。使用
php artisan dicms:backup-cms
您可以使用可选的--file=file_out.json
选项将备份保存到文件。要恢复网站
php artisan dicms::backup-cms --file=file_out.json
这将加载file_out.json
文件中的数据并恢复您的网站
计划备份
由于该项目主要针对想要展示项目的开发者,它被设计成易于在数据库擦除中生存。
例如,假设您在应用程序中有一个供人们玩耍的演示,您不会给他们访问CMS(通过策略)的权限,您希望每晚擦除并重新填充数据库。您可以在调度器中调用此函数每晚执行此操作
public function cleanUpDb() { // save the cms data. $cmsSave = new SystemBackup(); $cmsData = $cmsSave->getBackupData(); // refresh the db, and seed it since it will probably have demo data $this->call('migrate:fresh', ['--seed' => true]); // restore the CMS data $cmsSave->restore($cmsData); // Optimize some stuff $this->call('optimize:clear'); $this->call('optimize'); }
插件系统
DiCms有一个插件系统!
为什么您可能想知道?因为我想添加一个博客机制,但这会复杂化这个系统的发展。我想保持它所做的事情简单。唯一的方法就是使其可扩展。因此,默认内置了插件支持,并且第一个插件DiCmsBlogger被创建,以向DiCms添加博客组件,并解释如何创建插件。
如果您对创建插件感兴趣,请访问DiCmsBlogger GitHub页面,其中将包含有关如何构建插件的说明。
通往 1.0 版本的路线图
在撰写本文时,此软件包不是我视为“发布”的内容。我的计划是在所有功能都构建完成后正式发布为v1.0。此处空间旨在详细说明我认为发布v1.0所必需的功能和升级。
这些要求可能会改变(实际上,最有可能),我将在构建东西时划掉它们。
以下功能需要实现才能发布v1.0
- 需要添加评论。这里文档和配置评论。
- 用户界面需要彻底翻新。它非常丑陋,需要更新。
系统需要能够通过API和Artisan命令以编程方式备份使css和js脚本可重新排列- 存档和取消存档网站
- 启用预览
为图像等提供更好的资产支持提供更好的编辑器支持- 对GrapesJs进行大量定制
- 确保它在移动设备上看起来不错
- 向所有具有策略钩子的模型添加REST API
升级插件系统,允许从主页定制CSS/JS脚本、页眉和页脚。- 以图片形式说明如何创建一个简单的网站。
- 通过压缩、创建SHA等使备份更安全。
- 提供一个示例备份文件,该文件将构建默认网站。
- 为其他类型的设置机制添加替代方案,例如Redis。
为用户添加可发布的策略,方便扩展。可能通过Artisan命令实现。创建一个资产存储管理系统,用于集中式、共享管理。也许是一个插件?- 复制网站。
- 更新README文件,包括更好的说明,并定义路线图以包括版本里程碑。
此列表可能还会添加其他事项,或删除某些事项。