From 4725a7995a237d0f9019479dc53c81603b936150 Mon Sep 17 00:00:00 2001 From: Rene Reimann Date: Mon, 21 Sep 2026 09:03:26 +0200 Subject: [PATCH 1/4] Docs: add install/Packagist, restructure README for newcomers MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Add Quick Start (install → connect → try) with Composer/Packagist badges - Move How to use + Examples above the config/reference sections - Group Authentication + Framework integration as reference block - Flesh out Framework integration with Laravel/Symfony DI examples and cookbook references Co-Authored-By: Claude Opus 4.8 (1M context) --- README.md | 224 ++++++++++++++++++++++++++++++++++++------------------ 1 file changed, 148 insertions(+), 76 deletions(-) diff --git a/README.md b/README.md index c99c4cd..5ae7f1c 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,8 @@ # Zammad API Client for PHP (v3) -[![Tests](https://github.com/zammad/zammad-api-client-php/actions/workflows/tests.yml/badge.svg)](https://github.com/zammad/zammad-api-client-php/actions/workflows/tests.yml) +[![Tests](https://github.com/zammad/zammad-api-client-php/actions/workflows/tests.yml/badge.svg)](https://github.com/zammad/zammad-api-client-php/actions/workflows/tests.yml) +[![Latest Stable Version](https://poser.pugx.org/zammad/zammad-api-client-php/v)](https://packagist.org/packages/zammad/zammad-api-client-php) +[![Total Downloads](https://poser.pugx.org/zammad/zammad-api-client-php/downloads)](https://packagist.org/packages/zammad/zammad-api-client-php) PSR-compliant PHP client for the [Zammad](https://zammad.com) REST API. PHP 8.1+. @@ -10,11 +12,30 @@ PSR-compliant PHP client for the [Zammad](https://zammad.com) REST API. PHP 8.1+ ## Quick Start +**1. Install** via [Composer](https://getcomposer.org/) (published on [Packagist](https://packagist.org/packages/zammad/zammad-api-client-php)): + +```bash +composer require zammad/zammad-api-client-php +``` + +Using Laravel or Symfony? See [Framework integration](#framework-integration) to +resolve `ZammadClient` from the container instead of constructing it by hand. + +**2. Connect** — point the client at your Zammad instance and pass a +[personal access token](https://admin-docs.zammad.org/en/latest/settings/access-token.html): + ```php -use ZammadAPIClient\Endpoints\Tickets\TicketDTO; +require __DIR__ . '/vendor/autoload.php'; // skip if your framework autoloads + use ZammadAPIClient\ZammadClient; $client = ZammadClient::withToken('https://zammad.example', 'your-token'); +``` + +**3. Try it** — fetch, create, update and search tickets: + +```php +use ZammadAPIClient\Endpoints\Tickets\TicketDTO; // Fetch $ticket = $client->ticket()->find(1); @@ -45,80 +66,10 @@ foreach ($client->ticket()->search('error') as $ticket) { } ``` -## Getting started - -### Standalone PHP app - -```php - The env vars are named `...UNIT_TESTS...` for historical reasons. They are used by integration tests and the cookbook example. Unit tests (`make test`) need no env vars. - -For user and organization CRUD examples, refer to the integration tests in [`test/Integration/`](test/Integration/) (`UserIntegrationTest.php`, `OrganizationIntegrationTest.php`). Side-by-side v2→v3 migration examples are in [`docs/migration-v3-examples.md`](docs/migration-v3-examples.md). +That's it. The rest of this README covers [authentication options](#authentication), +the [three interaction styles](#how-to-use), every [DTO](#data-transfer-objects-dtos) +and [error handling](#error-handling). Runnable recipes live in +[`examples/cookbook/`](examples/cookbook/README.md). ## How to use @@ -355,6 +306,127 @@ $client->textModule()->import($csv); // Returns import summary arr All `import()` methods return an `array` — the Zammad API response containing import statistics (rows processed, skipped, errors). CSV format follows Zammad's import specification (header row with field names matching API field names). +## Examples + +The primary example is the [`examples/cookbook/`](examples/cookbook/README.md) directory — runnable recipes covering tickets, stateful resources, pagination, error handling, impersonation, and search. Run them against any Zammad instance: + +```bash +ZAMMAD_PHP_API_CLIENT_UNIT_TESTS_URL=http://your-zammad:3000 \ +ZAMMAD_PHP_API_CLIENT_UNIT_TESTS_TOKEN=your-token \ +php examples/cookbook/01-quick-start.php +``` + +> The env vars are named `...UNIT_TESTS...` for historical reasons. They are used by integration tests and the cookbook example. Unit tests (`make test`) need no env vars. + +For user and organization CRUD examples, refer to the integration tests in [`test/Integration/`](test/Integration/) (`UserIntegrationTest.php`, `OrganizationIntegrationTest.php`). Side-by-side v2→v3 migration examples are in [`docs/migration-v3-examples.md`](docs/migration-v3-examples.md). + +## Authentication + +```php +// Token — sends Authorization: Token token=your-token (Zammad personal access token) +ZammadClient::withToken($url, 'your-token'); + +// OAuth2 — sends Authorization: Bearer your-oauth-token (OAuth2 access token) +ZammadClient::withOAuth2($url, 'your-oauth-token'); + +// Basic Auth — sends Authorization: Basic base64(user:pass) +ZammadClient::withBasicAuth($url, 'admin@example.com', 'test'); + +// Options +ZammadClient::withToken($url, 'your-token', + new ConnectionConfig(verifySsl: false, maxRetries: 5), +); + +// Pass a PSR-3 Logger to log HTTP requests and retries +ZammadClient::withToken($url, 'your-token', + new ConnectionConfig(logger: $myLogger), +); +``` + +| ConnectionConfig property | Type | Default | Description | +|---------------------------|------|---------|-------------| +| `maxRetries` | `int` | `3` | Number of retries on HTTP 429 before throwing `RateLimitException` | +| `verifySsl` | `bool` | `true` | Verify SSL certificate of the Zammad server | +| `timeout` | `int` | `30` | Total request timeout in seconds | +| `connectTimeout` | `int` | `10` | Connection timeout in seconds | +| `logger` | `?LoggerInterface` | `null` | PSR-3 Logger for HTTP request/retry logging | + +## Framework integration + +Prefer to resolve `ZammadClient` from your framework's container instead of +constructing it by hand? Bridges are provided for Laravel and Symfony — configure +credentials once, then inject the same shared client everywhere. + +Full runnable setups: [`examples/cookbook/07-laravel.php`](examples/cookbook/07-laravel.php) +and [`examples/cookbook/08-symfony.php`](examples/cookbook/08-symfony.php). + +### Laravel + +The service provider is auto-discovered (Laravel 5.5+). Publish the config and set +your credentials in `.env`: + +```bash +php artisan vendor:publish --tag=zammad-config # copies config to config/zammad.php +``` + +```env +ZAMMAD_URL=https://zammad.example +ZAMMAD_TOKEN=your-token +``` + +Then inject the shared `ZammadClient` anywhere via the container: + +```php +use ZammadAPIClient\ZammadClient; + +class TicketController +{ + public function __construct(private ZammadClient $zammad) {} + + public function show(int $id) + { + return $this->zammad->ticket()->find($id); + } +} + +// Or resolve manually: app(ZammadClient::class) +``` + +For older Laravel versions, register `ZammadAPIClient\Bridge\LaravelServiceProvider::class` +in `config/app.php` manually. + +### Symfony + +Register the bundle in `config/bundles.php`: + +```php +ZammadAPIClient\Bridge\SymfonyBundle::class => ['all' => true], +``` + +Configure credentials in `config/packages/zammad.yaml`: + +```yaml +zammad: + url: '%env(ZAMMAD_URL)%' + token: '%env(ZAMMAD_TOKEN)%' +``` + +Then type-hint `ZammadClient` in any service — autowiring injects the shared instance: + +```php +use ZammadAPIClient\ZammadClient; + +class TicketService +{ + public function __construct(private ZammadClient $zammad) {} + + public function findTicket(int $id) + { + return $this->zammad->ticket()->find($id); + } +} +``` + ## Error Handling All errors are typed exceptions: From 4b5618aef317acace8b1a7158e08ae372e6b8c92 Mon Sep 17 00:00:00 2001 From: Rene Reimann Date: Mon, 21 Sep 2026 09:05:54 +0200 Subject: [PATCH 2/4] Docs: fix broken personal access token link (404) Point to the official API auth docs (docs.zammad.org/api/intro) instead of the non-existent admin-docs settings/access-token page. Co-Authored-By: Claude Opus 4.8 (1M context) --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 5ae7f1c..ad6cf1b 100644 --- a/README.md +++ b/README.md @@ -22,7 +22,7 @@ Using Laravel or Symfony? See [Framework integration](#framework-integration) to resolve `ZammadClient` from the container instead of constructing it by hand. **2. Connect** — point the client at your Zammad instance and pass a -[personal access token](https://admin-docs.zammad.org/en/latest/settings/access-token.html): +[personal access token](https://docs.zammad.org/en/latest/api/intro.html): ```php require __DIR__ . '/vendor/autoload.php'; // skip if your framework autoloads From 9dd56ab07aa62584a8a0e32772ef6fc48b1ee33e Mon Sep 17 00:00:00 2001 From: Rene Reimann Date: Mon, 21 Sep 2026 09:08:09 +0200 Subject: [PATCH 3/4] Docs: link recipe files in cookbook README The recipe filenames were plain code text and not clickable on GitHub. Turn the File column into relative links to each recipe. Co-Authored-By: Claude Opus 4.8 (1M context) --- examples/cookbook/README.md | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/examples/cookbook/README.md b/examples/cookbook/README.md index 354556d..083c186 100644 --- a/examples/cookbook/README.md +++ b/examples/cookbook/README.md @@ -11,16 +11,16 @@ cp .env.example .env | File | Description | |---|---| -| `00-plain.php` | Guzzle setup (used by recipes 01-06). Standalone, copy-paste-ready. | -| `01-quick-start.php` | Client instantiation + find ticket #1. | -| `02-crud.php` | Create, read, and delete tickets. | -| `03-listing.php` | `all()` streaming, `list()` pagination, `totalCount()`. | -| `04-updates.php` | `patch()` partial update + `TicketUpdateDTO`. | -| `05-impersonation.php` | `ImpersonationHandler` for scoped on-behalf-of requests. | -| `06-search.php` | Full-text search via `search()` and `searchList()`. | -| `07-laravel.php` | Laravel service container setup. | -| `08-symfony.php` | Symfony bundle setup. | -| `09-slim.php` | Non-Guzzle setup (Symfony HttpClient + Nyholm PSR-17). | +| [`00-plain.php`](00-plain.php) | Guzzle setup (used by recipes 01-06). Standalone, copy-paste-ready. | +| [`01-quick-start.php`](01-quick-start.php) | Client instantiation + find ticket #1. | +| [`02-crud.php`](02-crud.php) | Create, read, and delete tickets. | +| [`03-listing.php`](03-listing.php) | `all()` streaming, `list()` pagination, `totalCount()`. | +| [`04-updates.php`](04-updates.php) | `patch()` partial update + `TicketUpdateDTO`. | +| [`05-impersonation.php`](05-impersonation.php) | `ImpersonationHandler` for scoped on-behalf-of requests. | +| [`06-search.php`](06-search.php) | Full-text search via `search()` and `searchList()`. | +| [`07-laravel.php`](07-laravel.php) | Laravel service container setup. | +| [`08-symfony.php`](08-symfony.php) | Symfony bundle setup. | +| [`09-slim.php`](09-slim.php) | Non-Guzzle setup (Symfony HttpClient + Nyholm PSR-17). | ## Run From b24b97933598044806dc1d8eaf6a7d5e91c10b56 Mon Sep 17 00:00:00 2001 From: Rene Reimann Date: Mon, 21 Sep 2026 09:09:11 +0200 Subject: [PATCH 4/4] Docs: fix cookbook setup instructions Recipes read config via getenv(), and no .env.example exists. Replace the broken `cp .env.example .env` step with exporting ZAMMAD_URL/ZAMMAD_TOKEN. Co-Authored-By: Claude Opus 4.8 (1M context) --- examples/cookbook/README.md | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/examples/cookbook/README.md b/examples/cookbook/README.md index 083c186..49ea9e2 100644 --- a/examples/cookbook/README.md +++ b/examples/cookbook/README.md @@ -2,9 +2,12 @@ ## Setup +The recipes read their configuration from environment variables (via `getenv()`). +Export your Zammad URL and token before running them: + ```bash -cp .env.example .env -# Edit .env with your Zammad URL + token +export ZAMMAD_URL=https://zammad.example +export ZAMMAD_TOKEN=your-token ``` ## Recipes