如何使用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
Tweet
Eloquent 模型 - 一些用于显示推文小部件的刀片模板
在阅读本教程时,您可以按照此 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 提供了一种方法 可以在不中断脚本的情况下更新它们。