PHP code example of saintsystems / odata-client

1. Go to this page and download the library: Download saintsystems/odata-client library. Choose the download type require.

2. Extract the ZIP file and open the index.php.

3. Add this code to the index.php.
    
        
<?php
require_once('vendor/autoload.php');

/* Start to develop here. Best regards https://php-download.com/ */

    

saintsystems / odata-client example snippets


use SaintSystems\OData\ODataClient;
use SaintSystems\OData\GuzzleHttpProvider;

$httpProvider = new GuzzleHttpProvider();
$odataClient = new ODataClient($odataServiceUrl, null, $httpProvider);

use SaintSystems\OData\ODataClient;
use SaintSystems\OData\Psr17HttpProvider;

// Example using Symfony HTTP Client with Nyholm PSR-7
$httpClient = new \Symfony\Component\HttpClient\Psr18Client();
$requestFactory = new \Nyholm\Psr7\Factory\Psr17Factory();
$streamFactory = new \Nyholm\Psr7\Factory\Psr17Factory();

$httpProvider = new Psr17HttpProvider($httpClient, $requestFactory, $streamFactory);
$odataClient = new ODataClient($odataServiceUrl, null, $httpProvider);



aintSystems\OData\ODataClient;
use SaintSystems\OData\GuzzleHttpProvider;

class UsageExample
{
	public function __construct()
	{
		$odataServiceUrl = 'https://services.odata.org/V4/TripPinService';

		$httpProvider = new GuzzleHttpProvider();
		$odataClient = new ODataClient($odataServiceUrl, null, $httpProvider);

		// Retrieve all entities from the "People" Entity Set
		$people = $odataClient->from('People')->get();

		// Or retrieve a specific entity by the Entity ID/Key
		try {
			$person = $odataClient->from('People')->find('russellwhyte');
			echo "Hello, I am $person->FirstName ";
		} catch (Exception $e) {
			echo $e->getMessage();
		}

		// Want to only select a few properties/columns?
		$people = $odataClient->from('People')->select('FirstName','LastName')->get();
	}
}

$example = new UsageExample();



use SaintSystems\OData\ODataClient;
use SaintSystems\OData\GuzzleHttpProvider;

$httpProvider = new GuzzleHttpProvider();
$odataClient = new ODataClient($odataServiceUrl, null, $httpProvider);

// Method 1: Set headers on the client (applies to all requests)
$odataClient->setHeaders([
    'Authorization' => 'Bearer your-token-here',
    'X-Custom-Header' => 'MyCustomValue',
    'X-Client-Version' => '1.0.0'
]);

// Method 2: Add a single header to the client
$odataClient->addHeader('X-Request-ID', uniqid());

// Method 3: Add headers to specific queries using the fluent interface
$people = $odataClient->from('People')
    ->withHeader('X-Query-Context', 'get-all-people')
    ->withHeaders([
        'X-Debug' => 'true',
        'X-Performance-Track' => 'enabled'
    ])
    ->get();

// Headers set on the client persist across requests
$person = $odataClient->from('People')->find('russellwhyte');

// Query-specific headers only apply to that request
$airlines = $odataClient->from('Airlines')
    ->withHeader('X-Data-Source', 'airlines-api')
    ->get();



use SaintSystems\OData\ODataClient;
use SaintSystems\OData\GuzzleHttpProvider;

$httpProvider = new GuzzleHttpProvider();
$odataClient = new ODataClient($odataServiceUrl, null, $httpProvider);

// Method 1: Add custom options using string format
$people = $odataClient->from('People')
    ->addOption('timeout=30')
    ->addOption('format=minimal')
    ->get();
// Results in: /People?timeout=30&format=minimal

// Method 2: Add custom options using array format
$people = $odataClient->from('People')
    ->addOption(['timeout' => '30', 'debug' => 'true'])
    ->get();
// Results in: /People?timeout=30&debug=true

// Method 3: Mix with standard OData parameters
$people = $odataClient->from('People')
    ->select('FirstName', 'LastName')
    ->where('FirstName', 'Russell')
    ->addOption('version=2.0')
    ->get();
// Results in: /People?$select=FirstName,LastName&$filter=FirstName eq 'Russell'&version=2.0

// Method 4: Multiple addOption calls are merged (not overwritten)
$people = $odataClient->from('People')
    ->addOption('timeout=30')
    ->addOption('format=minimal')
    ->addOption(['debug' => 'true']);
// Results in: /People?timeout=30&format=minimal&debug=true

// Custom option keys are validated:
// ✓ Valid: 'timeout', 'custom_param', 'kebab-case', 'camelCase'
// ✗ Invalid: '$reserved' (starts with $), 'invalid key!' (special chars)



use SaintSystems\OData\ODataClient;
use SaintSystems\OData\GuzzleHttpProvider;

class CustomTimeoutODataClient extends ODataClient {
    private $customTimeout;

    public function __construct($baseUrl, $authProvider = null, $httpProvider = null, $timeout = 30) {
        parent::__construct($baseUrl, $authProvider, $httpProvider);
        $this->customTimeout = $timeout;
    }

    protected function createRequest($method, $requestUri) {
        $request = parent::createRequest($method, $requestUri);
        $request->setTimeout($this->customTimeout);
        return $request;
    }
}

// Usage with custom timeout
$httpProvider = new GuzzleHttpProvider();
$client = new CustomTimeoutODataClient('https://api.example.com/odata', null, $httpProvider, 60);
$result = $client->from('Products')->get(); // Uses 60-second timeout



use SaintSystems\OData\ODataClient;
use SaintSystems\OData\GuzzleHttpProvider;

$httpProvider = new GuzzleHttpProvider();
$client = new ODataClient('https://services.odata.org/V4/TripPinService', null, $httpProvider);

// Get a person with address information
$person = $client->from('People')->find('russellwhyte');

// Access nested properties directly
$city = $person->AddressInfo[0]->City;           // Object-style access
$country = $person->AddressInfo[0]->CountryRegion; // Deep nesting supported

// Complex nested structures work naturally
if ($person->Settings && $person->Settings->Preferences) {
    $theme = $person->Settings->Preferences->Theme;
}

// Safe access with dot notation - returns null if any part doesn't exist
$city = $person->getProperty('AddressInfo.0.City');
$country = $person->getProperty('AddressInfo.0.CountryRegion');
$theme = $person->getProperty('Settings.Preferences.Theme');

// Works with array indices and object properties
$firstFriendName = $person->getProperty('Friends.0.FirstName');
$homeAddress = $person->getProperty('AddressInfo.0.Address');

// Check existence using hasProperty()
if ($person->hasProperty('AddressInfo.0.City')) {
    $city = $person->getProperty('AddressInfo.0.City');
}

// Also works with isset() for object-style access
if (isset($person->AddressInfo[0]->City)) {
    $city = $person->AddressInfo[0]->City;
}

// Check for deeply nested paths
if ($person->hasProperty('Settings.Preferences.AutoSave')) {
    $autoSave = $person->getProperty('Settings.Preferences.AutoSave');
}

// Get people with address information
$people = $client->select('UserName,FirstName,LastName,AddressInfo')
                 ->from('People')
                 ->get();

foreach ($people as $person) {
    echo "Person: " . $person->FirstName . " " . $person->LastName . "\n";

    // Access nested address info - remains as array for easy filtering
    $addresses = $person->AddressInfo;

    // Filter addresses by type
    $homeAddresses = array_filter($addresses, function($address) {
        return isset($address['Type']) && $address['Type'] === 'Home';
    });

    // Access properties within filtered results
    foreach ($homeAddresses as $address) {
        // Convert to Entity for object-style access
        $addrEntity = new \SaintSystems\OData\Entity($address);
        echo "  Home Address: " . $addrEntity->Address . ", " . $addrEntity->City . "\n";
    }
}

// Query for folders with nested Info and Children data
$folders = $client->select('Id,Name,CreatorNameShort,Info,Info/IsAHomeFolder,Children/Id,Children/Name')
                  ->from('Items')
                  ->where('HasChildren', true)
                  ->get();

foreach ($folders as $folder) {
    echo "Folder: " . $folder->Name . "\n";
    echo "Creator: " . $folder->CreatorNameShort . "\n";

    // Access nested Info properties
    if ($folder->Info) {
        echo "Is Home Folder: " . ($folder->Info->IsAHomeFolder ? 'Yes' : 'No') . "\n";

        // Safe navigation for optional nested properties
        if ($folder->hasProperty('Info.Settings.Theme')) {
            echo "Theme: " . $folder->getProperty('Info.Settings.Theme') . "\n";
        }
    }

    // Work with Children collection
    if ($folder->Children) {
        echo "Children:\n";

        // Filter children by type
        $subfolders = array_filter($folder->Children, function($child) {
            return $child['FileSizeBytes'] == 0; // Folders have 0 file size
        });

        foreach ($subfolders as $subfolder) {
            echo "  - " . $subfolder['Name'] . " (ID: " . $subfolder['Id'] . ")\n";
        }
    }
    echo "\n";
}

// Select specific nested properties
$result = $client->select('Id,Name,Info/IsAHomeFolder,Children/Name,AddressInfo/City')
                 ->from('Items')
                 ->get();

// Use in where clauses (if supported by the OData service)
$homeItems = $client->from('Items')
                    ->where('Info/IsAHomeFolder', true)
                    ->get();

// Expand related data and access nested properties
$peopleWithTrips = $client->from('People')
                          ->expand('Trips')
                          ->get();

foreach ($peopleWithTrips as $person) {
    foreach ($person->Trips as $trip) {
        // Access nested trip properties
        $tripEntity = new \SaintSystems\OData\Entity($trip);
        echo $person->FirstName . " has trip: " . $tripEntity->Name . "\n";
    }
}



use SaintSystems\OData\ODataClient;
use SaintSystems\OData\GuzzleHttpProvider;

$httpProvider = new GuzzleHttpProvider();
$client = new ODataClient('https://services.odata.org/V4/TripPinService', null, $httpProvider);

// Find people who have any completed trips
$peopleWithCompletedTrips = $client->from('People')
    ->whereAny('Trips', function($query) {
        $query->where('Status', 'Completed');
    })
    ->get();
// Generates: People?$filter=Trips/any(t: t/Status eq 'Completed')

// Find people where all their trips are high-budget
$peopleWithAllHighBudgetTrips = $client->from('People')
    ->whereAll('Trips', function($query) {
        $query->where('Budget', '>', 1000);
    })
    ->get();
// Generates: People?$filter=Trips/all(t: t/Budget gt 1000)

// Multiple conditions within lambda
$peopleWithQualifiedTrips = $client->from('People')
    ->whereAny('Trips', function($query) {
        $query->where('Status', 'Completed')
              ->where('Budget', '>', 500);
    })
    ->get();
// Generates: People?$filter=Trips/any(t: t/Status eq 'Completed' and t/Budget gt 500)

// Combining with regular conditions
$activePeopleWithTrips = $client->from('People')
    ->where('Status', 'Active')
    ->whereAny('Trips', function($query) {
        $query->where('Status', 'Pending');
    })
    ->get();
// Generates: People?$filter=Status eq 'Active' and Trips/any(t: t/Status eq 'Pending')



use SaintSystems\OData\ODataClient;
use SaintSystems\OData\GuzzleHttpProvider;

$httpProvider = new GuzzleHttpProvider();
$client = new ODataClient('https://services.odata.org/V4/TripPinService', null, $httpProvider);

// Simple batch with multiple GET requests
$response = $client->batch()
    ->get('People', 'get-people')
    ->get('Airlines', 'get-airlines')
    ->get('Airports', 'get-airports')
    ->execute();

// Batch with changeset for atomic operations
$response = $client->batch()
    ->startChangeset()
        ->post('People', [
            'FirstName' => 'John',
            'LastName' => 'Doe',
            'UserName' => 'johndoe',
            'Emails' => ['[email protected]']
        ], 'create-person')
        ->patch('People(\'russellwhyte\')', [
            'FirstName' => 'Jane',
            'LastName' => 'Smith'
        ], 'update-person')
    ->endChangeset()
    ->execute();

$response = $client->batch()
    // Individual queries (not in changeset)
    ->get('People?$top=5', 'get-top-people')

    // Atomic operations in changeset
    ->startChangeset()
        ->post('People', $newPersonData, 'create-person')
        ->delete('People(\'obsolete-id\')', 'delete-person')
    ->endChangeset()

    // More individual queries
    ->get('Airlines?$top=3', 'get-airlines')
    ->execute();