desarrolla2/twitter-client-bundle
Symfony bundle that integrates a Twitter client, providing services and configuration to call the Twitter API from your app. A lightweight wrapper to authenticate and perform common Twitter operations without wiring the client manually.
Installation:
composer require desarrolla2/twitter-client-bundle
Register the bundle in config/app.php under providers:
Desarrolla2\TwitterClientBundle\TwitterClientServiceProvider::class,
Environment Configuration:
Add Twitter API credentials to .env:
TWITTER_CONSUMER_KEY=your_consumer_key
TWITTER_CONSUMER_SECRET=your_consumer_secret
TWITTER_ACCESS_TOKEN=your_access_token
TWITTER_ACCESS_TOKEN_SECRET=your_access_token_secret
First Use Case:
Inject the TwitterClient service into a controller or command:
use Desarrolla2\TwitterClientBundle\TwitterClient;
class TwitterController extends Controller
{
public function __construct(private TwitterClient $twitterClient)
{
}
public function showTimeline()
{
$tweets = $this->twitterClient->getUserTimeline('laravel');
return view('timeline', compact('tweets'));
}
}
Leverage Laravel’s service container to bind the Twitter client:
// In AppServiceProvider@boot()
$this->app->bind(TwitterClient::class, function ($app) {
return new TwitterClient(
$app['config']['twitter.api_key'],
$app['config']['twitter.api_secret'],
$app['config']['twitter.access_token'],
$app['config']['twitter.access_token_secret']
);
});
Create an Artisan command for bulk operations:
use Illuminate\Console\Command;
use Desarrolla2\TwitterClientBundle\TwitterClient;
class FetchTrendingTopics extends Command
{
protected $signature = 'twitter:trending';
protected $description = 'Fetch trending topics';
public function handle(TwitterClient $twitterClient)
{
$topics = $twitterClient->getTrends('1'); // WOEID for worldwide
$this->info('Trending Topics:');
foreach ($topics as $topic) {
$this->line($topic['name']);
}
}
}
Extend the bundle by listening to tweet events (if supported):
// In EventServiceProvider@boot()
event(new TweetFetched($tweet));
Normalize Twitter API responses into Laravel collections:
$tweets = collect($twitterClient->getUserTimeline('laravel'))
->map(function ($tweet) {
return [
'id' => $tweet->id,
'text' => $tweet->text,
'created_at' => $tweet->created_at,
'user' => $tweet->user->screen_name,
];
});
Implement retry logic for rate-limited requests:
use Spatie\Backoff\BackableInterface;
use Spatie\Backoff\ShouldRetry;
class TwitterClient implements BackableInterface
{
public function getUserTimeline(string $screenName): array
{
try {
return $this->client->getUserTimeline($screenName);
} catch (RateLimitExceededException $e) {
if ($this->shouldRetry($e)) {
$this->retry();
}
throw $e;
}
}
}
Deprecated API Version: The bundle uses Twitter API v1.1, which is deprecated. Plan to migrate to v2 or fork the bundle.
Laravel-Symfony DI Conflicts: The bundle assumes Symfony’s DI container. Bind services manually:
$this->app->singleton(TwitterClient::class, function ($app) {
return new TwitterClient(
$app['config']['twitter.api_key'],
$app['config']['twitter.api_secret'],
$app['config']['twitter.access_token'],
$app['config']['twitter.access_token_secret']
);
});
No Built-in Caching: API responses aren’t cached by default. Implement Redis caching:
$tweets = Cache::remember("tweets_{$screenName}", now()->addHours(1), function () use ($twitterClient, $screenName) {
return $twitterClient->getUserTimeline($screenName);
});
Rate Limit Headers Ignored:
The bundle may not handle X-Rate-Limit-* headers. Add middleware:
$client->getMiddleware()->push(
Middleware::retry(
function ($retries, RequestOptions $options, ResponseInterface $response) {
return $response->hasHeader('x-rate-limit-remaining') &&
$response->getHeader('x-rate-limit-remaining')[0] == '0';
},
function ($retries, RequestOptions $options, ResponseInterface $response) {
$retryAfter = $response->getHeader('x-rate-limit-reset')[0];
return $retryAfter;
}
)
);
Enable Guzzle Debugging:
Add this to your AppServiceProvider:
$this->app->singleton(GuzzleHttp\Client::class, function () {
$client = new GuzzleHttp\Client();
$client->getEmitter()->addSubscriber(new \GuzzleHttp\Middleware::tap(function ($request) {
\Log::debug('Twitter Request:', [
'url' => (string) $request->getUri(),
'method' => $request->getMethod(),
'headers' => $request->getHeaders(),
]);
}));
return $client;
});
Mock Twitter API: Use VCR for testing:
composer require vcrphp/vcr
use VCR\VCR;
VCR::configure()
->setMode('all')
->addFilter(new VCR\Filter\UrlFilter('api.twitter.com'))
->addFilter(new VCR\Filter\HeaderFilter('Authorization'));
public function testTimeline()
{
VCR::turnOn();
$tweets = $this->twitterClient->getUserTimeline('laravel');
VCR::turnOff();
$this->assertCount(5, $tweets);
}
Custom Endpoints: Extend the client to support unsupported endpoints:
class ExtendedTwitterClient extends TwitterClient
{
public function getSpaces(string $broadcasterId)
{
return $this->client->request('GET', "/1.1/spaces/show.json", [
'query' => ['broadcaster_id' => $broadcasterId],
]);
}
}
Event Dispatching: Trigger Laravel events for tweets:
$tweets = $this->twitterClient->getUserTimeline('laravel');
foreach ($tweets as $tweet) {
event(new TweetFetched($tweet));
}
Queue Background Jobs: Offload API calls to queues:
FetchTweets::dispatch('laravel')->delay(now()->addMinutes(5));
class FetchTweets implements ShouldQueue
{
use Dispatchable, InteractsWithQueue, Queueable;
public function handle(TwitterClient $twitterClient)
{
$tweets = $twitterClient->getUserTimeline($this->screenName);
// Process tweets...
}
}
Environment Variables:
Ensure .env variables are loaded in config/services.php:
'twitter' => [
'api_key' => env('TWITTER_CONSUMER_KEY'),
'api_secret' => env('TWITTER_CONSUMER_SECRET'),
'access_token' => env('TWITTER_ACCESS_TOKEN'),
'access_token_secret' => env('TWITTER_ACCESS_TOKEN_SECRET'),
],
OAuth Token Rotation: Implement token refresh logic if needed:
if ($this->isTokenExpired()) {
$this->refreshAccessToken();
}
Error Handling: Catch specific exceptions:
try {
$tweets = $twitterClient->getUserTimeline('nonexistent');
} catch (TwitterException $e) {
if ($e->getCode() === 404) {
return response()->view('user.not_found');
}
}
How can I help you explore Laravel packages today?