sammyk/facebook-query-builder

一种优雅且高效的方法,用于生成Facebook Graph API的嵌套请求。

2.0.0 2015-05-11 21:27 UTC

This package is auto-updated.

Last update: 2024-09-08 01:57:43 UTC


README

Build Status Latest Stable Version Total Downloads License

一个查询构建器,可以轻松创建复杂的嵌套请求,以便通过Facebook Graph API获取大量特定数据。

Facebook Query Builder没有生产依赖。

$fqb = new SammyK\FacebookQueryBuilder\FQB;

$photosEdge = $fqb->edge('photos')->fields(['id', 'source'])->limit(5);
$request = $fqb->node('me')->fields(['id', 'email', $photosEdge]);

echo (string) $request;
# https://graph.facebook.com/me?fields=id,email,photos.limit(5){id,source}

简介

Facebook Query Builder使用与Graph API相同的命名约定来表示三个主要概念

  1. 节点:节点表示Facebook上的“现实世界的事物”,例如用户或页面。
  2. 边:边表示两个或更多节点之间的关系。例如,“照片”节点会有一个“评论”边。
  3. 字段:节点与其关联属性。这些属性称为字段。例如,用户有“id”和“name”字段。

当您向Graph API发送请求时,URL的结构如下

https://graph.facebook.com/node-id/edge-name?fields=field-name

要使用Facebook Query Builder生成相同的URL,您会这样做

$edge = $fqb->edge('edge-name')->fields('field-name');
echo $fqb->node('node-id')->fields($edge);

如果您执行该脚本,可能会惊讶地看到URL略有不同,因为它会输出

https://graph.facebook.com/node-id?fields=edge-name{field-name}

这两个URL在功能上相同,唯一的区别是Graph API返回响应数据的方式。Facebook Query Builder生成的URL的不同之处在于,它被表示为嵌套请求

这正是Facebook Query Builder之所以强大的原因。它通过PHP界面生成流畅、易于阅读的格式化嵌套请求,来完成繁重的工作。

安装

Facebook Query Builder使用Composer安装。将Facebook Query Builder包添加到您的composer.json文件中。

{
    "require": {
        "sammyk/facebook-query-builder": "^2.0"
    }
}

用法

初始化

要开始与Facebook Query Builder交互,您只需实例化一个FQB对象。

// Assuming you've included your composer autoload.php file before this line.
$fqb = new SammyK\FacebookQueryBuilder\FQB;

您可以将许多配置选项传递给FQB构造函数。

一个基本示例

以下是一个基本示例,获取登录用户的idemail(假设用户授予您的应用email权限)。

$fqb = new SammyK\FacebookQueryBuilder\FQB;

$request = $fqb->node('me')
               ->fields(['id', 'email'])
               ->accessToken('user-access-token')
               ->graphVersion('v3.1');

echo $request;
# https://graph.facebook.com/v3.1/me?access_token=user-access-token&fields=id,email

$response = file_get_contents((string) $request);

var_dump($response);
# string(50) "{"id":"12345678","email":"foo-bar\u0040gmail.com"}"

获取多个边的跨数据

Facebook Query Builder的核心是它对嵌套请求的支持。嵌套请求允许您通过一个请求从Graph API获取大量数据。

以下示例将获取登录用户的姓名和前5张他们被标记的照片,只需一次Graph调用即可。

$fqb = new SammyK\FacebookQueryBuilder\FQB([/* . . . */]);

$photosEdge = $fqb->edge('photos')->fields(['id', 'source'])->limit(5);
$request = $fqb->node('me')->fields(['name', $photosEdge]);

echo $request;
# https://graph.facebook.com/me?fields=name,photos.limit(5){id,source}

// Assumes you've set a default access token
$response = file_get_contents((string) $request);

var_dump($response);
# string(1699) "{"name":"Sammy Kaye Powers","photos":{"data":[{"id":"123","source":"https:\/\/scontent.xx.fbcdn.net\/hphotos-xfp1 . . .

边可以包含其他边,以实现无限深度。这使得在保持代码可读性的同时,能够执行相当复杂的图调用。

以下示例将获取用户 1234 的姓名和他们在其中标记的前10张照片。对于每张照片,它获取前2条评论和所有点赞。

$fqb = new SammyK\FacebookQueryBuilder\FQB([/* . . . */]);

$likesEdge = $fqb->edge('likes');
$commentsEdge = $fqb->edge('comments')->fields('message')->limit(2);
$photosEdge = $fqb->edge('photos')
                  ->fields(['id', 'source', $commentsEdge, $likesEdge])
                  ->limit(10);

$request = $fqb->node('1234')->fields(['name', $photosEdge]);

echo $request;
# https://graph.facebook.com/1234?fields=name,photos.limit(10){id,source,comments.limit(2){message},likes}

// Assumes you've set a default access token
$response = file_get_contents((string) $request);

var_dump($response);
# string(10780) "{"name":"Some Foo User","photos":{"data":[ . . .

发送嵌套请求

由于Facebook查询构建器只是一个生成嵌套请求语法的工具,因此它不会为您向Graph API发起请求。您必须使用某种HTTP客户端来发送请求。

我们假设您已经在Facebook上创建了一个应用,并且获得了访问令牌

使用Facebook PHP SDK进行请求

发送请求并接收响应的推荐方式是使用官方的 Facebook PHP SDK v5。您需要从原生Facebook PHP SDK中创建一个Facebook\Facebook超级服务类的实例。

$fb = new Facebook\Facebook([
    'app_id' => 'your-app-id',
    'app_secret' => 'your-app-secret',
    'default_graph_version' => 'v3.1',
    ]);
$fqb = new SammyK\FacebookQueryBuilder\FQB;

$fb->setDefaultAccessToken('my-access-token');

$request = $fqb->node('me')->fields(['id', 'name', 'email']);

echo $request->asEndpoint();
# /me?fields=id,name,email

try {
    $response = $fb->get($request->asEndpoint());
} catch (Facebook\Exceptions\FacebookSDKException $e) {
    echo $e->getMessage();
    exit;
}

var_dump($response->getDecodedBody());

您会发现我们正在使用asEndpoint()方法将生成的请求发送到SDK。这是因为SDK会自动将Graph API主机名添加到URL前缀。asEndpoint()方法将返回不带前缀的URL版本。

官方的Facebook PHP SDK会自动将Graph API版本、应用密钥证明和访问令牌添加到URL中,因此您不需要在FQB对象上设置这些选项。

使用原生PHP进行请求

正如您在上面的基本示例中看到的,您可以使用PHP灵活的file_get_contents()将请求发送到Graph API。只需确保使用default_graph_version设置您的Graph API版本前缀,并使用app_secret设置您的应用密钥,以确保所有请求都使用应用密钥证明签名

$fqb = new SammyK\FacebookQueryBuilder\FQB([
    'default_graph_version' => 'v3.1',
    'app_secret'            => 'your-app-secret',
]);

// Grab Mark Zuckerberg's public info
$request = $fqb->node('4')->accessToken('my-access-token');

echo $request;
# https://graph.facebook.com/v3.1/4?access_token=my-access-token&appsecret_proof=2ad43b865030f51531ac36bb00ce4f59d9f879ecce31b0977dbfd73fa4eca7b6

$response = file_get_contents((string) $request);

var_dump($response);

有关处理响应的更多信息,请参阅下文的使用原生PHP处理响应

获取访问令牌

由于Facebook查询构建器是专门用于构建嵌套请求语法的,因此它不能直接用于获取访问令牌。

Facebook登录过程在后台使用OAuth 2.0。因此,您可以使用任何OAuth 2.0客户端库从Facebook获取用户访问令牌。以下是一些建议:

配置设置

可以通过FQB构造函数设置多个配置设置。

$fqb = new SammyK\FacebookQueryBuilder\FQB([
    'default_access_token'  => 'your-access-token',
    'default_graph_version' => 'v3.1',
    'app_secret'            => 'your-app-secret',
]);

设置访问令牌

如果您正在使用Facebook PHP SDK并已为SDK设置了默认访问令牌,那么您无需担心将访问令牌附加到请求中。

如果您使用其他HTTP客户端,您可以在使用default_access_token选项实例化FQB服务时设置默认回退访问令牌,或者您可以使用accessToken()方法将访问令牌附加到嵌套请求中。

$fqb = new SammyK\FacebookQueryBuilder\FQB([
    'default_access_token' => 'fallback_access_token',
]);

$request = $fqb->node('me');
echo $request->asEndpoint();
# /me?access_token=fallback_access_token

$request = $fqb->node('me')->accessToken('bar_token');
echo $request->asEndpoint();
# /me?access_token=bar_token

设置Graph版本

设置您想要使用的Graph API版本非常重要,因为Graph API受到破坏性更改计划的影响。

如果您正在使用Facebook PHP SDK并已为SDK设置了默认的Graph版本,那么您无需担心在Facebook查询构建器中设置Graph版本。

如果您使用其他HTTP客户端,您可以在使用default_graph_version选项实例化FQB服务时设置默认回退Graph版本,或者您可以使用graphVersion()方法按请求设置它。

$fqb = new SammyK\FacebookQueryBuilder\FQB([
    'default_graph_version' => 'v3.1',
]);

$request = $fqb->node('me');
echo $request->asEndpoint();
# /v3.1/me

$request = $fqb->node('me')->graphVersion('v1.0');
echo $request->asEndpoint();
# /v1.0/me

PS:Graph v1.0已停用。💀

启用应用密钥证明

作为额外的安全功能,您可以使用应用密钥证明对Graph API的每个请求进行签名。强烈建议您编辑您的应用程序设置,要求所有请求都需要应用密钥证明

如果您使用Facebook PHP SDK向Graph API发送请求,它将自动为您附加应用密钥证明。

如果您使用其他HTTP客户端,如果请求中设置了访问令牌和应用密钥,则将生成应用密钥证明。您可以在使用app_secret选项实例化FQB服务时设置应用密钥。

$fqb = new SammyK\FacebookQueryBuilder\FQB([
    'app_secret' => 'foo_secret',
]);

$request = $fqb->node('me')->accessToken('bar_token');
echo $request->asEndpoint();
# /me?access_token=bar_token&appsecret_proof=2ceec40b7b9fd7d38fff1767b766bcc6b1f9feb378febac4612c156e6a8354bd

启用Graph的测试版

在Graph API的更改推出到生产之前,它们首先部署到测试层

默认情况下,当您生成嵌套请求时,它将以Graph API的生产主机名https://graph.facebook.com/开头。

echo (string) $fqb->node('4');
# https://graph.facebook.com/4

要为由FQB生成的请求启用测试层,请设置enable_beta_mode选项为true。启用后,所有生成的URL都将以Graph API的测试版主机名https://graph.beta.facebook.com/开头。

$fqb = new SammyK\FacebookQueryBuilder\FQB([
    'enable_beta_mode' => true,
]);

echo (string) $fqb->node('4');
# https://graph.beta.facebook.com/4

方法参考

node()

node(string $graphNodeName): FQB

返回一个新的可变FQB实体实例。任何有效的Graph节点或端点都可以传递给node()

$userNode = $fqb->node('me');

edge()

node(string $edgeName): GraphEdge

返回一个可变的GraphEdge实体实例,以便传递给FQB::fields()方法。

$photosEdge = $fqb->edge('photos');

fields()

fields(mixed $fieldNameOrEdge[, mixed $fieldNameOrEdge[, ...]]): FQB

GraphNodeGraphEdge实体设置字段和边。字段和边可以作为参数数组或列表传递。

$edge = $fqb->edge('some_edge')->fields(['field_one', 'field_two']);
$node = $fqb->node('some_node')->fields('my_field', 'my_other_field', $edge);

modifiers()

modifiers(array $modifiers): FQB

一些Graph API端点支持名为“修饰符”的额外参数。

支持修饰符的示例端点是/{object-id}/comments

// Order the comments in chronological order
$commentsEdge = $fqb->edge('comments')->modifiers(['filter' => 'stream']);
$request = $fqb->node('1044180305609983')->fields('name', $commentsEdge);

limit()

limit(int $numberOfResultsToReturn): FQB

您可以使用limit()方法指定Graph API应从一个边返回的结果数量。

$edge = $fqb->edge('photos')->limit(7);

由于“limit”功能只是Graph API中的一个修饰符,因此limit()方法是将limit参数发送到modifiers()方法的便捷方法。因此,相同的功能可以表示为

$edge = $fqb->edge('photos')->modifiers(['limit' => 7]);

accessToken()

accessToken(string $accessToken): FQB

您可以使用accessToken()方法为特定请求设置访问令牌。

$request = $fqb->node('BradfordWhelanPhotography')->accessToken('foo-token');

echo $request->asEndpoint();
# /BradfordWhelanPhotography?access_token=foo-token

graphVersion()

graphVersion(string $graphApiVersion): FQB

您可以使用graphVersion()方法为特定请求设置Graph版本URL前缀。

$request = $fqb->node('me')->graphVersion('v3.1');

echo $request->asEndpoint();
# /v3.1/me

asUrl()

asUrl(): string

您可以使用asUrl()方法获取生成的请求作为完整URL。

$request = $fqb->node('me');

echo $request->asUrl();
# https://graph.facebook.com/me

魔法方法__toString()asUrl()方法的别名,因此将FQB实例转换为字符串将执行相同操作。

$request = $fqb->node('me');

echo (string) $request;
# https://graph.facebook.com/me

asEndpoint()

asEndpoint(): string

asEndpoint()asUrl()方法相同,但返回的URL不带Graph API主机名前缀。

$request = $fqb->node('me');

echo $request->asEndpoint();
# /me

这对于与官方Facebook PHP SDK一起使用尤其方便,因为SDK会自动将Graph主机名前缀添加到URL中。

处理响应

响应将取决于您使用哪个HTTP客户端与Graph API接口。

使用Facebook PHP SDK的响应

get()post()delete()方法的所有响应都返回来自原生Facebook PHP SDK的Facebook\FacebookResponse

$fb = new Facebook\Facebook([/* . . . */]);
$fqb = new SammyK\FacebookQueryBuilder\FQB([/* . . . */]);

$fb->setDefaultAccessToken('my-access-token');

$request = $fqb->node('me')->fields(['email', 'photos']);

echo $request->asEndpoint();
# /me?fields=email,photos

try {
    $response = $fb->get($request->asEndpoint());
} catch (Facebook\Exceptions\FacebookSDKException $e) {
    echo $e->getMessage();
    exit;
}

$userNode = $response->getGraphUser();

// Access properties like an array
$email = $userNode['email'];

// Get data as array
$userNodeAsArray = $userNode->asArray();

// Get data as JSON string
$userNodeAsJson = $userNode->asJson();

// Iterate over the /photos edge
foreach ($userNode['photos'] as $photo) {
    // . . .
}

// Morph the data with a closure
$userNode['photos']->each(function ($value) {
    $value->new_height = $value->height + 22;
});

有关FacebookResponse实体的更多信息,请参阅官方文档FacebookResponse entity

使用原生PHP的响应

如果您使用file_get_contents()将请求发送到Graph API,响应将是从Graph API返回的JSON字符串。您可以将JSON响应解码为普通的PHP数组。

$fqb = new SammyK\FacebookQueryBuilder\FQB([/* . . . */]);

$request = $fqb->node('4')
               ->fields(['id', 'name'])
               ->accessToken('user-access-token');

echo $request;
# https://graph.facebook.com/4?access_token=user-access-token&fields=id,name

$response = file_get_contents((string) $request);

$data = json_decode($response, true);

var_dump($data);
# array(2) { ["id"]=> string(1) "4" ["name"]=> string(15) "Mark Zuckerberg" }

如果Graph API返回了错误响应,file_get_contents()将返回false并引发警告。这可能会引起问题,因为Graph API在响应体中返回错误详情。

要获取错误响应数据,我们需要告诉file_get_contents()在响应包含错误HTTP状态代码时也返回响应体。我们可以通过将ignore_errors设置为true使用stream_context_create()函数来做到这一点。

您还可以通过检查响应头来进一步调查错误响应。头存储在$http_response_header变量中,该变量由file_get_contents()自动设置。

$fqb = new SammyK\FacebookQueryBuilder\FQB([/* . . . */]);

$request = $fqb->node('Some-Invalid-Node')->accessToken('user-access-token');

echo $request;
# https://graph.facebook.com/Some-Invalid-Node?access_token=user-access-token

$context = stream_context_create(['http' => ['ignore_errors' => true]]);
$response = file_get_contents((string) $request, null, $context);

$data = json_decode($response, true);
var_dump($data);
/*
array(1) {
  ["error"]=>
  array(4) {
    ["message"]=>
    string(27) "Invalid OAuth access token."
    ["type"]=>
    string(14) "OAuthException"
    ["code"]=>
    int(190)
    ["fbtrace_id"]=>
    string(11) "A8oB9BtqtZ4"
  }
}
*/

var_dump($http_response_header);
/*
array(14) {
  [0]=>
  string(24) "HTTP/1.1 400 Bad Request"
  [1]=>
  string(89) "WWW-Authenticate: OAuth "Facebook Platform" "invalid_token" "Invalid OAuth access token.""
  [2]=>
  string(30) "Access-Control-Allow-Origin: *"
  [3]=>
  string(44) "Content-Type: text/javascript; charset=UTF-8"
  [4]=>
  string(26) "X-FB-Trace-ID: h8oB7BtrtZ3"
  [5]=>
  string(17) "X-FB-Rev: 4971439"
  [6]=>
  string(16) "Pragma: no-cache"
  [7]=>
  string(23) "Cache-Control: no-store"
  [8]=>
  string(38) "Expires: Sat, 01 Jan 2000 00:00:00 GMT"
  [9]=>
  string(21) "Vary: Accept-Encoding"
  [10]=>
  string(100) "X-FB-Debug: FOOE54KJadh9P2HOSUlSFQmNEEf/9CF4ZtgZQ=="
  [11]=>
  string(35) "Date: Fri, 09 Oct 2015 04:43:44 GMT"
  [12]=>
  string(17) "Connection: close"
  [13]=>
  string(19) "Content-Length: 113"
}
*/

测试

只需从这个项目根目录运行phpunit

$ ./vendor/bin/phpunit

贡献

有关详细信息,请参阅CONTRIBUTING

更改日志

请参阅CHANGELOG以获取历史记录。

鸣谢

许可

MIT许可(MIT)。有关更多信息,请参阅许可文件

安全

如果您在这个库中发现安全漏洞,请私下通知项目维护者以解决问题。