0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

【Laravel×graphql(lighthouse)】アクセサの値を取得する際のアクセサが実行されるタイミング

Last updated at Posted at 2022-06-26

テーブル定義

table
users
    id - integer
    first_name - string
    last_name - string

アクセサの定義

App/Models/User.php

/**
 * ユーザーのフルネームの取得
 *
 * @return string
 */
public function getFullNameAttribute()
{
    return "{$this->first_name} {$this->last_name}";
}

タイプ

User.graphql
type User{
  id: ID!
  first_name: String!
  last_name: String!
  fullName: String! ## キャメルケースでもスネークケースでも対応できる
}

リゾルバ

App/GraphQL/Queries/User.php
/**
* @param  null  $_
* @param  array<string, mixed>  $args
*/
public function __invoke($_, array $args)
{
  $users = User::get();
    return $users;
}

実行タイミング

  • 取得処理を実行後toArrayを行う
User::get()->toArray();

- 取得処理を実行後対象の値を使用

$user User::first();
$user->fullName;
  • graphqlのデータ取得時
query user{
  id
  first_name
  last_name
  fullName ## こちらを取得しようとしなければアクセサは実行されない
}

注意事項

  • graphqlでのデータ取得時にはレコードごとにModelが実行される
    例えば、アクセサにAPIのデータ取得処理や、重い処理を実装していた場合、get()やall()などで複数データを一気に取得する際、実行がレコード数になってしまうとレスポンス速度の低下が発生します。
    graphqlでの取得時に対象のデータを取得しようとすると、レコードごとにModelが実行されるため以下のような処理を実行してもレコード分実行されてしまいました。
App/Models/User.php
+ public fullNames;
/**
 * ユーザーのフルネームの取得
 *
 * @return string
 */
public function getFullNameAttribute()
{
+   if(isset($this->fullNames[$this->id])){
+     // すでにfullNamesに値が存在したらデータをそのまま返却する
+     return $this->fullNames[$this->id];
+   }
    return "{$this->first_name} {$this->last_name}";
}
App/GraphQL/Queries/User.php
/**
* @param  null  $_
* @param  array<string, mixed>  $args
*/
public function __invoke($_, array $args)
{
+ // 先に必要なデータを取得して、ModelのfullNamesにセット
+ User::fullNames = $this->getFullNames();
  $users = User::get();
    return $users;
}

対応策

ここからは上記のようなことが発生した際に自分が実装した対応策になります。
※ もっとうまい回避方法がある気がするのですが、一旦このような方法で実装しました。(有識者の方良い方法があればご教授いただければと思います。)
こちらの方法だと、リレーション先の取得などが使用できなくなるため必要な場合は、Arrayの中に含めて上げる必要があります。

App/GraphQL/Queries/User.php
/**
* @param  null  $_
* @param  array<string, mixed>  $args
*/
public function __invoke($_, array $args)
{
  $users = User::get();
+ //usersテーブルのカラムリストを取得
+ $columns = Schema::getColumnListing('users');

+ $userArray = [];

+ foreach($users as $key => $user){
+   // Userでの取得を単純な配列に変換(toArrayを使用するとそのタイミングでアクセサがレコードごとに実行されてしまうため注意)
+   foreach($columns as $column){
+     $userArray[$key][$column] = $user[$column];
+   }
+   $userArray[$key]['fullName'] = $userFullNames[$user->id];
+ }

-  return $users;
+ return $usersArray;
}
0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?