Snipe-IT 服务提供者开发指南:在 Provider 中注册验证规则与模型观察者
后端企业应用【免费下载链接】snipe-itA free open source IT asset/license management system项目地址https://gitcode.com/GitHub_Trending/sn/snipe-it点击查看免费下载本篇指南聚焦 Snipe-IT开源 IT 资产/授权管理系统中app/Providers/**目录的开发约定详细讲解如何通过ValidationServiceProvider注册命名验证规则以及如何在AppServiceProvider::boot()中挂载模型观察者。读完本文你将掌握 Snipe-IT 自定义验证规则的完整链路Provider 注册 → 模型$rules引用 → 控制器/表单校验触发并理解观察者注册方式与项目约定的边界为什么禁止在模型上使用#[ObservedBy]属性、为什么通用规则不能放进app/Rules。一、app/Providers目录的职责划分app/Providers存放 Laravel 应用级服务提供者。在 Snipe-IT 中这些 Provider 各自承担明确的引导职责本文涉及的两种核心模式分别由两个 Provider 承载Provider职责ValidationServiceProvider注册所有命名验证规则Validator::extend()/extendImplicit()闭包AppServiceProvider在boot()中挂载模型观察者、配置分页器与视图组件等目录下的其他 Provider如 AuthServiceProvider、EventServiceProvider、RouteServiceProvider 等分别负责权限策略绑定、事件监听注册与路由加载本文不展开。二、命名验证规则统一注册在 ValidationServiceProviderSnipe-IT 的约定是新增的命名验证规则一律以Validator::extend()或extendImplicit()闭包的形式写在 ValidationServiceProvider.php 的boot()方法中随后即可在模型或表单请求的$rules数组里以字符串形式直接引用该规则名。2.1 基本注册模式规则闭包接收 Laravel Validator 传入的标准四个参数$attribute被校验的字段名$value被校验字段的当前值$parameters规则字符串中冒号后以逗号分隔的参数数组$validator当前的 Validator 实例可通过$validator-getData()读取同一次请求中的其他字段以email_array为例它校验逗号分隔的收件人列表是否全部是合法邮箱Validator::extend(email_array, function ($attribute, $value, $parameters, $validator) { $value str_replace( , , $value); $array explode(,, $value); $email_to_validate []; foreach ($array as $email) { $email_to_validate[alert_email][] $email; } $rules [alert_email.* email]; $messages [ alert_email.* trans(validation.custom.email_array), ]; $validator Validator::make($email_to_validate, $rules, $messages); return $validator-passes(); });可以看到闭包内部把用户输入拆分为数组后用内置的email规则逐项校验并把错误消息映射到validation.custom.email_array翻译键。2.2 什么时候用extendImplicit()fmcs_company的启发Laravel 默认会跳过字段为空null/缺失时的显式扩展规则因此如果某条规则必须在空值提交时也要触发就必须用Validator::extendImplicit()注册这和内置的required、filled、accepted使用隐式规则是同一原因。源码中fmcs_company就是典型例子——它的职责正是严格多公司模式FMCS下有公司归属的非超级管理员必须选择一个公司不允许提交空值Validator::extendImplicit(fmcs_company, function ($attribute, $value, $parameters, $validator) { $settings Setting::getSettings(); if (! $settings-full_multiple_companies_support) { return true; } if ((bool) $settings-null_company_is_floater) { return true; } if (! empty($value)) { return true; } if (! auth()-check()) { return true; } $actor auth()-user(); if ($actor-isSuperUser()) { return true; } if (! $actor-companies()-exists()) { return true; } return false; });它的通过条件覆盖了完整场景FMCS 关闭、允许浮动空公司、表单已填值、CLI/Seeder 等无认证上下文、超级管理员、无公司归属用户在空伪公司命名空间合法操作。规则同时在Validator::replacer(fmcs_company, ...)中把:attribute替换为公司的翻译文案。2.3 用Validator::replacer()美化错误消息当需要把规则参数嵌入翻译后的错误消息时可以像two_column_unique_undeleted那样注册一个replacerValidator::replacer(two_column_unique_undeleted, function ($message, $attribute, $rule, $parameters) { $message str_replace(:table1, $parameters[0], $message); $message str_replace(:table2, $parameters[2], $message); // Change underscores to spaces for a friendlier display $message str_replace(_, , $message); return $message; });三、常用内置命名规则与参数速查下面按源码中 ValidationServiceProvider.php 的实际实现整理项目中最常用、可直接复用的命名规则及其参数约定。3.1 软删除场景下的唯一性规则Snipe-IT 大量使用 Laravel 软删除deleted_at。内置unique规则无法区分已删除记录与现存记录会导致重复数据无法重新创建因此项目提供了一整套配套规则规则名参数语义源码注释unique_undeleted:table,field表名、字段名仅在与现存未删除记录比较时保证唯一见$rules中大量使用如asset_tag unique_undeleted:assets,asset_tagexists_undeleted:table,column表名、列名默认id校验值指向的行的确存在且未被软删除用于用户输入 ID 的查找如 checkout 目标用法exists_undeleted:users,idunique_undeleted_in_scope:col1,col2,...作用域列名列表在兄弟节点范围内唯一支持树形表与 FMCS 公司内唯一NULL 按标准 SQL 语义自成桶模型侧只需写name unique_undeleted_in_scope:parent_id,company_idtwo_column_unique_undeleted:other_col另一列名两列组合唯一参数自动由 Trait 补齐表名与 ID见下节unique_undeleted内部还含有一个资产序列号的专门分支当校验的是assets.serial且系统设置unique_serial ! 1时直接放行Asset.php 中serial nullable|string|unique_undeleted:assets,serial。模型中的实际用法来自源码Asset.phpasset_tag [required, min:1, max:255, unique_undeleted:assets,asset_tag, not_array]Category.phpname required|min:1|max:255|two_column_unique_undeleted:category_typeCompany.phpname required|max:255|unique_undeleted_in_scope:parent_idtwo_column_unique_undeleted的参数补全依赖 UniqueUndeletedTrait 与 TwoColumnUniqueUndeletedTrait它们会把表名和当前记录 ID 自动前置到规则字符串中所以模型侧只需声明需要参与唯一约束的业务列。3.2 树形结构 / 父子关系规则Location.parent_id、Company.parent_id这类自引用字段需要防止环与深度失控项目按场景拆成多条规则各自给出可读的错误消息规则名语义non_circular:table,pk[,depth]沿父链向上追溯禁止任一祖先等于自身主键depth默认 50防止无限循环parent_must_be_top_level:table,pk被选父节点本身必须是顶级节点其parent_id为 NULL防止层级超过 1 层must_have_no_children:table,pk仅更新时生效如果当前行已有子节点则不允许给它再指定父节点parent_within_scope校验调用方有权限把行迁移到新父节点下按公司作用域比对防止越权改parent_id扩大作用域parent_matches_location_companyFMCS 下Location 的父级必须与子级属于同一公司阻断 GHSA-jmrm-535m-cx3c 类跨租户写入Location.php 的完整组合示例parent_id nullable|exists:locations,id|non_circular:locations,id|parent_matches_location_company,Company.php 的完整组合示例parent_id nullable|integer|exists:companies,id|parent_must_be_top_level:companies,id|must_have_no_children:companies,id|parent_within_scope,3.3 FMCS多公司支持相关规则多公司严格模式full_multiple_companies_support下各业务模型Accessory、Asset、Component、Consumable、Location 等的company_id/location_id普遍链式声明了company_id integer|nullable|exists:companies,id|fmcs_company, location_id exists:locations,id|nullable|fmcs_location,fmcs_company严格模式下强制有公司归属的用户提交非空公司隐式规则见 2.2。fmcs_location当scope_locations_fmcs开启时校验被引用的 Location 的有效公司归属沿父链追溯effectiveFmcsCompanyId()必须落在请求提交的company_id/company_ids作用域内无公司上下文时放行。注意源码中这两条规则都通过withoutGlobalScopes()绕过CompanyableScope查找真实记录——否则作用域会把外部租户的记录隐藏成不存在反而放行了跨租户写入。3.4 自定义字段与表单校验规则Snipe-IT 允许管理员自定义字段并配置正则与选项Provider 中也提供了配套校验valid_regex校验自定义字段里配置的regex:... 字符串在preg_match下不会抛异常仅验证可编译不验证语义。checkboxes/radio_buttons校验提交的多选值/单选值确实存在于 CustomField 定义的选项列表中兼容逗号分隔字符串的旧式提交。not_array拒绝数组值如 Asset.php 中model_id、asset_tag上使用。3.5 用户安全相关规则cant_manage_self禁止用户把自己的id设为manager_id自己当自己的上级。disallow_same_pwd_as_user_fields密码不得与username、email、first_name、last_name相同。letters/numbers/case_diff/symbols密码复杂度检测分别校验字母、数字、大小写混排与符号使用 Unicode 属性正则\pL、\pN等。3.6 其他is_unique_across_company_and_location跨company_idlocation_id双作用域唯一目前用于 Department.phpname required|string|max:255|is_unique_across_company_and_location:departments,name。错误消息通常挂在lang/*/validation.php的custom键下便于多语言覆盖。四、app/Rules的边界只放加密自定义字段规则对象项目明确规定app/Rules目录是加密自定义字段规则对象的专属领地禁止把通用规则对象放进去。查看 app/Rules 目录可见其成员具有明显的一致性——AlphaEncrypted、BooleanEncrypted、CssColor、DateEncrypted、EmailEncrypted、IPEncrypted、IPv4Encrypted、IPv6Encrypted、MacEncrypted、NumericEncrypted、RegexEncrypted、UrlEncrypted、ValidJson、AllowedUploadExtension、ExternalUrl等它们都服务于加密存储的自定义字段的加密后校验需求。这里的取舍逻辑很清晰通用、可复用的业务规则唯一性、树形结构、FMCS 作用域等→ 以闭包形式集中在ValidationServiceProvider字符串规则名在模型$rules中即写即用无需实例化对象。依赖具体加密算法/字段类型的规则加密字段的值必须能解密、格式正确→ 实现为独立的 Rule 类对象Rule::class或new XxxEncrypted()形式使用放在app/Rules。顺带一提UniqueUndeleted.php 也位于该目录它是加密字段默认值场景下对unique_undeleted规则的对象化封装与 Trait 提供的字符串形式互补。五、观察者注册统一放在 AppServiceProvider::boot()项目约定模型观察者通过Model::observe(ModelObserver::class)在 AppServiceProvider.php 的boot()方法中显式挂载禁止在模型类上使用 PHP 8 的#[ObservedBy]属性。当前源码中的完整注册块AppServiceProvider.phpAccessory::observe(AccessoryObserver::class); Asset::observe(AssetObserver::class); AssetModel::observe(AssetModelObserver::class); Component::observe(ComponentObserver::class); Consumable::observe(ConsumableObserver::class); License::observe(LicenseObserver::class); Location::observe(LocationObserver::class); Maintenance::observe(MaintenanceObserver::class); Setting::observe(SettingObserver::class); User::observe(UserObserver::class);对应的观察者实现位于 app/Observers如 AssetObserver.php、UserObserver.php各自监听模型的created/updated/deleting等事件用于维持库存快照、日志记录、关联校验等副作用。统一在 Provider 挂载的优势在于所有观察者注册点集中可见升级/排查时只需检查一个文件同时避免#[ObservedBy]属性与代码库中广泛存在的动态模型扩展、软删除作用域交互时产生意外行为。六、AppServiceProvider 的其余引导工作同文件内的常见约定虽然观察者挂载是boot()的核心但同文件中还包含几项 Snipe-IT 部署时常被问到的引导逻辑一并说明以便理解该文件的完整上下文强制 HTTPS当APP_URL以https://开头或设置了APP_FORCE_TLS时调用$url-forceScheme(https)若未设置APP_ALLOW_INSECURE_HOSTS则用URL::forceRootUrl()固定根 URL防止 Host 头伪造配置异常时输出APP_URL相关的错误日志AppServiceProvider.php。分页器Paginator::useBootstrap()使用 Bootstrap 风格分页。视图组件为layouts.default和partials.impersonation-banner绑定 SidebarComposer 与 ImpersonationBannerComposer。Schema 默认长度Schema::defaultStringLength(191)兼容 MySQL 旧索引长度限制。Http 客户端宏为HttpClientResponse注册throwIfNotJson()宏当同步适配器请求返回非 JSON 内容如误指向供应商 Web 控制台的 HTML 页面时抛出 SyncAdapterVendorException避免Sync complete. 0 hosts, 0 errors式的静默失败。register() 条件注册本地环境注册 Telescope生产环境且配置了 Rollbar token 时注册 RollbarServiceProvider并单例绑定自定义 SCIM 配置 SnipeSCIMConfig 覆盖默认 SCIM 行为AppServiceProvider.php。七、从规则到校验触发一条完整的调用链理解了注册约定后把整条链路串起来便于在实际开发中定位问题注册ValidationServiceProvider::boot()里Validator::extend(xxx, ...)将规则名注册进 Laravel 验证器。声明模型$rules如 Asset.php、Category.php或表单请求类app/Http/Requests中以字符串规则形式引用如unique_undeleted:assets,asset_tag带参数的规则依赖 UniqueUndeletedTrait 等 Trait 自动补齐表名与 ID。触发控制器调用模型校验或$request-validate()时Laravel 按规则字符串执行闭包$validator-getData()让规则能够读取同表单的其他字段如parent_must_be_top_level读取主键、fmcs_location读取company_id。消息校验失败时Validator::replacer()负责把参数渲染进validation.custom.*翻译字符串用户看到可读的错误提示。八、开发约定速查清单新命名验证规则 →Validator::extend()/extendImplicit()闭包写入 ValidationServiceProvider.php 的boot()。需要空值也触发校验的规则如必须选公司→ 用extendImplicit()并在闭包内自行处理各项放行条件。参数型规则表名、字段名、作用域列→ 用冒号 逗号分隔传入必要时配Validator::replacer()美化消息。通用规则对象 → 不要放进app/Rules那里只放加密自定义字段相关 Rule 类。观察者 → 在 AppServiceProvider.php 的boot()用Model::observe(Observer::class)显式注册不要使用#[ObservedBy]属性。多公司/作用域相关的规则在实现中大量使用withoutGlobalScopes()绕过作用域查找真实记录编写类似规则时务必注意这一点否则会形成作用域把外部记录藏起来 → 校验误放行的安全漏洞。赞分享后端企业应用【免费下载链接】snipe-itA free open source IT asset/license management system项目地址https://gitcode.com/GitHub_Trending/sn/snipe-it点击查看免费下载相关推荐ES6-learning类和面向对象编程的完整指南ES6 learning类和面向对象编程的完整指南 欢迎来到ES6 learning项目的终极教程 今天我们将深入探讨JavaScript ES6中最激design_patterns_in_typescript服务发现机制观察者模式与中介者模式的实践design_patterns_in_typescript服务发现机制观察者模式与中介者模式的实践 你是否在开发分布式系统时遇到过服务节点动态上下线难以追踪的示例工程Laravel-Excel 服务提供者解析ExcelServiceProvider 注册流程Laravel Excel 服务提供者解析ExcelServiceProvider 注册流程 服务提供者的核心作用 在 Laravel 框架中服务提供者S后端上一篇强力突破语言障碍Screen Translator让屏幕文字翻译变得如此简单下一篇百度网盘直链解析工具深度解析技术架构与高效下载实践创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

相关新闻

Everhour 自动化实战指南:基于 Rube MCP(Composio)的 Claude Skill 工作流

Everhour 自动化实战指南:基于 Rube MCP(Composio)的 Claude Skill 工作流

AI 技能AI 插件人工智能工作流自动化 【免费下载链接】awesome-claude-skills A curated list of awesome Claude Skills, resources, and tools for customizing Claude AI workflows 项目地址: https://gitcode.com/GitHub_Trending/aw/awesome-claude-skills 点击…

2026/10/2 21:29:38 阅读更多 →
AstroWind 开发手册:基于 Astro v7 与 Tailwind CSS v4 的模板架构解析与 AI Agent 协作指南

AstroWind 开发手册:基于 Astro v7 与 Tailwind CSS v4 的模板架构解析与 AI Agent 协作指南

前端UI组件 【免费下载链接】astrowind ⭕️ AstroWind: A free template using Astro v7 and Tailwind CSS v4. Astro starter theme. 项目地址: https://gitcode.com/GitHub_Trending/as/astrowind 点击查看 免费下载 AstroWind 是一个免费开源的网站模板&#x…

2026/10/2 21:28:37 阅读更多 →
6G显存跑AI漫剧全流程:显存优化与ComfyUI工作流精简实战

6G显存跑AI漫剧全流程:显存优化与ComfyUI工作流精简实战

1. 为什么6G显存能跑通AI漫剧全流程?——从硬件瓶颈到工作流重构的真实逻辑很多人看到标题第一反应是:“6G显存做60秒AI视频?是不是标题党?”我实测过,不是。但这个“能跑通”,有非常严格的前置条件——它不…

2026/10/2 21:28:37 阅读更多 →

最新新闻

TerraScan点云处理实战:参数原理与LiDAR测绘精度控制

TerraScan点云处理实战:参数原理与LiDAR测绘精度控制

简介:本资源是一份面向测绘、遥感、地理信息系统(GIS)及三维建模领域从业者与高校相关专业师生的技术参考文献,系统讲解基于TerraScan软件的LiDAR点云数据处理全流程。内容涵盖LiDAR技术原理与发展现状、TerraScan核心功能&#x…

2026/10/2 22:51:07 阅读更多 →
HGRV轨迹预测:贝叶斯粒子滤波建模与Python实现

HGRV轨迹预测:贝叶斯粒子滤波建模与Python实现

简介:这是一份关于高超声速滑翔飞行器(HGRV)轨迹预测的完整复现资料,面向具备一定编程和数学基础、对贝叶斯推断与粒子滤波感兴趣的科研人员和工程师。资源以docx文档形式整理了论文复现思路与详细代码解释,覆盖意图代…

2026/10/2 22:51:07 阅读更多 →
LabVIEW数据存储指南:TDMS文件读写方案与性能优化

LabVIEW数据存储指南:TDMS文件读写方案与性能优化

先说结论:这套存储读写方案我在实验室里用了快四年,从单通道几十Hz的慢速采集,到八通道连续一周的疲劳试验,再到偶尔要回放分析的老数据,基本都覆盖到了。如果你正在用LabVIEW做数据采集、信号处理或者设备状态记录&am…

2026/10/2 22:51:07 阅读更多 →
URLLC短码长通信:突破香农极限的实时可靠传输

URLLC短码长通信:突破香农极限的实时可靠传输

1. 什么是URLLC场景下的短码长 regime?——从工厂产线到远程手术的真实需求倒逼出来的通信范式你有没有想过,为什么5G宣传里总说“一毫秒时延”,但实际用手机打视频电话,卡顿还是时有发生?问题不在基站功率&#xff0c…

2026/10/2 22:51:07 阅读更多 →
AI写作合规指南:守住作者性的技术边界

AI写作合规指南:守住作者性的技术边界

1. 事件本质与行业震动:一场关于“作者性”的边界测试 “Author Dropped from Literary Prize over AI Allegations”——这行标题不是一则娱乐八卦,而是一记敲在当代文学创作神经末梢上的重锤。它背后没有算法黑箱的神秘感,也没有技术厂商的…

2026/10/2 22:51:07 阅读更多 →
蛋白质功能位点识别平台构建:从数据到部署的机器学习全流程

蛋白质功能位点识别平台构建:从数据到部署的机器学习全流程

简介:这份PDF文献面向生物信息学、蛋白质功能研究方向的初学者与科研人员,系统讲解如何用支持向量机(SVM)构建蛋白质功能位点识别的通用机器学习平台。内容涵盖非同源序列提取、序列特征编码(基本信息、物化特征、结构…

2026/10/2 22:50:06 阅读更多 →

日新闻

从零搭建AI工程化:模型之外的完整闭环

从零搭建AI工程化:模型之外的完整闭环

先搞清楚一件事:从零开始做 AI 工程化,难的从来不是调模型、写提示词,而是把一套原型 Demo 变成长得像是“正经系统”的东西。你手里可能已经有了能跑通的代码,也可能刚读完一些概念,但真到了要把它变成可维护、可观测…

2026/10/2 0:00:20 阅读更多 →
大模型训练显存估计与混合精度训练实战指南

大模型训练显存估计与混合精度训练实战指南

1. 大模型训练显存估计与混合精度训练详解显存不够用,几乎是每个做大模型训练的人都会撞上的第一堵墙。你可能也经历过:模型代码写完了,数据管道跑通了,满心欢喜地按下训练启动脚本,结果几秒钟后终端弹出一行红字——C…

2026/10/2 0:00:20 阅读更多 →
小样本学习数据集选型指南:27个真正可用的高质量数据集

小样本学习数据集选型指南:27个真正可用的高质量数据集

1. 小样本学习的“弹药库”:为什么你总在找数据集,却总找不到真正能用的? 小样本、数据集——这两个词最近半年在我处理的200多个AI项目咨询里,出现频率排进前三。不是模型调不好,不是代码写不对,而是卡在…

2026/10/2 0:00:20 阅读更多 →

周新闻

如何划分训练/验证集:Spirula Studio五种eval_mode策略详解

如何划分训练/验证集:Spirula Studio五种eval_mode策略详解

如何划分训练/验证集:Spirula Studio五种eval_mode策略详解 【免费下载链接】spirula-studio Cross-vendor 3D Gaussian Splatting trainer - video to splat to mesh, Vulkan or CUDA. 项目地址: https://gitcode.com/GitHub_Trending/sp/spirula-studio Sp…

2026/10/1 19:40:48 阅读更多 →
SEO怎么推广速查手册新手避坑实战指南

SEO怎么推广速查手册新手避坑实战指南

SEO怎么推广速查手册新手避坑实战指南 模板网站太丑不够用?别急着加滤镜,那是治标不治本。很多老板盯着后台流量掉得眼红,却还在纠结首页Banner的圆角是不是3像素。这就像穿着西装去挖土,姿势不对,努力白费。我整理这份 速查手册…

2026/10/1 19:41:40 阅读更多 →
FireRed-OpenStoryline少样本仿写深度解析:AI Agent如何复刻你的独特文案风格与节奏

FireRed-OpenStoryline少样本仿写深度解析:AI Agent如何复刻你的独特文案风格与节奏

FireRed-OpenStoryline少样本仿写深度解析:AI Agent如何复刻你的独特文案风格与节奏 【免费下载链接】FireRed-OpenStoryline FireRed-OpenStoryline is an AI video editing agent that transforms manual editing into intention-driven directing through natural language …

2026/10/1 20:05:24 阅读更多 →

月新闻

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/2 10:36:31 阅读更多 →
Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/2 5:26:06 阅读更多 →
黑夜航拍船只数据集训练YOLOV5模型全流程解析

黑夜航拍船只数据集训练YOLOV5模型全流程解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/2 6:09:11 阅读更多 →