LaravelでTwitter投稿(画像つき)【ダウンロード可】

こんにちは。フリーランス・コンサルタント&エンジニアの 九保すこひ です。

さてさて、前回・前々回と画像に関連する機能をLaravelで開発してみました。

そして、画像関連で他にも何かお届けできる内容がないかと考えていたところ、画像がメインというわけではないのですが、ひとつあるアイデアが浮かんできました。

それが、

LaravelからTwitter投稿する(画像つき)

です。

実は以前PHPからツイッター投稿する機能を開発したことがあったんですが、それは画像なしのテキスト・オンリーでした。

そのため、今回はちょうどいい流れなのでサイトにアップデートがあった場合に自動的にTwitterに投稿ができる機能をつくってみたいと思います。

ぜひ皆さんのお役に立てると嬉しいです😊✨

開発環境: Laravel 5.8、Vue 2.6

やりたいこと

今回開発する具体的な機能は次のとおりです。

  1. 商品情報をDBに登録する
  2. 登録されたら自動的にツイッターに「新着」として投稿

では、実際にやっていきましょう。
今日も Let’s Code!

前提として

今回の機能を実装するためには、TwitterでAPIキーとアクセス・トークンをつくっておく必要があります。

もしまだ作成していない方は、ツイッターでAPIキーとアクセス・トークンを取得するを参考にして先にこれらの情報を取得しておいてください。

Laravel側の作業

APIキー&アクセス・トークンをセットする

取得したAPIキーとアクセス・トークンは.env内に以下のように書き込んでおきます。

TWITTER_CONSUMER_KEY=("API key" の内容)
TWITTER_CONSUMER_SECRET=("API secret key" の内容)
TWITTER_ACCESS_TOKEN=("Access token" の内容)
TWITTER_ACCESS_SECRET=("Access token secret" の内容)

また、これらの情報をconfig()で取得できるようconfig/services.phpを開いて以下のように登録します。

<?php

return [

    // 省略

    'twitter' => [
        'consumer_key'    => env('TWITTER_CONSUMER_KEY'),
        'consumer_secret' => env('TWITTER_CONSUMER_SECRET'),
        'access_token'    => env('TWITTER_ACCESS_TOKEN'),
        'access_secret'   => env('TWITTER_ACCESS_SECRET')
    ]

];

パッケージをインストールする

今回必要なパッケージをインストールします。
以下のコマンドを実行してください。

composer require laravel-notification-channels/twitter
composer require sukohi/clamp-bolt:4.*

(ちなみに2つ目は私が公開しているパッケージで、保存画像とDBデータを繋げて管理できるようになるパッケージです)

インストールが完了したら、ファイル用のDBテーブルをつくります。
以下のコマンドを実行してください。

php artisan vendor:publish --provider="Sukohi\ClampBolt\ClampBoltServiceProvider"
php artisan migrate

作成されたテーブルはこのようになります。
ここに今回は画像データが保存されることになります。

モデルとマイグレーションをつくる

では、今回はproductsというテーブルに商品データを登録していきますので、以下のコマンドでモデルとマイグレーションをつくってください。

php artisan make:model Product -m

するとapp/Product.phpというファイルが作成されるので、画像も管理できるようにClampBoltTraitを登録しておきましょう。

<?php

namespace App;

use Illuminate\Database\Eloquent\Model;
use Sukohi\ClampBolt\ClampBoltTrait;

class Product extends Model
{
    use ClampBoltTrait;
}

そして、database/migrations/****_**_**_******_create_products_table.phpというファイルも作成されているので、中身を以下のように変更します。(太字が追加してところです)

<?php

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

class CreateProductsTable extends Migration
{
    /**
     * Run the migrations.
     *
     * @return void
     */
    public function up()
    {
        Schema::create('products', function (Blueprint $table) {
            $table->bigIncrements('id');
            $table->string('name')->comment('商品名');
            $table->unsignedInteger('price')->comment('価格');
            $table->timestamps();
        });
    }

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

変更したら以下のコマンドでマイグレーションを実行します。

php artisan migrate

実行するとDBテーブルはこのようになります。

Notificationをつくる

先ほどインストールしたパッケージlaravel-notification-channels/twitterLaravelが提供するメッセージ機能Notificationを使って実装しますので、専用のNewProductArrivedというNotificationをつくります。

以下のコマンドを実行してください。

php artisan make:notification NewProductArrived

すると、app/Notifications/NewProductArrived.phpが作成されるので、開いて中身を以下のように変更してください。

<?php

namespace App\Notifications;

use App\Product;
use Illuminate\Notifications\Notification;
use NotificationChannels\Twitter\TwitterChannel;
use NotificationChannels\Twitter\TwitterStatusUpdate;

class NewProductArrived extends Notification
{
    private $product;

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

    public function via($notifiable)
    {
        return [TwitterChannel::class];
    }

    public function toTwitter($notifiable)
    {
        $text = "新着!\n【". $this->product->name ."】という商品が登録されました\n".
                url('product/'. $this->product->id);
        $attachment = $this->product->getAttachment('product_image');
        return (new TwitterStatusUpdate($text))->withImage($attachment->path);
    }
}

ルートをつくる

続いて、ルートです。
以下をroutes/web.phpに追加してください。

Route::get('product/create', 'ProductController@create');
Route::post('product', 'ProductController@store');  // Ajax

コントローラーをつくる

次にコントローラーです。
次のコマンドを実行してください。

php artisan make:controller ProductController

すると、app/Http/Controllers/ProductController.phpというファイルが作成されるので中身を次のようにします。

<?php

namespace App\Http\Controllers;

use App\Notifications\NewProductArrived;
use Illuminate\Http\Request;
use NotificationChannels\Twitter\TwitterChannel;

class ProductController extends Controller
{
    public function create() {

        return view('product.create');

    }

    public function store(Request $request) {

        $request->validate([
            'name' => 'required|string',
            'price' => 'required|integer|min:0',
            'image' => 'required|image'
        ]);

        $product = new \App\Product();
        $product->name = $request->name;
        $product->price = $request->price;
        $product->attach('product_image', $request->image);
        $result = $product->save();

        // ツイッターに投稿
        \Notification::route(TwitterChannel::class, '')->notify(new NewProductArrived($product));

        return ['result' => $result];

    }
}

create()が商品の登録フォームで、store()Ajaxで登録情報と画像を受け取るメソッドです。

store()の中では、productsテーブルに新しい商品を追加し、attach()で画像のデータをattachmentsに保存しています。

そして、保存が完了したらNewProductArrived()を呼び出してその情報を元にツイッター投稿を実行します。

ビューをつくる

そして、商品データを登録するフォームをつくります。
resources/views/product/create.blade.phpというファイルをつくって中身を以下のようにしてください。

<html>
<head>
    <link href="https://stackpath.bootstrapcdn.com/bootstrap/4.4.1/css/bootstrap.min.css" rel="stylesheet">
</head>
<body class="p-4">
<div id="app" class="container">
    <div class="row">
        <div class="col-4">
            <div class="form-group">
                <label>商品名</label>
                <input class="form-control" type="text" v-model="name">
                <div class="text-danger" v-if="errors.name" v-text="errors.name"></div>
            </div>
            <div class="form-group">
                <label>価格</label>
                <input class="form-control" type="text" v-model="price">
                <div class="text-danger" v-if="errors.price" v-text="errors.price"></div>
            </div>
            <div class="form-group">
                <label>画像</label>
                <input class="form-control" type="file" accept="image/*" @change="onFileChange">
                <div class="text-danger" v-if="errors.image" v-text="errors.image"></div>
            </div>
            <button class="btn btn-primary" type="button" @click="onSubmit">画像をアップロードする</button>
        </div>
    </div>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue@2.6.0"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/axios/0.19.0/axios.min.js"></script>
<script>

    new Vue({
        el: '#app',
        data: {
            name: '',
            price: 0,
            imageFile: null,
            errors: {
                name: '',
                price: '',
                image: ''
            }
        },
        methods: {
            onFileChange(e) {

                // 選択された画像を変数で保持する
                this.imageFile = e.target.files[0];

            },
            onSubmit() {

                // 画像をアップロード
                const url = '/product';
                let formData = new FormData();
                formData.append('name', this.name);
                formData.append('price', this.price);
                formData.append('image', this.imageFile);

                axios.post(url, formData)
                    .then(response => {

                        if(response.data.result) {

                            alert('商品登録が完了しました。');

                        }

                    })
                    .catch(error => {

                        this.errors = {};
                        const errors = error.response.data.errors;

                        for(let key in errors) {

                            this.errors[key] = errors[key][0];

                        }

                    });

            }
        }
    });

</script>
</body>
</html>

この中で重要なのは、onFileChange()onSubmit()です。

onFileChange()では、画像が選択されたときに画像データを変数に格納し、onSubmit()ではそのデータを含めて入力データをAjaxで送信しています。

なお、FormDataを使ってパラメータを作っていることに注意してください。これはファイルデータの送信が必要だからです。

テストしてみる

では、実際に商品を登録してツイッター投稿ができるかチェックしてみましょう!

まずページを開いて必要な項目を入力します。

そして、アップロードボタンをクリックします。

すると、以下のポップアップ表示されました。

では、ツイッターの方がどうなってるかチェックしてみましょう。

はい!うまく画像つきで投稿されています。
お疲れ様でした😊✨

ダウンロードする

今回実際に開発したソースコード一式を以下からダウンロードすることができます。

※ ただしパッケージのインストール、コンフィグファイルの設定などはご自身で行ってください。

Laravelにデータ登録されたらTwitterに投稿

ツイッターでAPIキーとアクセス・トークンを取得する

LaravelTwitterと連携するためには、Twitterが提供するキーとトークンを取得しなければいけません。(正確には以下の4つ)

  • TWITTER_CONSUMER_KEY
  • TWITTER_CONSUMER_SECRET
  • TWITTER_ACCESS_TOKEN
  • TWITTER_ACCESS_SECRET

この項目ではこれらの情報を取得するための手順を紹介します。

※ もうすでにキー&トークンを持っている方はこの作業は不要です。

ツイッターにAPIが使えるよう申請する

まずは基本のツイッター・アカウントが必要ですのでアカウントを持っていない人はこちらから登録を済ませておいてください。

登録が済んだら、次は開発者としての登録です。
Apply for accessにアクセスして「Apply for a developer account」ボタンをクリ行くしてください。

すると、利用目的を選択する画面になるので適当にご自身にあうものを選択して「Next」ボタンをクリックします。

すると色々と入力する項目が表示されますが必要なのは以下の2ヶ所だけです。住んでいる国、そして呼んでほしい名前(つまりニックネームや開発者名)です。

すると、「どんな風にツイッターAPIを使うの??」を聞かれるので、(ここが一番ややっこしいです😫)それぞれに「英語」で答えます。

なお、必要な項目の回答例は次のとおりです。

(In your words)

I develop features to tweet from my web applications in PHP, JavaScript, etc. using Twitter API.
So we do NOT retrieve and don’t use Twitter data in the web applications.
The purpose is just tweeting.

(和訳: ツイッターAPIを使い、PHPやJavaScriptからツイートする機能を開発します。なので、ツイッターのデータを取得することも使うこともしません。ツイートするためです)

(Will your app use Tweet, Retweet, like, follow, or Direct Message functionality?)

For example, if information about a specific product is registered in my web app, the content will be tweeted automatically.

(和訳: 例えば、ある特定の商品が登録された場合に自動的にツイートをします)

「Next」ボタンをクリックすると、確認ページへ移動しますので「同意しました」チェックボックスにチェックをいれて「Looks good!」ボタンをクリックします。

これで申請自体は完了しました。

後は、メールアドレスに本人確認のメールが届いていますので、「Confirm your email」ボタンをクリックすればOKです。

クリックすると以下のようなページが表示されます。

(超意訳: 完了〜!もうAPIとかいろいろ使えるよ😊✨)

アプリを登録

登録が完了したら、同じページの中程に「Create an app」という項目があるのでクリックします。

そして、ページ右上の「Create an app」ボタンをクリックします。

すると、作成するアプリの内容を聞かれますので、簡単に以下のようにして簡単に回答します。

・App name

Laravel 5.8 Test(アプリ名)

・Application description

A tweet test from Laravel 5.8.

(Laravel 5.8からのツイート・テスト)

・Tell us how this app will be used (required)

If information about a specific product is registered in Laravel, the content will be tweeted automatically.

(特定の商品が登録されたら、自動的にツイートします)

入力が済んだら、「Create」ボタンをクリックします。

すると、制限事項に関する情報が表示されるので問題なければ「Create」ボタンをクリックしてください。

すると、アプリ登録が完了し以下のような表示になるので、「Keys and tokens」をクリックします。

初めて表示する場合は、APIキーは存在していますがトークンが作成されていない状態なので、まずは「Access token & acdess token secret」の下にある「Create」ボタンをクリックしてください。

すると、以下のようにトークンも表示されます。

開発のご依頼お待ちしております
開発のご依頼はこちらから: お問い合わせ
どうぞよろしくお願いいたします! by 九保すこひ

おわりに

ということで、今回はLaravelからTwitterに自動で投稿する方法をお届けしました。

今回は商品が登録されたら投稿という形でしたが、以下のような内容も考えられますので、可能性は無限大と言っていいんじゃないでしょうか。

  • 登録されている商品が値下げされた
  • 毎週水曜日の5%引きセールを投稿
  • 登録者数がゾロ目になったらみんなに報告
  • 商品が削除されたら「売り切れ」として報告

などなど。

ぜひ皆さんのサイトもTwitterと連携をしてみてはいかがでしょうか。

ではでは〜!

このエントリーをはてなブックマークに追加       follow us in feedly