{"id":30830561,"url":"https://github.com/thenativeweb/eventsourcingdb-client-php","last_synced_at":"2025-09-06T15:55:27.483Z","repository":{"id":292735812,"uuid":"980260215","full_name":"thenativeweb/eventsourcingdb-client-php","owner":"thenativeweb","description":"The official PHP client SDK for EventSourcingDB.","archived":false,"fork":false,"pushed_at":"2025-08-25T05:12:59.000Z","size":183,"stargazers_count":7,"open_issues_count":0,"forks_count":3,"subscribers_count":3,"default_branch":"main","last_synced_at":"2025-08-25T07:54:16.058Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"PHP","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/thenativeweb.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE.md","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":".github/CODEOWNERS","security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2025-05-08T20:48:47.000Z","updated_at":"2025-08-25T05:13:01.000Z","dependencies_parsed_at":null,"dependency_job_id":"cf31948e-9e71-4a56-8d48-5c1796c9f8b6","html_url":"https://github.com/thenativeweb/eventsourcingdb-client-php","commit_stats":null,"previous_names":["thenativeweb/eventsourcingdb-client-php"],"tags_count":20,"template":false,"template_full_name":null,"purl":"pkg:github/thenativeweb/eventsourcingdb-client-php","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/thenativeweb%2Feventsourcingdb-client-php","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/thenativeweb%2Feventsourcingdb-client-php/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/thenativeweb%2Feventsourcingdb-client-php/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/thenativeweb%2Feventsourcingdb-client-php/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/thenativeweb","download_url":"https://codeload.github.com/thenativeweb/eventsourcingdb-client-php/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/thenativeweb%2Feventsourcingdb-client-php/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":273926543,"owners_count":25192318,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-09-06T02:00:13.247Z","response_time":2576,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2025-09-06T15:55:16.599Z","updated_at":"2025-09-06T15:55:27.467Z","avatar_url":"https://github.com/thenativeweb.png","language":"PHP","funding_links":[],"categories":[],"sub_categories":[],"readme":"# eventsourcingdb\n\nThe official PHP client SDK for [EventSourcingDB](https://www.eventsourcingdb.io) – a purpose-built database for event sourcing.\n\nEventSourcingDB enables you to build and operate event-driven applications with native support for writing, reading, and observing events. This client SDK provides convenient access to its capabilities in PHP.\n\nFor more information on EventSourcingDB, see its [official documentation](https://docs.eventsourcingdb.io/).\n\nThis client SDK includes support for [Testcontainers](https://testcontainers.com/) to spin up EventSourcingDB instances in integration tests. For details, see [Using Testcontainers](#using-testcontainers).\n\n## Getting Started\n\nInstall the client SDK:\n\n```shell\ncomposer require thenativeweb/eventsourcingdb\n```\n\nImport the `Client` class and create an instance by providing the URL of your EventSourcingDB instance and the API token to use:\n\n```php\nrequire __DIR__ . '/vendor/autoload.php';\n\nuse Thenativeweb\\Eventsourcingdb\\Client;\n\n$client = new Client('http://localhost:3000', 'secret');\n```\n\nThen call the `ping` function to check whether the instance is reachable. If it is not, the function will throw an exception:\n\n```php\n$client-\u003eping();\n```\n\n*Note that `ping` does not require authentication, so the call may succeed even if the API token is invalid.*\n\nIf you want to verify the API token, call `verifyApiToken`. If the token is invalid, the function will throw an exception:\n\n```php\n$client-\u003everifyApiToken();\n```\n\n### Writing Events\n\nCall the `writeEvents` function and hand over an array with one or more events. You do not have to provide all event fields – some are automatically added by the server.\n\nSpecify `source`, `subject`, `type`, and `data` according to the [CloudEvents](https://docs.eventsourcingdb.io/fundamentals/cloud-events/) format.\n\nThe function returns the written events, including the fields added by the server:\n\n```php\nuse Thenativeweb\\Eventsourcingdb\\EventCandidate;\n\n$writtenEvents = $client-\u003ewriteEvents([\n  new EventCandidate(\n    'https://library.eventsourcingdb.io',\n    '/books/42',\n    'io.eventsourcingdb.library.book-acquired',\n    [\n      'title' =\u003e '2001 – A Space Odyssey',\n      'author' =\u003e 'Arthur C. Clarke',\n      'isbn' =\u003e '978-0756906788',\n    ],\n  ),\n]);\n```\n\n#### Using the `isSubjectPristine` precondition\n\nIf you only want to write events in case a subject (such as `/books/42`) does not yet have any events, import the `IsSubjectPristine` class, use it to create a precondition, and pass it in an array as the second argument:\n\n```php\nuse Thenativeweb\\Eventsourcingdb\\IsSubjectPristine;\n\n$writtenEvents = $client-\u003ewriteEvents([\n  // events\n], [\n  new IsSubjectPristine('/books/42'),\n]);\n```\n\n#### Using the `isSubjectOnEventId` precondition\n\nIf you only want to write events in case the last event of a subject (such as `/books/42`) has a specific ID (e.g., `0`), import the `IsSubjectOnEventId` class, use it to create a precondition, and pass it in an array as the second argument:\n\n```php\nuse Thenativeweb\\Eventsourcingdb\\IsSubjectOnEventId;\n\n$writtenEvents = $client-\u003ewriteEvents([\n  // events\n], [\n  new IsSubjectOnEventId('/books/42', '0'),\n]);\n```\n\n*Note that according to the CloudEvents standard, event IDs must be of type string.*\n\n#### Using the `isEventQlQueryTrue` precondition\n\nIf you want to write events depending on an EventQL query, use the `IsEventQlQueryTrue` function to create a precondition:\n\n```php\nuse Thenativeweb\\Eventsourcingdb\\IsEventQlQueryTrue;\n\n$writtenEvents = $client-\u003ewriteEvents([\n  // events\n], [\n  new IsEventQlQueryTrue(\"FROM e IN events WHERE e.type == 'io.eventsourcingdb.library.book-borrowed' PROJECT INTO COUNT() \u003c 10\")\n]);\n```\n\n*Note that the query must return a single row with a single value, which is interpreted as a boolean.*\n\n### Reading Events\n\nTo read all events of a subject, call the `readEvents` function with the subject and an options object. Set the `recursive` option to `false`. This ensures that only events of the given subject are returned, not events of nested subjects.\n\nThe function returns an iterator, which you can use in a `foreach` loop:\n\n```php\nuse Thenativeweb\\Eventsourcingdb\\ReadEventsOptions;\n\n$events = $client-\u003ereadEvents(\n  '/books/42',\n  new ReadEventsOptions(\n    recursive: false,\n  ),\n);\n\nforeach ($events as $event) {\n  // ...\n}\n```\n\n#### Reading From Subjects Recursively\n\nIf you want to read not only all the events of a subject, but also the events of all nested subjects, set the `recursive` option to `true`:\n\n```php\nuse Thenativeweb\\Eventsourcingdb\\ReadEventsOptions;\n\n$events = $client-\u003ereadEvents(\n  '/books/42',\n  new ReadEventsOptions(\n    recursive: true,\n  ),\n);\n\nforeach ($events as $event) {\n  // ...\n}\n```\n\nThis also allows you to read *all* events ever written. To do so, provide `/` as the subject and set `recursive` to `true`, since all subjects are nested under the root subject.\n\n#### Reading in Anti-Chronological Order\n\nBy default, events are read in chronological order. To read in anti-chronological order, provide the `order` option and set it to `Order::ANTICHRONOLOGICAL`:\n\n```php\nuse Thenativeweb\\Eventsourcingdb\\Order;\nuse Thenativeweb\\Eventsourcingdb\\ReadEventsOptions;\n\n$events = $client-\u003ereadEvents(\n  '/books/42',\n  new ReadEventsOptions(\n    recursive: false,\n    order: Order::ANTICHRONOLOGICAL,\n  ),\n);\n\nforeach ($events as $event) {\n  // ...\n}\n```\n\n*Note that you can also use `Order::CHRONOLOGICAL` to explicitly enforce the default order.*\n\n#### Specifying Bounds\n\nSometimes you do not want to read all events, but only a range of events. For that, you can specify the `lowerBound` and `upperBound` options – either one of them or even both at the same time.\n\nSpecify the ID and whether to include or exclude it, for both the lower and upper bound:\n\n```php\nuse Thenativeweb\\Eventsourcingdb\\Bound;\nuse Thenativeweb\\Eventsourcingdb\\BoundType;\nuse Thenativeweb\\Eventsourcingdb\\ReadEventsOptions;\n\n$events = $client-\u003ereadEvents(\n  '/books/42',\n  new ReadEventsOptions(\n    recursive: false,\n    lowerBound: new Bound('100', BoundType::INCLUSIVE),\n    upperBound: new Bound('200', BoundType::EXCLUSIVE),\n  ),\n);\n\nforeach ($events as $event) {\n  // ...\n}\n```\n\n#### Starting From the Latest Event of a Given Type\n\nTo read starting from the latest event of a given type, provide the `fromLatestEvent` option and specify the subject, the type, and how to proceed if no such event exists.\n\nPossible options are `ReadIfEventIsMissing::READ_NOTHING`, which skips reading entirely, or `ReadIfEventIsMissing::READ_EVERYTHING`, which effectively behaves as if `fromLatestEvent` was not specified:\n\n```php\nuse Thenativeweb\\Eventsourcingdb\\ReadEventsOptions;\nuse Thenativeweb\\Eventsourcingdb\\ReadFromLatestEvent;\nuse Thenativeweb\\Eventsourcingdb\\ReadIfEventIsMissing;\n\n$events = $client-\u003ereadEvents(\n  '/books/42',\n  new ReadEventsOptions(\n    recursive: false,\n    fromLatestEvent: new ReadFromLatestEvent(\n      subject: '/books/42',\n      type: 'io.eventsourcingdb.library.book-borrowed',\n      ifEventIsMissing: ReadIfEventIsMissing::READ_EVERYTHING,\n    ),\n  ),\n);\n\nforeach ($events as $event) {\n  // ...\n}\n```\n\n*Note that `fromLatestEvent` and `lowerBound` can not be provided at the same time.*\n\n### Running EventQL Queries\n\nTo run an EventQL query, call the `runEventQlQuery` function and provide the query as a string. The function returns an iterator, which you can use in a `foreach` loop:\n\n```php\n$rows = $client-\u003erunEventQlQuery(\n  'FROM e IN events PROJECT INTO e',\n);\n\nforeach ($rows as $row) {\n  // ...\n}\n```\n\n*Note that each row returned by the iterator is an associative array and matches the projection specified in your query.*\n\n### Observing Events\n\nTo observe all events of a subject, call the `observeEvents` function with the subject as the first argument and an options object as the second argument. Set the `recursive` option to `false`. This ensures that only events of the given subject are returned, not events of nested subjects.\n\nThe function returns an asynchronous iterator, which you can use e.g. inside a `foreach` loop:\n\n```php\nuse Thenativeweb\\Eventsourcingdb\\ObserveEventsOptions;\n\n$events = $client-\u003eobserveEvents(\n  '/books/42',\n  new ObserveEventsOptions(\n    recursive: false,\n  ),\n);\n\nforeach ($events as $event) {\n  // ...\n}\n```\n\n#### Observing From Subjects Recursively\n\nIf you want to observe not only all the events of a subject, but also the events of all nested subjects, set the `recursive` option to `true`:\n\n```php\nuse Thenativeweb\\Eventsourcingdb\\ObserveEventsOptions;\n\n$events = $client-\u003eobserveEvents(\n  '/books/42',\n  new ObserveEventsOptions(\n    recursive: true,\n  ),\n);\n\nforeach ($events as $event) {\n  // ...\n}\n```\n\nThis also allows you to observe *all* events ever written. To do so, provide `/` as the subject and set `recursive` to `true`, since all subjects are nested under the root subject.\n\n#### Specifying Bounds\n\nSometimes you do not want to observe all events, but only a range of events. For that, you can specify the `lowerBound` option.\n\nSpecify the ID and whether to include or exclude it:\n\n```php\nuse Thenativeweb\\Eventsourcingdb\\Bound;\nuse Thenativeweb\\Eventsourcingdb\\BoundType;\nuse Thenativeweb\\Eventsourcingdb\\ObserveEventsOptions;\n\n$events = $client-\u003eobserveEvents(\n  '/books/42',\n  new ObserveEventsOptions(\n    recursive: false,\n    lowerBound: new Bound('100', BoundType::INCLUSIVE),\n  ),\n);\n\nforeach ($events as $event) {\n  // ...\n}\n```\n\n#### Starting From the Latest Event of a Given Type\n\nTo observe starting from the latest event of a given type, provide the `fromLatestEvent` option and specify the subject, the type, and how to proceed if no such event exists.\n\nPossible options are `ObserveIfEventIsMissing::WAIT_FOR_EVENT`, which waits for an event of the given type to happen, or `ObserveIfEventIsMissing::READ_EVERYTHING`, which effectively behaves as if `fromLatestEvent` was not specified:\n\n```php\nuse Thenativeweb\\Eventsourcingdb\\ObserveEventsOptions;\nuse Thenativeweb\\Eventsourcingdb\\ObserveFromLatestEvent;\nuse Thenativeweb\\Eventsourcingdb\\ObserveIfEventIsMissing;\n\n$events = $client-\u003eobserveEvents(\n  '/books/42',\n  new ObserveEventsOptions(\n    recursive: false,\n    fromLatestEvent: new ObserveFromLatestEvent(\n      subject: '/books/42',\n      type: 'io.eventsourcingdb.library.book-borrowed',\n      ifEventIsMissing: ObserveIfEventIsMissing::READ_EVERYTHING,\n    ),\n  ),\n);\n\nforeach ($events as $event) {\n  // ...\n}\n```\n\n*Note that `fromLatestEvent` and `lowerBound` can not be provided at the same time.*\n\n#### Aborting Observing\n\nIf you need to abort observing use `abortIn` before or within the `foreach` loop. The `abortIn` method expects the abort time in seconds. However, this only works if there is currently an iteration going on:\n\n```php\nuse Thenativeweb\\Eventsourcingdb\\ObserveEventsOptions;\n\n$events = $client-\u003eobserveEvents(\n  '/books/42',\n  new ObserveEventsOptions(\n    recursive: false,\n  ),\n);\n\n$client-\u003eabortIn(0.1);\nforeach ($events as $event) {\n  // ...\n  $client-\u003eabortIn(0.1);\n}\n```\n\n### Registering an Event Schema\n\nTo register an event schema, call the `registerEventSchema` function and hand over an event type and the desired schema:\n\n```php\n$eventType = 'io.eventsourcingdb.library.book-acquired';\n$schema = [\n  'type' =\u003e 'object',\n  'properties' =\u003e [\n    'title' =\u003e ['type' =\u003e 'string'],\n    'author' =\u003e ['type' =\u003e 'string'],\n    'isbn' =\u003e ['type' =\u003e 'string'],\n  ],\n  'required' =\u003e [\n    'title',\n    'author',\n    'isbn',\n  ],\n  'additionalProperties' =\u003e false,\n];\n\n$client-\u003eregisterEventSchema($eventType, $schema);\n```\n\n### Listing Subjects\n\nTo list all subjects, call the `readSubjects` function with `/` as the base subject. The function returns an asynchronous iterator, which you can use e.g. inside a `foreach` loop:\n\n```php\n$subjects = $client-\u003ereadSubjects('/');\n\nforeach($subjects as $subject) {\n  // ...\n}\n```\n\nIf you only want to list subjects within a specific branch, provide the desired base subject instead:\n\n```php\n$subjects = $client-\u003ereadSubjects('/books');\n\nforeach($subjects as $subject) {\n  // ...\n}\n```\n\n#### Aborting Listing\n\nIf you need to abort listing use `abortIn` before or within the `foreach` loop. The `abortIn` method expects the abort time in seconds. However, this only works if there is currently an iteration going on:\n\n```php\n$subjects = $client-\u003ereadSubjects('/');\n\n$client-\u003eabortIn(0.1);\nforeach($subjects as $subject) {\n  // ...\n  $client-\u003eabortIn(0.1);\n}\n```\n\n### Listing Event Types\n\nTo list all event types, call the `readEventTypes` function. The function returns an asynchronous iterator, which you can use e.g. inside a `foreach` loop:\n\n```php\n$eventTypes = $client-\u003ereadEventTypes();\n\nforeach($eventTypes as $eventType) {\n  // ...\n}\n```\n\n#### Aborting Listing\n\nIf you need to abort listing use `abortIn` before or within the `foreach` loop. The `abortIn` method expects the abort time in seconds. However, this only works if there is currently an iteration going on:\n\n```php\n$eventTypes = $client-\u003ereadEventTypes();\n\n$client-\u003eabortIn(0.1);\nforeach($eventTypes as $eventType) {\n  // ...\n  $client-\u003eabortIn(0.1);\n}\n```\n\n### Listing a Specific Event Type\n\nTo list a specific event type, call the `readEventType` function with the event type as an argument. The function returns the detailed event type, which includes the schema:\n\n```php\n$eventType = $client-\u003ereadEventType('io.eventsourcingdb.library.book-acquired');\n```\n\n### Using Testcontainers\n\nImport the `Container` class, call the `start` function to run a test container, get a client, run your test code, and finally call the `stop` function to stop the test container:\n\n```php\nrequire __DIR__ . '/vendor/autoload.php';\n\nuse Thenativeweb\\Eventsourcingdb\\Container;\n\n$container = new Container();\n$container-\u003estart();\n\n$client = $container-\u003egetClient();\n\n// ...\n\n$container-\u003estop();\n```\n\nTo check if the test container is running, call the `isRunning` function:\n\n```php\n$isRunning = $container-\u003eisRunning();\n```\n\n#### Configuring the Container Instance\n\nBy default, `Container` uses the `latest` tag of the official EventSourcingDB Docker image. To change that, call the `withImageTag` function:\n\n```php\nuse Thenativeweb\\Eventsourcingdb\\Container;\n\n$container = new Container()\n  -\u003ewithImageTag('1.0.0');\n```\n\nSimilarly, you can configure the port to use and the API token. Call the `withPort` or the `withApiToken` function respectively:\n\n```php\nuse Thenativeweb\\Eventsourcingdb\\Container;\n\n$container = new Container()\n  -\u003ewithPort(4000)\n  -\u003ewithApiToken('secret');\n```\n\n#### Configuring the Client Manually\n\nIn case you need to set up the client yourself, use the following functions to get details on the container:\n\n- `getHost()` returns the host name\n- `getMappedPort()` returns the port\n- `getBaseUrl()` returns the full URL of the container\n- `getApiToken()` returns the API token\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fthenativeweb%2Feventsourcingdb-client-php","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fthenativeweb%2Feventsourcingdb-client-php","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fthenativeweb%2Feventsourcingdb-client-php/lists"}