PHP Fractal-使您的API json变得漂亮,永远!
本文经Viraj Khatavkar同行评审。感谢所有SitePoint的同行评审员,使SitePoint的内容达到最佳状态!
如果您之前构建过API,我敢打赌您习惯于直接将数据作为响应输出。如果操作正确,这可能不会造成危害,但有一些实际的替代方案可以帮助解决这个问题。
其中一个可用的解决方案是Fractal。它允许我们在将模型作为响应返回之前,为模型创建一个新的转换层。它非常灵活,易于集成到任何应用程序或框架中。
关键要点
- PHP Fractal是一种解决方案,允许开发人员在将模型作为响应返回之前为其模型创建新的转换层,从而使JSON数据更易于管理和保持一致性。
- Fractal灵活且易于集成到任何应用程序或框架中。它的工作原理是使用Transformer将复杂的数据结构转换为更简单的格式,并使用Serializer来格式化最终输出。
- Fractal还允许在用户请求时包含子资源(关系)到响应中,从而为数据呈现增加了另一层灵活性和控制。
- 使用Fractal可以通过一次性急切加载关系来优化查询性能,从而解决了Eloquent延迟加载经常遇到的n 1问题。
安装
我们将使用Laravel 5.3应用程序来构建示例并将Fractal包与其集成,因此请继续使用安装程序或通过Composer创建一个新的Laravel应用程序。
<code>laravel new demo</code>
或
<code>composer create-project laravel/laravel demo</code>
然后,在文件夹内,我们需要Fractal包。
<code>composer require league/fractal</code>
创建数据库
我们的数据库包含users和roles表。每个用户都有一个角色,每个角色都有一个权限列表。
// app/User.php class User extends Authenticatable { protected $fillable = [ 'name', 'email', 'password', 'role_id', ]; protected $hidden = [ 'password', 'remember_token', ]; /** * @return \Illuminate\Database\Eloquent\Relations\BelongsTo */ public function role() { return $this->belongsTo(Role::class); } }
// app/Role.php class Role extends Model { protected $fillable = [ 'name', 'slug', 'permissions' ]; /** * @return \Illuminate\Database\Eloquent\Relations\HasMany */ public function users() { return $this->hasMany(User::class); } }
创建Transformer
我们将为每个模型创建一个Transformer。我们的UserTransformer类如下所示:
// app/Transformers/UserTransformer.php namespace App\Transformers; use App\User; use League\Fractal\TransformerAbstract; class UserTransformer extends TransformerAbstract { public function transform(User $user) { return [ 'name' => $user->name, 'email' => $user->email ]; } }
是的,创建Transformer就这么简单!它只是以开发人员可以管理的方式转换数据,而不是留给ORM或存储库。
我们扩展TransformerAbstract类并定义transform方法,该方法将使用User实例调用。RoleTransformer类也是如此。
namespace App\Transformers; use App\Role; use League\Fractal\TransformerAbstract; class RoleTransformer extends TransformerAbstract { public function transform(Role $role) { return [ 'name' => $role->name, 'slug' => $role->slug, 'permissions' => $role->permissions ]; } }
创建控制器
我们的控制器应该在将数据发送回用户之前转换数据。我们现在将处理UsersController类,暂时只定义index和show操作。
// app/Http/Controllers/UsersController.php class UsersController extends Controller { /** * @var Manager */ private $fractal; /** * @var UserTransformer */ private $userTransformer; function __construct(Manager $fractal, UserTransformer $userTransformer) { $this->fractal = $fractal; $this->userTransformer = $userTransformer; } public function index(Request $request) { $users = User::all(); // 从数据库获取用户 $users = new Collection($users, $this->userTransformer); // 创建资源集合转换器 $users = $this->fractal->createData($users); // 转换数据 return $users->toArray(); // 获取转换后的数据数组 } }
index操作将从数据库查询所有用户,使用用户列表和转换器创建一个资源集合,然后执行实际的转换过程。
{ "data": [ { "name": "Nyasia Keeling", "email": "crooks.maurice@example.net" }, { "name": "Laron Olson", "email": "helen55@example.com" }, { "name": "Prof. Fanny Dach III", "email": "edgardo13@example.net" }, { "name": "Athena Olson Sr.", "email": "halvorson.jules@example.com" } // ... ] }
当然,一次返回所有用户是没有意义的,我们应该为此实现分页器。
分页
Laravel倾向于简化事情。我们可以像这样实现分页:
<code>laravel new demo</code>
但是为了使这与Fractal一起工作,我们可能需要添加一些代码来转换数据,然后再调用分页器。
<code>composer create-project laravel/laravel demo</code>
第一步是从模型分页数据。接下来,我们像以前一样创建一个资源集合,然后在集合上设置分页器。
Fractal为Laravel提供了一个分页器适配器来转换LengthAwarePaginator类,它还为Symfony和Zend提供了一个适配器。
<code>composer require league/fractal</code>
请注意,它为分页详细信息添加了额外的字段。您可以在文档中阅读更多关于分页的信息。
包含子资源
现在我们已经熟悉了Fractal,是时候学习如何在用户请求时包含子资源(关系)到响应中了。
我们可以请求包含额外资源到响应中,例如http://demo.vaprobash.dev/users?include=role。我们的转换器可以自动检测正在请求的内容并解析include参数。
// app/User.php class User extends Authenticatable { protected $fillable = [ 'name', 'email', 'password', 'role_id', ]; protected $hidden = [ 'password', 'remember_token', ]; /** * @return \Illuminate\Database\Eloquent\Relations\BelongsTo */ public function role() { return $this->belongsTo(Role::class); } }
$availableIncludes属性告诉转换器我们可能需要包含一些额外的数据到响应中。如果include查询参数请求用户角色,它将调用includeRole方法。
// app/Role.php class Role extends Model { protected $fillable = [ 'name', 'slug', 'permissions' ]; /** * @return \Illuminate\Database\Eloquent\Relations\HasMany */ public function users() { return $this->hasMany(User::class); } }
$this->fractal->parseIncludes行负责解析include查询参数。如果我们请求用户列表,我们应该看到类似这样的内容:
// app/Transformers/UserTransformer.php namespace App\Transformers; use App\User; use League\Fractal\TransformerAbstract; class UserTransformer extends TransformerAbstract { public function transform(User $user) { return [ 'name' => $user->name, 'email' => $user->email ]; } }
如果每个用户都有一个角色列表,我们可以将转换器更改为如下所示:
namespace App\Transformers; use App\Role; use League\Fractal\TransformerAbstract; class RoleTransformer extends TransformerAbstract { public function transform(Role $role) { return [ 'name' => $role->name, 'slug' => $role->slug, 'permissions' => $role->permissions ]; } }
包含子资源时,我们可以使用点表示法来嵌套关系。假设每个角色都有一个存储在单独表中的权限列表,并且我们想列出具有其角色和权限的用户。我们可以这样做include=role.permissions。
有时,我们需要默认包含一些必要的关联,例如地址关联。我们可以通过在转换器中使用$defaultIncludes属性来实现。
// app/Http/Controllers/UsersController.php class UsersController extends Controller { /** * @var Manager */ private $fractal; /** * @var UserTransformer */ private $userTransformer; function __construct(Manager $fractal, UserTransformer $userTransformer) { $this->fractal = $fractal; $this->userTransformer = $userTransformer; } public function index(Request $request) { $users = User::all(); // 从数据库获取用户 $users = new Collection($users, $this->userTransformer); // 创建资源集合转换器 $users = $this->fractal->createData($users); // 转换数据 return $users->toArray(); // 获取转换后的数据数组 } }
我最喜欢Fractal包的一件事是能够将参数传递给include参数。文档中的一个很好的例子是按顺序排列。我们可以将其应用到我们的示例中,如下所示:
{ "data": [ { "name": "Nyasia Keeling", "email": "crooks.maurice@example.net" }, { "name": "Laron Olson", "email": "helen55@example.com" }, { "name": "Prof. Fanny Dach III", "email": "edgardo13@example.net" }, { "name": "Athena Olson Sr.", "email": "halvorson.jules@example.com" } // ... ] }
这里重要的部分是list($orderCol, $orderBy) = $paramBag->get('order') ?: ['created_at', 'desc'];,这将尝试从用户include获取order参数,并将其应用于查询构建器。
我们现在可以通过传递参数来按顺序排列包含的用户列表(/roles?include=users:order(name|asc))。您可以在文档中阅读更多关于包含资源的信息。
但是,如果用户没有任何关联的角色会怎样?它将停止并出现错误,因为它期望的是有效数据而不是null。让我们从响应中删除该关系,而不是显示其null值。
<code>laravel new demo</code>
急切加载
因为Eloquent在访问模型时会延迟加载模型,所以我们可能会遇到n 1问题。这可以通过一次性急切加载关系来解决,以优化查询。
<code>composer create-project laravel/laravel demo</code>
这样,在访问模型关系时,我们将不会有任何额外的查询。
结论
我在阅读Phil Sturgeon撰写的《构建你不会讨厌的API》时偶然发现了Fractal,这是一本很棒且内容丰富的读物,我强烈推荐。
您在构建API时是否使用过转换器?您是否有任何首选的执行相同工作的包,或者您只是使用json_encode?请在下面的评论部分告诉我们!
PHP Fractal常见问题解答
什么是PHP Fractal,为什么它很重要?
PHP Fractal是一个强大的工具,有助于为API呈现和转换数据。它很重要,因为它提供了一种标准化的方法来输出复杂、嵌套的数据结构,确保API的数据输出一致、结构良好且易于理解。这使得开发人员更容易使用您的API,并减少了出错的可能性。
PHP Fractal是如何工作的?
PHP Fractal的工作原理是获取复杂的数据结构并将其转换为更易于使用的格式。它通过两个主要组件来实现:Transformer和Serializer。Transformer负责将复杂的数据转换为更简单的格式,而Serializer则格式化最终输出。
PHP Fractal中的Transformer是什么?
PHP Fractal中的Transformer是定义应用程序数据应如何在API响应中输出的类。它们获取复杂的数据结构并将它们转换为更简单、更易于使用的格式。这允许您精确控制API响应中包含哪些数据以及数据的结构。
PHP Fractal中的Serializer是什么?
PHP Fractal中的Serializer负责格式化API的最终输出。它们获取已由Transformer转换的数据,并将其格式化为特定的结构。这允许您确保API的输出一致且易于理解。
我如何在项目中实现PHP Fractal?
在项目中实现PHP Fractal包括通过Composer安装Fractal库,为数据创建Transformer,然后使用Fractal类使用Transformer转换数据。然后,您可以使用Fractal的Serializer之一输出转换后的数据。
我可以将PHP Fractal与任何PHP项目一起使用吗?
是的,PHP Fractal是一个独立的库,可以与任何PHP项目一起使用。它不依赖于任何特定的框架或平台,这使得它成为任何PHP开发人员的通用工具。
使用PHP Fractal的好处是什么?
使用PHP Fractal提供了许多好处。它确保API的输出一致且结构良好,使开发人员更容易使用。它还提供了一种标准化的方法来转换复杂的数据结构,减少了出错的可能性,并使代码更容易维护。
PHP Fractal与其他数据转换工具相比如何?
PHP Fractal以其简单性和灵活性而脱颖而出。它提供了一种直接的方法来转换复杂的数据结构,并且它使用Transformer和Serializer允许高度定制。这使得它成为任何使用API的开发人员的强大工具。
我可以自定义PHP Fractal的输出吗?
是的,PHP Fractal是高度可定制的。您可以创建自定义Transformer来精确控制数据的转换方式,并且您可以使用不同的Serializer以不同的方式格式化输出。这允许您根据您的特定需求调整API的输出。
我在哪里可以了解更多关于PHP Fractal的信息?
有很多资源可以帮助您了解更多关于PHP Fractal的信息。官方PHP League网站提供了全面的文档,并且网上有许多教程和博文。此外,PHP Fractal GitHub存储库是一个探索代码并查看其使用方法示例的好地方。
以上是PHP Fractal-使您的API json变得漂亮,永远!的详细内容。更多信息请关注PHP中文网其他相关文章!

热AI工具

Undresser.AI Undress
人工智能驱动的应用程序,用于创建逼真的裸体照片

AI Clothes Remover
用于从照片中去除衣服的在线人工智能工具。

Undress AI Tool
免费脱衣服图片

Clothoff.io
AI脱衣机

Video Face Swap
使用我们完全免费的人工智能换脸工具轻松在任何视频中换脸!

热门文章

热工具

记事本++7.3.1
好用且免费的代码编辑器

SublimeText3汉化版
中文版,非常好用

禅工作室 13.0.1
功能强大的PHP集成开发环境

Dreamweaver CS6
视觉化网页开发工具

SublimeText3 Mac版
神级代码编辑软件(SublimeText3)

JWT是一种基于JSON的开放标准,用于在各方之间安全地传输信息,主要用于身份验证和信息交换。1.JWT由Header、Payload和Signature三部分组成。2.JWT的工作原理包括生成JWT、验证JWT和解析Payload三个步骤。3.在PHP中使用JWT进行身份验证时,可以生成和验证JWT,并在高级用法中包含用户角色和权限信息。4.常见错误包括签名验证失败、令牌过期和Payload过大,调试技巧包括使用调试工具和日志记录。5.性能优化和最佳实践包括使用合适的签名算法、合理设置有效期、

会话劫持可以通过以下步骤实现:1.获取会话ID,2.使用会话ID,3.保持会话活跃。在PHP中防范会话劫持的方法包括:1.使用session_regenerate_id()函数重新生成会话ID,2.通过数据库存储会话数据,3.确保所有会话数据通过HTTPS传输。

RESTAPI设计原则包括资源定义、URI设计、HTTP方法使用、状态码使用、版本控制和HATEOAS。1.资源应使用名词表示并保持层次结构。2.HTTP方法应符合其语义,如GET用于获取资源。3.状态码应正确使用,如404表示资源不存在。4.版本控制可通过URI或头部实现。5.HATEOAS通过响应中的链接引导客户端操作。

匿名类在PHP中的主要作用是创建一次性使用的对象。1.匿名类允许在代码中直接定义没有名字的类,适用于临时需求。2.它们可以继承类或实现接口,增加灵活性。3.使用时需注意性能和代码可读性,避免重复定义相同的匿名类。

在PHP中,异常处理通过try,catch,finally,和throw关键字实现。1)try块包围可能抛出异常的代码;2)catch块处理异常;3)finally块确保代码始终执行;4)throw用于手动抛出异常。这些机制帮助提升代码的健壮性和可维护性。

PHP中有四种主要错误类型:1.Notice:最轻微,不会中断程序,如访问未定义变量;2.Warning:比Notice严重,不会终止程序,如包含不存在文件;3.FatalError:最严重,会终止程序,如调用不存在函数;4.ParseError:语法错误,会阻止程序执行,如忘记添加结束标签。

在PHP中,include,require,include_once,require_once的区别在于:1)include产生警告并继续执行,2)require产生致命错误并停止执行,3)include_once和require_once防止重复包含。这些函数的选择取决于文件的重要性和是否需要防止重复包含,合理使用可以提高代码的可读性和可维护性。

PHP和Python各有优势,选择依据项目需求。1.PHP适合web开发,尤其快速开发和维护网站。2.Python适用于数据科学、机器学习和人工智能,语法简洁,适合初学者。
