alexislefebvre/async-tweets-bundle
## Getting Started
### Minimal Setup for Laravel Integration
Since this is a Symfony bundle, Laravel integration requires **Symfony Bridge** or a **standalone approach** (recommended for Laravel). Here’s how to start:
1. **Install Dependencies**
```bash
composer require abraham/twitteroauth doctrine/dbal doctrine/orm
(Note: Laravel uses illuminate/database instead of Doctrine by default—see "Implementation Patterns" for alternatives.)
Configure Twitter API Keys
Store keys in .env (Laravel convention):
TWITTER_CONSUMER_KEY=your_key
TWITTER_CONSUMER_SECRET=your_secret
TWITTER_TOKEN=your_token
TWITTER_TOKEN_SECRET=your_token_secret
First Use Case: Fetch Tweets Create a Laravel command to mimic the Symfony CLI:
php artisan make:command FetchTweets
Command Logic (in app/Console/Commands/FetchTweets.php):
use Abraham\TwitterOAuth\TwitterOAuth;
use Illuminate\Support\Facades\Log;
public function handle() {
$connection = new TwitterOAuth(
config('twitter.consumer_key'),
config('twitter.consumer_secret'),
config('twitter.token'),
config('twitter.token_secret')
);
$tweets = $connection->get('statuses/home_timeline', ['count' => 200]);
$this->storeTweets($tweets); // Implement storage logic (see below)
$this->info('Fetched ' . count($tweets) . ' tweets.');
}
Run it:
php artisan fetch:tweets
Database Setup
Create a tweets table manually or use a migration:
php artisan make:migration create_tweets_table
Migration Example (adapted from Symfony’s schema):
Schema::create('tweets', function (Blueprint $table) {
$table->id();
$table->string('user_id');
$table->text('text');
$table->string('profile_image_url_https')->nullable();
$table->integer('retweet_count')->default(0);
$table->integer('favorite_count')->default(0);
$table->boolean('is_retweet')->default(false);
$table->timestamps();
});
php artisan fetch:tweets hourly via Laravel’s scheduler (app/Console/Kernel.php):
protected function schedule(Schedule $schedule) {
$schedule->command('fetch:tweets')->hourly();
}
php artisan make:job FetchTweetsJob
public function handle() {
$this->fetchAndStoreTweets();
}
Dispatch it in the command:
FetchTweetsJob::dispatch();
public function index() {
$tweets = Tweet::latest()->paginate(5); // Match Symfony’s 5/tweet limit
return view('tweets.index', compact('tweets'));
}
resources/views/tweets/index.blade.php):
@foreach($tweets as $tweet)
<div class="tweet">
<img src="{{ $tweet->profile_image_url_https }}" alt="Profile">
<p>{{ $tweet->text }}</p>
<span>❤️ {{ $tweet->favorite_count }}</span>
<span>🔄 {{ $tweet->retweet_count }}</span>
</div>
@endforeach
--table output).is_retweet flag and style accordingly (e.g., italics or a "RT" prefix).media table (one-to-many with tweets) and display with:
@if($tweet->media)
<img src="{{ $tweet->media->url }}" class="img-fluid">
@endif
read_at column to the tweets table and update via:
$tweet->read_at = now();
$tweet->save();
Tweet::whereNull('read_at')->latest()->get();
php artisan make:command PruneOldTweets
public function handle() {
Tweet::where('created_at', '<', now()->subDays(30))->delete();
$this->info('Pruned old tweets.');
}
$schedule->command('prune:old-tweets')->weekly();
$tweetRepo->findBy(...) → Laravel: Tweet::where(...)->get().EntityManager::persist() → Laravel: $tweet->save().class TweetRepository {
public function findUnread() {
return Tweet::whereNull('read_at')->latest()->get();
}
}
try {
$tweets = $connection->get('statuses/home_timeline', ['count' => 200]);
} catch (\Exception $e) {
if ($e->getCode() === 88) { // Rate limit exceeded
sleep(60); // Wait 1 minute
retry();
}
}
<img src="{{ $tweet->media->url }}" loading="lazy" class="max-w-full h-auto">
storage/logs/laravel.log:
$this->info('Fetching tweets...'); // Logs to console
Log::info('Tweets fetched', ['count' => count($tweets)]); // Logs to file
php artisan schedule:run
retweeted_status. Parse it:
$text = $tweetData['retweeted_status']['text'] ?? $tweetData['text'];
$isRetweet = isset($tweetData['retweeted_status']);
Schema::table('tweets', function (Blueprint $table) {
$table->index('created_at');
$table->index('user_id');
});
$mock = Mockery::mock('overload:Abraham\TwitterOAuth\TwitterOAuth');
$mock->shouldReceive('get')->andReturn([/* mock data */]);
$response = $this->get('/tweets');
$response->assertSee('Twitter timeline');
.env and validate input:
$this->validate(request(), ['tweet_id' => 'required|integer']);
in_reply_to_status_id (for threading).lang (to filter by language).entities (for hashtags/mentions).How can I help you explore Laravel packages today?