uncgits / ccps-core
CCPS 框架核心组件
Requires
- php: ^7.3 || ^8.0
- ext-json: *
- barryvdh/laravel-debugbar: ^3.4
- barryvdh/laravel-ide-helper: ^2.8
- beyondcode/laravel-dump-server: ^1.4
- doctrine/dbal: ^2.9
- facade/ignition: ^2.3.6
- guzzlehttp/guzzle: ^7.0.1
- kyslik/column-sortable: ^6.0
- laravel/framework: ^8.0
- laravel/sanctum: ^2.0
- laravel/slack-notification-channel: ^2.0
- laravel/socialite: ^5.0
- laravel/ui: ^3.0
- lavary/laravel-menu: ^1.7
- livewire/livewire: ^2.0
- mattlibera/livewire-flash: ^0.4
- phlak/twine: ^4.2
- propaganistas/laravel-phone: ^4.2
- pulse00/monolog-parser: ^0.0.4
- santigarcor/laratrust: ^6.0
- socialiteproviders/microsoft-azure: ^4.0
- spatie/laravel-backup: ^6.11
- uncgits/laravel-breadcrumbs: ^5.5
- dev-master
- 3.3.1
- 3.3.0
- 3.2.3
- 3.2.2
- 3.2.1
- 3.2
- 3.1.3
- 3.1.2
- 3.1.1
- 3.1
- 3.0.4
- 3.0.3
- 3.0.2
- 3.0.1
- 3.0
- 2.x-dev
- 2.3.0
- 2.2.2
- 2.2.1
- 2.2.0
- 2.1.2
- 2.1.1
- 2.1.0
- 2.0.2
- 2.0.1
- 2.0
- 1.17.2
- 1.17.1
- 1.17.0
- 1.16.0
- 1.15.1
- 1.15.0
- 1.14.3
- 1.14.2
- 1.14.1
- 1.14.0
- 1.13.3
- 1.13.2
- 1.13.1
- 1.13.0
- 1.12.3
- 1.12.2
- 1.12.1
- 1.12.0
- 1.11.3
- 1.11.2
- 1.11.1
- 1.11.0
- 1.10.1
- 1.10.0
- 1.9.2
- 1.9.1
- 1.9.0
- 1.8.2
- 1.8.1
- 1.8.0
- 1.7.0
- 1.6.3
- 1.6.2
- 1.6.1
- 1.6.0
- 1.5.1
- 1.5.0
- 1.4.1
- 1.4.0
- 1.3.0
- 1.2.2
- 1.2.1
- 1.2.0
- 1.1.1
- 1.1.0
- 1.0.5
- 1.0.4
- 1.0.3
- 1.0.2
- 1.0.1
- 1.0.0
- 1.0.0-rc9
- 1.0.0-rc8
- 1.0.0-rc7
- 1.0.0-rc6
- 1.0.0-rc5
- 1.0.0-rc4
- 1.0.0-rc3
- 1.0.0-rc2
- 1.0-rc1
- 0.6
- 0.5.4
- 0.5.3
- 0.5.1
- 0.5
- 0.4.1
- 0.4
- 0.3.2
- 0.3.1
- 0.3
- 0.2.1
- 0.2
- 0.1.4
- 0.1.3
- 0.1.2
- 0.1.1
- 0.1
- dev-develop
- dev-feature/schema-dump
- dev-feature/testing
- dev-feature/php8
- dev-release/3.0
- dev-feature/tallstack
- dev-bugfix/mailer-env
- dev-bugfix/email-queue-rmb
- dev-release/2.0.1
- dev-bugfix/remove-run-from-notification
- dev-feature/eloquentcrud-trashed-boolean
- dev-release/1.15.0
- dev-hotfix/scheduler-dependency-on-db
- dev-release/1.4.1
- dev-release/1.4.0
- dev-feature/bootstrap-themes
- dev-feature/socialite-4
- dev-hotfix/timezone-fix-successful-jobs
- dev-hotfix/cronjob-meta-tag-blank-overwriting
- dev-feature/horizon-subfolder-shim
- dev-release/1.3.0
- dev-feature/menu-clarifications
- dev-feature/redis-queues
- dev-release/1.2.2
- dev-hotfix/module-index-fix
- dev-hotfix/cronjob-tags-fix
- dev-release/1.2.0
- dev-feature/user-simplification
- dev-feature/azure-avatars
- dev-release/1.1.1
- dev-feature/log-viewer-config-max-file-size
- dev-feature/azure-integration
- dev-release/1.1.0
- dev-release/1.0.5
- dev-release/1.0.4
- dev-release/1.0.3
- dev-release/1.0.2
- dev-release/1.0.1
- dev-feature/datatables
- dev-feature/cli
This package is auto-updated.
Last update: 2024-09-17 23:17:30 UTC
README
本包旨在将 Laravel 8(版本 ^8.0)的新安装神奇地转换为 CCPS 框架,其中包括构建 UNCG CCPS 网络应用程序所需的所有核心功能。
谁负责维护这个包?
UNCG CCPS 开发者团队负责维护此应用程序 - ccps-developers-l@uncg.edu
包含内容
此核心存储库中包含了一些内容,这些内容预计将被用于/包含在基于 CCPS 框架构建的每个应用程序中
- 默认视图、路由、数据库迁移
- 闪存消息
- Guzzle HTTP 客户端
- 面包屑导航
- 菜单
- ACL(角色和权限)与自定义角色映射
- 社交登录(包括 Azure 和 Google 集成)
- 应用程序配置变量(存储在数据库中)
- 日志记录和实时日志查看器
- 应用程序缓存管理(基本)
- 队列/作业管理(数据库驱动程序)
- 电子邮件 - 发送邮件历史记录
- 计划任务和计划任务历史记录
- 备份
- Google Hangouts Chat 通知频道
- Google Hangouts Chat 日志频道
- 用户自定义的频道通知(基于事件)
- 易于支持 Laravel Dusk
- 易于支持 Laravel Horizon 和基于 Redis 的队列
- 内置对 Laravel Sanctum 的简单 API 密钥支持
升级框架
如果您从先前的版本升级到本版本的 CCPS 核心,请参阅 UPGRADE.md
文件中的说明。
版本历史
完整历史记录可在 VERSION.md
文件中查看。
注意:CCPS 核心的 3.0 版本将整个堆栈迁移到远离 Bootstrap 和 jQuery,而是引入了“TALL Stack” - TailwindCSS、AlpineJS、Livewire 和 Laravel。如果您需要继续使用 Bootstrap 4,请使用版本 2.*,或阅读以下内容了解如何自定义视图以远离默认设置。
关于上下文和环境说明
本包旨在在 Docker 容器内部安装,在开发机器上开发应用程序。预期开发将在本地进行,生成应用程序将包含在单独的存储库中,并将其作为整体部署到生产虚拟机(使用相同的 Docker 容器)。所考虑的流程如下
1) 创建一个新的 Laravel 应用程序 2) 安装此包 3) 为您的应用程序初始化一个新的存储库 4) 将更改提交到您自己的远程应用程序存储库 5) 如有需要,使用 composer
更新应用程序元素,因为 CCPS 核心已更新
环境要求
对于本地环境,您需要
- 运行 PHP 版本 ^7.3+ 或 ^8.0 和 Apache 的 Docker 容器
- 运行 MariaDB 10+ 的 Docker 容器
- 可选但很有帮助 - 这两个容器联网(因此您可以在 Laravel 中使用容器名称作为
DB_HOST
) - 访问 MariaDB 容器的数据库(建议使用 Sequel Pro 或其他 GUI 应用程序,但如果您愿意,可以使用命令行)
首次安装
如果您是第一次在新 Laravel 应用程序上安装 CCPS 核心,请继续阅读。
如果您正在将已使用 CCPS 核心构建的应用程序部署到新服务器,请参阅 部署 CCPS 核心 部分
安装前
CCPS 核心可以安装在两种配置之一中
- 到
/var/www/html
目录,如果使用顶级域名访问应用程序(Laravel 框架的官方支持方法) - 例如https://myapp.uncg.edu
- 如果计划使用“子文件夹”方法(通过主机机URL和符号链接访问)指向
/var/www/apps
目录 - 例如https://myserver.uncg.edu/myapp
顶级域名方法
如果你使用的是官方支持的安装方法(顶级域名指向/public/
文件夹)
- 编辑你的机器的
hosts
文件,将新的开发域名解析到127.0.0.1 - 编辑PHP/Apache Docker容器的
vhosts.conf
文件,将其指向你要安装Laravel应用的文件夹中的/public/
目录。例如,假设你使用“myApp”作为应用的名称<VirtualHost *:80> DocumentRoot /var/www/html/myApp/public ServerName myApp.local AllowEncodedSlashes On </VirtualHost>
- 重启PHP/Apache容器,以便重新加载主机配置。
- 按照下面的说明,将新的Laravel应用到容器中的
html
文件夹中。
符号链接/子文件夹方法
如果你使用的是符号链接方法进行安装(子文件夹安装)
- 编辑你的机器的
hosts
文件,确保你的顶级域名解析到127.0.0.1 - 编辑PHP/Apache Docker容器的
vhosts.conf
文件,将该主机名指向/var/www/html
目录。例如,假设你配置应用可通过myserver.local/myApp
访问<VirtualHost *:80> DocumentRoot /var/www/html ServerName myServer.local AllowEncodedSlashes On </VirtualHost>
- 重启PHP/Apache容器,以便重新加载主机配置。
- 按照下面的说明,将新的Laravel应用到容器中的
apps
文件夹中。
安装和初始化CCPS核心
请确保你已遵循预安装部分中的说明来首先设置你的机器。
注意:如果在除了全新Laravel安装以外的其他环境下安装此包可能会产生意外的结果!除非/直到本README中另有说明,请只按照以下步骤在全新Laravel安装上安装CCPS核心包。
- 设置数据库并保留信息 - 安装CCPS核心框架时你需要这些信息。在继续之前,你必须设置数据库,否则安装将失败。
- 登录到容器,并使用
laravel new myApp
在期望的位置(html
或apps
文件夹)安装新的Laravel 6.*应用 - 这比使用laravel new myApp
更受欢迎,因为我们可以指定要使用的Laravel版本。laravel new
将始终拉取最新的稳定版本Laravel。 - 使用
cd
进入应用的目录。 - 编辑
composer.json
以包含下面的存储库。("需要添加的存储库") - 运行
composer require uncgits/ccps-core
来安装此包(它将自动添加到composer.json
中作为需求)。如果你正在安装开发版本,你的命令看起来可能像:composer require uncgits/ccps-core:dev-[branchname]
。从Laravel 5.8开始,不需要在composer.json
中添加minimum-stability: dev
子句,因为它默认包含在内。 - 运行
php artisan ccps:init
并按照提示完成初始化(应用设置)。如果你希望在每一步都有yes/no提示,请添加-p
或--prompt
标志。 - 如果你正在将应用安装到
apps
文件夹(符号链接方法),你需要设置符号链接:ln -s /var/www/apps/myApp/public /var/www/html/myApp
。 - 假设你已经按照预安装部分中正确地设置了hosts文件,那么你已经完成了!导航到你的应用地址,你就可以开始了。
需要添加的存储库
CCPS核心中使用的某些子包不在Packagist上,需要添加到你的应用的composer.json
中(Composer不会从子存储库中读取这些存储库,因此需要手动将它们插入到你的应用中。)
在composer.json
中,你需要添加以下内容
"repositories": [
{
"type": "git",
"url": "https://bitbucket.org/uncg-its/ccps-core"
},
{
"type": "git",
"url": "https://bitbucket.org/uncg-its/laravel-breadcrumbs"
},
{
"type": "git",
"url": "https://github.com/tomhatzer/monolog-parser"
}
],
部署CCPS核心应用
从CCPS Core基础构建您的应用后,如果您想将其部署到测试机器、服务器等,您可以简单地
- 从您的上游仓库拉取它
- 运行
composer install
以获取当前composer.lock
中列出的所有依赖项的依赖 - 运行
php artisan ccps:deploy
- 这将跳过大多数来自ccps:init
的步骤,因为这些更改将提交到您的仓库,但将执行重要的步骤,如将您的.env
文件复制,设置您的应用程序密钥,并运行迁移/种子。您也可以使用--p
或--prompt
标志在这里逐项进行(就像使用ccps:init
一样)。
注意:当使用
ccps:deploy
时,CCPS Core将对数据库迁移执行与传统Laravel略有不同。所有CCPS Core迁移(位于vendor/uncgits/ccps-core/migrations
)将始终在用户和其他包迁移之前运行。请相应地计划您的应用程序迁移。
您还应该确保在部署应用程序后,不要在生产环境中使用DebugBar - 因此,您应该在应用程序的 .env
文件中将 DEBUGBAR_ENABLED
设置为 false
。如果 DEBUGBAR_ENABLED
设置为 true
,则无论 APP_DEBUG
的值如何,都会显示DebugBar。
用法
首次登录
要登录,默认凭据是
- 用户名:admin@admin.com
- 密码:admin
如果您在
ccps:init
或ccps:deploy
期间选择更改它,则初始密码可能不同。
您可以创建更多用户,然后如果您愿意,可以删除原始用户 - 除了作为安全措施外,没有必要保留默认用户。
设置其他认证方法
UNCG官方支持Google和Azure认证,因此您需要将其中之一或两个添加到应用程序中作为接受登录方法,才能使用它们。在应用程序的 .env
文件中,您需要修改 APP_LOGIN_METHODS
变量,并将登录方法设置为 local
、azure
和 google
的组合,用逗号分隔。
local
仅允许本地认证local,azure
允许本地或Azure认证google
仅允许Google认证
您还需要将 APP_ALLOW_SIGNUPS
设置为 true
,以便允许新用户的注册。当然,您还需要填写 SOCIALITE_AZURE_*
或 SOCIALITE_GOOGLE_*
信息,这些信息来自您在Azure或Google环境中创建应用程序时获得的信息。
完成此操作后,用户将能够通过第三方提供商进行身份验证/创建帐户。如果您需要进一步限制对您应用程序的访问,建议通过将 APP_ALLOW_SIGNUPS
设置为 false
,或通过在认证流程中插入其他逻辑(例如 AuthController.php
或通过其他中间件)来禁止新帐户注册。这取决于应用程序开发人员根据需要实现。
登录重定向
默认情况下,应用程序会将未经认证的用户(将收到403错误)重定向到登录页面,然后返回到之前的目标。您可以通过在 .env
文件中添加以下内容来禁用此行为,并显示403错误给这些用户
APP_LOGIN_REDIRECT=false
扩展核心功能
大多数控制器、模型、事件、监听器都提供了一种方式,允许应用程序开发者为自己的需求进行重写。为此,CCPS Core 包(在 vendor
中)包含了具有完整功能的基本类(命名空间为 Uncgits\Ccps\*
),同时也将每个类的版本发布到 App\CcpsCore
命名空间中。在整个 Core 代码中,而不是引用或使用 Uncgits\Ccps\*
命名空间的类,代码使用的是 App\CcpsCore\*
命名空间的类。所有这些发布的类只是简单地 扩展 核心类,没有任何额外的功能 - 因此,它们基本上与核心类执行相同的功能,但可以轻松地添加/覆盖基本类的功能。
例如,Uncgits\Ccps\Controllers\CacheController
类是缓存模块的控制器。假设你想向应用程序的缓存部分添加一个方法,以便你可以更直观地看到缓存当前包含哪些文件。你只需进入 App\Http\Controllers\CcpsCore\CacheController
,添加一个 viewCacheItems
方法,并编写相应的逻辑、路由、视图等。所有核心类的功能将通过继承得以保留,同时你的新自定义方法也将得到实现。
同样,如果你想更改现有方法的工作方式(例如,CacheController@index
),你只需在 App\Http\Controllers\CcpsCore\CacheController
类对象中覆盖它。如果你这样做,请注意原始方法做了什么/提供了什么,并确保你复制它或从子类调用父类方法。
扩展核心视图
默认情况下,应用程序的所有视图都从 vendor/uncgits/ccps-core/src/views
文件夹加载,这是通过扩展 Laravel 在 config/view.php
中搜索视图文件的基本路径来实现的。这意味着,包括 Blade 视图、组件、部分、Livewire 文件等在内的所有视图引用都由 CCPS Core 提供,无需额外发布。
自定义视图
Laravel 提供的视图配置确保首先检查本地 resources/views
文件夹中的任何视图。所以如果你想覆盖 CCPS Core 提供的视图,只需将其副本放在 resources/views
中相同的路径,它就会替换默认视图!同样,这适用于任何 Blade 视图、组件、部分、Livewire 文件等。
视图组件类
版本 3.0 使用 视图组件 进行大多数布局相关框架。其中大部分是匿名的,但一些需要视图组件类来实现额外的功能。这些在 CcpsServiceProvider.php
中单独注册,如果你想要覆盖它们的功能,只需在你的 AppServiceProvider.php
的 boot()
方法中添加以下内容:
\Blade::component('button', \App\View\Components\MyButton::class);
然后运行 php artisan view:clear
,你应该就会使用你的组件类来替换默认组件。
Livewire 组件类
这些与视图组件类完全相同。要覆盖并使用自己的类,只需在 AppServiceProvider.php
中进行相同的更改。
Livewire::component('flash', \App\Livewire\MyFlash::class);
然后运行 php artisan view:clear
,你应该就会使用你的组件类来替换默认组件。
应用程序日志
Monolog / Laravel 日志
CCPS Core 包含一个日志查看器页面,以便更轻松地在屏幕上阅读应用程序日志。
日志很简单,符合 Laravel 文档中列出的可能性。
Log::info('hi there'); // sends to default channel, defined in config/logging.php
Log::channel('general')->info('hi there'); // sends to 'general' channel regardless of default logging settings
Log::stack(['general','slack'])->info('hi there'); // sends to a custom stack of channels regardless of default logging settings
Log::info('hi there', ['stop-crons' => 'all']); // sends to default channel with extra context info (parseable in a Listener, see below)
日志通道
可以通过 Laravel 文档添加通道并进一步自定义间隔和级别 - 配置位于 config/logging.php
。默认情况下,除了 Laravel 核心日志外,安装此包时还将设置以下通道:
general
通道queue
通道cron
通道access
通道database
通道acl
通道notifications
通道备份
通道application-snapshots
通道exceptions
通道
每日日志生存周期
当运行 ccps:init
或 ccps:deploy
命令时,您将被提示输入保留每日日志文件的天数默认值(在 .env
文件中设置 APP_LOG_MAX_FILES
)。
日志事件
当消息写入日志时,Laravel 会触发一个 Illuminate\Log\Events\MessageLogged
类的事件。默认情况下,CCPS 核心附带 PostLogEntry
监听器,但它没有在 EventServiceProvider 中连接(您可以自己完成)。此监听器可以帮助您根据消息的严重性或根据您随日志调用发送的一些上下文信息在该处进行操作。
例如,也许您希望在日志中记录的消息严重性超过某个级别时停止某些应用计划任务。基于上面的示例,您的 Log::
调用可能看起来像 Log::emergency('应用崩溃了!', ['stop-crons' => 'all']);
,在 PostLogEntry
监听器的 handle()
方法的 $event->context
对象将包含一个数组,该数组是 ['stop-crons' => 'all']
。因此,在您的监听器代码中,您可以使用类似以下的方式进行嗅探:
public function handle($event) {
if (isset($event->context['stop-crons'])) {
$cronsToStop = $event->context['stop-crons'];
// other calls here to automatically disable cronjobs
}
}
您在这里的逻辑可能将所有计划任务设置为禁用状态。
默认 CCPS 日志
CCPS 核心包含了对某些事件的日志记录作为其基本功能的一部分。
操作 | 使用的日志文件 |
---|---|
缓存已清除 | 通用 |
应用配置已更新 | 通用 |
队列任务成功 | 队列 |
队列任务失败 | 队列 |
计划任务开始 | 计划任务 |
计划任务结束 | 计划任务 |
检测到过期的锁文件 | 计划任务 |
用户登录成功 | 访问 |
用户登录失败 | 访问 |
用户注销 | 访问 |
未捕获的 QueryException | 数据库 |
用户添加/删除/编辑 | 访问控制 |
权限添加/删除/编辑 | 访问控制 |
角色添加/删除/编辑 | 访问控制 |
备份完成或失败 | 备份 |
备份调试(生成清单和压缩文件) | 备份 |
备份清理完成或失败 | 备份 |
通知系统通知 | 通知 |
应用快照 | 应用快照 |
异常 | 异常 |
将日志记录到 Splunk
截至 2019 年 7 月,CCPS 组(以及作为一个整体的 ITS)使用 Splunk,具体用于数据收集/聚合目的。
因此,在版本 1.7.0 中添加了日志格式化程序,以便日志可以以 Splunk 兼容的 JSON 格式从 Laravel 生成。要将日志记录到 Splunk,请利用 logging.php
中的日志通道的 formatter
键,并将其指向 Uncgits\Ccps\Components\Log\Formatter\SplunkJsonFormatter
。
'splunk' => [
'driver' => 'daily',
'path' => storage_path('logs/mysplunklog.log'),
'level' => 'info',
'formatter' => \Uncgits\Ccps\Components\Log\Formatter\SplunkJsonFormatter::class,
]
为 Splunk 格式化日志
为了有效地将日志发送到 Splunk,您应该使用 \Log::
门面,并将数组作为第二个参数(context
)传递。此 context
数组可以灵活配置,但为了最大效率,请使用以下信息进行格式化:
[
'category' => '', // general category for the event that triggers the log, such as access, acl, cron, queue, etc.
'operation' => '', // what was being attempted / done? - for queues, for instance, success or failure; for model events, for instance, create / update / delete, etc.
'result' => '', // success (operation was successful), failure (operation failed predictably), error (operation failed unexpectedly)
'data' => '', // any relevant data or models (note for models that the output will be an array, and so the $hidden attribute on the model will be honored)
]
这三个键将有助于在 Splunk 中有效地分类发生的事件,以便更容易搜索。如果您愿意,可以传递其他数据;您传递的任何其他键都将收集到最终记录的 JSON 对象中的 other
键中。
异常也将以这种格式记录,其中 event
和 type
键设置为 exception
,Exception 类(以及如果包含则用户 ID)汇总到 data
键。
事件键值
截至版本 1.7.0,CCPS 核心使用以下值作为 category
键:access、acl、auth、cron、email、error、model、notification、queue。
您可以根据需要选择这些值在您的应用程序中挂钩,或者创建自己的值。这完全取决于您希望在 Splunk 中看到数据的方式!
其他功能
计划任务
可以使用 php artisan ccps:make:cronjob MyCronJobName
创建 Cron Job 文件,并在自动生成的类文件中进行配置(位于 app/Cronjobs
)。Laravel 调度器作为执行 Cron Job 的驱动程序使用 - 然而,还有一个额外的层(ccps_cronjob_meta
表)来帮助启用/禁用任务、设置计划等。
注意:
ccps:make:cronjob
在完成后会自动执行composer dump-autoload
。
创建 Cron Job 后,您需要运行 php artisan migrate
以将元数据插入数据库 - 如果不这样做,CCPS 核心将无法识别该任务;它不会运行,也不会出现在 Cron Job 图形用户界面页面。
根据 Laravel 的建议,Web 服务器的 crontab 需要设置为每分钟执行一次 php artisan schedule:run
。
Cron Job 对象
默认情况下,每个 Cronjob 类本身控制一些关于任务的基本数据
class SayHello extends Cronjob {
protected $schedule = '* * * * *'; // default schedule (overridable in database)
protected $display_name = 'SayHello'; // default display name (overridable in database)
protected $description = 'No description provided.'; // default description name (overridable in database)
// etc.
}
如果您想在应用程序的部署中标准化这些事物,可以在类本身上自由设置 $schedule
、$display_name
和 $description
。但是,您可以通过 GUI 在数据库中覆盖这些中的任何一个,并且如果存在,数据库值将优先于类值。
每个 Cronjob 应该返回一个实现 CronjobResultInterface
的对象。默认情况下,这是 Uncgits\Ccps\Helpers\CronjobResult
类。此类接受两个参数:布尔值 $success
和字符串 $message
。截至 CCPS Core 2.0,最佳实践如下
- 如果您的任务成功:
return new CronjobResult(true);
- 如果您的任务以可预测和可接受的方式失败,返回
$success
的值为 false,并提供描述错误的消息:return new CronjobResult(false, 'API 无法访问');
- 这将触发CronjobFailed
事件,并在配置的情况下触发通知。 - 任何未捕获的异常都应被视为 应用程序错误,并应向上冒泡到全局异常处理器进行报告。请谨慎使用
\Exception
或\Throwable
的 catch-all... 通常应允许其发生,因为这代表应用程序错误而不是任务失败。
一般来说,计划一个“正常事件流程” - 包括预期的结果中的幸福路径和不幸福路径。任何在这个范围内的事情都应该一般地返回为 CronjobResult
,而任何超出这个范围的事情都应该留作更大的应用程序问题。
锁定文件
每个 cronjob 在运行时会在 /storage/cron
中生成一个锁定文件。如果此文件存在,Cron job 不会运行,因为锁定文件的目的就是防止 Cron job 覆盖自身。Laravel 的 withoutOverlapping()
方法在一定程度上做到了这一点,但在异常终止的 Cron job 进程后,锁定文件将继续存在。
要清除锁定文件,请访问应用程序中的 Cron Jobs 页面并在 GUI 中进行操作。
如果有锁定文件导致的冲突,将触发 App\CcpsCore\Events\CronLockFileConflict
事件。您可以根据需要覆盖基类(按照标准 CCPS Core 程序),并附加任何您想要的监听器。如果您想将此事件转换为可通知的事件,请阅读以下关于通知系统的文档。
默认 Cron Jobs
CCPS 核心随带多个内置 Cron Job 类
CheckForStaleLockFiles
- 确保cron jobs不会异常终止LogApplicationSnapshot
- 记录应用程序的当前状态(见下文)PurgeExpiredTokens
- 清除过期的 API 令牌RestoreMappedRoles
- 如果使用映射角色组,将映射角色恢复到用户SyncMappedRoleGroupsFromGrouper
- 如果使用Grouper进行此目的,则同步映射角色组
检查过期的锁文件
第一个打包任务是一个健康检查任务,旨在帮助检测Cron Job的锁文件存在时间过长(默认60分钟)。这默认附带一个通知。
如果您想覆盖此Cron Job类的功能,它为此进行了结构化,CCPS Core中的许多其他事物也是如此 - 调用的类是App\Cronjobs\CcpsCore\CheckForStaleLockFiles
,它覆盖了来自vendor
的父类。只需在该类中覆盖父类的execute()
方法即可。例如,如果您想更改检测间隔,您应该可以通过复制粘贴父类中的方法并更改Carbon
类中引用的间隔来更改它。
捆绑的事件(App\Events\CcpsCore\StaleLockFileDetected
)和通知(App\Notifications\CcpsCore\StaleLockFileAlert
)也可以以类似方式覆盖以实现额外的/不同的功能、更改发送到日志/通知的消息等。
记录应用程序快照
第二个打包任务也是一种健康检查,因为它收集有关应用程序的信息,包括:带有远程的应用程序仓库、包要求、已安装的包。这样做的目的是能够快速确定哪些包可能过时,通过自定义脚本(或者可能在Splunk等服务中进行聚合)。
同样,捆绑的Cron Job也可以覆盖,因为它附带了一个应用程序级别的版本:App\Cronjobs\CcpsCore\LogApplicationSnapshot
。
面包屑导航
注意:此包是从
davejamesmiller/laravel-breadcrumbs
分叉的,该包不再维护。其使用可能在CCPS Core的未来版本中发生变化
CCPS Core使用uncgits/laravel-breadcrumbs
包。文档:https://bitbucket.org/uncg-its/laravel-breadcrumbs
每个模块的面包屑都位于模块本身内部。按照包说明,面包屑是通过routes/breadcrumbs.php
加载的 - 如果添加不属于扩展模块的其他面包屑,请将其注册在那里,或者添加一个指令以包含来自文件系统其他部分的单独文件,该文件包含应用程序面包屑。
队列和作业
CCPS Core利用Laravel队列系统进行异步后台任务。具体来说,队列是为电子邮件和API调用设计的 - 这些操作在动作进行时不需要用户关注。CCPS Core相对于标准Laravel的主要增强是队列历史记录。包括四个数据库表 - 一个用于挂起的作业,一个用于成功的作业,一个用于失败的作业,以及一个用于作业批次(在Laravel 8中引入)。
这些项目的多数操作遵循Laravel关于队列和作业的文档,但重要的是要注意,CCPS(目前)依赖于本地数据库进行队列操作。因此,在标准的CCPS .env
文件中,QUEUE_DRIVER
被设置为database
。
最后,CCPS Core默认没有放置任何队列运行机制。因此,可以像Laravel文档中描述的那样正常排队作业,但除非应用程序开发者实现了队列工作者,否则不会运行任何作业。这可以通过开发者认为合适的方式进行(使用Laravel Horizon、Supervisor(从ccps-docker-php-apache
的1.3.0版本开始可用),或者使用Cron Job运行一定数量的单个queue:work
操作等)。
Laravel Horizon
截至1.3.0版本,CCPS Core支持Redis - 但是队列监控部分不会以相同的方式工作。因此,建议使用Laravel Horizon等工具来监控和管理使用Redis驱动器的队列。
Laravel Horizon 本身不支持从 Laravel 的子文件夹安装中运行,因为 Laravel 框架的子文件夹安装既不被官方支持也不被推荐。然而,由于 CCPS Core 提供了一些适配器以能够在子文件夹中运行,并且框架的一个目标就是通过符号链接以这种方式运行,因此 1.4.0 版本引入了一个独立的适配器,以便 Laravel Horizon 3.0 及以上版本能够在子文件夹中运行,而无需修改 Horizon 代码本身。
要快速将 Horizon 与您的 CCPS Core 应用程序一起运行,请执行以下步骤
- 要求 Horizon 3.0 或以上版本:
composer require laravel/horizon
- 运行 Horizon 的必需安装步骤(
php artisan horizon:install
) - 如果您的应用程序运行在子文件夹中:在安装 Horizon 之后,运行 CCPS Core 适配器:
php artisan ccps:horizon:shim
- 如果您的应用程序运行在子文件夹中:在您的
.env
文件中添加HORIZON_SUBFOLDER
的条目 - 这应该列出您的应用程序使用的子文件夹,包括尾随斜杠。例如,如果您的应用程序安装在 "https://myserver.com/my-app",那么您将使用HORIZON_SUBFOLDER=my-app/
。
现在您应该能够通过在 horizon.php
中定义的任何路径访问 Horizon 控制台。
注意:当您升级应用程序并拉入新的 Horizon 版本时,请遵循 Horizon 文档的建议,并使用
php artisan horizon:publish
发布新的 GUI 资产。
访问控制和 GUI 集成
目前,开发者需要自行实现访问控制和 GUI 集成。GUI 集成(例如,点击“队列和作业”项将您带到 Horizon 而不是默认的基于数据库的队列屏幕)应在 config/ccps.php
文件中轻松实现。
然而,对于访问控制,强烈建议至少在 config/horizon.php
文件中应用 permission:queues.*
中间件 - 否则任何人都可以登录并查看 Horizon 控制台及其组件。
手动安装 Horizon 适配器
如果您希望自行安装适配器(手动),请查看此包中的 src/artisan/ShimHorizon.php
文件以了解正在执行的操作,并根据需要更改您的 routes/web.php
和 HomeController.php
文件。基本上,适配器覆盖了通配符 Horizon 路由并将其路由到 HomeController
中的自定义方法,该方法将子文件夹路径注入 Horizon 将使用的 JavaScript 变量。无需更改 Horizon JavaScript 或视图。
电子邮件和电子邮件队列
队列电子邮件
CCPS Core 考虑到将所有发送的电子邮件排队为默认行为。这很有好处,因为 CCPS Core 还有一个单独的电子邮件“队列”或“日志”,它跟踪并记录每个发送的电子邮件。
为确保电子邮件正确排队,请根据 Laravel 文档,在您的 Mailable 类的 __construct
方法中使用以下内容
public function __construct() {
$this->onQueue('email');
}
此外,为确保电子邮件始终排队,即使您调用 Mail::send()
,您的类应实现 ShouldQueue
类(Illuminate\Contracts\Queue\ShouldQueue
),如下所示,根据 Laravel 文档
use Illuminate\Contracts\Queue\ShouldQueue;
class MyMail extends Mailable implemens ShouldQueue {
// etc.
}
遵循此标准可确保所有电子邮件都将通过电子邮件队列运行,并准确记录发送的消息以及发送它的作业。
历史电子邮件日志
CCPS Core 通过挂钩 Illuminate\Mail\Events\MessageSent
事件将发送的电子邮件分别记录在常规队列作业之外。这包括每个电子邮件的原始版本,可以在浏览器中查看。
数据库配置项脚手架
CCPS Core 提供了添加数据库可配置项的机制,这对于向无法访问代码库(因此无法访问 .env
文件)的用户公开配置项非常有用。
该模型是App\CcpsCore\DbConfig
模型。它被设计为与Config模块无缝配合使用,该模块提供一个单页,列出所有正在运行的数据库配置项。如果您想以不同的方式处理,您可以禁用此模块并编写自己的 - 或者添加第二个配置页面,您可以使用模块的流程作为示例(但仍然可以使用底层的DbConfig
模型)。
添加您的配置项
由于CCPS Core默认没有可配置的数据库项,默认视图(发布到resources/views/partials/config-form.blade.php
)仅包含一个段落标签。
要生成您的配置项,只需在resources/views/partials/config-form.blade.php
文件中构建您的表单。提交此表单后(它必须是一个PATCH
请求),除了提交、CSRF和方法字段之外,每个表单字段都将被解析,如果键在数据库中不存在,则创建(如果键在数据库中存在,则更新) - 这种行为是内置在自定义请求对象Uncgits\Ccps\Requests\ConfigUpdateRequest
中的。
验证
与CCPS Core中的许多其他地方一样(见扩展核心功能),预计开发者在开发自己的应用程序时需要编辑某些核心代码以满足他们的需求。这里也是如此,因此App\Http\Requests\ConfigUpdateRequest
类在初始化CCPS Core后发布。
在这里,您可以覆盖rules()
方法,以围绕您将要构建的数据库配置项添加自己的验证规则。
自定义请求处理
同样,您可以选择完全替换App\Http\Requests\ConfigUpdateRequest
类上的persist()
方法,以自己的方式处理请求。
通知系统
1.4.1版本引入了一个专门的模块,允许用户配置何时/何地/关于什么他们将接收通知。这个概念相当简单,主要基于两个主要思想
- 一个
Notification Event
是一个可以生成通知的事件。 - 一个
Notification Channel
是接收这些通知的载体。
当发生一个被归类为通知事件的Event时,配置为“订阅”该事件的任何通道都将接收到相应的通知。用户可以登录,定义自己的通道,并决定最适合他们的流程。
支持的通道类型
目前,CCPS Core支持4种内置通道类型(目前不可扩展):电子邮件、短信(仅限于AT&T、Verizon、T-Mobile、Sprint运营商)、Google Chat webhook和Slack webhook。
入门
最简单的方法是使用命令ccps:make:notification {NotificationName} {EventName}
- 这将为与该系统兼容的通知/事件组合设置所有必需的脚手架。具体来说,它会
- 生成一个完整的脚手架的
Notification
类 - 生成一个具有适当特性和方法的
Event
类 - 生成一个markdown电子邮件草稿(用于'mail'通道)
- 生成一个纯文本电子邮件草稿(用于'sms'通道,因为短信实际上是通过可邮寄的手机号码地址发送的)
- 创建迁移,将新事件添加到
ccps_notification_events
表
将新事件添加到NotificationSubscriber
安装的脚手架的一部分是app\Listeners\CcpsCore\NotificationSubscriber.php
类,它扩展了供应商提供的此文件版本(按照典型的CCPS Core约定)。在此文件中,您需要手动将每个新事件注册到App\Listeners\CcpsCore\NotificationSubscriber@sendNotifications
监听器的subscribe()
方法中。这不是自动完成的,因为这样做可能会在您准备好使用之前将事件暴露给所有用户。
因此,如果您创建了一个名为 SomethingHappened
的事件,您需要确保您的 subscribe()
方法可以读取
public function subscribe($events)
{
$events->listen(
'App\Events\SomethingHappened',
'App\Listeners\CcpsCore\NotificationSubscriber@sendNotifications'
);
parent::subscribe($events);
}
配置您的事件和通知
NotifiesChannels
特性在事件类上定义了一些属性,这些属性有助于将其连接到通知类。这些属性如下:
$notificationClass
- 当此事件被触发时应该触发的通知的类名。$notificationClassArgs
- 通知类接受的参数数组$userIdsToNotify
- 可选参数,用于指定接收通知的用户子集(请参阅下文)
在您开发通知类时,只需记住在必要时返回并更新事件上的这些属性。
在通知事件上设置可通知性
在您的应用程序中,可能存在不同权限的用户应该看到不同的通知选项的情况 - 也就是说,您可能希望管理员能够订阅 TheSystemIsDown
事件,但不是您的最终用户。因此,每个事件都包含一个 public static function canBeNotified()
方法,该方法简单地返回一个 '真值' 来反映您想要使用的任何逻辑。这与 Laravel 的 Gates 的工作方式相似。
在用户设置通知首选项时,将评估这些方法中的每一个,因此,将 auth()->user()->can('something')
或 auth()->user()->hasRole('something')
等内容链接进来可能是一个好习惯。这是一个轻松地将 ACL / 角色 / 权限钩入的地方...或者使逻辑尽可能复杂!如果您愿意,可以传递一个现有的 User
而不是使用当前登录的用户。
修改通知频道设置的用户将只能看到应向他们显示的事件。每个事件在发送时也会进行检查(以防用户订阅后事件代码被更改以禁止其访问),如果有这种“孤儿”配置,则不会发送通知,并将异常记录下来。
请注意,
canBeNotified()
方法的默认结果是简单的true
。
手动选择用户 ID 子集以符合通知条件
相同的事件经常可以用不同的意图或上下文触发 - 例如,当涉及模型时。您希望所有用户都能接收通知,如果他们“拥有”的博客文章收到评论,因此设置一个 CommentAdded
事件是有意义的。然而,如果不区分哪些用户接收通知,这将使用户 A 在用户 B 的帖子收到通知时可能也会收到通知。
因此,您需要在您的 CommentAdded
事件类上设置 $userIdsToNotify
属性 - 在构造函数中为其分配新值,如下所示:
class CommentAdded
{
use Dispatchable, InteractsWithSockets, SerializesModels, NotifiesChannels;
public function __construct(Post $post)
{
$this->notificationClass = NotifyAuthorOfComment::class;
$this->notificationClassArgs = [
'You have a new comment!',
];
$this->userIdsToNotify = [$post->author->id];
}
Laravel Sanctum 的 API 令牌
从 CCPS 核心版本 1.16.* 开始,通过 Laravel Sanctum 可用轻量级 API 令牌功能。该功能的安装和用法遵循记录的流程,并使用户能够管理自己的令牌。它还在表中添加了 expires_at
列,以及一个定时任务,用于手动吊销/销毁过期令牌。
基本用法
默认情况下,只有 admin
角色可以使用 API 令牌。有四种权限:tokens.create
、tokens.edit
、tokens.revoke
和 tokens.admin
。第四种应该保留给应用程序的行政用户,因为它将授予查看和编辑所有令牌的能力。因此,首先确保您的 ACL 已配置为允许您选择的角色与 API 令牌交互。然后,其余的都可以在账户区域中查看和管理。
令牌功能
默认情况下,新令牌不授予任何能力。只要您不在代码中使用$token->can()
语句,这就可以了。然而,如果您想开始对令牌进行范围控制,可以通过ACL模块来实现。在那里,您可以通过简单的文本提示来修改单个令牌的能力。将来可能会以更系统的方式实现这一点,但至少在基本层面上是可能的。
清除过期的令牌
包含的定时任务PurgeExpiredTokens
会定期检查过期的令牌并将它们自动撤销。或者,任何拥有tokens.admin
权限的人都可以手动撤销令牌。
扩展
控制器类已公开,您可以按需覆盖。如果您想覆盖/扩展API令牌功能,您应该能够在典型的CCPS Core风格中做到这一点。
部署脚本
默认情况下,一个基础的deploy.sh
文件包含在您的应用程序基本路径中。该文件包含一些常见的命令,您可以将它们取消注释来构建您的部署脚本。然后可以触发它,在您的应用程序中提供一个一键部署脚本!这也可以忽略,甚至删除,都不会造成影响。
默认情况下,出于安全原因,文件权限不允许文件被执行。您可以自己使用chmod
更改文件,或者根据需要更改Git索引中的文件权限(git update-index --chmod=+x deploy.sh
)。
模型上的可加密特性
版本1.4.1引入了Encryptable
特性,它可以被任何Eloquent模型使用。在模型中,您可以定义一个包含应加密的属性键的protected $encryptable
数组。之后,数据将在保存到数据库之前被加密,并在检索时解密。
注意:对于您加密的字段,请确保您的数据库列足够大,可以容纳加密数据(通常至少为text
类型,但可能需要使用mediumtext
或longtext
,具体取决于列的内容)。一般来说,一个string
字段不足以包含加密数据。
示例
class Subscriber extends Model
{
use Encryptable;
protected $guarded = ['id'];
protected $encryptable = ['home_address'];
与数据库中存储的任何加密数据一样,查询将无法搜索任何加密字段。如果您打算依赖查询搜索大量数据,则不建议加密数据。
MODEL_ENCRYPTION
的.env
值可以设置为false
以覆盖此加密(如果需要)... 然而,请记住,在true
和false
之间来回切换是不推荐的,因为应用程序无法通过查看数据本身来程序化地确定值是否被加密。
映射的角色组
默认情况下,新用户在应用程序ACL中没有角色。一旦用户登录,管理员(或另一个有权限的用户)必须在用户可以采取任何行动之前,在ACL中为新用户授予适当的角色。映射角色组在CCPS Core 1.15中被引入,是一种自动化此步骤的方法。
基本功能
映射角色组定义了一个角色和提供者,以及一组电子邮件地址(角色映射)。当用户登录时,会检查角色映射,如果找到匹配项,则自动将匹配的角色应用于用户。定义映射角色组的最简单方法是使用ad-hoc
设置,在那里您可以手动管理电子邮件地址。
保持角色与角色映射方法同步
角色映射将在用户创建时自动进行,无论什么情况。如果您不希望发生这种情况,您可以覆盖RegisterController
和AuthController
文件中的相应方法,或者简单地创建没有映射角色组。
除了这个之外,CCPS Core在初始检查完成后提供了三种管理应用程序中角色的方法。在你的.env
文件中,你可以将ROLE_MAPPING_METHOD
定义为以下之一
none
(默认)手动管理所有用户和角色login
每次登录时使用映射角色组重新检查用户的角色cronjob
使用RestoreMappedRoles
定时任务按计划管理角色
重要 - 如果你要实现此功能,你必须确保你的管理员用户包含在映射角色组中。如果你不这样做,那么在下一次检查时,这些用户将被锁定!
与Grouper同步
如果你愿意,应用程序可以配置为通过Grouper API(需要Grouper API Laravel Wrapper包,请参阅本README文件的末尾)同步映射角色组。你需要做的是将映射角色组定义为synced
组,并供应组名(包括stem)。然后,当捆绑的SyncMappedRoleGroupsFromGrouper
定时任务启用并运行时,它将更新所有synced
映射角色组的成员资格。
Google Hangouts Chat频道(webhook)
CCPS Core可以通过webhook将任何通知发送到Google Hangouts Chat频道。要这样做
- 从你想要发送到的聊天室获取你的webhook
- 将此webhook插入到你的
.env
文件中的GOOGLE_CHAT_DEFAULT_CHANNEL
条目下 - 使用
php artisan make:notification
创建一个新的通知 - 在通知中,添加
use Uncgits\Ccps\Channels\GoogleChatWebhookChannel;
并在via()
方法中将GoogleChatWebhookChannel::class
添加到你的返回数组中。 - 在你的通知类中实现一个
toGoogleChat()
方法,执行以下操作
return (new GoogleChatMessage)
->content('My message')
->to(config('ccps.google_chat_channels.default'));
你还可以将其抽象出来,在应用程序中配置多个频道。你可以通过创建一个执行此操作的通知类来实现
public $message;
public $webhookUrl;
public function __construct($message, $channel = 'default')
{
$this->message = $message;
$this->webhookUrl = config('ccps.google_chat_channels.' . $channel);
}
然后在config/ccps.php
文件中使用类似的内容
'google_chat_channels' => [
'default' => env('GOOGLE_CHAT_DEFAULT_CHANNEL', null),
'my-channel' => 'http://something.com/otherthing,
],
然后,在实例化你的通知时,将频道作为第二个参数传递:new SomethingHappened('something happened!', 'my-channel')
。这只是一个在应用程序中配置此内容的示例,但频道和消息都已包含在CCPS Core中,因此你可以按需使用它们。
Google Hangouts Chat日志频道(webhook)
除了上面部分的手动通知外,你还可以将Google Chat webhook连接到日志记录器
'google_chat' => [
'driver' => 'custom',
'via' => Uncgits\Ccps\Logging\GoogleChatLogger::class,
'url' => env('MY_GOOGLE_CHAT_WEBHOOK_URL'),
'level' => 'error'
]
url
和level
属性由你配置 - 只需确保driver
设置为'custom',并且via
设置为Uncgits\Ccps\Logging\GoogleChatLogger::class
。
CRUD生成
截至CCPS Core 1.9.0,此包是可选的,必须单独要求。请按照仓库README中的说明进行安装。
CCPS Crud Generator包将提供一种快速部署新CRUD模型的方法。文档可以在包存储库中找到。
如果你想要安装它,请在composer.json
中的repositories
条目中添加以下内容,因为该包不在Packagist上
{
"type": "git",
"url": "https://bitbucket.org/uncg-its/ccps-crud"
}
在CCPS Core中使用CRUD生成器将自动为你提供一个控制器、模型、一组视图、模型的数据库迁移、角色填充器、权限填充器、实现填充器的数据库迁移以及路由。一旦使用CRUD生成器生成模型,开发者就可以根据需要修改任何生成的组件;该包不会保留它生成的CRUD集合的任何知识。
请注意,CCPS Core确实为此包提供了CRUD存根,可以将其适应任何其他你可能选择安装的CRUD生成器。
闪存消息
CCPS Core 1.9.0+使用laracasts/flash包。
在版本1.9.0之前,使用的是standaniels/flash包;然而,由于仓库缺乏活动,Laracasts版本正在替换它。
Guzzle HTTP客户端
CCPS核心包括Guzzle HTTP客户端。
应用程序和数据库备份
CCPS核心利用Spatie Laravel Backup包提供内置的备份功能。请注意,任何打算使用此功能的虚拟机/镜像必须安装mysql-client
库,以便可用mysqldump
二进制文件。
此包的使用说明可以在包主页上找到,但一些CCPS特定项目包括
- 备份和清理过程中每个事件广播的日志记录(通过Laravel日志记录,以及使用已经在CCPS核心中就位自定义监听器)
- 此包的配置文件已作为CCPS核心的一部分发布,并从默认设置修改为关闭自动电子邮件,并且排除备份中的
storage_path()
文件夹。您可以根据需要自由编辑它以适应您的应用程序需求。
可选使用Laravel策略与Laratrust策略
Laratrust包当前“劫持”了Laravel默认策略/门控行为使用的can()
方法。在Laratrust文档中提供了一个解决方案(通过向User
对象添加子句,用默认的替换Laratrust的can()
)。在CCPS核心1.14.2之前,这将导致中断,因为基本User
模型完全使用了LaratrustUserTrait
,因此即使覆盖类中实现正确,解决方案也会失败。
从CCPS核心1.14.2开始,您的基User
模型有两个选项。默认的App\CcpsCore\User
模型(就像以前一样)将扩展完全使用LaratrustUserTrait
的User
模型 - Uncgits\Ccps\Models\User
。然而,还有一个替代方案:Uncgits\Ccps\Models\UserWithPolicies
-此用户实现了解决方案方法,允许使用Laravel策略以及Laratrust(注意,如果您想Laratrust进行检查,则需要遵循文档中的建议并使用hasPermission()
或其他建议,而不是can()
方法)。要使用此功能,更改您的App\CcpsCore\User
模型定义
// use Uncgits\Ccps\Models\User as BaseModel; // OLD
use Uncgits\Ccps\Models\UserWithPolicies; // NEW
class User extends BaseModel
{
// ....
}
最后,提供了一个第三种选项,如果您想“从头开始”而不使用任何策略,则可以扩展此类。此类是Uncgits\Ccps\Models\UserBare
// use Uncgits\Ccps\Models\User as BaseModel; // OLD
use Uncgits\Ccps\Models\UserBare; // NEW
class User extends BaseModel
{
// ....
}
辅助函数
这可以由应用程序开发人员根据需要进行处理。在Laravel应用程序中使用的一个流行约定是在应用程序的某个地方添加一个单独的文件,然后在composer.json
中注册它 - 这里有一个例子:https://stackoverflow.com/a/43243743。此方法的优势在于函数确实是全局的,不需要作为类的一部分来调用。
另一种可用的替代方案是使用辅助类。
当然,两种方法都是可接受的,但CCPS核心不提供任何开箱即用的东西。
存储库模式助手
提供的EloquentCrud
特质(符合内置的EloquentRepositoryInterface
合约)将允许您在存储库类中使用Eloquent(如果您决定要使用存储库模式)。它在上层提供基本的抽象,具有从查询中返回结果集的基本功能。具体细节可以通过查看EloquentCrud
类来了解,但这里在使用EloquentCrud
时有一些值得知道的好事情
- 在存储库上设置
$modelName
(完整类名)以将存储库绑定到Eloquent模型。 - 您可以在类上设置
$searchable
属性,如果您计划提供一些搜索功能(例如基于属性的搜索栏)。您应该按照以下结构进行设置:
public $searchable = [
'filename' => [
'operand' => 'like',
],
'created_before' => [
'operand' => '<',
'column' => 'created_at',
'cast' => 'datetime',
],
'created_after' => [
'operand' => '>',
'column' => 'created_at',
'cast' => 'datetime',
],
'status' => [
'operand' => '=',
]
];
$searchable
中的每个条目至少应包含operand
键,该键应是一个Eloquent兼容的操作符或单词'like'。从那里,如果您需要将请求变量映射到除变量自身名称之外的列,则可以添加column
键。在上面的示例中,表单字段键为created_before
,但需要映射到created_at
列。最后,如果需要将值转换为其他格式,请使用cast
键来完成此操作。截至CCPS Core 1.12.1,此处的唯一可用值是'datetime',它将结果转换为Carbon,正如您所期望的。随着需求的增加,可能还会添加更多选项。
存根和ccps:make
命令
CCPS Core包含多个自定义make
命令,以帮助您搭建和构建应用程序。
计划任务
php artisan ccps:make:cronjob
可以帮助您生成Cronjob类。有关更多使用信息,请参阅计划任务的文档。
升级
php artisan ccps:make:upgrade
可以帮助CCPS Core开发者生成升级脚本。有关更多使用信息,请参阅升级的文档。
ACL生成器/迁移
php artisan ccps:make:acl-seeders
可以帮助您生成生成器种子和数据库迁移,用于创建应用程序的新角色/权限。如果您正在使用CRUD生成器生成整个CRUD数据集,则此命令是多余的。此命令的目的是在您不使用CRUD生成器的情况下提供帮助。要使用它
运行
php artisan ccps:make:acl-seeders MyModel my/package-name
- 插入您的模型名称或生成器/迁移的前缀,并插入您的包名称以帮助在数据库中识别您的ACL项。生成的文件是不完整的,需要在运行数据库迁移之前填充。在您的
database/seeds
文件夹中,您应该更新MyModelRolesTableSeeder.php
文件,以便填充$roles
数组,并在MyModelPermissionsTableSeeder.php
中做同样操作。MyModelPermissionRoleTableSeeder.php
包含一个$rolePermissionMap
,也应填充。最后,在您的
database/migrations
文件夹中应该有一个新的迁移。编辑down()
方法以提供$permissionsToFind
和$rolesToFind
的值,以便down
迁移知道要断开/删除哪些权限和角色。注意,核心(不可编辑)角色将不会被删除,因此您可以将admin
包含在要移除权限的角色列表中。编辑这些项后,您可以使用
php artisan migrate
迁移数据库
通知和事件
php artisan ccps:make:notification
将搭建出通知和事件,以用于CCPS通知系统。有关更多详细信息,请参阅上述通知部分。
服务类
如果您的编码风格使用服务类,您可以使用php artisan ccps:make:service MyClassService
创建一个空的服务类 - 如果它不存在,这将创建app/Services
文件夹。
存储库类
与服务类类似,如果您在编码风格中使用存储库模式,并且希望生成存储库类,您可以使用php artisan ccps:make:repository MyClass
(注意,您提供的是模型名称,而不是完整的类名,如MyClassRepository)。这将生成一个新类在app/Repositories
中,如果它不存在,则创建文件夹。每个存储库通过内置的EloquentRepositoryInterface
通过内置的EloquentCrud
特质实现。
CCPS框架中的模块
CCPS框架的许多“功能”(包括此核心包中的用户、ACL和配置区域)都集成在称为模块
的结构中。模块代表应用的一部分,将被检测并使用一组预设参数进行配置,例如查找面包屑、菜单项、图标、路由、视图等。默认情况下,这些功能无需任何修改即可正常工作。
模块的概念是为了两个主要目的
- 为了便于未来CCPS包的扩展
- 为了使应用开发者能够轻松更改模块的配置,而无需担心修改核心代码或发布过多文件,这将使得未来对核心框架的更新变得困难。
模块配置
config/ccps.php
文件包含一个定义所有模块相关信息的modules
数组。每个条目都通过模块名称进行索引。当安装更多CCPS包以扩展此核心包的基础功能时,用户将负责将模块信息添加到该文件中。
默认情况下,以下是配置文件中模块条目的内容
'users' => [
'package' => 'ccps-core', // the name of the package that this module came from
'icon' => 'fas fa-users', // classing for the icon (FontAwesome) that should represent this module on menus / nav panels / etc.
'title' => 'Users', // the text of this item in Menus and nav panels
'index' => 'users', // the "homepage" for this module
'parent' => 'admin', // for nesting - will control where the module shows up in the site hierarchy. set a parent prefix to use it or set to null, false, or '' to have it show up at root level.
'required_permissions' => 'users.*', // Laratrust permission set that is required to view items in these modules
'use_custom_routes' => false, // set to 'true' and add your own custom routes into routes/web.php or leave as false and inherit default routes
'custom_view_path' => false, // set to the folder where you will put custom views for this module. You will also need to vendor:publish using tag 'module-views' (and move those files to your desired location if you wish).
],
添加模块
要将额外的CCPS模块添加到该列表(从正确构建的CCPS包中),修改此数组以包含新的模块信息,按您希望它在菜单中显示的顺序排列。然后只需复制/粘贴已建立的核心模块结构,确保在package
下添加正确的包名。
模块编写
我应该何时考虑构建模块?
需要注意的是,您不需要将CCPS核心应用的全部附加组件都做成模块。模块被构想为“即插即用”的包,可以在其他CCPS核心应用中重复使用,并包含一些GUI元素。例如,如果您正在构建API库,那么可能不需要将其做成模块;一个普通的composer包即可。然而,如果您正在构建像“应用健康”仪表板这样的东西,您可能希望将其做成模块,因为它可能可以在多个应用中重复使用。
Shell包
可供使用的CCPS Module Shell package
(https://bitbucket.org/uncg-its/ccps-module-shell)可以作为构建自己的模块并将其添加到CCPS核心的起点。克隆它,删除远程仓库,并添加您自己的内容。不要覆盖此仓库!
模块结构
如果您希望将模块作为您包的一部分,以下是一些指南,基于CCPS框架将尝试查找路由、面包屑、视图等的位置。
面包屑导航
面包屑应放在src/breadcrumbs
中,并以模块名称命名(例如,mything.php
)。在内部,面包屑定义必须使用use ($module)
。
您的模块的“index”面包屑应引用其父级为$breadcrumbs->parent($module['parent'] ?: 'home');
您还应该考虑使用命名路由(见以下最佳实践部分),然后您的面包屑定义就相当简单:$breadcrumbs->push("Roles", route('acl.roles'));
但是,如果您决定不使用命名路由,您将需要将$prefix
变量纳入您的定义中(您将使用use ($module, $prefix)
),然后每个其他面包屑在显示应指向的URL时应引用$prefix
变量,如下所示:$breadcrumbs->push("Roles", url($prefix . '/acl/roles'));
路由
路由应放在src/routes
中,并以模块名称命名(例如,mything.php
)。在内部,只需放置您的路由定义。这里不需要做任何特别的事情。再次强调,推荐使用命名路由。
视图
视图可以放置在任何位置,只要你在包的 Service Provider 中定义了 $this->loadRoutesFrom()
指令。你应该包含将视图发布到应用程序的选项,因为这将与模块配置选项中的 custom_view_path
相匹配。
资产(CSS、JS)
默认情况下,CCPS 核心包含了四个构建过程的一部分文件 - ccps-core.scss
和 ccps-core.js
,以及 app.scss
和 app.js
。这些文件已预编译到 public
文件夹中,并且已经与主布局模板相关联。
app.*
文件包含关键的 JavaScript(Alpine.js)和 CSS(Tailwind)。这些文件不再像 CCPS Core 早期版本中那样保留在 ccps-core.*
文件中。主要原因是 TailwindCSS 提供了一个 purge
功能来清除未使用的样式。因此,CSS 的编译目前只包括基本 CCPS Core 应用程序所需的 Tailwind 类。
添加应用程序 CSS 和 JS
您的自定义 CSS 和 JS 应该添加到 app.*
文件中。
为此,还将发布一个默认的 tailwind.config.js
文件到应用程序的根目录,并配置为根据您应用程序 resources/views
文件夹中包含的 Blade 文件进行清除。因此,您在应用程序中选择的任何 Tailwind 类可能无法正确执行,直到您重新编译 CSS;如果您愿意,可以决定从 Tailwind 配置文件中移除 purge
指令以进行开发。
要编译 CSS 和 JS 资产,您需要能够运行 Laravel Mix
- 在您的开发机器上,从容器外部确保您能够运行 Laravel Mix。安装说明可以在 官方 Laravel 文档 中找到 - 需要
node
和npm
。 - 在您的开发机器上,从您应用程序的主文件夹中,运行
npm install
以安装所有必需的依赖和项目模板。 - 根据文档使用 Laravel Mix。不要修改
ccps-core.*
文件,因为它们可能会在未来版本的 CCSP Core 中被覆盖。确保您在项目的/webpack.mix.js
文件中添加了处理指令(该文件已提交到仓库)。 - 准备部署时,只需运行适当的
npm
命令(通常是npm run dev
或npm run production
)即可编译您的资产并将它们放置在正确的位置。当然,您还需要确保在模板文件中的 HTML 中链接了它们。 - 将这些文件提交到您的应用程序仓库,并按正常方式部署。
不需要在生产服务器上运行任何 npm
命令 - 事实上,UNCG CCPS 组使用的 Docker 镜像不包括 npm
。
再次强调,不要将您自己的 CSS 和 JS 添加到
ccps-core.*
文件中,因为它们可能会在 CCPS Core 更新时被未来版本的这些文件覆盖!
使用 Dusk 进行浏览器测试
如果您希望在应用程序中测试 Laravel Dusk,可以像平常一样安装包
composer require --dev laravel/dusk:^3.0
但是,Dusk 需要对 CCPS Core 使用的 Docker 镜像进行一些修改才能运行。这些修改包含在一个第二个安装脚本中。因此,在从 composer 安装包之后,运行
php artisan ccps:dusk:install
此安装程序将 Dusk 资产写入您的 tests
文件夹(因此不需要执行传统的 php artisan dusk:install
),并且还将 Dusk 中的浏览器可执行文件的权限更改,以便可以运行测试。
完成此操作后,请确保您的应用程序的 APP_URL
在您的 .env
文件中设置正确,然后您就可以像平常一样使用 php artisan dusk
运行测试。
升级 CCPS 核心版本
CCPS 核心版本可能会经历大小不一的变更。仅触及 vendor
文件夹内容的微小变更并不会引起太大问题。然而,由于 CCPS 核心版本发布了许多文件,并覆盖了许多 Laravel 默认设置,以便进行 进一步 定制,如果需要更改这些已发布的组件之一,那么前进的道路就会变得更加复杂。
因此,CCPS 核心使用了一个 模块化 的升级系统,该系统模仿了 Laravel 的数据库迁移。当升级涉及影响应用程序文件系统中的文件(而非 vendor
)的变更时,则需要一个 升级脚本。升级脚本是一些 PHP 文件,包含如何修改项目中已发布的文件以使其符合 CCPS 核心变更的说明。
升级脚本是如何工作的?
脚本位于 vendor/uncgits/ccps-core/src/upgrades
。它们像数据库迁移一样带有时间/日期戳。当其中一个脚本成功运行后,将在应用程序文件系统中留下一个签名文件(并且应该与仓库一起提交)- 在 /upgrades
文件夹中。
在运行升级过程时,这两个文件夹将在文件系统级别进行比较(而不是数据库),CCPS 框架将查找 CCPS 核心包中找到的升级文件,而应用程序文件系统中不存在相应的签名文件。对于它找到的每个文件,它都会执行。这个过程允许 CCPS 核心升级“批量”进行 - 例如,您可以从 1.0.1 升级到 1.0.6,并获取该范围内包含的所有升级。
创建新的升级脚本
除非您正在升级 CCPS 核心本身,否则您不需要使用升级脚本。如果这仍然适用于您,那么...
只需从正在工作的应用程序中运行 php artisan ccps:make:upgrade
,您将获得一个可以修改的升级占位符。然后,将其复制到 CCPS 核心代码库的 upgrades
文件夹中,确保其日期设置得当(就像迁移一样,升级将根据日期顺序执行)。
我应该何时进行升级而不是迁移?
如果您正在编写自己的应用程序代码,那么您不需要担心这个问题。然而,如果您正在编写 CCPS 核心代码,您将为需要接触数据库的操作创建 迁移,而为需要接触应用程序文件系统的操作创建 升级。
运行升级过程
在执行升级之前
升级脚本会修改发布到您的应用程序中的文件,而不是 /vendor
文件夹的一部分。因此,升级脚本所做的更改将被包含在提交到您的仓库中。因此,升级脚本应在开发环境中运行,一旦成功,就可以将新的提交推送到应用程序仓库。然后,从生产环境中,您只需要在生产应用程序上执行 git pull
来接收这些更改。
因此,不建议在生产应用程序上使用 ccps:upgrade
。ccps:upgrade
命令将警告您这一点,但您可以坚持使用。
还强烈建议您熟悉 git。首先,确保您与远程仓库保持最新状态,并且工作目录是干净的。如果您有脏文件,请提交或存档它们以稍后重新应用。原因在于升级没有像迁移那样的 up()
和 down()
方法。它们有一个单独的 upgrade()
方法,如果出现问题,您将想要从您的仓库中恢复到应用程序代码的最后一个已知良好版本。
执行升级
注意:您可以跳过以下步骤 2 和 3,改为运行
composer require uncgits/ccps-core:version-number --update-with-dependencies
如果您认为您的应用程序已经充分准备就绪并与远程仓库保持同步,那么您可以
- 登录到容器(如果您不在容器内,这将失败)
- 更新您的
composer.json
文件以指定您希望将哪个版本的uncgits/ccps-core
接入到您的应用程序中。 - 执行
composer update uncgits/ccps-core
将最新的 Core 版本拉入您的应用程序。 - 执行
php artisan ccps:upgrade
(推荐:使用-v
标志以获取详细输出)。此命令将扫描 CCPS Core 应用程序的vendor/uncgits/ccps-core/src/upgrades
文件夹以查找升级文件。它还会搜索您应用程序的/upgrades
文件夹。任何存在于vendor
升级文件夹中但不在应用程序文件夹中的文件都将按顺序执行。 - 执行
php artisan migrate
以执行升级中包含的任何数据库迁移 - 根据 Core 升级更改更新
.env
文件中的任何信息,以确保同步 - 根据
UPGRADE.md
文件执行任何php artisan vendor:publish
操作 - 通过 GUI 或通过
php artisan cache:clear
清除应用程序缓存。 - 测试您的应用程序,当您满意时,提交更改并推送。
注意:某些升级脚本可能需要重启应用程序,以及/或执行
composer dump-autoload
。正确编码的升级文件将自动执行这些操作,或者需要再次运行php artisan ccps:upgrade
。
部署升级后的应用程序
在您的远程服务器上,部署升级的过程应该很简单。您不需要(也不应该)在生产服务器上运行 php artisan ccps:upgrade
。相反,更改已提交到您的存储库,因此过程可能是这样的
- 登录到容器
- 运行
git pull
以获取更新的文件 - 运行
composer install
以根据composer.lock
安装更新的包(不要运行composer update
) 执行
php artisan migrate
- 通过 GUI 或
php artisan cache:clear
清除缓存 - 如果需要,重启 Laravel Horizon 或队列进程(例如:
supervisorctl restart your-process-name
) - 根据需要更新
.env
文件
升级会为我修复所有问题吗?
很可能不会。有一些问题升级脚本无法修复,开发者需要手动修复。UNCG CCPS 开发者团队的目标是提供详细的发布说明(类似于 Laravel 本身提供的说明),以便开发者可以自信地对升级脚本无法涵盖的任何代码更改进行更改。
有关任何手动升级步骤的信息,请检查 UPGRADE.md
。这将描述如何从紧接之前的版本升级到 CCPS Core 的 当前 版本。
最佳实践
命名路由
在 CCPS Core 中,使用了命名路由。这使得开发更加容易和整洁,并且这是应用程序开发人员推荐的约定。使用 url()
助手引用内部应用程序路径是不被推荐的。
数据库事务
Laravel 提供了将数据库操作包装在“事务”中的能力(在 Laravel 文档 中概述)。事务可以与查询构建器(DB
门面)和 Eloquent 一起使用。在基于 CCPS Core 构建的应用程序中的最佳实践是将所有数据库操作包装在事务中。这可以通过 DB::transaction()
方法(如果在抛出异常时将自动回滚)或使用 try
-catch
块的 DB::beginTransaction()
、DB::commit()
和 DB::rollBack()
指令来实现。
数据库“播种”
传统上,Laravel 将“种子”视为用于测试/假数据。然而,CCPS 核心使用种子器来生成实际的生产数据。我们通过数据库迁移来控制数据填充,因此同一种子器不应意外地运行两次。 如果您在开发中使用了种子器来生成假数据,请记住这一点。无论如何,使用 php artisan db:seed
运行时通常应指定一个种子器类,但在使用 CCPS 核心时,务必这样做,以防万一。
话虽如此,在开发自己的应用程序时,请考虑将数据库插入等操作作为迁移的一部分,遵循 CCPS 核心的模式。
CSS 和 JS
使用自己的文件或包含的 app.js
和 app.scss
来添加特定于应用程序的 CSS/JS,而不是向 ccps-core.*
文件添加内容。如果您这样做,您的添加内容可能在 CCPS 核心未来的更新中被覆盖!
推荐额外包
UNCG 主题
响应式 UNCG 网站包装器(Bootstrap 4,非官方) composer require uncgits/uncgtheme-laravel:^1.7
https://bitbucket.org/uncg-its/uncgtheme-laravel
Grouper API Laravel 包装器
围绕 Grouper API PHP 库包的包装器 - 必须同步映射角色群体与 Grouper 群组。 composer require uncgits/grouper-api-wrapper-laravel
https://bitbucket.org/uncg-its/grouper-api-wrapper-laravel
问题、错误、功能添加
所有正在进行的问题都在存储库的 问题跟踪器 中跟踪。