experiencebank / php-sdk
ExperienceBank PHP SDK
Requires
- php: ^8.3
- ext-json: *
- beberlei/assert: ^3
- guzzlehttp/guzzle: ^7.4
- monolog/monolog: ^1.19
- psr/log: ^1.0
- psr/simple-cache: ^1.0 || ^2.0 || ^3.0
- spomky-labs/base64url: ^2.0
Requires (Dev)
- friendsofphp/php-cs-fixer: ^3.95
- phpunit/phpunit: ^12.5
Suggests
None
Provides
None
Conflicts
None
Replaces
None
README
The ExperienceBank PHP SDK including an API client library
Installation
Requires PHP 8.3 or newer.
composer require experiencebank/php-sdk
Configuration
Simple client
<?php
use ExperienceBank\Sdk\ApiClient\Client;
use ExperienceBank\Sdk\ApiClient\Credentials;
$credentials = new Credentials(
getenv('API_PUBLIC_KEY'),
getenv('API_SECRET_KEY')
);
$apiClient = new Client($credentials);
Client with Redis cache and Monolog logging
Any PSR-16 cache can be used, for example symfony/cache:
<?php
use Symfony\Component\Cache\Adapter\RedisAdapter;
use Symfony\Component\Cache\Psr16Cache;
use Monolog\Handler\StreamHandler;
use Monolog\Logger;
use ExperienceBank\Sdk\ApiClient\Client;
use ExperienceBank\Sdk\ApiClient\Credentials;
$redis = new \Redis();
$redis->pconnect('127.0.0.1', 6379);
$cache = new Psr16Cache(new RedisAdapter($redis));
$credentials = new Credentials(
getenv('API_PUBLIC_KEY'),
getenv('API_SECRET_KEY')
);
$logger = new Logger('api-client');
$logger->pushHandler(new StreamHandler('api-client.log'));
$apiClient = Client::newCachingClient($credentials, $cache, $logger);
Only read methods are served from the cache (activity.find, availability.find, booking.get,
category.find, marketplace.find, supplier.find, webhook.find). Methods which change
something are always sent to the api, so a booking is never replayed from cache.
The default ttl is 30 seconds. Use withCache() to change it, or to add a cache to an existing
client. A ttl of 0 caches without expiry, false disables caching. Without a cache of your own,
an in-memory cache (ExperienceBank\Sdk\ApiClient\Cache\ArrayCache) is used:
$apiClient = $apiClient->withCache(60, $cache);
Client::isCacheable('booking.get'); // true
Client::isCacheable('booking.create'); // false
Upgrading to 2.0
2.0 requires PHP 8.3 or newer. Older PHP versions are supported by 1.x only.
doctrine/cache is abandoned and has been replaced by PSR-16 (psr/simple-cache 1, 2 or 3):
Client::newCachingClient(),Client::withCache()andCredentialsStorage::__construct()take aPsr\SimpleCache\CacheInterfaceinstead ofDoctrine\Common\Cache\Cache, andClient::getCache()returns one.- Replace Doctrine caches with a PSR-16 implementation, e.g.
RedisCachewithnew Psr16Cache(new RedisAdapter($redis))fromsymfony/cache, orArrayCachewithExperienceBank\Sdk\ApiClient\Cache\ArrayCache. - Credentials stored through
CredentialsStoragewith a Doctrine cache can't be read through a PSR-16 cache, as both store their entries differently. Store them again after upgrading. CredentialsStoragekeys must be valid PSR-16 keys, so they can't contain any of{}()/\@:.
Usage
Creating a supplier
$response = $apiClient->supplier()->create([
'name'=> 'Amazing Demo Activities',
'partnerSupplierId' => '15873',
'partner' => 'par_049a72c3-7a8d-48aa-94d1-0ba5a8e9e9f2',
'contact' => [
'name' => 'John Doe',
'email' => 'another@example.com'
]
]);
$supplierId = $response->getValue('result.supplierId');
The following methods are currently supported:
$this->client->supplier()->create(array $params);
$this->client->supplier()->update(array $params);
$this->client->supplier()->enable($supplierId);
$this->client->supplier()->disable($supplierId);
$this->client->supplier()->delete($supplierId);
$this->client->supplier()->find(Query $query);
$this->client->supplier()->generateAutoLoginUrl($supplierId, $email)->forMapping($mappingId);
$this->client->activity()->updated(array $params);
$this->client->activity()->find(Query $query);
$this->client->availability()->updated(array $params);
$this->client->availability()->find(Query $query);
$this->client->booking()->create(CreateBookingRequest $request);
$this->client->booking()->commit(CommitBookingRequest $request);
$this->client->booking()->get(GetBookingRequest $request);
$this->client->booking()->cancel(CancelBookingRequest $request);
$this->client->booking()->cancelled($bookingId);
$this->client->ticket()->affected(array $params);
$this->client->mapping()->enable($supplierId, $marketplaceId, $partnerId);
$this->client->mapping()->disable($mappingId);
$this->client->marketplace()->find(Query $query = null);
$this->client->category()->find();
$this->client->webhook()->subscribe($event, $url);
$this->client->webhook()->unsubscribe($webhookId);
$this->client->webhook()->find(Query $query);
But you can also call other RPC methods using the request() method.
$this->client->request(string $method, array $params);
Webhooks
Subscribing
Subscribe an url to an event to get notified in real time. Only one webhook per event can exist, so point each event at its own url.
<?php
use ExperienceBank\Sdk\ApiClient\Methods\Webhook\Query;
use ExperienceBank\Sdk\ApiClient\Methods\Webhook\Event;
$response = $apiClient->webhook()->subscribe(
Event::AVAILABILITY_UPDATED,
'https://example.com/webhooks/availability-updated'
);
$webhookId = $response->getValue('result.webhookId');
// List the webhooks. Pass an empty Query to get all of them.
$response = $apiClient->webhook()->find(new Query());
foreach ($response->getValue('result.data') as $webhook) {
echo $webhook['webhookId'].' '.$webhook['event'].' '.$webhook['url'];
}
// Paginate with the returned cursor
$next = $response->getValue('result.cursor.next');
if ($next !== null) {
$response = $apiClient->webhook()->find((new Query())->withCursor($next));
}
$apiClient->webhook()->unsubscribe($webhookId);
The supported events are Event::ACTIVITY_UPDATED and Event::AVAILABILITY_UPDATED.
Receiving notifications
Your endpoint must reply with a 200 status within 2 seconds, otherwise the notification is considered failed. Failed notifications are not retried, so acknowledge first and do the work afterwards (e.g. on a queue).
The delivered payload does not contain the name of the event, so pass in the event that the receiving url is subscribed to:
<?php
use ExperienceBank\Sdk\ApiClient\Methods\Webhook\AvailabilityUpdated;
use ExperienceBank\Sdk\ApiClient\Methods\Webhook\Event;
use ExperienceBank\Sdk\ApiClient\Methods\Webhook\Notification;
// $body can be a raw json string, a decoded array or a PSR-7 stream
$notification = Notification::fromJson(Event::AVAILABILITY_UPDATED, $body);
if ($notification instanceof AvailabilityUpdated) {
$notification->getSupplierId();
$notification->getActivityId();
$notification->getOptionId();
$notification->getLocalDateTime(); // \DateTimeImmutable
$notification->getLocalDateTimeString(); // raw ISO 8601 string
$notification->getAvailableCapacity();
$notification->getOldCapacity();
foreach ($notification->getTicketCategories() as $ticketCategory) {
$ticketCategory->getTicketCategoryId();
$ticketCategory->getAvailableCapacity(); // int or null
}
}
An ActivityUpdated notification carries getSupplierId() and getActivityId() only.
If you already know which event an endpoint receives you can skip the dispatch and call the concrete class directly:
$notification = AvailabilityUpdated::fromPayload($body);
Running tests
The tests need PHP 8.3 or newer and Composer. They don't call the real api, so no credentials or network access are needed.
Install the dependencies and run the whole suite:
composer install
vendor/bin/phpunit
Run a single test class, a single file or the tests matching a name:
vendor/bin/phpunit --filter ClientCacheTest
vendor/bin/phpunit tests/src/ApiClient/Cache/ArrayCacheTest.php
vendor/bin/phpunit --filter aTtlOfZeroCachesWithoutExpiry
The suite fails on any PHP deprecation, notice or warning triggered in src/, not only on failed
assertions. Details are printed below the results.
Without a local PHP 8.3
Run Composer and PHPUnit through Docker instead:
docker run --rm --user "$(id -u):$(id -g)" -v "$PWD":/app -w /app composer:2 composer install
docker run --rm --user "$(id -u):$(id -g)" -v "$PWD":/app -w /app php:8.3-cli vendor/bin/phpunit
Replace php:8.3-cli with another tag, e.g. php:8.5-cli, to test against a newer PHP version.
Coding style and security checks
vendor/bin/php-cs-fixer check # report coding style violations
vendor/bin/php-cs-fixer fix # fix them
composer audit # check dependencies for known vulnerabilities
The coding style rules are configured in .php-cs-fixer.dist.php. composer audit needs Composer 2.4 or
newer; with an older one, run it through the composer:2 Docker image as shown above.
Contributions
All contributions are welcomed through pull requests.
Please run the tests, the coding style fixer and composer audit (see Running tests)
before submitting.
License
MIT. See LICENSE file.