如何使用Laravel实时处理推文
介绍
本教程将展示如何使用 Twitter Streaming APIs 实时处理来自 Laravel 应用程序的推文。 有多种用例:也许您想自动回复提及您的公司,通过 Twitter 举办比赛,或者在用户抱怨您的产品时创建支持票。 在本教程中,我们将构建一个“特色推文”小部件,以在我们的应用程序主页上显示已批准的推文。
您可能会首先查看许多开发人员熟悉的 Twitter REST API。 这些 API 允许您做很多很酷的事情:代表应用程序用户读写推文、管理关注者和列表等等。 但是,如果您想在发送推文时对其进行处理,则 REST API 很难管理。 分页和速率限制很快成为后勤噩梦。
REST API 强制您 请求 信息,而流式 API 向您提供 信息。 您可以在 文档 中阅读有关它如何工作的更多信息,但它基本上是从 Twitter 到您的应用程序的管道,它提供持续的推文流。
在本教程结束时,您将在您的应用程序中拥有不断更新的推文集合,您可以批准或不批准这些推文显示在您的主页上。 这是您最终会得到的预览。
概述
工具
- Public Streaming API: 共有三个 Streaming API,但我们关心的是公共 API——更具体地说,是“过滤器”端点。 此端点将提供所有公共推文的流,按您定义的关键字过滤。
- Phirehose: Phirehose 库负责流式处理 API 的身份验证和其他实现细节。
- Homestead: 虽然您可以使用您选择的环境构建您的应用程序,但本教程将假设您使用的是 Homestead。
笔记
- Twitter 对 Streaming API 进行了特殊处理。 您只能从一个 Twitter 应用程序打开一个连接。
- 由于与 Streaming API 的连接具有特殊性质,因此将其与应用程序的面向 Web 的部分分开是很重要的。 在本教程中,我们将使用 Artisan 控制台命令创建连接。
- 由于 Streaming API 非常挑剔,重要的是不要在收集推文的同一进程中 对推文做任何 密集操作。 在本教程中,您只需将推文放入队列中。
- 请注意您正在跟踪的条款。 如果您尝试跟踪所有提及某个受欢迎的名人,您的应用程序可能会崩溃。
应用结构
以下是我们将要创建的应用程序的主要部分:
- 一个名为
TwitterStream的类,它将扩展 Phirehose 并在推文到达时将推文放入队列 - 一个 Artisan 命令
ConnectToStreamingAPI,它将使用TwitterStream的实例打开与 Streaming API 的连接 - 一个 作业类 、
ProcessTweet,它将包含处理推文时从队列中拉出时处理推文的处理程序 - A
TweetEloquent 模型 - 一些用于显示推文小部件的刀片模板
在阅读本教程时,您可以按照此 GitHub 存储库进行操作。 它对每个步骤都有单独的提交:
https://github.com/dabernathy89/Laravel-Twitter-Streaming-API-Demo
第 1 步 — 创建一个新的 Laravel 应用程序
使用 Laravel 安装程序,创建一个新的 Laravel 实例:
laravel new twitter-stream-test
完成后,将应用程序添加到您的 Homestead 配置文件 。 不要忘记使用您添加到配置中的任何自定义域来编辑您的 hosts 文件。 启动宅基地:
homestead up --provision
SSH 进入宅基地:
homestead ssh
最后,将 cd 放入您应用的文件夹中。
第 2 步 - 安装 Phirehose
接下来,您需要拉入 Phihose 库。 运行 composer require fennb/phirehose 以获取最新版本。 Phirehose 不支持 PSR-0 或 PSR-4 自动加载,因此您需要使用 Composer 的 classmap 自动加载选项。 在 database 条目之后添加一行:
"classmap": [
"database",
"vendor/fennb/phirehose/lib"
],
第 3 步 — 创建 ProcessTweet 作业
我在概述中提到,我们将把来自 Streaming API 的所有推文放到一个队列中。 在 Laravel 5.2 中,有一些特殊的 Job 类 用于处理队列中的项目。 您的应用程序将有一个名为 ProcessTweet 的工作,它将负责将推文从队列中拉出并对其进行处理。 您可以使用简单的 Artisan 命令创建作业:
php artisan make:job ProcessTweet
这将在您的 app/Jobs 文件夹中生成一个 Job 类。 您现在只需要对其进行两次调整。
- 你知道这个类将处理一条推文(即使我们还没有设置它)。 将 $tweet 变量传递给构造函数并将其设置为属性。
- 在
handle()方法中对推文做一些事情。 现在你可以只var_dump()来自推文的一些基本信息。
<?php
namespace App\Jobs;
use App\Jobs\Job;
use Illuminate\Queue\SerializesModels;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Contracts\Queue\ShouldQueue;
class ProcessTweet extends Job implements ShouldQueue
{
use InteractsWithQueue, SerializesModels;
protected $tweet;
/**
* Create a new job instance.
*
* @return void
*/
public function __construct($tweet)
{
$this->tweet = $tweet;
}
/**
* Execute the job.
*
* @return void
*/
public function handle()
{
$tweet = json_decode($this->tweet,true);
var_dump($tweet['text']) . PHP_EOL;
var_dump($tweet['id_str']) . PHP_EOL;
}
}
第 4 步 — 创建 TwitterStream 类
要使用 Phirehose,您需要创建一个简单的类来扩展基本 Phirehose 类。 这可以去任何你喜欢的地方,但我只是将它直接放在app文件夹中。 这是完整的课程:
<?php
namespace App;
use OauthPhirehose;
use App\Jobs\ProcessTweet;
use Illuminate\Foundation\Bus\DispatchesJobs;
class TwitterStream extends OauthPhirehose
{
use DispatchesJobs;
/**
* Enqueue each status
*
* @param string $status
*/
public function enqueueStatus($status)
{
$this->dispatch(new ProcessTweet($status));
}
}
有几点需要注意:
- 该类引入了
DispatchesJobs特征,以便轻松地将推文推送到队列中。 - 只有一个方法
enqueueStatus将由 Phirehose 为每条推文调用。
第 5 步 — 注册 TwitterStream 类
您需要在 Laravel 容器中注册 TwitterStream 类,以便它可以正确地拉入其依赖项。 在 AppServiceProvider 类的 register 方法中,添加以下内容:
$this->app->bind('App\TwitterStream', function ($app) {
$twitter_access_token = env('TWITTER_ACCESS_TOKEN', null);
$twitter_access_token_secret = env('TWITTER_ACCESS_TOKEN_SECRET', null);
return new TwitterStream($twitter_access_token, $twitter_access_token_secret, Phirehose::METHOD_FILTER);
});
您还需要在服务提供商的顶部添加 use Phirehose; 和 use App\TwitterStream;。 现在不要担心环境变量 - 您很快就会创建它们。
第 6 步 — 创建 Artisan 命令
生成 Artisan 命令,以便您可以通过命令行启动 Streaming API 连接:
php artisan make:console ConnectToStreamingAPI
这将生成样板控制台命令类。 然后你需要:
- 更新命令的签名和描述
- 通过构造函数拉入
TwitterStream类的实例 - 在命令的
handle()方法中,完成 Phirehose 对象的配置,包括您的搜索词,然后打开连接
这是完成的命令的样子。 它将拉入包含关键字 scotch_io 的推文:
<?php
namespace App\Console\Commands;
use Illuminate\Console\Command;
use App\TwitterStream;
class ConnectToStreamingAPI extends Command
{
/**
* The name and signature of the console command.
*
* @var string
*/
protected $signature = 'connect_to_streaming_api';
/**
* The console command description.
*
* @var string
*/
protected $description = 'Connect to the Twitter Streaming API';
protected $twitterStream;
/**
* Create a new command instance.
*
* @return void
*/
public function __construct(TwitterStream $twitterStream)
{
$this->twitterStream = $twitterStream;
parent::__construct();
}
/**
* Execute the console command.
*
* @return mixed
*/
public function handle()
{
$twitter_consumer_key = env('TWITTER_CONSUMER_KEY', '');
$twitter_consumer_secret = env('TWITTER_CONSUMER_SECRET', '');
$this->twitterStream->consumerKey = $twitter_consumer_key;
$this->twitterStream->consumerSecret = $twitter_consumer_secret;
$this->twitterStream->setTrack(array('scotch_io'));
$this->twitterStream->consume();
}
}
您还需要注册命令。 只需更新 App\Console\Kernel 类中的 $commands 属性:
protected $commands = [
Commands\ConnectToStreamingAPI::class
];
第 7 步 — 创建一个 Twitter 应用程序
用推特生成应用程序,获取密钥和访问令牌。 将它们添加到您的 .env 文件中:
TWITTER_CONSUMER_KEY=KEY TWITTER_CONSUMER_SECRET=SECRET TWITTER_ACCESS_TOKEN=TOKEN TWITTER_ACCESS_TOKEN_SECRET=SECRET
第 8 步 — 配置您的队列驱动程序
您可以根据需要设置队列,但出于演示目的,数据库驱动程序可以正常工作。 要进行设置,请更新您的 .env 文件:
QUEUE_DRIVER=database
默认情况下,您的应用程序将查找名称为 homestead 的数据库。 如果您想为您的应用程序使用单独的数据库,请不要忘记在 .env 文件中更新它:
DB_DATABASE=twitterstreamtest
您还需要运行以下命令来准备数据库队列:
php artisan queue:table
php artisan migrate
第 9 步 — 阅读一些推文!
现在你应该准备好开始处理一些推文了。 运行您的 Artisan 命令:
php artisan connect_to_streaming_api
您将在 Phirehose 的控制台中看到有关连接的一些信息。 它不会在每次处理推文时告诉您,但它会不时地为您提供有关连接状态的更新。
不久之后,您应该会有一些关于 Scotch.io 的推文排在队列中。 要检查是否有推文进入,请转到您的数据库并查看 jobs 表:
现在让我们尝试处理队列。 打开一个新的 shell 窗口,导航到 Homestead 中的应用程序,然后将第一项从队列中拉出:
php artisan queue:work
如果一切顺利,您应该会在控制台中看到推文的文本和 ID,来自 ProcessTweet 作业中的 handle() 方法。
第 10 步 — 设置推文模型
现在您已成功连接到 Streaming API,是时候开始构建您的精选推文小部件了。 首先生成一个 Tweet 模型和相应的数据库迁移:
php artisan make:model Tweet --migration
我们将为我们的模型添加一些属性,所以现在继续设置它们。 下面是您完成的模型和迁移的样子 - 请注意,我使用字符串作为模型 ID,因为 Twitter ID 很大。
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class Tweet extends Model
{
protected $fillable = ['id','json','tweet_text','user_id','user_screen_name','user_avatar_url','public','approved'];
}
<?php
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;
class CreateTweetsTable extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::create('tweets', function (Blueprint $table) {
$table->string('id');
$table->text('json');
$table->string('tweet_text')->nullable();
$table->string('user_id')->nullable();
$table->string('user_screen_name')->nullable();
$table->string('user_avatar_url')->nullable();
$table->boolean('approved');
$table->timestamps();
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::drop('tweets');
}
}
最后,迁移您的数据库:
php artisan migrate
第 11 步 — 使 ProcessTweet 工作变得有用
现在 ProcessTweet 作业只是在控制台中显示有关推文的一些信息。 更新 handle 方法,以便将推文保存到数据库:
public function handle()
{
$tweet = json_decode($this->tweet,true);
$tweet_text = isset($tweet['text']) ? $tweet['text'] : null;
$user_id = isset($tweet['user']['id_str']) ? $tweet['user']['id_str'] : null;
$user_screen_name = isset($tweet['user']['screen_name']) ? $tweet['user']['screen_name'] : null;
$user_avatar_url = isset($tweet['user']['profile_image_url_https']) ? $tweet['user']['profile_image_url_https'] : null;
if (isset($tweet['id'])) {
Tweet::create([
'id' => $tweet['id_str'],
'json' => $this->tweet,
'tweet_text' => $tweet_text,
'user_id' => $user_id,
'user_screen_name' => $user_screen_name,
'user_avatar_url' => $user_avatar_url,
'approved' => 0
]);
}
}
完成后,您可以运行队列侦听器以清空队列并将推文导入数据库:
php artisan queue:listen
您现在应该能够在数据库中看到一些推文:
第 12 步 — 设置身份验证
感谢 Laravel 的 auth 脚手架,这可能是最简单的一步。 赶紧跑:
php artisan make:auth
第 13 步 - 将推文传递到欢迎视图
目前,您的应用将仅在主登录页面上显示精选推文小部件。 经过身份验证的用户将被允许批准或不批准推文,因此他们将收到所有推文(分页)。 访问者将只能看到最近批准的五条推文。
通过更新 routes.php 文件中的主路由,将推文传递到现有的 welcome 视图中:
Route::get('/', function () {
if (Auth::check()) {
$tweets = App\Tweet::orderBy('created_at','desc')->paginate(5);
} else {
$tweets = App\Tweet::where('approved',1)->orderBy('created_at','desc')->take(5)->get();
}
return view('welcome', ['tweets' => $tweets]);
});
第 14 步 — 创建刀片模板
您需要为特色推文小部件创建三个刀片模板,全部存储在 resources/views/tweets 目录中:
list.blade.php将是面向公众的近期推文列表list-admin.blade.php将是所有推文的面向管理员的列表tweet.blade.php将是两个推文列表的一小部分共同点
list-admin 视图是最复杂的。 该列表包含在一个表单中,并包含一些无线电输入,以便注册用户可以轻松地批准推文。
以下是三个模板,按顺序排列:
// list.blade.php
@foreach($tweets as $tweet)
<div class="tweet">
@include('tweets.tweet')
</div>
@endforeach
// list-admin.blade.php
<form action="/approve-tweets" method="post">
{{ csrf_field() }}
@foreach($tweets as $tweet)
<div class="tweet row">
<div class="col-xs-8">
@include('tweets.tweet')
</div>
<div class="col-xs-4 approval">
<label class="radio-inline">
<input
type="radio"
name="approval-status-{{ $tweet->id }}"
value="1"
@if($tweet->approved)
checked="checked"
@endif
>
Approved
</label>
<label class="radio-inline">
<input
type="radio"
name="approval-status-{{ $tweet->id }}"
value="0"
@unless($tweet->approved)
checked="checked"
@endif
>
Unapproved
</label>
</div>
</div>
@endforeach
<div class="row">
<div class="col-sm-12">
<input type="submit" class="btn btn-primary" value="Approve Tweets">
</div>
</div>
</form>
{!! $tweets->links() !!}
// tweet.blade.php
<div class="media">
<div class="media-left">
<img class="img-thumbnail media-object" src="{{ $tweet->user_avatar_url }}" alt="Avatar">
</div>
<div class="media-body">
<h4 class="media-heading">{{ '@' . $tweet->user_screen_name }}</h4>
<p>{{ $tweet->tweet_text }}</p>
<p><a target="_blank" href="https://twitter.com/{{ $tweet->user_screen_name }}/status/{{ $tweet->id }}">
View on Twitter
</a></p>
</div>
</div>
第 15 步 - 在您的欢迎视图中显示小部件
准备好刀片模板后,您现在可以将它们带入 welcome 视图:
@extends('layouts.app')
@section('content')
<div class="container">
<div class="row">
<div class="col-md-8 col-md-offset-2">
<div class="tweet-list">
@if(Auth::check())
@include('tweets.list-admin')
@else
@include('tweets.list')
@endif
</div>
</div>
</div>
</div>
@endsection
要在您的列表中获得一些非常基本的样式,请将以下 CSS 添加到您的 app.blade.php 文件中:
.tweet {
padding: 10px;
border: 1px solid #ccc;
border-radius: 5px;
margin-bottom: 20px;
}
完成后,您现在可以查看小部件! 前往浏览器并访问您应用的主页。 如果您没有看到任何推文,请确保运行队列侦听器 (php artisan queue:listen) 以处理可能仍在其中的任何内容。 授权用户应该会看到类似这样的内容(还有更多推文……并且不那么模糊):
第 16 步 - 添加批准推文的路线
最后一步是使第 14 步中的管理员列表正常工作。 list-admin 模板中的表单当前指向不存在的路由。 您需要将其添加到您的 routes.php 文件中。 在这条路线中,我们将做一些基本的逻辑来批准或不批准推文。 这是它的外观:
Route::post('approve-tweets', ['middleware' => 'auth', function (Illuminate\Http\Request $request) {
foreach ($request->all() as $input_key => $input_val) {
if ( strpos($input_key, 'approval-status-') === 0 ) {
$tweet_id = substr_replace($input_key, '', 0, strlen('approval-status-'));
$tweet = App\Tweet::where('id',$tweet_id)->first();
if ($tweet) {
$tweet->approved = (int)$input_val;
$tweet->save();
}
}
}
return redirect()->back();
}]);
有了这条路线,您现在应该能够将推文标记为已批准或未批准。 尝试批准一些,然后以未经身份验证的用户身份访问该页面。 它应该看起来像这样:
结论
就是这样! 你已经将你的 Laravel 应用程序连接到 Twitter 流 API。 但是,它还没有完全准备好生产。 您还应该考虑其他一些事项:
- 您可能需要配置 Laravel 用来监控队列侦听器 的 Supervisor ,以监控您的 Artisan 命令并在失败时重新启动它。
- 您需要在部署过程中处理对 Supervisor 的调用。
- 您的搜索词可能会发生变化,Phiehose 提供了一种方法 可以在不中断脚本的情况下更新它们。