Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Twitter App Bundle Laravel Package

inori/twitter-app-bundle

inori/twitter-app-bundle is a Symfony bundle that helps integrate Twitter app functionality into PHP projects. It offers a foundation for configuring Twitter credentials and wiring API-backed features into your application, serving as a lightweight starting point for Twitter-connected Symfony servic...

View on GitHub
Deep Wiki
Context7

Getting Started

Reality check before you type anything. This is a Symfony2 bundle (Inori\TwitterAppBundle), not a Laravel package. There is no composer require, no Package Discovery, no config/twitter.php, and no service provider. Running it inside a Laravel app deterministically fails composer resolution: it pins symfony/symfony:~2.x against a modern app that requires symfony/*:^6. For a Laravel developer, "getting started" means reading it as reference and rebuilding its 30-line wiring idiomatically — not installing it.

Files to read first (in this order):

  1. DependencyInjection/Configuration.php — the authoritative list of config keys (consumer key/secret, access token/secret, defaults). Port these to config/twitter.php.
  2. Resources/config/services.yml — the service IDs and constructor wiring. This is the pattern you will reproduce in a TwitterServiceProvider.
  3. DependencyInjection/*Extension.php — how container parameters feed the client factory.
  4. InoriTwitterAppBundle.php — confirms the Symfony Bundle contract; nothing to map here.

First use case — a smoke test against verify_credentials. In the original Symfony2 host this is a console command pulling $container->get('inori_twitter_app.client') and dumping the response. A 200 with a valid user object means credentials and OAuth 1.0a signing are correct; a 401 means bad keys or clock skew, not the bundle.

In Laravel, the equivalent first step is the port itself. Stand up the replacement before touching any feature code:

// config/twitter.php
return [
    'consumer_key'    => env('TWITTER_CONSUMER_KEY'),
    'consumer_secret' => env('TWITTER_CONSUMER_SECRET'),
    'access_token'    => env('TWITTER_ACCESS_TOKEN'),
    'access_secret'   => env('TWITTER_ACCESS_SECRET'),
];
// app/Providers/TwitterServiceProvider.php
public function register(): void
{
    $this->app->singleton(TwitterClientContract::class, function ($app) {
        $c = $app['config']->get('twitter');
        return new TwitterOAuth($c['consumer_key'], $c['consumer_secret'],
                               $c['access_token'], $c['access_secret']);
    });
}

Then a throwaway artisan command that calls verify_credentials. Get this green before writing a single feature. If your first step is feature code, you will not know whether a failure is your code or the port.

Do not pursue the --ignore-platform-reqs / fork-and-vendor path. MIT permits it, but you would be vendoring a package you have to maintain forever for functionality available from a maintained upstream.

Implementation Patterns

Wrap, don't scatter. The bundle gives you a client, not a domain API. Even in the original Symfony app, the highest-value pattern is a thin TwitterService around TwitterOAuth and injecting that into controllers and commands. In Laravel this is non-negotiable — the whole reason you're porting is that the underlying transport will change (v2 endpoints, bearer tokens, a maintained client). One class to swap, not a codebase grep.

class TwitterService
{
    public function __construct(private TwitterOAuth $client) {}

    public function recentTweets(string $screenName, int $count = 20): array
    {
        $response = $this->client->get('statuses/user_timeline', [
            'screen_name' => $screenName,
            'count'       => $count,
        ]);
        return $response->statuses ?? []; // normalize to your DTOs, not stdClass
    }
}

Bind TwitterOAuth to a TwitterClientContract interface so tests can substitute a fake and the client can be swapped without touching call sites.

Separate app-only from user-context, explicitly. Two modes, different credentials, different failure modes:

  • App-only / consumer-only: public reads — timelines, search, user lookup. Only consumer key/secret. Suitable for cron jobs, cache warmers, widgets.
  • User-context: posting, DMs, anything account-scoped. Requires access token/secret. In the bundle these are the same client with optional config; in your port make the distinction a config flag or two separate bindings so you never accidentally ship with user-context credentials where app-only would do.

Queue every write. The client is synchronous and blocking. Any call on the request path couples user latency to a third-party API and burns your rate-limit budget in lockstep with your web tier. Posting, DMs, and anything user-triggered go through a queued job with retry/backoff. Reads can stay synchronous if cached.

Token bucket for rate limiting. X's tier caps dominate throughput, not the code. Enforce client-side with a token bucket and honor x-rate-limit-reset on 429s. Do not retry blindly — exponential backoff with jitter.

Contract test in CI. Because endpoint deprecation (404/410 after an X platform change) is your most likely silent breakage, add a test that hits your TwitterClientContract interface and asserts the expected shape. Cheaper than discovering it in production.

Credentials via secrets manager. The original bundle uses container parameters (effectively parameters.yml). In Laravel, back config/twitter.php with env() and either Laravel's encrypted config, Vault, or AWS Secrets Manager. Never commit credentials, even in the spike branch.

Gotchas and Tips

The dependency conflict is deterministic, not a risk to test. A Symfony2 bundle pins symfony/framework-bundle ~2.x and symfony/http-kernel ~2.x; Laravel 9+ needs ^6. Composer either refuses or drags your whole app back to a PHP 5.5–7.0-era stack. There is no "try it in a spike branch." Plan for it: this is a port, not an integration.

PHP 8 will fatally error on the bundle's own code. PHP 5-era idioms (untyped properties, array-offset response parsing like $response['statuses'] on stdClass) emit deprecations or fatal errors on 8.2+. This is a reason the reference code is reference, not a base to fork.

401s are almost never the bundle. Check credentials and clock skew before you read source. verify_credentials is the canonical diagnostic; get a 200 there before debugging anything else.

429s are silent if you don't handle them. The client returns stdClass — a rate-limit response looks identical to an empty result if you only read ->statuses. Always inspect $client->getLastHttpCode() (0.x API) or the response's HTTP status, and log it. Without this, you will "lose" tweets with no error.

Configuration.php is the source of truth for keys, not the README. There is no meaningful README beyond the description. If a config value isn't working, check DependencyInjection/Configuration.php — that file defines the keys, defaults, and whether access_token is required or optional for the mode you're in. Do not trust any prose about it.

The extension points you actually want are not in the bundle. It exposes a client factory and a container parameter scheme; it does not expose retry policy, rate-limit handling, or a response shape to hook into. That is why you rebuild rather than extend. In the Laravel port, the extension points are yours: the interface, the token-bucket contract, the job middleware.

Archived means no CVE response path. For a security-sensitive surface (OAuth tokens in flight), that is a standing liability. If the underlying OAuth client has an advisory, nobody is patching this wrapper. If you inherit a Symfony2 app using it, treat it as technical debt and schedule migration — the framework upgrade (Symfony 2.8 EOL'd in 2019) is larger than the Twitter feature, so scope the feature unless the framework is already on the roadmap.

Debug the raw response, not your DTOs. When something breaks, var_dump the raw stdClass (or $client->getLastHttpCode() plus getLastBody()) before assuming a mapping bug. The bundle does not normalize anything; any shape surprise is the API, not the bundle.

Record the rejection in an ADR. The durable output of this evaluation is a short note: evaluated inori/twitter-app-bundle, rejected for Laravel due to Symfony2 version pin, archive status, and dead v1.1 endpoint surface; replacement is a ~30-line TwitterServiceProvider over a maintained client. This stops the evaluation from resurfacing in review.

Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
diephp/sequences
users-au/socialite-provider
twidpay/twid-logger
mrnewport/laravel-plaid
mrnewport/laravel-repo
mrnewport/laravel-docsign
mrnewport/laravel-stow
mrnewport/laravel-flow
mrnewport/laravel-priceable
mrnewport/laravel-nestedterms
fredmeng/laravel-apidoc-generator
itstructure/laravel-multilingual-tools
pdustdar/elasticsearch
markupai/php-sdk
rlacerda83/lumem-microservice-shipment
uni-method/symfony-lib
tacticmedia/scim-server-bundle
neika-ai/symfony-bundle
mattleads/agent-publishing-bundle
glavweb/framework-bundle