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

Tv Maze Php Api Laravel Package

dariusiii/tv-maze-php-api

dariusiii/tv-maze-php-api is a lightweight PHP client for TVmaze, providing easy access to TV show schedules, episode guides, cast and crew details, and search endpoints. Designed for Laravel and plain PHP projects, it wraps API requests in a simple, readable interface.

View on GitHub
Deep Wiki
Context7

Getting Started

  1. Install (no framework lock-in, pure Composer):
    composer require dariusiii/tv-maze-php-api:^2.0
    
    The current line is 2.0.x (latest: 2.0.6, a patch). If you were pinned to ^1.0 or an old 2.0.x, bump the constraint — nothing in the 2.0.5 → 2.0.6 diff changes the public API.
  2. Confirm the curl extension is present. The wrapper talks HTTP via raw cURL, not Guzzle/PSR-18 (2.0.6 is literally "remove deprecated curl_close() call"). Run php -m | grep curl; on minimal Docker images this is the usual silent failure.
  3. Look first at composer.json to confirm the autoload namespace and the entry-point class. Wrapper repos frequently rename the namespace from the repo slug, so trust autoload.psr-4 over the URL.
  4. Then read the src/ directory and README for the client constructor. TVMaze's public API needs no key/token, so the constructor is usually empty or takes a base URL. Because it's cURL-based, don't expect an injectable HTTP client argument.
  5. First use case — search + fetch a show:
    use DariusIII\TvMaze\Client; // verify from composer.json
    
    $client = new Client();
    $hits   = $client->search('Severance');       // array of {score, show}
    $show   = $client->show($hits[0]['show']['id']);
    echo $show['name'] . ' — ' . ($show['image']['medium'] ?? 'no image');
    
  6. Laravel wiring (manual, since this package is PHP-only): register it as a singleton so any internal cURL handle / config is reused across requests:
    // app/Providers/AppServiceProvider.php
    $this->app->singleton(Client::class, fn () => new Client());
    
    If you want a TvMaze:: facade, add a small class that proxies to the singleton via the container.

Implementation Patterns

Repository + cache layer (recommended default). Don't call the wrapper from controllers or Blade templates. Wrap it:

class ShowRepository
{
    public function __construct(private Client $client) {}

    public function find(int $id): ?array
    {
        return Cache::remember("tvmaze.show.{$id}", now()->addDay(),
            fn () => $this->client->show($id));
    }

    public function search(string $q): array
    {
        return Cache::remember("tvmaze.search.".md5($q), now()->addMinutes(10),
            fn () => $this->client->search($q));
    }
}

Show metadata (name, premiered, network, image) is essentially immutable — 24h TTLs are safe. Episodes and schedule data change, so use shorter TTLs (1–6h).

Wrap behind your own interface, not just a repository. Since the package owns its transport (cURL), you can't swap in Http::fake() for tests. Define interface TvMazeGateway { public function show(int $id): ?array; public function search(string $q): array; }, bind the package Client to it in the container, and let tests bind a stub. This is the single highest-leverage change for testability.

$this->app->bind(TvMazeGateway::class, fn () => new TvMazeClientAdapter(app(Client::class)));

Separate the three concerns. TVMaze's endpoints map naturally to three fetch groups:

  • Show identity — show, search, singlesearch (cache long)
  • Episodes/AKA/crew — episodes, cast, crew (cache medium)
  • Schedule — schedule?date=YYYY-MM-DD&country=US (cache an hour, or prefetch via a scheduled command)

Queue bulk work. Importing every episode for 500 shows will blow the rate limit. Use a job per show with ->delay() or chunking, and let the cache absorb repeat reads:

Show::pluck('tvmaze_id')->each(fn ($id) =>
    SyncShowEpisodes::dispatch($id)->onQueue('tvmaze'));

Scheduled sync. TVMaze exposes a daily schedule endpoint — put it on a daily() or everySixHours() command in routes/console.php and write results into your own episodes table so the UI never waits on a remote call.

Search autocomplete. Front-end debounce → hit a Laravel endpoint that reads the 10‑minute cache → map the {score, show} shape down to {id, name, image.url, premiered} before returning JSON. Don't ship the raw TVMaze payload to the browser; it's fat and contains fields you shouldn't expose.

Normalize images. TVMaze returns image.medium (210×295) and image.original. Store both, render medium for lists and original for detail pages. All fields are nullable — a show without an image is normal.

DTO layer if the package returns arrays. If the wrapper hands back raw arrays, add a ShowData value object with fromArray() so your Blade/Inertia views aren't spelunking $show['_links']['self']['href'].

Gotchas and Tips

  • No Guzzle means no middleware. Retries, logging, and timeouts must be implemented in your adapter/decorator. Guzzle's RetryMiddleware and Laravel's Http::retry() are not available here — plan for that rather than discovering it mid-incident.
  • Rate limit is real and silent. TVMaze allows roughly 20 requests per 10 seconds per IP. There's no header back-off by default — add usleep/manual backoff in your adapter, or you'll get 429s that look like empty results if the package swallows exceptions.
  • search is fuzzy, singlesearch is exact. Use singlesearch when you want one canonical match; it returns a 404 when nothing matches rather than an empty array, so catch that specifically.
  • 404 vs. error handling. Unknown IDs return 404. Make your repository return null for a miss and let callers decide — don't let a HTTP exception 500 a detail page.
  • Null-heavy payloads. rating.average, network, image, summary, externals.imdb are all frequently null. Assume every field beyond id, name, url and _links can be missing.
  • summary contains HTML. It arrives as an HTML string with <p> tags. Escape on output or strip via strip_tags() before storing/displaying.
  • Date handling. Schedule endpoints require YYYY-MM-DD; passing a Carbon may or may not be coerced depending on the signature — cast with ->toDateString() explicitly.
  • Timezone trap. /schedule is queried by broadcast date in the target country, not UTC. Store the country in config alongside base URL and timeout.
  • No Laravel service provider is bundled. Don't look for config/tvmaze.php; write your own config array (services.tvmaze.base_uri, timeout, user_agent) and inject it into the singleton. Set a User-Agent — polite clients get throttled less.
  • curl_close() removal (2.0.6) is a non-event for you. It's been a no-op since PHP 8.0, so behavior is identical on modern PHP; it just makes the package 8.5-deprecation-clean. Don't hunt for a migration guide — there isn't one. If you're somehow still on PHP 7.x, handle release is now left to refcounting/GC, which is harmless for short-lived request-scoped clients.
  • Namespace ≠ repo name. It's the #1 first-hour stumble with zero-star wrappers. composer dump-autoload -o and inspect the generated autoload files if the import IDE suggestion doesn't appear.
  • Extension point without forking. Decorate rather than modify vendor code: your adapter delegates to the package Client and adds caching/retry/logging around it. Keeps composer update safe.
  • Pin the version. The 2.0.x line is patch-only and low-risk, but with essentially no dependents the surface can still shift in a minor. Use "dariusiii/tv-maze-php-api": "^2.0" and commit the lock file.
  • Debugging tip. When a mapping looks wrong, log in your adapter, not the vendor: Log::debug('tvmaze', ['method' => __FUNCTION__, 'status' => $status, 'body' => $raw]). TVMaze responses are small enough to log whole during development.
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