目录
关键要点
安装
创建数据库
创建Transformer
创建控制器
分页
包含子资源
急切加载
结论
PHP Fractal常见问题解答
什么是PHP Fractal,为什么它很重要?
PHP Fractal是如何工作的?
PHP Fractal中的Transformer是什么?
PHP Fractal中的Serializer是什么?
我如何在项目中实现PHP Fractal?
我可以将PHP Fractal与任何PHP项目一起使用吗?
使用PHP Fractal的好处是什么?
PHP Fractal与其他数据转换工具相比如何?
我可以自定义PHP Fractal的输出吗?
我在哪里可以了解更多关于PHP Fractal的信息?
首页 后端开发 php教程 PHP Fractal-使您的API json变得漂亮,永远!

PHP Fractal-使您的API json变得漂亮,永远!

Feb 10, 2025 am 09:01 AM

PHP Fractal - Make Your API's JSON Pretty, Always!

本文经Viraj Khatavkar同行评审。感谢所有SitePoint的同行评审员,使SitePoint的内容达到最佳状态!


如果您之前构建过API,我敢打赌您习惯于直接将数据作为响应输出。如果操作正确,这可能不会造成危害,但有一些实际的替代方案可以帮助解决这个问题。

其中一个可用的解决方案是Fractal。它允许我们在将模型作为响应返回之前,为模型创建一个新的转换层。它非常灵活,易于集成到任何应用程序或框架中。

PHP Fractal - Make Your API's JSON Pretty, Always!

关键要点

  • 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中文网其他相关文章!

本站声明
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn

热AI工具

Undresser.AI Undress

Undresser.AI Undress

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

AI Clothes Remover

AI Clothes Remover

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

Undress AI Tool

Undress AI Tool

免费脱衣服图片

Clothoff.io

Clothoff.io

AI脱衣机

Video Face Swap

Video Face Swap

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

热工具

记事本++7.3.1

记事本++7.3.1

好用且免费的代码编辑器

SublimeText3汉化版

SublimeText3汉化版

中文版,非常好用

禅工作室 13.0.1

禅工作室 13.0.1

功能强大的PHP集成开发环境

Dreamweaver CS6

Dreamweaver CS6

视觉化网页开发工具

SublimeText3 Mac版

SublimeText3 Mac版

神级代码编辑软件(SublimeText3)

热门话题

Java教程
1655
14
CakePHP 教程
1413
52
Laravel 教程
1306
25
PHP教程
1252
29
C# 教程
1226
24
在PHP API中说明JSON Web令牌(JWT)及其用例。 在PHP API中说明JSON Web令牌(JWT)及其用例。 Apr 05, 2025 am 12:04 AM

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

会话如何劫持工作,如何在PHP中减轻它? 会话如何劫持工作,如何在PHP中减轻它? Apr 06, 2025 am 12:02 AM

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

什么是REST API设计原理? 什么是REST API设计原理? Apr 04, 2025 am 12:01 AM

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

PHP中的匿名类是什么?您何时可以使用它们? PHP中的匿名类是什么?您何时可以使用它们? Apr 04, 2025 am 12:02 AM

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

您如何在PHP中有效处理异常(尝试,捕捉,最后,投掷)? 您如何在PHP中有效处理异常(尝试,捕捉,最后,投掷)? Apr 05, 2025 am 12:03 AM

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

说明PHP中的不同错误类型(注意,警告,致命错误,解析错误)。 说明PHP中的不同错误类型(注意,警告,致命错误,解析错误)。 Apr 08, 2025 am 12:03 AM

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

包括,require,incement_once,require_once之间有什么区别? 包括,require,incement_once,require_once之间有什么区别? Apr 05, 2025 am 12:07 AM

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

PHP和Python:比较两种流行的编程语言 PHP和Python:比较两种流行的编程语言 Apr 14, 2025 am 12:13 AM

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

See all articles