
Grocycode 协议解析与实战用条码引用 Grocy 中的任意实体【免费下载链接】grocyERP beyond your fridge - Grocy is a web-based self-hosted groceries household management solution for your home项目地址: https://gitcode.com/GitHub_Trending/gr/grocyGrocycode 是 Grocy 自研的一套轻量序列化协议它用一串形如grcy:p:13的文本即可唯一引用产品、电池、家务、食谱等任意 Grocy 实体并能编码为 DataMatrix / Code128 条码贴到实物上。读完本文你将掌握 Grocycode 的完整格式规范、实体类型体系、条码生成与扫描实战方法以及它在购买、消费、库存盘点等场景中如何被 Grocy 源码识别与解析。Grocycode 是什么给实体一张可被扫描的身份证Grocycode 本质上是一种引用 Grocy 任意实体的简单方式a simple way to reference to arbitrary Grocy entities。它不是一个独立的生态标准而是 Grocy 项目内部定义的文本协议每个 Grocycode 由**魔数magic、实体标识符entity identifier、对象标识符id以及一组有序的额外数据extra data**构成。它的独特之处在于两点扫描输入兼容凡是 Grocy 期望读取条码barcode的地方都接受 Grocycode 作为输入——也就是说你可以把grcy:p:13当成一个超级条码贴在对应物品上引用内部属性除了引用普通实体Grocycode 还可以引用 Grocy 内部属性例如特定的库存条目stock entry或特定的电池battery从而实现比普通 EAN 条码更精细的指向。从 helpers/Grocycode.php 的类注释可以确认其定位Grocycode is a simple, easily serializable format to reference stuff within Grocy. It consists of n (n ≥ 3) double-colon separated parts——即至少 3 段、用双冒号分隔的可序列化格式。序列化格式三个必选部分与无限扩展Grocycode 的序列化规范非常简洁由三个必选部分线性拼接、以双冒号:作为分隔符部分内容约束1. 魔数 magicgrcy固定字面量协议起始标记2. 实体标识符匹配正则[a-z]仅限小写英文字母不带任何重音/变音符最少 1 个字符3. 对象标识符匹配正则[0-9]纯数字即实体的主键 ID可选部分在三个必选部分之后可以追加任意数量的额外数据字段它们没有格式限制唯一硬性约束是不得包含双冒号:因为双冒号是字段分隔符。例如编码一个 ID 为13的产品Product序列化结果就是grcy:p:13源码中的解析与序列化实现helpers/Grocycode.php 完整实现了这套协议核心逻辑如下常量定义第 20-24 行PRODUCT p、BATTERY b、CHORE c、RECIPE r、MAGIC grcy合法实体清单第 47 行public static $Items [self::PRODUCT, self::BATTERY, self::CHORE, self::RECIPE];解析反序列化setFromCode第 87-102 行将字符串按:切分后从尾部反向处理——先array_pop校验末尾是否为魔数grcy不是则抛出Not a Grocycode再取出类型并校验是否在$Items白名单中否则抛出Unknown Grocycode type随后取出对象 ID剩余部分全部视为额外数据。这种从右往左的解析方式保证即使额外数据中包含单个冒号如grcy:p:1:a:b也能通过最后一段必须合法来收敛解析序列化__toString第 80-85 行把[魔数, 类型, ID, ...额外数据]用implode(:, $arr)拼接校验入口Validate第 52-63 行尝试构造new Grocycode($code)成功返回true抛异常则返回false。同时支持两种构造方式传入单个字符串直接解析new Grocycode(grcy:p:13)或传入(类型, ID, 额外数据数组)从数据构造new Grocycode(Grocycode::PRODUCT, 13)。实体标识符目前定义的四种类型原协议文档定义了三类实体标识符而从当前仓库源码helpers/Grocycode.php 第 20-24、47 行看实际已扩展为四种标识符实体额外字段说明p产品Products可选stock id可精确指向某个库存条目b电池Batteries无当前未定义任何额外字段c家务Chores无当前未定义任何额外字段r食谱Recipes无源码中已注册Grocycode::RECIPE说明原协议文档仅记载了p/b/c三类r食谱是 helpers/Grocycode.php 中$Items白名单里出现、且被 RecipesController.php 实际使用的第四类实体属于从源码结构推断出的当前实现事实。产品 Grocycode可直接指向具体库存条目的扩展格式产品ProductGrocycode 在基础格式之上扩展了一个可选的 stock id从而可以直接引用某一具体的库存条目stock entry。当需要在同一产品有多批不同批次/过期日期的库存时普通条码只能找到产品而带 stock id 的 Grocycode 能精确定位到那一批货。示例grcy:p:13:60bf8b5244b04其中13是产品 ID60bf8b5244b04是具体库存条目的 stock id。从源码看这一扩展在多个位置被使用StockController.php 的StockEntryGrocycodeImage中为某个库存条目生成图片时构造new Grocycode(Grocycode::PRODUCT, $stockEntry-product_id, [$stockEntry-stock_id])——额外数据数组正是[$stockEntry-stock_id]StockService.php 等处生成消费/转移标签时同样使用new Grocycode(Grocycode::PRODUCT, $productId, [$stockId])把库存 id 编码进去。电池与家务 Grocycode当前无额外字段电池BatteryGrocycode目前不定义任何额外字段格式即grcy:b:batteryId。对应实现见 BatteriesController.phpnew Grocycode(Grocycode::BATTERY, $args[batteryId])然后直接渲染为条码图片。家务ChoreGrocycode同样不定义额外字段格式为grcy:c:choreId。对应实现见 ChoresController.phpnew Grocycode(Grocycode::CHORE, $args[choreId])。这两个类型虽然没有额外数据段但其意义在于把执行某项家务给某块电池充电这类动作也变成了可被扫码触发的实体引用——将 Grocycode 贴在电池仓或家务看板上扫码即可直达对应页面。视觉编码DataMatrix 与 Code128 的选择Grocy 将 Grocycode 文本编码为条码时默认支持两种格式DataMatrix 2D 条码推荐默认同样信息量下占用空间更小、冗余度更高且在非平面表面如圆柱形瓶身上更容易被 2D 条码扫描枪读取Code128 1D 条码备选经典一维条码对扫描枪的兼容性最广泛。从原理上讲Grocy 对编码格式并没有排他性限制——理论上也可以使用 QR 码等其他格式但 DataMatrix 在空间效率与曲面读取成功率上的优势使其成为默认选择。该选择由配置文件中的GROCYCODE_TYPE设置项控制见 config-dist.php// 1D ( Code128) or 2D ( DataMatrix) Setting(GROCYCODE_TYPE, 2D);对应地GrocycodeTrait.php 的渲染逻辑会根据该设置分支if (GROCY_GROCYCODE_TYPE 2D) { $png (new DatamatrixFactory())-setCode((string)$grocycode)-setSize($size)-getDatamatrixPngData(); } else { $png (new BarcodeFactory())-setType(C128)-setCode((string)$grocycode)-setHeight($size)-getBarcodePngData(); }注意2D 模式用setSize控制整体尺寸1D 模式用setHeight控制条码高度二者参数语义不同。生成 Grocycode 图片内置路由与下载参数Grocy 为各类实体内置了 Grocycode 图片的生成路由见 routes.php路由控制器方法GET /product/{productId}/grocycodeStockController::ProductGrocycodeImageGET /stockentry/{entryId}/grocycodeStockController::StockEntryGrocycodeImageGET /stockentry/{entryId}/labelStockController::StockEntryGrocycodeLabelGET /recipe/{recipeId}/grocycodeRecipesController::RecipeGrocycodeImageGET /chore/{choreId}/grocycodeChoresController::ChoreGrocycodeImageGET /battery/{batteryId}/grocycodeBatteriesController::BatteryGrocycodeImage这些方法统一调用GrocycodeTrait::ServeGrocycodeImageGrocycodeTrait.php完成渲染与响应。该 trait 支持两个查询参数size控制生成图片的尺寸2D 模式下为 DataMatrix 的整体大小1D 模式下作为 Code128 的高度download设为真值时响应头切换为Content-Disposition: attachment; filenameGrocycode.png浏览器将直接下载 PNG 文件便于批量打印标签默认则以内联image/png返回。响应统一附带Cache-Control: no-cache与Last-Modified头避免条码图片被缓存导致内容过期。前端各视图如 products.blade.php、batteriesoverview.blade.php、stockentries.blade.php 等均通过打印 Grocycode 标签按钮触发这些路由前端逻辑可见 public/viewjs/batteriesoverview.js 等文件。扫描实战键盘模拟、双冒号与条码输入Grocycode 的落地使用依赖扫描枪。官方文档给出了关键实战建议扫描枪选型可以在 ebay 上买到便宜的二手扫描枪德国当地约 45€性价比高键盘模拟模式务必把扫描枪设置为**键盘模拟keyboard emulation**输出模式这样双冒号:才能被正确输入到任何 Grocy 表单的条码输入框中——Grocycode 的字段分隔符正是双冒号若扫描枪配置错误如未启用符号输出条码内容会残缺导致解析失败内容可键入性额外数据虽然理论上只要求不含双冒号但由于它最终要被编码为视觉表示并被读取实践中只应编码键盘可输入的字符原文脚注 [0] 特别强调这一点。扫码后发生了什么GetProductIdFromBarcode 的解析链在购买、消费、库存盘点等业务中Grocy 的 StockService::GetProductIdFromBarcode 是识别条码的核心入口其处理顺序是先尝试解析为产品 Grocycode调用Grocycode::Validate($barcode)校验若合法则构造new Grocycode($barcode)类型校验若解析出的类型不是Grocycode::PRODUCT直接抛出Invalid Grocycode——即当前库存流转流程只接受产品型 Grocycode返回产品 ID命中则直接返回$gc-GetId()回退到普通条码匹配若不是 Grocycode则在product_barcodes表中按barcode大小写不敏感COLLATE NOCASE查找对应产品。产品 Grocycode 是内置条码值得注意的实现细节迁移脚本 migrations/0238.sql 中product_barcodes_view视图把每个产品自动生成的 Grocycode 作为一条内置 barcode 记录并入视图-- Product Grocycodes SELECT p.id, p.id AS product_id, grcy:p: || CAST(p.id AS TEXT) AS barcode, ... FROM products p;也就是说每个产品天然就拥有一个grcy:p:id的官方条码它与用户自定义的 EAN 条码处于同一查询视野中任何接受条码输入的界面都隐式支持它。前端如 public/viewjs/consume.js 还专门处理从 Grocycode 中尝试获取 stock id的逻辑配合grcy:p:pid:stockId这种带库存条目标识的扩展格式使用。注意事项与协议边界大小写敏感实体标识符必须是小写字母正则[a-z]GRCY:P:13这类写法无法通过解析ID 为纯数字对象标识符匹配[0-9]不能包含字母或符号额外数据禁止双冒号额外字段内不得再出现:否则解析时会与分隔符混淆扩展性由于格式是魔数 类型 ID 任意有序数据新增实体类型只需在Grocycode::$Items白名单中注册新标识符并在控制器中提供对应构造即可协议本身无需变更扫描环境2D 扫描枪配合 DataMatrix 在曲面上的读取成功率更高是官方推荐的默认组合GROCYCODE_TYPE 2D如需兼容老旧 1D 扫描枪可切换为 Code128。Grocycode 的价值在于把条码从单纯的产品编码升级为通用实体寻址协议它既是可打印、可扫描的物理标签也是 Grocy 内部各业务模块间传递实体引用的一等公民从 helpers/Grocycode.php 的解析实现到 routes.php 的路由注册、再到 migrations/0238.sql 的内置条码视图整条链路完整自洽值得任何想在自己系统中引入实体可寻址条码方案的开发者参考。【免费下载链接】grocyERP beyond your fridge - Grocy is a web-based self-hosted groceries household management solution for your home项目地址: https://gitcode.com/GitHub_Trending/gr/grocy创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考