bmlt-enabled / bmlt-php-query-client
A PHP client for querying BMLT (Basic Meeting List Tool) servers with built-in geocoding support
Requires
- php: >=8.1
- ext-curl: *
- ext-json: *
- guzzlehttp/guzzle: ^7.8
- psr/log: ^1.1|^3.0
Requires (Dev)
- friendsofphp/php-cs-fixer: ^3.0
- phpdocumentor/phpdocumentor: ^3.5
- phpstan/phpstan: ^1.10
- phpunit/phpunit: ^10.0
- squizlabs/php_codesniffer: ^3.7
README
A modern PHP client for querying BMLT (Basic Meeting List Tool) servers with built-in geocoding support using Guzzle HTTP client.
Features
- 🚀 Modern PHP 8.1+ - Uses enums, readonly classes, and named parameters
- 🏛️ Complete BMLT API coverage - All semantic endpoints supported
- 🌍 Built-in geocoding - Uses OpenStreetMap Nominatim for address-to-coordinates conversion
- 🔍 Type-safe API - Full type definitions with readonly data objects
- ⚡ HTTP client - Built on Guzzle HTTP with proper error handling
- 📦 Composer ready - Easy installation via Composer
- 🎯 Well tested - Comprehensive unit and integration tests
- 🛠️ Developer friendly - Clear exceptions and validation
Requirements
- PHP 8.1 or higher
- ext-curl
- ext-json
Installation
composer require bmlt-enabled/bmlt-php-query-client
Quick Start
Basic Usage
<?php use BmltEnabled\BmltQueryClient\Client\BmltClient; use BmltEnabled\BmltQueryClient\Types\VenueType; use BmltEnabled\BmltQueryClient\Types\Weekday; // Initialize the client $client = new BmltClient( rootServerUrl: 'https://latest.aws.bmlt.app/main_server' // NYC demo server ); // Search for meetings $meetings = $client->searchMeetings([ 'venue_types' => VenueType::VIRTUAL->value, 'page_size' => 10, ]); foreach ($meetings as $meeting) { echo "Meeting: {$meeting->meeting_name}\n"; echo "Time: {$meeting->start_time}\n"; if ($meeting->virtual_meeting_link) { echo "Link: {$meeting->virtual_meeting_link}\n"; } echo "---\n"; }
Using the Factory
<?php use BmltEnabled\BmltQueryClient\BmltQueryClient; // Create client using factory method $client = BmltQueryClient::create( rootServerUrl: 'https://your-bmlt-server.org/main_server' ); $serverInfo = $client->getServerInfo(); echo "Server version: {$serverInfo->version}\n";
API Reference
Client Configuration
$client = new BmltClient( rootServerUrl: 'https://your-server.org/main_server', // Required defaultFormat: BmltDataFormat::JSON, // Optional timeout: 30, // Request timeout in seconds userAgent: 'my-app/1.0.0', // Custom user agent enableGeocoding: true, // Enable geocoding features );
Search Methods
Search Meetings
// Basic search $meetings = $client->searchMeetings([ 'weekdays' => [Weekday::SUNDAY->value, Weekday::MONDAY->value], 'venue_types' => VenueType::IN_PERSON->value, 'page_size' => 20, ]); // Search by coordinates use BmltEnabled\BmltQueryClient\Types\Coordinates; $coordinates = new Coordinates(40.7580, -73.9855); // Times Square $nearbyMeetings = $client->searchMeetingsByCoordinates( $coordinates, radiusMiles: 5.0, searchParams: ['page_size' => 10] ); // Search by address (uses geocoding) $addressMeetings = $client->searchMeetingsByAddress( address: 'Times Square, New York, NY', radiusMiles: 2.0, sortByDistance: true, searchParams: ['venue_types' => VenueType::VIRTUAL->value] );
Server Information
// Get server info $serverInfo = $client->getServerInfo(); echo "Version: {$serverInfo->version}\n"; echo "Languages: " . implode(', ', $serverInfo->langs ?? []) . "\n"; // Get meeting formats $formats = $client->getFormats(); foreach ($formats as $format) { echo "{$format->key_string}: {$format->name_string}\n"; } // Get service bodies $serviceBodies = $client->getServiceBodies(); foreach ($serviceBodies as $serviceBody) { echo "{$serviceBody->name} ({$serviceBody->type})\n"; }
Geocoding
// Geocode an address $result = $client->geocodeAddress('Central Park, New York, NY'); echo "Coordinates: {$result->coordinates->latitude}, {$result->coordinates->longitude}\n"; echo "Address: {$result->display_name}\n"; // Reverse geocode coordinates $coordinates = new Coordinates(40.7614, -73.9776); $address = $client->reverseGeocode($coordinates); echo "Address: {$address->display_name}\n";
Fluent Query Builder
use BmltEnabled\BmltQueryClient\Client\{MeetingQueryBuilder, QuickSearch}; // Complex fluent query $eveningVirtual = (new MeetingQueryBuilder($client)) ->virtualOnly() ->startingAfter(17, 0) // After 5 PM ->endingBefore(21, 0) // Before 9 PM ->onWeekdays(Weekday::MONDAY, Weekday::FRIDAY) ->paginate(10) ->execute(); // Quick search patterns $quickSearch = new QuickSearch($client); $todaysMeetings = $quickSearch->today()->execute(); $tonightVirtual = $quickSearch->tonight()->virtualOnly()->execute(); $weekendInPerson = $quickSearch->weekend()->inPersonOnly()->execute(); // Geographic search with fluent interface $nearbyMeetings = (new MeetingQueryBuilder($client)) ->inPersonOnly() ->morning() ->executeNearAddress('Times Square, NY', 2.0);
Data Types
The library provides strongly-typed data objects:
Meeting Object
// Meeting properties $meeting->id_bigint; // Meeting ID $meeting->meeting_name; // Meeting name $meeting->weekday_tinyint; // Day of week (1=Sunday) $meeting->start_time; // Start time (HH:MM) $meeting->venue_type; // 1=In-person, 2=Virtual, 3=Hybrid $meeting->virtual_meeting_link; // Virtual meeting URL $meeting->latitude; // Latitude $meeting->longitude; // Longitude $meeting->distance_in_miles; // Distance (when searching by location) // ... and many more
Enums
use BmltEnabled\BmltQueryClient\Types\{Weekday, VenueType, Language, BmltDataFormat}; // Weekday enum (BMLT uses 1-7, Sunday=1) Weekday::SUNDAY; // 1 Weekday::MONDAY; // 2 // ... etc // Venue types VenueType::IN_PERSON; // 1 VenueType::VIRTUAL; // 2 VenueType::HYBRID; // 3 // Supported languages Language::ENGLISH; // 'en' Language::SPANISH; // 'es' // ... etc // Data formats BmltDataFormat::JSON; // 'json' BmltDataFormat::CSV; // 'csv' // ... etc
Error Handling
The library provides comprehensive error handling with specific exception types:
use BmltEnabled\BmltQueryClient\Exceptions\BmltQueryException; try { $meetings = $client->searchMeetings(['invalid' => 'parameter']); } catch (BmltQueryException $e) { echo "Error type: {$e->getType()}\n"; echo "User message: {$e->getUserMessage()}\n"; if ($e->isRetryable()) { echo "This error can be retried\n"; } if ($e->isType(BmltQueryException::TYPE_GEOCODING_ERROR)) { echo "Geocoding failed\n"; } }
Exception Types
TYPE_NETWORK_ERROR
- Network connectivity issues (retryable)TYPE_TIMEOUT_ERROR
- Request timeout (retryable)TYPE_VALIDATION_ERROR
- Invalid parameters (not retryable)TYPE_GEOCODING_ERROR
- Geocoding service error (retryable)TYPE_RESPONSE_ERROR
- Invalid server response (retryable for 5xx)TYPE_RATE_LIMIT_ERROR
- Too many requests (retryable)
Configuration
Runtime Configuration
You can update client settings after initialization:
// Update user agent $client->setUserAgent('my-updated-app/2.0.0'); echo $client->getUserAgent(); // 'my-updated-app/2.0.0' // Update timeout $client->setTimeout(60); // 60 seconds echo $client->getTimeout(); // 60 // Update root server URL $client->setRootServerUrl('https://new-server.org/main_server'); echo $client->getRootServerUrl(); // Update default format $client->setDefaultFormat(BmltDataFormat::JSONP); echo $client->getDefaultFormat()->value; // 'jsonp'
Geocoding Options
use BmltEnabled\BmltQueryClient\Services\GeocodingService; // Create custom geocoding service $geocodingService = new GeocodingService( timeout: 10, retryCount: 3, userAgent: 'my-app/1.0.0', countryCode: 'us', // Bias results to US viewbox: [-74.2, 40.4, -73.7, 40.9], // NYC bounding box [w,s,e,n] bounded: true, // Restrict to viewbox ); $client = new BmltClient( rootServerUrl: 'https://your-server.org/main_server', geocodingService: $geocodingService );
Testing
The library includes comprehensive tests:
# Run unit tests ./vendor/bin/phpunit --testsuite="Unit Tests" # Run integration tests (requires internet connection) ./vendor/bin/phpunit --testsuite="Integration Tests" # Run all tests ./vendor/bin/phpunit # Run with coverage (requires xdebug) ./vendor/bin/phpunit --coverage-html coverage
API Documentation
The library includes comprehensive PHPDoc annotations. You can generate HTML API documentation using:
# Generate API documentation composer docs # View documentation open docs/api/index.html
The generated documentation includes:
- Complete API reference for all classes, methods, and properties
- Usage examples and code samples
- Type information and parameter descriptions
- Exception documentation
- Inheritance diagrams
Development
# Install dependencies composer install # Run tests composer test # Static analysis composer analyse # Code style check composer cs-check # Fix code style composer cs-fix # Generate documentation composer docs
Examples
See the examples/
directory for complete working examples:
- basic-usage.php - Basic API usage examples
- geocoding.php - Geocoding examples
- error-handling.php - Error handling examples
License
MIT License. See LICENSE file for details.
Contributing
Contributions are welcome! Please read the contributing guidelines and submit pull requests.
Support
Related Projects
- bmlt-query-client - TypeScript/JavaScript version
- BMLT Root Server - The BMLT server software