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

Php Symfony Tibber Api Bundle Laravel Package

webproject-xyz/php-symfony-tibber-api-bundle

A Symfony bundle for integrating the Tibber API into PHP applications, offering ready-to-use services and configuration to query electricity prices, consumption data, and other Tibber resources with minimal setup and clean dependency injection.

View on GitHub
Deep Wiki
Context7

Getting Started

Before you composer require anything, understand what this is: webproject-xyz/php-symfony-tibber-api-bundle is a Symfony bundle, not a Laravel package. It ships a *Bundle class, DependencyInjection/ extension + compiler passes, and expects Symfony's container, Configuration tree, and autoconfiguration. Laravel will not discover or boot it automagically — config/app.php providers list is irrelevant to it.

That said, 1.0.0 makes it usable from Laravel in two realistic ways:

Option A — use it as a plain library (recommended for most Laravel apps). Install it, ignore the bundle wiring, and resolve the underlying client/service classes yourself in a service provider:

composer require webproject-xyz/php-symfony-tibber-api-bundle:^1.0
// app/Providers/TibberServiceProvider.php
public function register(): void
{
    $this->app->singleton(TibberClient::class, fn () => new TibberClient(
        token: config('services.tibber.token'),
    ));

    // one named binding per Tibber account/home
    foreach (config('services.tibber.accounts', []) as $name => $cfg) {
        $this->app->bind("tibber.{$name}", fn () => new TibberClient($cfg['token']));
    }
}

Option B — borrow the config shape only. Read DependencyInjection/Configuration.php in the package to learn the supported keys (accounts, cache TTLs, HTTP options), then mirror them into config/services.php. Do not copy the XML/YAML service definitions; they reference Symfony-only services (cache.app, http_client, event_dispatcher).

Where to look first: the DependencyInjection/ folder (account schema + compiler passes — it's the de-facto API documentation for multi-account), then the cache layer to see how keys are derived, then the console commands (they reveal the CLI error-boundary behaviour fixed in 1.0.0).

First use case: an hourly price widget. Pull today's + tomorrow's prices for the configured home, cache them, render a blade chart, and refresh on a scheduler tick. That exercises auth, multi-account resolution, and the cache invalidation path — the three things most likely to bite you.

⚠️ Platform check first: Symfony 8 requires PHP 8.4+. Verify php -v before anything else; a Laravel 10/11 app on PHP 8.2 cannot install this at all.

Implementation Patterns

Multi-account as first-class, not an afterthought. 1.0.0's headline feature is multiple Tibber accounts/homes in one process. In Laravel terms, think of it as multi-tenant config:

// config/services.php
'tibber' => [
    'default'  => env('TIBBER_ACCOUNT', 'home'),
    'accounts' => [
        'home'    => ['token' => env('TIBBER_TOKEN_HOME')],
        'cabin'   => ['token' => env('TIBBER_TOKEN_CABIN')],
        'rental'  => ['token' => env('TIBBER_TOKEN_RENTAL')],
    ],
],

Resolve per-request or per-job with a small resolver rather than reaching into globals — this is the Laravel equivalent of the bundle's compiler-pass tagging:

$client = app(TibberClientResolver::class)->for($user->tibber_account);

Cache outside the bundle's cache layer. The bundle's "smart caching" assumes a PSR-6/PSR-16 pool. In Laravel, either inject a Symfony\Component\Cache\Adapter\Psr16Adapter wrapping Laravel's Cache, or — usually simpler and more observable — disable the bundle cache and wrap calls in Cache::remember yourself:

$prices = Cache::remember(
    "tibber:{$account}:prices:".now()->format('Y-m-d-H'),
    now()->addMinutes(30),
    fn () => $client->getPrices(),
);

Reasons to prefer your own layer: you get Laravel's tags, cache()->forget(), Horizon visibility, and a key format you control. The 1.0.0 fix list ("key lengths, invalidation") tells you the internal key derivation is subtle enough that you don't want to debug it blind.

Queue the fetch, cache the result. Tibber's API is rate-limited and your prices only change on the hour. The clean pattern:

// app/Jobs/RefreshTibberPrices.php — scheduled hourly, slightly after the hour
Schedule::job(new RefreshTibberPrices)->hourlyAt(2);
public function handle(): void
{
    foreach (config('services.tibber.accounts') as $name => $cfg) {
        try {
            Cache::put(
                "tibber:{$name}:prices:today",
                app(TibberClientResolver::class)->for($name)->getPrices(),
                now()->endOfDay(),
            );
        } catch (Throwable $e) {
            report($e);                    // never let one account kill the loop
            $this->fail($e);               // or continue, and fail the batch at the end
        }
    }
}

Timezones are the load-bearing detail. Tibber prices are hourly in the home's local timezone, and DST transitions create 23- and 25-hour days. Always store timestamps UTC and convert at the view layer; never build daily buckets by now()->startOfDay() unless you know the home's tz. The 1.0.0 "caching timezone" fix is the same class of bug — assume it can recur in your own wrapper.

Console commands are worth borrowing, not running. The bundle's CLI commands are Symfony Console commands with a documented error boundary (partial failures → non-zero exit, per-account messages). If you need scheduled syncs, model your Artisan command on that contract: per-account try/catch, aggregate exit code, structured output. Don't try to register Symfony commands into Artisan — write Artisan equivalents.

Gotchas and Tips

  • Symfony 8 = PHP 8.4. Hard blocker, not a soft one. Check composer.json before planning; a failed install here usually means a too-old PHP, not a bad package.
  • The bundle class will not be booted. Symfony\Component\HttpKernel\Bundle\Bundle subclasses are inert in Laravel. Don't add it to any provider list and don't expect tibber.* container aliases to exist — construct services manually.
  • No Laravel facade, no published config, no migrations. Everything the bundle documents as config/packages/tibber.yaml is YAML you must translate by hand. Treat the Symfony config tree as the spec, not as something that works.
  • Compiler passes are invisible to you. Tagged-service collection (the multi-account mechanism) happens at Symfony container compile time. In Laravel you must replicate it with explicit bindings or a resolver class — the multi-account feature does not "just work" outside Symfony.
  • Cache key length is a real failure mode. Memcached caps keys at 250 bytes; Redis is friendlier but not infinite. If you're building keys from tokens, account names, plus date ranges, hash the variable segment: hash('xxh128', $account.'|'.$range). The 1.0.0 fix addressed this — your own wrapper can reintroduce it.
  • Invalidation at hour boundaries is where bugs live. A cache entry written at 13:59 for "today's prices" is stale at 14:00. Either key by hour, or set TTL to the next hour boundary (now()->addHour()->startOfHour()), never a flat addHour().
  • Multi-account + queues = token leakage risk. Don't serialise a client (and its token) into a job payload. Serialise the account name and resolve the client inside handle(). Use ShouldBeUnique per account to prevent thundering-herd fetches when several scheduled jobs overlap.
  • v1.0.0 is freshly stabilised. Two of the four commits are dependency bumps and one is a cluster of correctness fixes (timezone, key length, invalidation, CLI error boundaries) — that's a lot of churn landing at once. Pin to ^1.0 and add a contract test that asserts today's price array has the shape your Blade views expect, so a 1.0.x patch can't silently break rendering.
  • Errors surface as HTTP client exceptions. Wrap calls in try/catch (Throwable) and decide policy explicitly: stale-cache-serve (Cache::get fallback), retry with backoff, or fail the job. Tibber auth tokens expire rarely, but per-home token misconfiguration is the common failure and should be reported with the account name attached.
  • Extension point to prefer: the injectable HTTP client. If the bundle accepts a PSR-18 client, hand it Laravel's Http::buildClient() (or a Guzzle instance with HandlerStack middleware) to get logging, retries, and X-Request-Id propagation for free — far more valuable than fighting the container.
  • Sanity check before adopting: count the call sites you actually need (prices, consumption, real-time subscription). If it's one or two read-only endpoints, hitting Tibber's GraphQL API directly with Http::withToken()->post() is a smaller dependency than a Symfony bundle bridged into Laravel — and avoids the whole PHP 8.4 / container-wiring conversation.
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.
uni-method/symfony-lib
tacticmedia/scim-server-bundle
neika-ai/symfony-bundle
mattleads/agent-publishing-bundle
glavweb/framework-bundle
glavweb/extra-bundle
glavweb/api-bundle
glavweb/admin-bundle
adachsoft/api-version-bundle
elsayed85/laravel-api-exceptions
ouhssini/laravel-demo-mode
daworks/ncloud-outbound-mailer-driver
gp247/cms
ignibyte/aic-gates
nexa-merchant/blog
novasa/laravel-language-center
opencage/geocode
adolfoholzer/parameters
livenetworks/ln-starter
cgv/localized-resource