
九保すこひです(フリーランスのITコンサルタント、エンジニア)
さてさて、マーケティングとしても重要な位置づけになっているSNS
の勉強を続けています。
なぜならSNS
は、
- 広告を出さずに商品へ誘導できたり、
- 価値観を同じにできるので採用をしやすかったり、
- 口コミが出ればさらに集客できる
などメリットが多数あります。
でも、逆に一番のデメリットと言えば・・・
そう、
炎上する
可能性があるってことですね。
しかもX
(Twitter
)の場合は拡散性がとても高いので一度火がつくと延焼しやすいと言われてます。
そこで
今回はLaravel
を使って「ツイートを承認式にして、事前に誰かのチェックを入れられる」機能をつくってみることにしました。
ぜひ何かの参考になりましたら嬉しいです。
「ビックリマンチョコ、
美味しかったなぁ。
手の感覚が当時と一緒だし」
開発環境: Laravel 11.x
目次 [非表示]
実装する機能の概要
今回は、例えば「アイドルとマネージャーさん」のような関係を考えてます。
つまり、
- アイドルさんが今回のシステムでツイートを登録する
- マネージャーさんにメールで文章が届く
- チェックして問題なければ、ツイートを許可し実際に X へ反映する
という流れです。
※ なので、もしかすると「新人さんにツイートを任せるけどちょっと心配…」といったケースにも使えるかもしれませんね
前提として
すでにTwitter API
にアクセスするための以下4つのキーを取得していることが前提です。
- CONSUMER KEY(API Key)
- CONSUMER SECRET (API Secret)
- ACCESS TOKEN(Access Token)
- ACCESS SECRET(Access Secret)
なお、APIの登録やキーの取得は以下のページがわかりやすいです。
そして、4つのキーを取得したら、.env
にセットしておいてください。
.env
TWITTER_CONSUMER_KEY="(ここにAPI Key)"
TWITTER_CONSUMER_SECRET="(ここにAPI Key Secret)"
TWITTER_ACCESS_TOKEN="(ここにAccess Token)"
TWITTER_ACCESS_TOKEN_SECRET="(ここにAccess Token Secret)"
※ また、今回は「ツイートの承認部分」がメインなのでツイートの保存などは省略します。
パッケージをインストールする
次にツイートするために必要なパッケージをインストールします。
以下のコマンドを実行して下さい。
composer require abraham/twitteroauth
これで準備は完了です。
では実際につくっていきましょう
DBまわりをつくる
まずはデータベース周りです。
以下のコマンドで一気につくってしまいましょう!
php artisan make:model Tweet -m
すると、モデルとマイグレーションが作成されるので中身を以下のようにします。
app/Models/Tweet.php
<?php
namespace App\Models;
use App\Events\TweetSaved;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
class Tweet extends Model
{
use HasFactory;
protected $dispatchesEvents = [
'saved' => TweetSaved::class,
];
}
なお、この中のTweetSaved
イベントは次でつくります。
database/migrations/****_**_**_******_create_tweets_table.php
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
/**
* Run the migrations.
*/
public function up(): void
{
Schema::create('tweets', function (Blueprint $table) {
$table->id();
$table->string('body')->comment('ツイート本文');
$table->dateTime('tweeted_at')->nullable()->comment('ツイート日時');
$table->timestamps();
});
}
/**
* Reverse the migrations.
*/
public function down(): void
{
Schema::dropIfExists('tweets');
}
};
では、この状態でマイグレーションを実行してみましょう。
以下のコマンドを実行して下さい。
php artisan migrate
すると、実際のテーブルはこうなりました。
イベントをつくる
では、モデルの中でセットしたTweetSaved
をつくって、「Tweetモデルでデータが保存されたら自動で実行される」コードをつくっていきましょう
以下のコマンドを実行して下さい。
php artisan make:event TweetSaved
※なお、変更したときも通知できるようにsaved
イベントを選択しました。
すると、ファイルが作成されるので中身を以下のようにします。
app/Events/TweetSaved.php
<?php
namespace App\Events;
use App\Mail\TweetPosted;
use App\Models\Tweet;
use Illuminate\Broadcasting\Channel;
use Illuminate\Broadcasting\InteractsWithSockets;
use Illuminate\Broadcasting\PresenceChannel;
use Illuminate\Broadcasting\PrivateChannel;
use Illuminate\Contracts\Broadcasting\ShouldBroadcast;
use Illuminate\Foundation\Events\Dispatchable;
use Illuminate\Queue\SerializesModels;
use Illuminate\Support\Facades\Mail;
class TweetSaved
{
use Dispatchable, InteractsWithSockets, SerializesModels;
/**
* Create a new event instance.
*/
public function __construct(Tweet $tweet)
{
$to = 'manager@example.com'; // マネージャーのメールアドレス
Mail::to($to)->send(new TweetPosted($tweet)); // メール送信
}
/**
* Get the channels the event should broadcast on.
*
* @return array<int, \Illuminate\Broadcasting\Channel>
*/
public function broadcastOn(): array
{
return [
new PrivateChannel('channel-name'),
];
}
}
Mailable をつくる
では、ツイートが登録されたときに(マネージャーさんに)送信されるメール送信の部分をつくっていきましょう。
以下のコマンドを実行して下さい。
php artisan make:mail TweetPosted
※イベントのTweetSaved
と名前がかぶると面倒なのでTweetPosted
にしました
すると、Mailable
ファイルが作成されるので中身を変更します。
app/Mail/TweetPosted.php
<?php
namespace App\Mail;
use App\Models\Tweet;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Mail\Mailable;
use Illuminate\Mail\Mailables\Content;
use Illuminate\Mail\Mailables\Envelope;
use Illuminate\Queue\SerializesModels;
class TweetPosted extends Mailable
{
use Queueable, SerializesModels;
/**
* Create a new message instance.
*/
public function __construct(private Tweet $tweet)
{}
/**
* Get the message envelope.
*/
public function envelope(): Envelope
{
return new Envelope(
subject: 'ツイートが投稿されました',
);
}
/**
* Get the message content definition.
*/
public function content(): Content
{
$tweet_approval_url = route('tweet.approve', ['tweet' => $this->tweet->id]);
return new Content(
view: 'emails.tweet_posted',
with: [
'tweet' => $this->tweet,
'tweet_approval_url' => $tweet_approval_url,
],
);
}
/**
* Get the attachments for the message.
*
* @return array<int, \Illuminate\Mail\Mailables\Attachment>
*/
public function attachments(): array
{
return [];
}
}
Mailable のビューをつくる
では、先ほどのTweetPosted
の中でセットしたビューを作成します。
以下のコマンドを実行して下さい。
php artisan make:view emails.tweet_posted
resources/views/emails/tweet_posted.blade.php
ツイートが投稿されました。<br>
投稿の判断をしてください。<br><br>
【ツイート内容】<br>
{!! nl2br($tweet->body) !!}<br><br>
--------------------------------<br>
投稿を承認しますか?<br>
<a href="{{ $tweet_approval_url }}">X に反映させる</a>
コントローラーをつくる
続いてコントローラーです。
以下のコマンドを実行して下さい。
app/Http/Controllers/TweetController.php
<?php
namespace App\Http\Controllers;
use Abraham\TwitterOAuth\TwitterOAuth;
use App\Models\Tweet;
use Illuminate\Http\Request;
class TweetController extends Controller
{
public function test()
{
// テスト用にここでツイート投稿する
$tweet = new Tweet();
$tweet->body = "パスタ買って返ったら、\nウチに新品のパスタ2袋も買ってあった。
\n\n今日からイタリア人になります。
";
$tweet->save(); // ここで saved イベントが実行される
return 'メールが送信されました!';
}
public function approve(Tweet $tweet)
{
$tweet_result = $this->tweet($tweet);
if ($tweet_result === true) {
$tweet->tweeted_at = now();
$tweet->saveQuietly(); // ここではセーブイベントを実行しない
return 'ツイート完了しました!';
}
return 'ツイートに失敗しました。。';
}
private function tweet(Tweet $tweet): bool
{
$connection = new TwitterOAuth( // 本来は config から取得するべきです
env('TWITTER_CONSUMER_KEY'),
env('TWITTER_CONSUMER_SECRET'),
env('TWITTER_ACCESS_TOKEN'),
env('TWITTER_ACCESS_TOKEN_SECRET')
);
$connection->setApiVersion(2);
$parameters = [
'text' => $tweet->body,
];
$connection->post('tweets', $parameters, ['jsonPayload' => true]);
return in_array($connection->getLastHttpCode(), [200, 201], true);
}
}
test()
はテスト用につくったもので、アクセスすると自動でツイートが保存され、自動でTweetSaved
イベントが実行されるという流れです。
ルートをつくる
では、最後にルートです。
routes/web.php
<?php
use Illuminate\Support\Facades\Route;
use App\Http\Controllers\TweetController;
// Tweet
// 注: 本来はログイン必須にするべきです!
Route::prefix('tweet')->controller(TweetController::class)->group(function () {
Route::get('test', 'test');
Route::get('approve/{tweet}', 'approve')->name('tweet.approve');
});
なお、コード中にも書いてありますが、ログイン必須にすべきですし、さらに言うと「投稿できる人」と「承認できる人」の認証タイプ(guard
)は分けておくべきです。(投稿した人が承認できると問題なので)
では、これ作業は完了です。
お疲れ様でした
テストしてみる
では、実際にテストしてみましょう
ブラウザでテスト用に作ったURL
(https://******/tweet/test
)にアクセスします。
すると・・・・・・
はい
メールが送信されたメッセージが表示されました。
では、実際にメールを確認してみましょう。
どうなるでしょうか・・・・・・
はい
承認用のメールが送信されていました。
では、画像の中にあるリンクをクリックして承認してみましょう。
うまくいくでしょうか・・・・・・
はい
ツイート完了メッセージが表示されました。
で、実際のツイートはというと・・・・・・
このように投稿されていました。
では、テーブルの方も確認しておきましょう。
こちらもきちんとtweeted_at
も登録されていました。
このデータを元にすでに投稿されたかどうかをチェックできるわけですね。
すべて成功です
企業様へのご提案
今回のようなシステムを組むことでツイートへの炎上を事前に防ぐことが期待できます。
また、今回は一人だけの承認でしたが、
- 複数人での承認も可能ですし、
- 全員 or 過半数が OK ならツイートする
というようなシステムをつくることもできます。
また、Twitter API
は月 1,500回までなら無料(2024.5.3 現在)で使用することもできるため費用負担もそれほど必要ではないこともおすすめする理由の1つです。(毎日5ツイートしても150ツイートです)
もしそういったシステムをご利用になりたい場合は、ぜひお問い合わせからご連絡下さい。
お待ちしております。
おわりに
ということで、今回は「X(Twitter)の見守り機能」を作ってみました。
(利用規約がどうなってるかはわかりませんが)親が管理して子供がツイートする場面とかにも使えるでしょうし、経営権のある複数人がOK
したものだけツイートするという使い方もできるかもですね。
ぜひこれで炎上が減ればいいと思ってます。(というか、ちょっとトガッたことを言うと、自分が炎上しそうで怖い今日この頃です)
ではでは〜
「ちょっとずつ仕事&プライベート垢
でいいね増えてきました
有料教材のおかげ。迫社長、感謝」