lustmored / lockme-sdk
LockMe SDK
Requires
- php: >=8.2.0
- ext-json: *
- league/oauth2-client: ^2.2
- lustmored/oauth2-lockme: ^1.6.0
- symfony/lock: ^6.0 || ^7.0 || ^8.0
Requires (Dev)
- friendsofphp/php-cs-fixer: ^3.70
- phpstan/phpstan: ^2.1
Suggests
None
Provides
None
Conflicts
None
Replaces
None
README
PHP SDK for interacting with the LockMe API. This library provides a simple interface for authentication and making API calls to the LockMe platform.
For comprehensive API documentation, please visit https://apidoc.lock.me/.
Requirements
PHP 8.2 or newer is required.
This package depends on:
- lustmored/oauth2-lockme (^1.6.0), the LockMe OAuth2 provider
- league/oauth2-client (^2.2)
- symfony/lock (^6.0 || ^7.0 || ^8.0)
- PHP ext-json
Installation
You can install the package via composer:
composer require lustmored/lockme-sdk
Configuration
To use the SDK, you need to create an instance with your client credentials:
use Lockme\SDK\Lockme; $sdk = new Lockme([ "clientId" => 'YOUR_CLIENT_ID', "clientSecret" => "YOUR_CLIENT_SECRET", "redirectUri" => 'YOUR_REDIRECT_URI', // Optional: Custom API domain (defaults to https://api.lock.me) "apiDomain" => 'https://api.lock.me', // Optional: API version (defaults to the provider's default, currently v2.7) "version" => 'v2.7', // Optional: default scopes (defaults to ['rooms_manage']) "scopes" => ['rooms_manage'], // Optional: directory of the lock files guarding the token refresh, when semaphores are not available "tmp_dir" => sys_get_temp_dir(), ]);
The options are passed on to the LockMe OAuth2 provider, so every
option of the provider (e.g. ignoreSslErrors, proxy, timeout) works here too. A ready provider can be
supplied as the provider option instead.
The second constructor argument takes the collaborators of the provider, e.g. ['httpClient' => $client] to
supply your own HTTP client:
$sdk = new Lockme($options, ['httpClient' => $client]);
Authentication
The SDK uses OAuth2 for authentication. Here's how to implement the authentication flow:
Step 1: Get Authorization URL
// Define the scopes you need - rooms_manage is required for booking operations $authUrl = $sdk->getAuthorizationUrl(['rooms_manage']); // Redirect the user to the authorization URL header('Location: ' . $authUrl); exit;
Step 2: Handle the Callback
// In your callback URL handler $code = $_GET['code']; $state = $_GET['state']; try { // Exchange the authorization code for an access token $accessToken = $sdk->getTokenForCode($code, $state); // Save the token for future use file_put_contents('token.json', json_encode($accessToken)); } catch (Exception $e) { echo 'Error: ' . $e->getMessage(); }
Step 3: Use the Saved Token
try { // Load the token from storage and set up automatic saving when refreshed $sdk->loadAccessToken( fn() => file_get_contents('token.json'), fn($token) => file_put_contents('token.json', json_encode($token)) ); // Now you can make API calls $rooms = $sdk->RoomList(); } catch(Exception $e) { echo 'Error: ' . $e->getMessage(); }
Every API call takes an optional access token as its last argument; without one the token loaded above is used.
A RuntimeException is thrown when there is neither.
Error Handling
Every refusal of the API is thrown as a subclass of
Lockme\OAuth2\Client\Provider\Exception\LockmeIdentityProviderException (itself a
League\OAuth2\Client\Provider\Exception\IdentityProviderException), chosen by the HTTP status of the
response. The message carries the API's description of the error and the code the HTTP status.
| Status | Exception |
|---|---|
| 400 | BadRequestException |
| 401 | UnauthorizedException |
| 403 | ForbiddenException |
| 404 | NotFoundException |
| 409 | ConflictException |
| 422 | UnprocessableEntityException |
| other 4xx | ClientErrorException (base of all the above) |
| 5xx | ServerErrorException |
use Lockme\OAuth2\Client\Provider\Exception\ConflictException; use Lockme\OAuth2\Client\Provider\Exception\LockmeIdentityProviderException; use Lockme\OAuth2\Client\Provider\Exception\NotFoundException; try { $reservationId = $sdk->AddReservation($data); } catch (NotFoundException $e) { // The room does not exist or is not accessible } catch (ConflictException $e) { // The hour was booked meanwhile } catch (LockmeIdentityProviderException $e) { // Any other refusal; getCode() is the HTTP status, getResponseBody() the raw body echo 'Error: ' . $e->getMessage(); }
Up to API version 2.6 the API reports every refusal with status 500, so ServerErrorException is all you get
there. Since version 2.7 (the default) the status tells what went wrong, see the
API documentation.
An UnexpectedValueException is thrown when the API answers with a body of a different shape than the method
promises (e.g. not a JSON object).
API Usage Examples
Test Connection
$result = $sdk->Test();
Get Room List
$rooms = $sdk->RoomList();
Get Room Details
$roomId = 123; $room = $sdk->GetRoom($roomId);
Edit Room Details
$roomId = 123; $data = [ 'calendarMargin' => 15, // numeric value ]; $room = $sdk->EditRoom($roomId, $data);
Get Bookings for a Room
use DateTime; $roomId = 123; $date = new DateTime(); $reservations = $sdk->GetReservations($roomId, $date);
Add a Booking
$data = [ 'date' => '2023-01-01', // Date in YYYY-MM-DD format 'hour' => '11:00:00', // Time in HH:MM:SS format 'roomid' => 123, // Room ID 'extid' => 'abc123', // External ID (your system's ID) 'name' => 'John', // Customer's first name 'surname' => 'Doe', // Customer's last name 'email' => 'john.doe@example.com', // Customer's email 'phone' => '+1234567890', // Customer's phone number 'people' => 4, // Number of people 'pricer' => 1, // Pricer ID (pricing option) 'comment' => 'Special requests', // Booking comment 'price' => 100.00, // Price ]; $reservationId = $sdk->AddReservation($data);
Get Booking Details
$roomId = 123; $reservationId = 'abc123'; $reservation = $sdk->Reservation($roomId, $reservationId);
Note: Whenever a booking ID is used, you can also use an external ID (the one set via API) by using the format "ext/{id}". For example:
$reservationId = 'ext/abc123';
Edit a Booking
$roomId = 123; $reservationId = 'abc123'; $data = [ 'name' => 'John', // Customer's first name 'surname' => 'Doe', // Customer's last name 'email' => 'john.doe@example.com', // Customer's email 'phone' => '+1234567890', // Customer's phone number 'people' => 4, // Number of people 'pricer' => 1, // Pricer ID (pricing option) 'comment' => 'Updated requests', // Booking comment 'price' => 100.00, // Price ]; $result = $sdk->EditReservation($roomId, $reservationId, $data);
Delete a Booking
$roomId = 123; $reservationId = 'abc123'; $result = $sdk->DeleteReservation($roomId, $reservationId);
Get Date Settings
$roomId = 123; $date = new DateTime(); $settings = $sdk->GetDateSettings($roomId, $date);
Set Date Settings
$roomId = 123; $date = new DateTime(); $settings = [ // Specific hour settings [ "hour" => "16:00:00", // Time slot "pricers" => [1227], // Available pricing options for this slot ], [ "hour" => "18:00:00", "pricers" => [1227, 1228], ] ]; $result = $sdk->SetDateSettings($roomId, $date, $settings);
Get Departments
$departments = $sdk->DepartmentList(); $department = $sdk->GetDepartment(123);
Discount Codes
// List the codes of the partners the authorized user belongs to $codes = $sdk->CodeList(); // Create 5 amount codes worth 50 PLN for two rooms, valid until the end of the year $created = $sdk->AddCodes([ 'partner' => 42, // Partner ID, one of the "partners" of getResourceOwner() 'rooms' => [123, 124], // Rooms the codes are valid for 'value' => 50, // Amount, or percent when no currency is set 'currency' => 'PLN', // Omit for a percent code 'valid' => '2026-12-31', // Expiration date, omit for no expiration 'limit' => 1, // Uses per code, 0 for unlimited 'days' => [1, 2, 3, 4, 5], // Weekdays the code is valid on, 1 - Monday, ..., 7 - Sunday 'code' => 'XMAS', // Code text, prefixed with the partner's code prefix 'description' => 'Christmas', 'number' => 5, // Number of codes to create ]); // $created is a list of the created codes, e.g. ['PFX-XMAS-1', 'PFX-XMAS-2', ...] // Code details with the bookings it counts as used $code = $sdk->GetCode('PFX-XMAS-1'); // Change the expiration, limit, description, days or active state $code = $sdk->EditCode('PFX-XMAS-1', ['valid' => '2027-01-31', 'limit' => 2]); // Deactivate a code, e.g. once the voucher behind it was used elsewhere $sdk->DeactivateCode('PFX-XMAS-1');
Available Methods
getAuthorizationUrl(array $scopes, ?array &$session): Get the authorization URL for OAuth2 flowgetTokenForCode(string $code, string $state, ?string $sessionState): Exchange authorization code for access tokenrefreshToken(?AccessToken $accessToken): Refresh an access tokensetDefaultAccessToken($token): Set the default access token for API calls (deprecated, useloadAccessToken())loadAccessToken(callable $load, ?callable $save): Load and optionally set up saving of access tokengetResourceOwner(): Get the user the access token belongs toTest(): Test the API connectionRoomList(): Get list of roomsGetRoom(int $roomId): Get room detailsEditRoom(int $roomId, array $data): Update room details (calendarMarginonly)Reservation(int $roomId, string|int $id): Get booking detailsAddReservation(array $data): Create a new bookingDeleteReservation(int $roomId, string|int $id): Delete a bookingEditReservation(int $roomId, string|int $id, array $data): Edit a bookingMoveReservation(int $roomId, string|int $id, array $data): Move a bookingGetReservations(int $roomId, DateTimeInterface $date): Get bookings for a room on a specific dateGetMessage(int $messageId): Get a messageMarkMessageRead(int $messageId): Mark a message as readGetDateSettings(int $roomId, DateTimeInterface $date): Get settings for a specific dateSetDateSettings(int $roomId, DateTimeInterface $date, array $settings): Set settings for a specific dateRemoveDateSettings(int $roomId, DateTimeInterface $date): Remove custom settings for a specific dateGetDaySettings(int $roomId, int $day): Get settings for a specific day of the weekSetDaySettings(int $roomId, int $day, array $settings): Set settings for a specific day of the weekDepartmentList(): Get list of departmentsGetDepartment(int $departmentId): Get department detailsCodeList(): Get list of discount codesGetCode(string $code): Get discount code details with the bookings it counts as usedAddCodes(array $data): Create discount codes, returns the created codesEditCode(string $code, array $data): Change a discount codeDeactivateCode(string $code): Deactivate a discount code
Development
composer check # php-cs-fixer (dry run) and phpstan
composer cs:fix # apply the code style
License
This package is licensed under the GPL-3.0-or-later License - see the LICENSE file for details.
Author
- Jakub Caban (kuba@lock.me)