Laravel Eloquentでリレーション先のデータを付与した状態でデータ抽出

標題の通りです。

非常にシンプルでして、withを使います。

下記で紹介したModel / controllerを引用しながらwithの処理を追加していきます。

上記の$movieデータに追加して、Actor modelも一緒にリレーションされた状態でデータ抽出したいと思います。

movie Modelに リレーションにactors()を追加します。

<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;

class Movie extends Model
{
    use HasFactory;

    protected $fillable = [
        'movie_title',
    ];

    public function tags()
    {        
        return $this-->hasMany(Tag::class);
    }

    public function actors()
    {        
        return $this-->hasMany(Actor::class);
    }


}

Controllerの処理

->with('actors')を追加します。
public function search($words)
{
    
    $movie = LatestChannel::with('tags')
    ->whereHas('tags', function ($query) use ($words) {
            return $query->where('tag_name', "LIKE", "%".$words."%");
        })
    ->orWhere('movie_title', "LIKE", "%".$words."%")
    ->with('actors') // 追加
    ->get();

    return $movie;

}

これで、movieデータに +で movieに紐づく actorsのデータも一緒に抽出することが出来ます。

1つのModelからリレーション先の検索ORカラム検索にヒットしたデータを抽出 / Eloquent/with/orWhere

LaravelのEloquentを利用して、複数の条件でデータ抽出をします。下記の① OR ② の抽出です。

①:Modelのカラムから条件を指定
②:リレーション先の条件を指定

・利用するシチュエーション

例えば、検索窓を設置した場合。
「映画タイトル」OR「映画のハッシュタグ」どちらかにヒットさせる検索窓にする場合などです。

・Model

Movie Model と Tag Model それを繋ぐリレーションを記載しています。

①:Movie Model

<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;

class Movie extends Model
{
    use HasFactory;

    protected $fillable = [
        'movie_title',
    ];

    public function tags()
    {        
        return $this-->hasMany(Tag::class);
    }    
}

②:Movie Tag

<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;

class Tag extends Model
{
    use HasFactory;

    protected $fillable = [
        'tag_name',
        'movie_id',
    ];

}

Controllerの処理

実際にControllerで抽出する条件を書いていきます。

public function search($words)
{
    
    $movie = Movie::with('tags')
    ->whereHas('tags', function ($query) use ($words) {
            return $query->where('tag_name', "LIKE", "%".$words."%");
        })
    ->orWhere('movie_title', "LIKE", "%".$words."%")
    ->get();

    return $movie;

}

・リレーション先の条件を抽出する with 
・Or条件で抽出する orWhere
を併用することで、実装可能です。

検索窓に、映画のタイトルを検索しても、ハッシュタグを検索しても、どちらかにヒットする movie Modelのデータが抽出されます。

Laravel論理削除&& リレーション先のデータも一括削除

Laravelの削除には、物理削除・論理削除があります。

物理削除はDBのレコードから削除します。対して、論理削除はEloquentでの抽出などには含まれないが、データベース上には存在し続けます。

後ほど後述しますが、”deleted_at” (timestamp型) を追加、SoftDeletesトレイとを追加することによって利用出来ます。

①:論理削除の設定 / 実施 / 復元

Usersテーブルに論理削除の設定を追加していきます。

①-1:migrationでカラムを追加

php artisan make:migration add_softdelete_to_users_table --table=users

migrationファイルは、upに$table->softDeletes();を追加します。

downにはdeleted_atを追加しています。

これは、$table->softDeletes();を追加することによって、カラム自体はdeleted_atが追加されるためです。

<?php

use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;

class AddSoftdeleteToUsersTable extends Migration
{
    /**
     * Run the migrations.
     *
     * @return void
     */
    public function up()
    {
        Schema::table('users', function (Blueprint $table) {
            $table->softDeletes();
        });
    }

    /**
     * Reverse the migrations.
     *
     * @return void
     */
    public function down()
    {
        Schema::table('users', function (Blueprint $table) {
            $table->dropColumn('deleted_at');
        });
    }
}

①-2:Model で Userで softDelet トレイトを追加

<?php

namespace App\Models;

use Illuminate\Contracts\Auth\MustVerifyEmail;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Foundation\Auth\User as Authenticatable;
use Illuminate\Notifications\Notifiable;
use Laravel\Sanctum\HasApiTokens;

use Illuminate\Database\Eloquent\SoftDeletes;// 追加

class User extends Authenticatable
{
    use HasApiTokens, HasFactory, Notifiable;
    use SoftDeletes; // 追加

//以下省略//

これで、論理削除の準備は完了です。

①-3:論理削除の実施

削除方法は、物理削除と同じです。ただし、DB::ファザードでは有効ではありません。Eloquentを利用した処理によるのでご注意を。

Controllerにて、

$user = User::find($id);
$user->delete();

上記にて、論理削除が実施されます。

DBを見て頂くと、

deleted_atカラムに、削除したtimestampが記述されていると思います。これで論理削除完了です。 ( 論理削除されていないデータは、deleted_atがnullです。 )

①-4:論理削除されたデータを復元

restore() メソッドにて復元出来ます。 ただし、論理削除したデータを抽出してください。 User::find($id)では、論理削除したデータは抽出出来ません。(むしろ、これで抽出出来なくするために論理削除した訳ですので.)

下記で復元出来ます。

$user = User::onlyTrashed()->find($id)->restore();

②:論理削除時にリレーション先のデータを削除

論理削除時にリレーション先のデータを削除していきます。

上記までの処理を継続して、Userを利用していきます。

前提としては、Userにリレーションが設定していることを前提とします。

<?php

namespace App\Models;

use Illuminate\Contracts\Auth\MustVerifyEmail;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Foundation\Auth\User as Authenticatable;
use Illuminate\Notifications\Notifiable;
use Laravel\Sanctum\HasApiTokens;

use Illuminate\Database\Eloquent\SoftDeletes;

class User extends Authenticatable
{
    use HasApiTokens, HasFactory, Notifiable;
    use SoftDeletes;

//
//あいだ省略
//


    public function comment()
    {        
        return $this->hasMany(Comment::class, 'user_id', 'id');
    }

    public function post()
    {        
        return $this->hasMany(Post::class, 'user_id', 'id');
    }

Userが削除された際に、紐付いているcommentデータ、postデータも一緒に削除されるようにします。

class User  に追加していきます。

<?php

namespace App\Models;

use Illuminate\Contracts\Auth\MustVerifyEmail;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Foundation\Auth\User as Authenticatable;
use Illuminate\Notifications\Notifiable;
use Laravel\Sanctum\HasApiTokens;

use Illuminate\Database\Eloquent\SoftDeletes;

class User extends Authenticatable
{
    use HasApiTokens, HasFactory, Notifiable;
    use SoftDeletes;

//
//あいだ省略
//


    /**
     * Userの削除に連動して、リレーション先のデータも削除
     */
    protected static function boot()
    {
        parent::boot();
        static::deleting(function ($user) {
            $user->comment()->delete();
            $user->post()->delete();
        });
    }


    public function comment()
    {        
        return $this->hasMany(Comment::class, 'user_id', 'id');
    }

上記設定にて、論理削除時に、リレーション先のデータも一緒に削除されます。

$user = User::find($id);
$user->delete();

■参考サイト

リレーション先の削除に関して、下記のサイト参考にさせて頂きました。

https://shinyasunamachi.com/blog/Laravel8%E3%81%A7%E8%A6%AA%E3%82%92%E8%AB%96%E7%90%86%E5%89%8A%E9%99%A4%E3%81%97%E3%81%9F%E3%82%89%E3%83%AA%E3%83%AC%E3%83%BC%E3%82%B7%E3%83%A7%E3%83%B3%E5%85%88%E3%82%82%E8%AB%96%E7%90%86%E5%89%8A%E9%99%A4%E3%81%99%E3%82%8B

Laravel / collectionでsort.インデックスキーが変わらない問題

標題の通りです。collectionをsortなどで並び替えた際に、デフォルトだとインデックスキーが変わらないのです。

どういうことかというと

基のcollectionのインデックスキーは 0 ~ 9並んでいます。
Illuminate\Support\Collection {#1022 ▼
   #items: array:10 [▼
     0 => array:2 [▶]
     1 => array:2 [▶]
     2 => array:2 [▶]
     3 => array:2 [▶]
     4 => array:2 [▶]
     5 => array:2 [▶]
     6 => array:2 [▶]
     7 => array:2 [▶]
     8 => array:2 [▶]
     9 => array:2 [▶]
   ]
   #escapeWhenCastingToString: false

これを、例えばarray:2の中の情報を基に並び替えるとします。
collection->sortByDesc(‘XXXX’) みたいに降順にします。

collectionの中身は並び変わるが、インデックスキーは基のままです。
Illuminate\Support\Collection {#1304 ▼
   #items: array:10 [▼
     1 => array:2 [▶]
     2 => array:2 [▶]
     5 => array:2 [▶]
     3 => array:2 [▶]
     0 => array:2 [▶]
     6 => array:2 [▶]
     7 => array:2 [▶]
     8 => array:2 [▶]
     9 => array:2 [▶]
     4 => array:2 [▶]
   ]
   #escapeWhenCastingToString: false
これを並び替えと同時に、インデックスキーも0 ~ 9へ並び替えたい

最後に、values()のメソッドを追加すればOKです。

collection->sortByDesc('XXXX')->values();

こうすることで、並び替わるのと同時にインデックスキーも0~9に振り返られています。(中身が見えないので、変わっているのか分かりづらいですね…)

Illuminate\Support\Collection {#1340 ▼
   #items: array:10 [▼
     0 => array:2 [▶]
     1 => array:2 [▶]
     2 => array:2 [▶]
     3 => array:2 [▶]
     4 => array:2 [▶]
     5 => array:2 [▶]
     6 => array:2 [▶]
     7 => array:2 [▶]
     8 => array:2 [▶]
     9 => array:2 [▶]
   ]
   #escapeWhenCastingToString: false
 }

【準備編】Laravelのサービスコンテナを理解しよう|なぜサービスコンテナが有効か.

Laravelのサービスコンテナを初心者が正しく理解することは非常に難易度が高いかと思います。 まずは、サービスコンテナを理解する前にイメージしておくこと考えて見たいと思います。

サービスコンテナを理解する前に、サービスとは何でしょうか。

明確な定義はありませんが、特定の機能/処理を持ったclassのこと。と定義して問題ないかと思います。

サービスはなぜ必要なのでしょうか。

極論、サービスを作らなくてもサービスを作っていくことは可能かと思います。簡単なサービスならば特に考える必要もないでしょう。ただ一定規模のサービスを作ってくと、Fat Controllerの問題にぶち当たります。 Controllerで多くの処理を記述するため、処理が理解しづらい、大きなControllerになってしまいます。

そのために、サービスという一定の規模処理郡をControllerから切り離して、必要に応じて呼び出すことで、シンプルなContolloerになります。また、各処理を疎結合にすることも可能です。

①:実際にサービスを作ってみる

app>Services>CookService.php

サービスを作るディレクトリは特段決まっている訳ではありません。が、app配下にServicesディレクトリを作り、その配下にサービスを定義していくことが一般的です。

今回は、CookServiceを作ってみます。 Cookに wash, cut, bakeといった機能を持ちます。$sozaiを引数に受け取り、$sozaiを処理していきます。

<?php
namespace App\Services;
class CookService
{

    public function wash($sozai)
    {
        $washed_sozai = // washの処理
        return $washed_sozai;
    }


    public function cut($sozai)
    {
        $cuted_sozai = // cutの処理        
        return $cuted_sozai;
    }


    public function bake($sozai)
    {
        $baked_sozai = // bakeの処理        
        return $baked_sozai;
    }
}

②:サービスを使ってみる

上記で作ったサービスを使ってみます。

サービスを作る、サービスを使う、という過程においては必ずしもサービスコンテナを利用する必要はありません。

まずは、サービスコンテナを利用しない方法からいきましょう。

app>Http>Controllers>CurryController.php

CurryControllerで、CookServiceを利用していきましょう。

下記のように、サービスをnewでインスタンス化して、メソッドを呼び出しております。

<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use App\Services\CookService;

class CurryController extends Controller
{

    public function 洗う()
    {
        $cook = new CookService;
        洗済みのじゃがいも = $cook->wash(じゃがいも);

        洗済みのにんじん = $cook->wash(にんじん);

        洗済みのたまねぎ = $cook->wash(たまねぎ);
    }

    public function 切る()
    {
        $cook = new CookService;
        切済みのじゃがいも = $cook->cut(じゃがいも);

        切済みのにんじん = $cook->cut(にんじん);

        切済みのたまねぎ = $cook->cut(たまねぎ);
    }

    public function 焼く()
    {
        $cook = new CookService;
        焼いた野菜 = $cook->bake(じゃがいも, にんじん, たまねぎ);
    }


}

③:依存性の自動解決

各メソッドで$cooksを受け取っています。 newでインスタンス化はしていません。 コンストラクタでタイプヒントした際に、依存性のあるクラスに対して自動的に必要なクラスをnewしてくてれいます。

<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use App\Services\CookService;

class CurryController extends Controller
{


    protected $cooks;

    public function __construct(CookService $cooks)
    {
        $this->cooks = cooks;
    }


    public function 洗う()
    {
        洗済みのじゃがいも = $this->cooks->wash(じゃがいも);

        洗済みのにんじん = $this->cooks->wash(にんじん);

        洗済みのたまねぎ = $this->cooks->wash(たまねぎ);
    }

    public function 切る()
    {
        切済みのじゃがいも = $this->cooks->cut(じゃがいも);

        切済みのにんじん = $this->cooks->cut(にんじん);

        切済みのたまねぎ = $this->cooks->cut(たまねぎ);
    }

    public function 焼く()
    {
        焼いた野菜 = $this->cooks->bake(じゃがいも, にんじん, たまねぎ);
    }


}

④:複数のServicesを利用したい場合

複数のServiceをControllerで利用したい場合はどうしたらいいでしょうか。

1つの方法として make でサービスを呼び出します。

<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use App\Services\CookService;
use App\Services\BuyService; // 追加
use App\Services\WashDishesService; // 追加

class CurryController extends Controller
{

    protected $cooks;
    protected $buys;
    protected $washes;

    public function __construct()
    {

        $this->cooks = app()->make(CookService::class);
        $this->buys = app()->make(BuyService::class);
        $this->washes = app()->make(WashDishesService::class);


    }

    public function 買う()
    {
        $this->buys->goToSupermarket('にんじん');
        $this->buys->goToSupermarket('じゃがいも');
        $this->buys->goToSupermarket('たまねぎ');
    }




    public function 洗う()
    {
        洗済みのじゃがいも = $this->cooks->wash(じゃがいも);

        洗済みのにんじん = $this->cooks->wash(にんじん);

        洗済みのたまねぎ = $this->cooks->wash(たまねぎ);
    }

    public function 切る()
    {
        切済みのじゃがいも = $this->cooks->cut(じゃがいも);

        切済みのにんじん = $this->cooks->cut(にんじん);

        切済みのたまねぎ = $this->cooks->cut(たまねぎ);
    }

    public function 焼く()
    {
        焼いた野菜 = $this->cooks->bake(じゃがいも, にんじん, たまねぎ);
    }

    public function お皿洗い()
    {
        $this->washes->washClear('お皿');
    }


}

LaravelのクラスベースのCoponents整理 / 使い方解説

クラスベースのCoponentsの使い方を解説していきます。

readoubleでも解説されています。わかりやすく解説されていますが、もう少し単純化して整理していきます。https://readouble.com/laravel/8.x/ja/blade.html

①:クラスベースComponentsを使うまでのSTEP

大きく分けて下記の4STEPに分かれると思います。

・Comonetsを追加する
・Comonetsを記述する
・Comonetsを呼び出す
・Comonetsにデータを渡す

②:登場人物 ( ファイル )

②-1:app>View>Componets>XXXX.php
②-2:app>resources>componets>YYYY.blade.php
②-3:app>resources>ZZZZ.blade.php

②-3:app>resources>ZZZZ.blade.php は実際に描画で利用しているbladeです。

③:クラスベースのCoponentsの使い方

それでは、実際にSTEPに沿いながら、登場人物をどうやって使うのかを解説していきます。

③−1:Comonetsを追加する

下記のコマンドを実行することで、

php artisan make:component XXXX

②-1:app>View>Componets>XXXX.phpが生成されます。それと同時に②-2:app>resources>componets>YYYY.blade.phpも生成されます。(同時に生成されないためには、オプションに–inlineを追加)

③−2:Componetsを記述する

②-2:app>resources>componets>YYYY.blade.php

ここには、Componentとして利用したい塊を記述します。

例えば、{{$category}} という変数を受け取り、
下記のような2つの<div>に囲まれたHTMLを使うことを想定しています。(複数の場所で、複数の$categoryに応じて、記述したい場合に、毎回HTMLを記述していくのは大変ですね。)

<div class="title">
 {{$category}}のランキング
</div>

<div class="description">
 {{$category}}がお気に入りの登録数に応じてランク付けされています。
</div>

②-1:app>View>Componets>XXXX.php

<?php
namespace App\View\Components;
use Illuminate\View\Component;

class Ranking extends Component
{

    /**
     * カテゴリー
     *
     * @var 
     */
    public $category;

    public function __construct($category)
    {
        $this->category = $category;
    }

    public function render()
    {
        return view('components.YYYY');//②-2:app>resources>componets>YYYY.blade.phpで生成されたファイル
    }
}

$categoryで受け取った変数を、②-2:app>resources>componets>YYYY.blade.phpに渡します。

③−3:Comonetsを呼び出す

②-3:app>resources>ZZZZ.blade.php

blade内で、作成したCoponentsを呼び出してみます。

呼び出す際には、②-1:app>View>Componets>XXXX.phpで生成したファイル名を参照にして呼び出します。

コンポーネントのレンダー
コンポーネントを表示するために、Bladeテンプレート1つの中でBladeコンポーネントタグを使用できます。Bladeコンポーネントタグは、文字列x-で始まり、その後にコンポーネントクラスのケバブケース名を続けます。

https://readouble.com/laravel/8.x/ja/blade.html

②-1:app>View>Componets>XXXX.phpの場合は、
(ややこしいので、②-1:app>View>Componets>Ranking.php とします。)

<x-ranking></x-ranking>

で呼び出すことが出来ます。

④:Comonetsにデータを渡す

③で、Componentsを呼び出しましたが、これでは$category 変数を渡すことが出来ていません。これを渡すには、$categoryを指定します。 Contollerから$categoryデータを受け取った場合に、このままComponetsに渡せます。

<x-ranking :category="$category"></x-ranking>

⑤:複数の変数をComponetsに渡す

app>View>Componets>XXXX.php

<?php
namespace App\View\Components;
use Illuminate\View\Component;

class Ranking extends Component
{

    /**
     * カテゴリー
     *
     * @var 
     */
    public $category;
    public $tag; //追加

    public function __construct($category, $tag) //追加
    {
        $this->category = $category;
        $this->tag = $tag; //追加
    }

    public function render()
    {
        return view('components.YYYY');
    }
}

app>resources>ZZZZ.blade.php

<x-ranking :category="$category" :tag="$tag"></x-ranking>

⑥:Unresolvable dependency resolving [Parameter #0 [ {$YYYY} ]] in class App\View\Components{XXXX} のエラーが出た場合

下記にて解説しています。

Unresolvable dependency resolving [Parameter #0 [ {$YYYY} ]] in class App\View\Components\{XXXX}

Laravelにて、Componentsクラスを記述している際のエラー解決方法を解説していきます。このようなエラーが発生しました。

viewへcollectionのデータを渡す際に発生したので、、まさか、、、componentでcollection渡せない…??? と思ってしまいましたが、そういった問題ではなかったです。 下記解説です。

■問題点①

調べていくとキャッシュがクリア出来ていない場合に、発生するエラー表示のようです。

■問題点①の解決策

php artisan view:clear 

■問題点②

上記のキャッシュクリアしても、エラーが変わらず、消えない…という場合。
1つ疑って頂きたいのは、

変数名に _ アンダーバーを利用していませんか??

例えば、$category_channels このようにアンダーバーを利用している場合は変更が必要です。

■問題点②の解決策

<x-ranking :category-channels=”$category_channels”>で複数単語を用いて変数を記述するさいには、””_””を利用せずに、””-“”記述する必要があるようです。

app>resources>ranking.blade.php
////

<x-ranking :category-channels="$category_channels" />

////

// Errorのパターン:<x-ranking :category_channels=”$category_channels” />

これを、View>Componetsで受け取る際には、キャメルケースで受けることが出来ます。

app>View>Componets>Ranking.php
<?php
namespace App\View\Components;
use Illuminate\View\Component;

class Ranking extends Component
{

    /**
     * ランキング掲載のチャンネルデータ
     */
    public $category_channels;

    public function __construct($categoryChannels)
    {
        $this->category_channels = $categoryChannels;
    }

    public function render()
    {
        return view('components.ranking');
    }
}

参考記事

https://laracasts.com/discuss/channels/laravel/errorexception-unresolvable-dependency-resolving-parameter-0-required-auth-profile-in-class-appviewcomponentsuserprofileprofileinfo-view-claragonwwwaclresourcesviewsuserprofileprofile-pagebladephp-httpacltestauth-profile1edit

Componetsの使い方については下記で解説しています。

LaravelとAPI Gatewayの通信に、アクセストークンの認証を追加

こちらの記事をベースに進めていきます。
上記の記事では、LaravelからAPIGatewayを経由してDynamoDBと通信をしております。 
ただし、上記の設定だとエンドポイントがバレると誰でもデータ取得出来てしまう状況した。 APIGatewayにアクセストークンの認証を追加することでセキュリティを高めます。

APIGatewayの通信に認証を追加する際には、Cognito, Lambdaなどで追加できます。今回は、Cognitoを利用していきます。

そして今回も、既に素晴らしい記事を書いて頂いている方がいたので、ほぼそちらを参考に進めてまいります。↓↓↓↓

Cognitoで認証されたユーザーだけがAPI Gatewayを呼び出せるオーソライザーを使ってみた

Cognitoユーザーの「アカウントステータス」をCONFIRMEDに変更するのに躓いている方は、こちらの記事を参考にして頂ければ問題ないかと思います。↓↓↓↓

【AWS】CognitoのFORCE_CHANGE_PASSWORDをCONFIRMEDに変える方法

さて、アクセストークンは発行できましたでしょうか。

aws cognito-idp admin-initiate-auth --user-pool-id CognitoユーザープールID --client-id アプリクライアントID --auth-flow ADMIN_NO_SRP_AUTH --auth-parameters USERNAME=ユーザ名,PASSWORD=パスワード {

コマンドを実行した結果の「”IdToken”:」部分です。

こちらのトークンを利用して、Laravelにアクセストークンを追加し、アクセス可能な状態にします。

.env
AWS_APIGATEWAY_ACCESS_KEY={IdTokenの部分}
Contoroller

追加する部分は1箇所.  headerにトークンを追加します。

'Authorization: '.env('AWS_APIGATEWAY_ACCESS_KEY'), 

public function index()
{
    
    $header = [
        'Content-Type: application/json',
        'Authorization: '.env('AWS_APIGATEWAY_ACCESS_KEY'), // headerにkeyを追加
    ];

        $params = [
        "OperationType" => "SCAN"
    ];

        
    $curl = curl_init();
    curl_setopt($curl, CURLOPT_URL, env('AWS_APIGATEWAY_URL'));
    curl_setopt($curl, CURLOPT_POST, TRUE);
    curl_setopt($curl, CURLOPT_POSTFIELDS, json_encode($params));
    curl_setopt($curl, CURLOPT_HTTPHEADER, $header);
    curl_setopt($curl, CURLOPT_RETURNTRANSFER, TRUE);
    
    $output= curl_exec($curl);
    $result = json_decode($output);
    curl_close($curl);

    dd($result);
}

LaravelからDynamoDBのデータ取得|Lambda×API Gateway経由

標題にある通り、LaravelからDynamoDBのデータを取得します。
その際に、AWSサービスの「Lambda」と「API Gateway」経由して取得します。

今回、かなり参考にさせて頂いた記事がこちらです。
AWS API GatewayとLambdaでDynamoDB操作

API Gateway → Lambda → DynamoDB までの部分はこちらを参考にさせて頂きつつ、
・途中でエラーで詰まった部分の紹介
・API GatewayとLaravelとの連携部分についての紹介(curlを利用します。)
をしていきます。

■前提

・Laravelインストール済み
・AWSアカウント取得済み

LaravelからDynamoDBのデータ取得の流れ

①:DynamoDBのテーブル、レコード作成
②:Lambda作成
③:API Gateway作成
④:API Gatewayテスト実施
⑤:API Gateway公開
⑥:ローカル環境(mac / ターミナル)から、API Gatewayへリクエスト
⑦:LaravelからAPI Gatewayへリクエスト
おまけ:LaravelからAPI Gatewayの通信に認証を追加

①〜⑤は、こちらの記事を参考に進めて頂けたらと想います。 AWS API GatewayとLambdaでDynamoDB操作 

⑥:ローカル環境(mac / ターミナル)から、API Gatewayへリクエスト

①~⑤で、API Gatewayテストが完了し、DynamoDBのデータが正しくResponseされているでしょうか。

■SCANを実施したい場合のコマンド

$ curl -X POST 'https://XXXXXX.execute-api.ap-northeast-1.amazonaws.com/APItest/dynamodbctrl' -d '{"OperationType":"SCAN"}' | jq

ここで自分が見誤った部分が、リクエストする際のURL部分です。
ステージエディターのURLを利用すれば問題ないのですが、階層によってURLが違うので注意して下さい。
こちらの方と同じ勘違いをして、「Missing Authentication Token」となってしまいました。 【AWS】APIGatewayのURLにアクセスするとエラー「Missing Authentication Token」が表示される

⑦:LaravelからAPI Gatewayへリクエスト

ローカル環境から、curlを利用してデータが返ってきましたか。

curlを利用して、LaravelからAPI Gatewayへリクエストして、DynamoDBのデータを取得していきます。

public function index()
{
    
    $header = [
        'Content-Type: application/json',
    ];

        $params = [
        "OperationType" => "SCAN"
    ];

        
    $curl = curl_init();
    curl_setopt($curl, CURLOPT_URL, env('AWS_APIGATEWAY_URL'));
    curl_setopt($curl, CURLOPT_POST, TRUE);
    curl_setopt($curl, CURLOPT_POSTFIELDS, json_encode($params));
    curl_setopt($curl, CURLOPT_HTTPHEADER, $header);
    curl_setopt($curl, CURLOPT_RETURNTRANSFER, TRUE);
    
    $output= curl_exec($curl);
    $result = json_decode($output);
    curl_close($curl);

    dd($result);
    }

curlはPHPに標準で含まれているので、importをする必要はありません。

env(‘AWS_APIGATEWAY_URL’)

ステージの呼び出しURLを指定して下さい。

curl_setopt($curl,CURLOPT_POSTFIELDS, json_encode($params));

連想配列から、jsonへ変換しています。

これで、dd($result);で、ターミナルからcurlしたデータと同じデータが返ってくると思います。

LaravelからAPI Gatewayの通信に認証を追加

下記にてまとめております。

Laravel,balde「@auth・Auth::user()」が反応しない件

今回、非常にピンポイントなシチュエーションによる問題です。

■前提条件

・マルチログイン認証機能で、guard: users,adminを2つ作成
・guardのdefaultをusers指定

■問題発生状況

・adminでログイン状態
・baldeにて、「@auth」や「Auth::user()」がnullで返ってくる

■原因

原因は、guardのdefault指定のようです。

config > auth.php

の中で、defaultを指定を下記でしておりました。

    'defaults' => [
        'guard' => 'users',
        'passwords' => 'users',
    ],

「@auth」や「Auth::user()」「Auth::login()」 等で呼び出すのは auth.php でdefault に指定したguardのようです。

adminでログイン状態でも、defaultがusersだったのでnullが返ってきたようです。

■解決策

defalut以外のguard を呼び出すには Auth::guard(‘admin’) のように guard 名を指定する必要があります。