oleksyuk / apaleo-bundle
Symfony bundle for integrating the Apaleo hotel PMS API SDK
Package info
github.com/maks-oleksyuk/apaleo-bundle
Type:symfony-bundle
pkg:composer/oleksyuk/apaleo-bundle
Requires
- php: ^8.4
- nyholm/psr7: ^1.8.2
- oleksyuk/apaleo-php: ^0.1
- psr/cache: ^3.0
- symfony/config: ^8.0
- symfony/dependency-injection: ^8.0
- symfony/http-client: ^8.0
- symfony/http-client-contracts: ^3.0
- symfony/http-kernel: ^8.0
Requires (Dev)
- friendsofphp/php-cs-fixer: ^3.95.27
- phpstan/phpstan: ^2.3.1
- phpunit/phpunit: ^13.4.3
- rector/rector: ^2.7
- symfony/cache: ^8.0
- symfony/error-handler: ^8.1.5
- symfony/framework-bundle: ^8.0
Suggests
- symfony/framework-bundle: Profiler HTTP Client panel for Apaleo calls, framework.yaml overrides for its HTTP client, and cache.app as the default token cache
Provides
None
Conflicts
None
Replaces
None
README
apaleo-bundle
Symfony bundle for apaleo-php — the framework-agnostic PHP SDK for the Apaleo hotel PMS API.
Installation
composer require oleksyuk/apaleo-bundle
Register the bundle in config/bundles.php (Flex would do this automatically for a published recipe; do it by hand for now):
return [ // ... Oleksyuk\Apaleo\Bundle\ApaleoBundle::class => ['all' => true], ];
Configuration
Add your Apaleo API credentials to .env.local (never commit real secrets to .env):
APALEO_CLIENT_ID=your-client-id APALEO_CLIENT_SECRET=your-client-secret
These are the defaults the bundle reads (%env(APALEO_CLIENT_ID)% / %env(APALEO_CLIENT_SECRET)%). Override them or set a custom base URI (e.g., a sandbox environment), via config/packages/apaleo.php:
<?php declare(strict_types=1); namespace Symfony\Component\DependencyInjection\Loader\Configurator; return App::config([ 'apaleo' => [ 'client_id' => env('APALEO_CLIENT_ID'), 'client_secret' => env('APALEO_CLIENT_SECRET'), // 'base_uri' => 'https://api.sandbox.apaleo.com', // optional, defaults to https://api.apaleo.com // 'token_cache' => 'cache.redis', // optional PSR-6 pool for the access token, defaults to cache.app // 'identity_base_uri' => 'http://localhost:8080', // optional, defaults to https://identity.apaleo.com ], ]);
FrameworkBundle is optional. Without it, the bundle still wires its own HTTP client with the same timeout and retries, but the access token is cached in memory only (a new token per PHP-FPM request) unless token_cache points at a pool.
Run bin/console config:dump-reference apaleo at any time to see the full, current config tree.
Usage
Inject ApaleoClient like any other autowired service:
use Oleksyuk\Apaleo\ApaleoClient; final readonly class PropertyController { public function __construct( private ApaleoClient $apaleo ) {} public function list(): Response { $properties = $this->apaleo->inventory()->properties()->list(); // ... } }
See the apaleo-php README for the full SDK API (Inventory resources, pagination, filters, exceptions).
HTTP client, timeouts and retries
The bundle registers a scoped client, apaleo.http_client, for every call the SDK makes (API and identity server). It defaults to a 10 s timeout and 2 retries of 5xx/transport errors, only for GET/HEAD, because a 502 after a POST may still have been applied. A 429 isn't retried: the HTTP client would sleep for whatever Retry-After says, uncapped, inside your web request. It surfaces as ApaleoRateLimitException with retryAfterSeconds instead, so you decide whether to wait (e.g. re-dispatch a Messenger message with a DelayStamp). With FrameworkBundle, these calls show up under apaleo.http_client in the profiler's HTTP Client panel, and you can override any option the usual way:
<?php // config/packages/framework.php declare(strict_types=1); namespace Symfony\Component\DependencyInjection\Loader\Configurator; return App::config([ 'framework' => [ 'http_client' => [ 'scoped_clients' => [ 'apaleo.http_client' => [ 'scope' => '.*', 'timeout' => 30, ], ], ], ], ]);
The profiler records request headers, including the token request's Authorization: Basic header, which carries your client secret. Keep the profiler on your own machine: don't enable it on a shared environment that uses production credentials.
Token cache
The access token lives about an hour. With FrameworkBundle it's cached in cache.app, so every PHP-FPM request reuses it instead of asking the identity server again. With several app servers, point token_cache at a shared pool so they share one token too:
<?php // config/packages/cache.php declare(strict_types=1); namespace Symfony\Component\DependencyInjection\Loader\Configurator; return App::config([ 'framework' => [ 'cache' => [ 'pools' => [ 'cache.apaleo' => [ 'adapter' => 'cache.adapter.redis', 'provider' => env('REDIS_URL'), ], ], ], ], ]);
<?php // config/packages/apaleo.php declare(strict_types=1); namespace Symfony\Component\DependencyInjection\Loader\Configurator; return App::config([ 'apaleo' => [ 'token_cache' => 'cache.apaleo', ], ]);
Development
This package has its own tooling, mirroring apaleo-php:
task lint # PHPStan (max level), PHP CS Fixer, Rector, composer validate task test # PHPUnit task fix # auto-fix CS Fixer / Rector issues