php-tmdb/symfony
Symfony bundle that integrates the TMDB API into your app, providing service configuration and dependency injection for querying movies, TV shows, people, and related metadata via php-tmdb/api.
Install via Composer:
composer require php-tmdb/symfony
Register the bundle (Flex usually does this automatically). In config/bundles.php:
return [
// ...
Tmdb\Symfony\TmdbBundle::class => ['all' => true],
];
Configure your TMDB credentials. Create config/packages/php_tmdb.yaml:
php_tmdb:
api_key: '%env(TMDB_API_KEY)%'
# api_token: '%env(TMDB_API_TOKEN)%' # for v4 bearer auth
language: 'en'
Add TMDB_API_KEY=your_key_here to .env.
Inject and use the client. The bundle registers Tmdb\Client as a service (alias php_tmdb.client). Autowire it:
use Tmdb\Client;
class MovieController
{
public function __construct(private Client $tmdb) {}
public function show(int $id): Response
{
$movie = $this->tmdb->getMovieRepository()->getMovie($id);
// ...
}
}
First use case: fetch a movie by ID and render its title/poster. The repository methods (getMovie, getPopular, search) are the most ergonomic starting point.
Where to look first:
vendor/php-tmdb/symfony/DependencyInjection/Configuration.php – all available config keys and defaults.Wrap the client in a domain service. Avoid injecting Tmdb\Client directly into controllers everywhere. Create e.g. App\Service\TmdbService that centralises error handling, caching, and image URL construction.
class TmdbService
{
public function __construct(private Client $tmdb) {}
public function getMovie(int $id): array
{
return $this->tmdb->getMovieRepository()->getMovie($id);
}
}
Use API-specific interfaces for direct endpoint access:
$this->tmdb->getMoviesApi()->getMovie($id);
$this->tmdb->getTvApi()->getTv($id);
$this->tmdb->getSearchApi()->searchMovies('inception');
$this->tmdb->getDiscoverApi()->discoverMovies(['with_genres' => 28]);
Prefer repositories for common queries. They handle pagination and parameter mapping:
$popular = $this->tmdb->getMovieRepository()->getPopular(['page' => 2]);
$nowPlaying = $this->tmdb->getMovieRepository()->getNowPlaying();
Configure a persistent PSR-16 cache to avoid hammering the API. The bundle accepts a cache service ID:
# config/services.yaml
services:
app.tmdb_cache:
class: Symfony\Component\Cache\Adapter\Psr16Adapter
arguments: ['@cache.app']
# config/packages/php_tmdb.yaml
php_tmdb:
cache: 'app.tmdb_cache'
Build image URLs from the configuration endpoint (cached once):
$config = $this->tmdb->getConfiguration();
$base = $config->getImageBaseUrl();
$sizes = $config->getImageSizes();
$posterUrl = $base . $sizes['poster']['w500'] . $movie['poster_path'];
Handle pagination by passing an options array as the second argument:
$page2 = $this->tmdb->getMovieRepository()->getPopular(['page' => 2]);
$totalPages = $page2['total_pages'];
Testing: mock Tmdb\Client in unit tests, or use Guzzle’s MockHandler when you need to test the HTTP layer. For functional tests, override the php_tmdb.client service with a stub.
Last release was 2021. The bundle supports Symfony 4/5/6 but not Symfony 7. Check compatibility with composer why-not php-tmdb/symfony and pin Symfony 6 if needed.
API authentication modes. TMDB v3 uses api_key; v4 uses a Bearer api_token. The bundle supports both via config, but mixing them can lead to 401s. Use one consistently.
Default cache may be in-memory. If you don’t configure cache, the library may use a per-request array cache, causing repeated API calls. Always wire a persistent PSR-16 adapter.
Rate limits. TMDB allows roughly 50 requests/second. Caching is your primary defence; consider a retry/backoff wrapper around calls if you hit bursts.
Error handling. API failures throw Tmdb\Exception\TmdbApiException (check exact namespace in your installed version). Catch and log it, and degrade gracefully:
try {
$movie = $this->tmdb->getMovieRepository()->getMovie($id);
} catch (\Tmdb\Exception\TmdbApiException $e) {
// 404 or other API error
}
Configuration endpoint costs a request. $this->tmdb->getConfiguration() performs an API call the first time. Cache it (the bundle’s cache usually covers it) or store image base URLs in your own config.
Language and region. Set language (e.g., de) and region (e.g., DE) in php_tmdb for localised titles, release dates, and certifications. Omitting them returns US English defaults.
Autowiring alias. If Tmdb\Client is not autowired, add an alias manually:
services:
Tmdb\Client:
alias: php_tmdb.client
Debugging HTTP traffic. The library uses Guzzle under the hood, so Symfony’s HTTP profiler won’t capture requests. Inject a PSR-3 logger via the logger config option (if available) or add a Guzzle middleware to log requests/responses.
Upgrading the underlying library. The bundle may pin an older version of php-tmdb/api. You can override it in composer.json ("php-tmdb/api": "^4.0") but test for breaking changes in method signatures.
Newer TMDB endpoints. The library targets v3 and may lag behind new features (e.g., certain trending or watch-provider endpoints). For those, use the client’s underlying HTTP client or issue a manual request with the configured API key.
How can I help you explore Laravel packages today?