前回まででOpenWeatherApiから「現在の天気」が取得・表示できました。
次はツイッターから必要なデータを探してブラウザ表示させるまでを実装してゆきます。
準備
パッケージインストール
composer require abraham/twitteroauth
でパッケージをインストールしておいてください。
ルーティング
/api/tweets にGETアクセスすると、getTweetsメソッドに来るよう定義します。
Route::get('/tweets', [TwitterController::class, 'getTweets']);
※api.php に設定したルートは、自動でurlに/apiが付与されるので実際のapiアクセス先は、/api/tweets となります
Twitter Api接続に必要なデータをconfigに追記
コントローラーで使いたいapi接続情報を、/config/const.php に追記します
OpenWeather用データの下に、twitter用のデータを書いています。
.envに本当のデータを定義して、configで.envを呼び出している形になります。
これをコントローラーで呼び出す部分は以下の通りです。
複数メソッドでツイッターに接続するので、__construct内でまとめて定義しています。
Serach Tweetの基本的な使い方
$tweetList = $this->connection ->get('/search/tweets', $tweets_params) ->statuses;
上記でツイートが取得できます。
$this->connection : コンストラクタでnewしたTwitterOAuthインスタンスが入っています
->get(‘/search/tweets’, $tweets_params): 第一引数にurlを、第二引数に検索条件が入っています
↑↑この$tweet_paramsは、検索したい条件の配列です。以下のような値を定義しています。
$tweets_params = [ 'q' => '東京 天気', //検索したいキーワード 'count' => 10, //取得件数。デフォルトは15件 ];
‘q’以外は任意なので、必要に応じて変更してください。
返ってくるデータ
$this->connection->get(‘/search/tweets’, $tweets_params);
このコードで返ってくるデータは
こんな風にstatuses配下に収まっています。
なので取得時に ->statuses を書いておくことで、ひとつ階層を浅くできるので(satussesを省ける)書いておいたほうが後で楽だと思います。
エラー時
ちなみにエラー時は
errors が返ってきます。
実際に書いたツイッター取得用のコード(Controller)
上は基本的な使い方ですが、今回は天気・食べ物の2種類分apiを叩きたかったので
変数でキーワードを渡すなどして最終的に以下のようになりました。
ユーザー画面での、Osaka, Sapporo などselectBoxでの値変更がトリガーとなっています。
App\Http\Controllers\Api\TwitterController 内 public function getTweets(Request $request) // ajaxでここに来る { $destination = $request->destination; //天気関連ツイート取得 $tweetWeatherList = $this->getTweetByKeywords($destination, '#イマソラ'); //食べ物関連ツイート取得 $tweetFoodList = $this->getTweetByKeywords($destination, '美味しい'); return response()->json( // jsonをJS側に返す [ 'weather' => $tweetWeatherList, 'food' => $tweetFoodList, ] ); } private function getTweetByKeywords($destination, $keyword) //実際のデータ取得関数 { //検索キーワードを設定。 -をつけると除外検索ができる $q = $destination . $keyword . ' -相互 filter:images -#相互RT exclude:retweets'; $tweets_params = [ 'q' => $q, 'count' => config('const.api.twitter.settings.getNum'), 'tweet_mode' => 'extended', ]; $tweetList = $this->connection->get('/search/tweets', $tweets_params)->statuses; //以下はbladeで画像を表示させるための準備なので //必要ない場合もあります foreach ($tweetList as $tweet) { $tweet->mediaUrl = '画像なし'; //初期値 //画像urlを取得 $mediaExist = $tweet->extended_entities->media ?? ''; if ($mediaExist) { $media = $tweet->extended_entities->media; foreach ($media as $m) { if ($m->type === 'photo') { $tweet->mediaUrl = $m->media_url_https; } } } } return $tweetList; }
これでJSからPHP側に値が渡ってきた場合の処理はかけましたので、JS側を書いてゆきます。
BladeからJS、JSからAjax送信
順番が前後しますが、フロント側の実装です。
ブラウザでselectBoxが選択された(changeイベント発生)がトリガーとなり、ajaxが走ります。
ajax
以下ajax部分のみ抜粋。
$.ajax({ headers: { 'X-CSRF-TOKEN': $('meta[name="csrf-token"]').attr('content'), }, url: '/api/tweets', // api.phpに定義したルート type: 'GET', data: { 'destination': destination // selectboxで選ばれた地域名が入る }, dataType: 'json', }) .done(function (response) { const makeTweetHtml = function (index, tweet) { var block = '<div class="col">' + '<a href="https://twitter.com/' + tweet.user.screen_name + '/status/' + tweet.id_str + '" class="test-dark" target="_blank">' + '<p>画像:<img src="' + tweet.mediaUrl + '" class="img-fluid"></p>' + '<p>ツイート内容:' + tweet.full_text + '</p></a>' + '</div>'; targetDom.append(block); } // //天気 // var targetDom = $('#js_tweetWeatherWrap') targetDom.html(""); //前回の取得内容をリセット $.each(response.weather, makeTweetHtml) // //食べ物 // var targetDom = $('#js_tweetFoodWrap') targetDom.html(""); //前回の取得内容をリセット $.each(response.food, makeTweetHtml) }) .fail(function () { console.log("failed"); })
これで、セレクトボックスで選んだ地域名のお天気関連ツイート、食べ物関連ツイートがブラウザに表示されます。
食べ物関連ツイートは見切れていますが、ちゃんと設定した件数表示されています。
cssは未実装同然なのでどうにかしたいのですが、その前にこれをVue.jsに書き換えてから。。
実際考えながら書いていると時間がかかりましたが、まとめると1ページで収まるくらいシンプルですね。