Laravel中将Eloquent模型转为API响应数据必须使用资源机制,包括:一、API资源类标准转换;二、模型访问器动态格式化;三、资源内闭包查询关联数据;四、可见性控制字段输出;五、模型作用域封装查询逻辑。

如果您在Laravel项目中需要将Eloquent模型转换为结构清晰、安全可控的API响应数据,则必须借助框架内置的资源(Resources)机制。以下是实际可用的多种实现方式:
一、使用API资源类进行标准转换
API资源类是Laravel官方推荐的数据格式化层,它将模型实例封装并定义其JSON输出结构,避免控制器中混杂数据组装逻辑。该方式适用于单个模型或集合的标准化输出。
1、执行Artisan命令生成资源类:php artisan make:resource UserResource
2、编辑app/Http/Resources/UserResource.php文件,在toArray()方法中定义字段映射:
3、在控制器中返回资源实例:return new UserResource($user);
4、若需返回多个模型,使用集合资源:return UserResource::collection($users);
二、利用模型访问器动态转换字段
访问器在模型属性被读取时自动触发,适合对原始字段做轻量级、通用性格式化(如价格单位换算、状态码转文字),无需额外资源类即可生效,且对调用方完全透明。
1、在模型中定义访问器方法,命名格式为get{CamelCase}Attribute:
2、例如将数据库中以“分”存储的价格转为带符号的“元”:protected function getPriceAttribute($value) { return '¥' . number_format($value / 100, 2); }
3、在控制器中直接访问:$user->price 即获得格式化后结果
4、如需同时暴露原始值与加工值,配合$appends声明附加属性:
三、在资源类中嵌套闭包查询获取关联数据
当关联数据需按当前模型属性动态过滤(如仅查本公司的地址),不能依赖预加载的静态关系时,可在资源类toArray()中使用闭包查询,并通过use捕获模型属性值,确保上下文隔离与类型安全。
1、在UserResource的toArray()中提前提取关键字段:$companyId = $this->company_id ?? null;
2、构建带条件的关联查询:
3、使用when()方法处理空值情形:->when($companyId, fn($q) => $q->where('company_id', $companyId))
4、将查询结果传入嵌套资源:AddressResource::collection(Address::query()->...->get())
四、通过模型可见性控制字段输出
不依赖资源类时,可直接操作模型实例的可见字段集合,适用于快速调试、临时接口或简单场景。该方式绕过资源层,但缺乏复用性与结构约束。
1、调用makeVisible()显式声明需暴露的字段:$user->makeVisible(['id', 'name', 'email']);
2、调用makeHidden()屏蔽敏感字段:$user->makeHidden(['password', 'remember_token']);
3、调用toArray()生成精简数组:$user->toArray();
4、最终转为JSON响应:$user->toJson(JSON_UNESCAPED_UNICODE);
五、结合模型作用域封装复杂查询逻辑
将资源内重复出现的查询条件抽象为模型作用域,提升可读性、可测试性与复用性。作用域定义在模型中,资源类仅负责调用,职责分离明确。
1、在Address模型中定义作用域方法:public function scopeForCompanyAndContactType($query, $companyId)
2、作用域内部组合条件:return $query->where('company_id', $companyId)->where(function ($q) { $q->where('is_shipping', 1)->orWhere('is_billing', 1); });
3、在资源类中调用该作用域:Address::forCompanyAndContactType($this->company_id)->get()
4、将结果交由对应资源类处理:AddressResource::collection(...)


















