Laravel包开发:扩展FormRequest需引入全框架是否合理?
简介
我正在开发一个Laravel包,它能根据请求中的EditorJS块自动生成请求验证规则。为了让开发者用起来更方便,我提供了一个继承自FormRequest的EditorJSFormRequest类,开发者可以像使用普通FormRequest一样在控制器里用它,它会自动为定义好的块类型构建验证规则。
我的问题
FormRequest类来自Illuminate\Foundation\Http\FormRequest,但它不是独立包,必须引入整个laravel/framework才能使用。我觉得引入整个框架属于不良实践,想知道有没有其他解决办法;如果没有,我甚至开始怀疑当前方案的合理性,考虑要不要重构全部代码。
背景说明
我把当前的实现逻辑贴出来,方便参考:
EditorJSFormRequest类代码
namespace FurisonTech\LaraveditorJS; use Illuminate\Foundation\Http\FormRequest; abstract class EditorJSFormRequest extends FormRequest { protected array $editorJSFieldRuleBuilders = []; /** * EditorJSFormRequest constructor. * @param array<EditorJSRequestFieldRuleBuilder> $editorJSFieldRuleBuilders */ public function __construct(array $editorJSFieldRuleBuilders = []) { parent::__construct(); $this->editorJSFieldRuleBuilders = $editorJSFieldRuleBuilders; } /** * Get the validation rules that apply to the request. * @return array */ final public function rules(): array { $rules = []; // Build rules for each Editor.js field foreach ($this->editorJSFieldRuleBuilders as $builder) { $rules = array_merge($rules, $builder->buildRules($this)); } // Merge with additional rules return array_merge($rules, $this->additionalRules()); } /** * Additional validation rules. * @return array */ abstract protected function additionalRules(): array; }
开发者使用示例
class SaveArticleRequest extends EditorJSFormRequest { private const ALLOWED_EMBED_SERVICES = ['youtube', 'twitter', 'instagram', 'facebook', 'imgur']; public function __construct() { parent::__construct([ new EditorJSRequestFieldRuleBuilder('article', [ 'table' => new TableBlockRulesSupplier(200, 20, 255, 3), 'header' => new HeaderBlockRulesSupplier(255, null), 'paragraph' => new ParagraphBlockRulesSupplier(2500, null), 'image' => new ImageBlockRulesSupplier(255, 10), 'audioPlayer' => new AudioPlayerBlockRulesSupplier(12), 'embed' => new EmbedBlockRulesSupplier(self::ALLOWED_EMBED_SERVICES, 255, 5), 'list' => new ListBlockRulesSupplier(100, 500, null), ]) ]); } /** * Determine if the user is authorized to make this request. */ public function authorize(): bool { return false; } protected function additionalRules(): array { return []; } }
解决方案分析
方案一:保留当前实现,明确依赖定位
如果你的包专门针对Laravel开发者,要求依赖laravel/framework完全可行:
- 使用这个包的开发者本身就在Laravel项目中,框架已经存在,不会额外引入冗余代码;
- 在
composer.json中明确指定laravel/framework的版本范围(比如^10.0 || ^11.0),清晰告知用户包的适用场景,避免版本兼容问题。
方案二:解耦核心逻辑,做分层设计
如果想让包更灵活,甚至支持非Laravel项目,可以重构代码分层:
- 核心规则生成层:把规则生成的逻辑提取到独立类(比如
EditorJSRuleGenerator)中,这个类不依赖任何Laravel组件,只接收块配置参数,返回标准的验证规则数组; - Laravel适配层:单独创建
EditorJSFormRequest类(放在src/Laravel子目录),让它依赖核心生成器,同时继承Laravel的FormRequest,保持现有便捷性; - 依赖配置:在
composer.json中把Laravel相关依赖设为可选(用suggest字段提示),或者通过自动加载规则让用户按需引入适配层代码。
方案三:尝试独立验证组件(局限性较大)
Laravel的illuminate/validation是独立包,但FormRequest属于illuminate/foundation,而后者依赖框架的容器、请求处理等多个组件,所以单独引入illuminate/validation无法直接使用FormRequest。如果只是生成规则,核心逻辑可以基于illuminate/validation,但无法保留FormRequest的便捷集成,这个方案性价比不高。
总结
如果包的定位是Laravel专属工具,直接依赖laravel/framework完全没问题,开发者不会有额外负担;如果想扩大适用范围,建议优先选择分层解耦的方案,既保留现有便捷性,又能支持更多场景。
内容的提问来源于stack exchange,提问作者Estoo

