Help us understand the problem. What is going on with this article?

laravelでカバー画像も表示できるブックレビューアプリを作った。※自分の学習用です

何を作った?

PHP、laravelの勉強として、カバー画像も表示できるブックレビューアプリを作りました。
まずpaizaラーニングを参考に掲示板アプリを作り、そこにGoogleBooksAPIsでマンガのカバー画像を引っ張ってきます。

http://book-review123456.herokuapp.com/articles

基本的な機能はよくある掲示板アプリと同様です。なのでAPIを利用した画像の取得・利用について書きます。

その他の機能についてはこちらで簡単にまとめました。laravelで作った画像も表示できるブックレビューの機能について ※ポートフォリオの解説です

スクリーンショット 2020-01-19 17.29.05.png ※イメージ画像

レビューを投稿するまでの流れ(ログイン済みと想定)

①まず検索窓にマンガのタイトルを書きます。
②候補のカバー画像がいくつか出てきます。この画像はボタンになっていて、クリックして選択できます。
③画像を選択したらタイトルと本文を記入し、投稿して完成です。いいね!ボタンもあります。
僕は左側に画像、右にタイトルと本文を配置しました。

検索フォームを作る

getCover.blade.php
  {{ Form::model(['route' => ['article.getCover']]) }}
        <div class='form-group'>
            {{ Form::label('bookName', 'Book name:') }}
            {{ Form::text('bookName', null) }}
            {{ Form::submit('検索する', ['class' =>'btn btn-primary'])}}
        </div>
  {{ Form::close() }}

  <div class = 'form-group'>
          <a href={{ route('article.new') }}>戻る</a>
   </div>

bookNameはマンガのタイトル。下記のgetCoverメソッドに送る。

GoogleBooksAPIsの導入

下記を参考にしました。
書籍検索APIはGoogleBooksAPIsがオススメ【導入も楽ちんです】

書籍検索APIであるGoogle Books APIsの使い方(PHPでのサンプルコードあり)

PostController.php
public function getCover(Request $request)
    {      
        if($request->filled('bookName')){
          $content= $request->bookName;
          $data = "https://www.googleapis.com/books/v1/volumes?q=" .urlencode($content) ."&maxResults=10";
          $json = file_get_contents($data);
          $json = mb_convert_encoding($json, 'UTF8', 'ASCII,JIS,UTF-8,EUC-JP,SJIS-WIN');
          $json_decode = json_decode($json,true);
        }else {
          $json_decode = [];
        }

受け取ったbookNameは\$contentに代入されます。
\$dataはGoogleBooksAPIs。タイトル名をそのまま埋め込むと正しくエンコードされないので、urlencode()に入れます。

JSONデータの取得に関しては下記を参考にさせていただきました。
PHPでJSONデータの取得の仕方

変更点

デプロイする段階でエラーが出たため、再度作り直しました。以前はhttpclientを使用していたのですが、検索の精度には影響なしと判断したため、現在は使用していません(デプロイのエラーには影響していないので、使っても使わなくても変わらない、という認識です)。

画像をボタンとして表示する

getCover.blade.php
   @if ($json_decode)
      @foreach ($json_decode['items'] as $item)
          <form style="height:200px;width:200px;float:left" action="{{action('ArticleController@create')}}" method="get">
              <input type="hidden" value="{{ $item['volumeInfo']['imageLinks']['thumbnail'] }}" name="url">
              <button type="submit"><img src = "{{ $item['volumeInfo']['imageLinks']['thumbnail'] }}" ></button>
          </form>
      @endforeach
   @endif

ボタンを表示します。Formファザード は使っていません。foreachで複数件表示して、それぞれをボタンにします。
配列は入れ子になっていて、画像を表示するURLは\$json_decode['items']の中の['volumeInfo']の中の['imageLinks']の中にある['thumbnail']に格納されています。複数件取得することができるのでforeachを使用しています(['items']以下が複数件取得できます)。

課題この方法だと、配列が変化するとエラーになってしまいます。例えば、GoogleBooksAPIsを利用してJSONのデータを10件取得した場合、その中に配列['thumbnail']を含んでいないデータが一つでもある場合はエラーになってしまいます。いくつか方法は試したのですが、まだ解決できていません。

ArticleController.php
public function create(Request $request)
    { 
        $posts = $request->url;
        $message = 'New article';

        return view('new',['message' =>$message, 'posts' =>$posts]);
    }

送られた画像URLを\$postsに格納し、投稿編集画面に送ります。

タイトルと本文を書く

ArticleController.php
   <h1>edit review</h1>
   <p>{{$message}}</p>

   //下記に画像URL渡します。表示用。
   <img src={{$posts}}>

   //投稿フォーム
   {{ Form::open(['route' =>'article.store'])}}

//下記にも画像URL渡します。まだ保存はされていないので、このフォームでPOSTしてデータベースに保存します。
      <div class = 'form-group'>       
          {{ Form::hidden('url',$posts)}}
      </div>

       //レビューのタイトル。
      <div class = 'form-group'>
          {{ Form::label('title','Title:')}}
          {{ Form::text('title', null)}}
      </div>

      //レビュー本文。
      <div class = 'form-group'>
          {{ Form::label('content','Content:')}}
          {{ Form::text('content',null)}}
      </div>

      //このレビューを投稿するユーザー。このアプリではログインしたユーザーだけが投稿できます。
      //投稿画面にアクセスできるということは、このユーザーは既にログインしていると言えます。
      //なのでAuth::user()->nameを投稿者として、この記事のユーザー名にします。
      <div class='form-group'>
            {{ Form::label('user_name', Auth::user()->name) }}
            {{ Form::hidden('user_name',Auth::user()->name ) }}
        </div>

      <div class = 'form-group'>
          <a href={{ route('article.getCover') }}>画像検索</a>
      </div>

      <div class = 'form-group'>
          {{ Form::submit('作成する', ['class' =>'btn btn-primary'])}}
          <a href={{ route('article.list') }}>一覧に戻る</a>
      </div>
      {{ Form::close() }}

      //フォームが空欄の場合はフラッシュメッセージを表示します。
      @if (session('flash_message'))
            <div class="flash_message">
                {{ session('flash_message') }}
            </div>

ストアメソッドで保存する

ArticleController.php
public function store(Request $request, Article $article)
    {
        if($request->content != ""  && $request->title !=""){
          $article = new Article();
          $user = \Auth::user();

          $article->image_url = $request->url;
          $article->title = $request->title;
          $article->content = $request->content;
          $article->user_name = $request->user_name;
          $article->user_id = $user->id;
          $article->save();
          return redirect()->route('article.show',['id'=>$article->id]);
        }else{
          session()->flash('flash_message', '空欄を埋めてください');
          return redirect()->back();
      }
    }

上記のstoreメソッドで保存し、\$article->image_urlを表示するviewを作成します。
下記がルートになります。

web.php
//レビューのリスト。
Route::get('/articles','ArticleController@index')->name('article.list');
//検索ページに飛ぶ
Route::get('/article/getCover','PostController@getCover');
//書籍名を検索する
Route::post('/article/getCover','PostController@getCover')->name('article.getCover');
//選択した画像を編集画面にgetで送る。
Route::get('/article/new','ArticleController@create')->name('article.new');
//新規投稿のレビューをデータベースに保存する。
Route::post('/article', 'ArticleController@store')->name('article.store');
//投稿したレビューを表示する。
Route::get('/article/{id}','ArticleController@show')->name('article.show');
//レビューを削除する
Route::delete('/article/{id}','ArticleController@destroy')->name('article.delete');
//投稿したレビューを再び編集する
Route::get('/article/edit/{id}', 'ArticleController@edit')->name('article.edit');
//@editで編集したデータをポストして保存する
Route::post('/article/update/{id}', 'ArticleController@update')->name('article.update');


課題 / 問題点

  • マイグレーションでエラーが発生したため、下記URLを参考にCSRFの仕組みを無効化することで対処しています。なので参考にされる際は注意してもられると。CSRFの仕組みを理解するため、今は生のPHPで掲示板を制作しています。順番おかしいですね。

 【Laravel】419のHTTPエラーが出た場合の対処法!

もっとわかりやすく書いた方がいいし、用語の使い方も修正した方がいいですよね。
もっと勉強して随時アップデートしたいです。

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away