首頁 > web前端 > js教程 > 主體

JSONAPI在PHP的使用方法

php中世界最好的语言
發布: 2018-04-13 16:03:09
原創
1908 人瀏覽過

這次帶給大家JSONAPI在PHP中的使用方法,JSONAPI在PHP中使用的注意事項有哪些,以下就是實戰案例,一起來看一下。

現在服務端程式設計師的主要工作已經不再是套模版,而是編寫基於 JSON 的 API 接口。可惜大家寫介面的風格往往迥異,這就為系統整合帶來了許多不必要的溝通成本,如果你有類似的困擾,那麼不妨關註一下 JSONAPI ,它是一個基於 JSON 建構 API 的規範標準,一個簡單的 API 介面大致如下所示:

# JSONAPI

# 簡單說明一下:根節點中的 data 用來放置主物件的內容,其中 type 和 id 是必須要有的字段,用來表示主物件的類型和標識,其它簡單的屬性統統放置到 attributes 裡,如果主對象存在一對一、一對多等關聯對象,那麼就放置到 relationships 裡,不過只是透過 type 和 id 欄位放置一個鏈接,關聯對象的實際內容統統放置在根接點中的 included 裡。

有了 JSONAPI,資料解析的過程變得規範起來,節省了不必要的溝通成本。不過如果要手動建立 JSONAPI 資料還是很麻煩的,好在透過使用 Fractal 可以讓實作過程相對自動化一些,上面的例子如果用 Fractal 實現大概是這個樣子:

<?php
use League\Fractal\Manager;
use League\Fractal\Resource\Collection;
$articles = [
  [
    &#39;id&#39; => 1,
    'title' => 'JSON API paints my bikeshed!',
    'body' => 'The shortest article. Ever.',
    'author' => [
      'id' => 42,
      'name' => 'John',
    ],
  ],
];
$manager = new Manager();
$resource = new Collection($articles, new ArticleTransformer());
$manager->parseIncludes('author');
$manager->createData($resource)->toArray();
?>
登入後複製

如果讓我選最愛的 PHP 工具包,Fractal 一定榜上有名,它隱藏了實作細節,讓用戶完全不必了解 JSONAPI 協議即可上手。不過如果你想在自己的專案裡使用的話,與直接使用 Fractal 相比,可以試試 Fractalistic ,它對 Fractal 進行了封裝,使其更好用:

<?php
Fractal::create()
  ->collection($articles)
  ->transformWith(new ArticleTransformer())
  ->includeAuthor()
  ->toArray();
?>
登入後複製

如果你是裸寫 PHP 的話,那麼 Fractalistic 基本上就是最佳選擇了,不過如果你使用了一些全端框架的話,那麼 Fractalistic 可能還不夠優雅,因為它無法和框架本身已有的功能更完美的融合,以 Lavaral 為例,它本身內建了一個 API Resources 功能,在此基礎上我實作了一個 JsonApiSerializer,可以和框架完美融合,程式碼如下:

<?php
namespace App\Http\Serializers;
use Illuminate\Http\Resources\MissingValue;
use Illuminate\Http\Resources\Json\Resource;
use Illuminate\Http\Resources\Json\ResourceCollection;
use Illuminate\Pagination\AbstractPaginator;
class JsonApiSerializer implements \JsonSerializable
{
  protected $resource;
  protected $resourceValue;
  protected $data = [];
  protected static $included = [];
  public function construct($resource, $resourceValue)
  {
    $this->resource = $resource;
    $this->resourceValue = $resourceValue;
  }
  public function jsonSerialize()
  {
    foreach ($this->resourceValue as $key => $value) {
      if ($value instanceof Resource) {
        $this->serializeResource($key, $value);
      } else {
        $this->serializeNonResource($key, $value);
      }
    }
    if (!$this->isRootResource()) {
      return $this->data;
    }
    $result = [
      'data' => $this->data,
    ];
    if (static::$included) {
      $result['included'] = static::$included;
    }
    if (!$this->resource->resource instanceof AbstractPaginator) {
      return $result;
    }
    $paginated = $this->resource->resource->toArray();
    $result['links'] = $this->links($paginated);
    $result['meta'] = $this->meta($paginated);
    return $result;
  }
  protected function serializeResource($key, $value, $type = null)
  {
    if ($type === null) {
      $type = $key;
    }
    if ($value->resource instanceof MissingValue) {
      return;
    }
    if ($value instanceof ResourceCollection) {
      foreach ($value as $k => $v) {
        $this->serializeResource($k, $v, $type);
      }
    } elseif (is_string($type)) {
      $included = $value->resolve();
      $data = [
        'type' => $included['type'],
        'id' => $included['id'],
      ];
      if (is_int($key)) {
        $this->data['relationships'][$type]['data'][] = $data;
      } else {
        $this->data['relationships'][$type]['data'] = $data;
      }
      static::$included[] = $included;
    } else {
      $this->data[] = $value->resolve();
    }
  }
  protected function serializeNonResource($key, $value)
  {
    switch ($key) {
      case 'id':
        $value = (string)$value;
      case 'type':
      case 'links':
        $this->data[$key] = $value;
        break;
      default:
        $this->data['attributes'][$key] = $value;
    }
  }
  protected function links($paginated)
  {
    return [
      'first' => $paginated['first_page_url'] ?? null,
      'last' => $paginated['last_page_url'] ?? null,
      'prev' => $paginated['prev_page_url'] ?? null,
      'next' => $paginated['next_page_url'] ?? null,
    ];
  }
  protected function meta($paginated)
  {
    return [
      'current_page' => $paginated['current_page'] ?? null,
      'from' => $paginated['from'] ?? null,
      'last_page' => $paginated['last_page'] ?? null,
      'per_page' => $paginated['per_page'] ?? null,
      'to' => $paginated['to'] ?? null,
      'total' => $paginated['total'] ?? null,
    ];
  }
  protected function isRootResource()
  {
    return isset($this->resource->isRoot) && $this->resource->isRoot;
  }
}
?>
登入後複製

對應的 Resource 基本上還跟以前一樣,只是回傳值改了一下:

<?php
namespace App\Http\Resources;
use App\Article;
use Illuminate\Http\Resources\Json\Resource;
use App\Http\Serializers\JsonApiSerializer;
class ArticleResource extends Resource
{
  public function toArray($request)
  {
    $value = [
      &#39;type&#39; => 'articles',
      'id' => $this->id,
      'name' => $this->name,
      'author' => $this->whenLoaded('author'),
    ];
    return new JsonApiSerializer($this, $value);
  }
}
?>
登入後複製

對應的 Controller 也跟原來差不多,只是加入了一個 isRoot 屬性,用來識別根:

<?php
namespace App\Http\Controllers;
use App\Article;
use App\Http\Resources\ArticleResource;
class ArticleController extends Controller
{
  protected $article;
  public function construct(Article $article)
  {
    $this->article = $article;
  }
  public function show($id)
  {
    $article = $this->article->with('author')->findOrFail($id);
    $resource = new ArticleResource($article);
    $resource->isRoot = true;
    return $resource;
  }
}
?>
登入後複製

整個過程沒有對 Laravel 的架構進行太大的侵入,可以說是目前 Laravel 實作 JSONAPI 的最優解決方案了,有興趣的可以研究一下 JsonApiSerializer 的實現,雖然只有一百多行程式碼,但是我卻費了好大的力氣才實現,可以說是行行皆辛苦啊。                                     

##相信看了本文案例你已經掌握了方法,更多精彩請關注php中文網其它相關文章!

推薦閱讀:

怎麼提速最佳化vue-cli的程式碼

Vue.js通用應用程式框架Nuxt.js使用詳解

JS實作標籤捲動切換   

#

以上是JSONAPI在PHP的使用方法的詳細內容。更多資訊請關注PHP中文網其他相關文章!

相關標籤:
來源:php.cn
本網站聲明
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn
熱門教學
更多>
最新下載
更多>
網站特效
網站源碼
網站素材
前端模板