Laravel5.7とTwitterOAuth(TwitterAPI)を使ってハッシュタグをAPI制限に掛かる事なくDBに突っ込むクーロンを作る

#そろそろTwitterAPI分かってきたので、指定のハッシュタグを呟いたユーザーや投稿データを収集していく。

Laravel初めてみて何知れば良いかわからないって人やAPIって何？？って人は今回の記事で勉強するのが丁度良いボリュームだと思うので、やってみてください( ◠‿◠ )

※~~めんどくさいので~~配列のハッシュタグと画像関連は取得しませんが、一応説明だけあとで入れておきます。

###仕様
- Cronを走らせた時点から現在の最新ツイートまで取得し続ける
- 現在から過去のツイートは初期取得時以外に取得しない（要望あれば別記事で両方する方法書く~~けどしんどい~~）
- ツイートに紐づいた画像や配列（複数）のハッシュタグは取得しない
- RTは含まない

###事前準備&環境

- 前回の記事でLaravelのインストールとTwitterOAuthが使える状態になっている

> まだのかたはこちら
[Laravel5.7でTwitterOAuthを使って認証やらツイート取得やら](https://qiita.com/namizatop/items/439c0604ca15c1ef00cd)

- Laravel5.7
- MySQL5.6

###ハッシュタグのモデルとマイグレーションを作る

```terminal
php artisan make:model Hashtag -m
```

これで`database/migrations`に`2019_07_04_123456_create_hashtags_table.php`と`app/Http/`に`Hashtag.php`が作成されたはずなので、早速マイグレーションを設定する。

```php:2019_07_04_123456_create_hashtags_table.php
<?php

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

class CreateHashtagsTable extends Migration
{
    /**
     * Run the migrations.
     *
     * @return void
     */
    public function up()
    {
        Schema::create('hashtags', function (Blueprint $table) {
            $table->increments('id');
            $table->string('tweet_id')->comment('ツイートID');
            $table->string('text')->comment('ツイート内容');
            $table->dateTime('tweet_created_at')->comment('ツイート日時');
            $table->string('screen_name')->comment('@スクリーンネーム');
            $table->string('user_name')->comment('ユーザー名');
            $table->string('profile_image_url')->nullable()->comment('プロフィール画像');
            $table->string('profile_background_image_url')->nullable()->comment('プロフィール画像');
            $table->integer('friends_count')->comment('フォロー数');
            $table->integer('followers_count')->comment('フォロワー数');
            $table->integer('statuses_count')->comment('ツイート数');
            $table->integer('retweet_count')->comment('リツイート数');
            $table->integer('favorite_count')->comment('いいね数');
            $table->dateTime('acquired_at')->comment('取得した日時');
        });
    }

    /**
     * Reverse the migrations.
     *
     * @return void
     */
    public function down()
    {
        Schema::dropIfExists('hashtags');
    }
}

```

こんな感じでマイグレーションを通して、、

```terminal
php artisan migrate
```

次はModel！と言いたいがCronから書いた方が分かりやすそうなので、また後で。

###Cronを書いていく

言わずもがな、コマンド叩いて時間設定するだけでその時間に処理をしてくれる頼もしい味方

####Cronファイルを作成する

`GetHashtagCommand`の部分はお好きな名前で

```terminal
php artisan make:command GetHashtagCommand
```

これで`app/Console/Commands/`に`GetHashtagCommand.php`が作成されるはずなので、早速書いていく。
初期はこのような感じになっているはず。

```php:Hashtag
<?php

namespace App\Console\Commands;

use Illuminate\Console\Command;

class GetHashtagCommand extends Command
{
    /**
     * The name and signature of the console command.
     *
     * @var string
     */
    //ここに設定した名前でコマンドを叩くとCronが走る
    protected $signature = 'command:name';

    /**
     * The console command description.
     *
     * @var string
     */

    //Cronの説明的なやつ
    protected $description = 'Command description';

    /**
     * Create a new command instance.
     *
     * @return void
     */

    //コンストラクタ
    public function __construct()
    {
        parent::__construct();
    }

    /**
     * Execute the console command.
     *
     * @return mixed
     */

    //ここに実行したい処理を記述する
    public function handle()
    {
        //
    }
}
```

じゃあ実際に書いていくよー。
まずはuseでHashtagモデルを指定するよ

```php:GetHashtagCommand.php
namespace App\Console\Commands;

use Illuminate\Console\Command;
//追加
use App\Http\Hashtag;
```

コマンド名はとりあえず`get:hashtag`にしました。

```php:Hashtag
protected $signature = 'get:hashtag';
```

ハッシュタグはあんまり思い浮かばないので、`#駆け出しエンジニアとつながりたい`とかにしておきます。
今回はRTを除くため`-RT`という条件を追加していますが、RTも収集するならハッシュタグだけを指定してください。

```php:GetHashtagCommand.php
    public function handle()
    {
        //任意のハッシュタグを設定する
        $hashtag = "-RT #駆け出しエンジニアとつながりたい";

        //DBにデータがあるか確認
        $query = Hashtag::get();

        //初期データ
        if (!is_object($query)) {
            //DBから最大値を取得
            $max = $query->max('tweet_id');
            //tweet_idの最大値から+1してDBのデータと被らないようにする
            $since_id = $max +1;
        } else {
            $since_id = null;
        }

        //TwitterAPIでデータを取得
        $twitter_api = Hashtag::getHashtagLatestApi($hashtag, $since_id);

        //TwitterAPIからデータが返ってきているか確認
        if (is_object($twitter_api)) {
            //念の為ツイートデータが入ってるか確認
            if (isset($twitter_api->statuses)) {
                //ツイート保存する処理
                $twitter_store = Hashtag::hashtagStore($twitter_api);
            }
        }
    }
```

###Cronで呼び出されるメソッドを記述したモデル

```php:Hashtag.php
<?php

namespace App;

use Illuminate\Database\Eloquent\Model;

class Hashtag extends Model
{
    //created_atとupdated_atは使わないのでfalseにしておく
    public $timestamps = false;

    //最新のツイートを取得する
    public static function getHashtagLatestApi(string $hashtag, int $since_id = null)
    {
        //TwitterAPIを呼び出してデータを取得する
        $twitter_api = \Twitter::get("search/tweets", [
            'q' => $hashtag,
            'count' => 100,
            'since_id' => $since_id
        ]);

        return $twitter_api;   
    }

    //ツイートオブジェクトを形成してDBに保存する
    public static function hashtagStore(object $twitter_api)
    {
        //ステータス情報の取得
        $statuses = $twitter_api->statuses;

        if (is_array($statuses)) {
            //ステータス情報のカウント
            $status_count = count($statuses);

            for ($i = 0; $i < $status_count; $i++) {
                //インスタンスを作成
                $hashtag = new Hashtag;
                //取得したツイート情報を変数に格納
                $status = $statuses[$i];

                //ツイート情報
                $hashtag->tweet_id = $status->id;
                $hashtag->text = $status->text;
                $hashtag->tweet_created_at = date('Y-m-d H:i:s', strtotime($status->created_at));
                //ツイートしたユーザーの情報
                $hashtag->screen_name = $status->user->screen_name;
                $hashtag->user_name = $status->user->name;
                $hashtag->profile_image_url = $status->user->profile_image_url;
                $hashtag->profile_background_image_url = $status->user->profile_background_image_url;
                $hashtag->friends_count = $status->user->friends_count;
                $hashtag->followers_count = $status->user->followers_count;
                $hashtag->statuses_count = $status->user->statuses_count;
                $hashtag->retweet_count = $status->retweet_count;
                $hashtag->favorite_count = $status->favorite_count;
                $hashtag->acquired_at = now();
                //DBへ保存する
                $hashtag->save();
            }
        }
    }
}

```

ここでツイートに付属する画像や配列のハッシュタグもツイート情報に付属しているので、
条件分岐でごにょごにょして保存してください。

###Cronのスケジュールを作成する

では収集して保存する処理までは一通り終わったので、実際にcronで指定した日付毎に、処理を走らせるスケジュールを登録しましょう！( ◠‿◠ )

`app/Console/`の`Karnel.php`を開いてください。

初期状態はこのようになっていると思います。

```php:Karnel.php
<?php

namespace App\Console;

use Illuminate\Console\Scheduling\Schedule;
use Illuminate\Foundation\Console\Kernel as ConsoleKernel;

class Kernel extends ConsoleKernel
{
    /**
     * The Artisan commands provided by your application.
     *
     * @var array
     */
    protected $commands = [
        //
    ];

    /**
     * Define the application's command schedule.
     *
     * @param  \Illuminate\Console\Scheduling\Schedule  $schedule
     * @return void
     */
    protected function schedule(Schedule $schedule)
    {
        // $schedule->command('inspire')
        //          ->hourly();
    }

    /**
     * Register the commands for the application.
     *
     * @return void
     */
    protected function commands()
    {
        $this->load(__DIR__.'/Commands');

        require base_path('routes/console.php');
    }
}

```

設定するところをコメントアウトで説明します。

```php:Karnel.php
    //ここに実行したいcronを指定します。
    protected $commands = [
        \App\Console\Commands\GetHashtagCommand::class,
    ];
```

```php:Karnel.php
    //ここで実行するコマンドと走らせる時間を設定する
    protected function schedule(Schedule $schedule)
    {
        $schedule->command('get:hashtag')->everyFiveMinutes();
    }
```

ちなみに今回は5分に1回cronを実行するようにしているので、時間はお好きなようにどうぞ！

| Cronスケジュールオプション   | 説明                     |
|:-----------------------|:-------------------------|
| ->everyMinute();       | 毎分タスク実行               |
| ->everyFiveMinutes();  | ５分毎にタスク実行             |
| ->everyTenMinutes();   | 10分毎にタスク実行            |
| ->everyThirtyMinutes();| 30分毎にタスク実行            |
| ->hourly();            | 毎時タスク実行               |
| ->hourlyAt(17);        |一時間ごと、毎時１７分にタスク実行 |


####参考サイト

> [Laravelでバッチ処理(Cron)を実行する](https://leben.mobi/blog/laravel5_batch/php/)

###これで完了。

早速先ほど設定した実行コマンドを叩いてCronを走らせてみる。

```terminal
php artisan 'get:hashtag'
```

取得できました！！
これで5分に1回100件ずつ勝手に取得するようになりました。


###最後に

今回は最新ツイートを取得する方法を書きましたが、需要があれば過去のハッシュタグを収集する方法やリツイートを同じ様に収集する方法も書こうかなーっと思ってます。

とりあえず終わり。