# PHP

> Merge templates from PHP with textcontrol/textcontrol-reportingcloud: Composer setup, options, mergeDocument, exceptions, demo scripts and the Laminas module.

- **Product:** ReportingCloud
- **Section:** Documentation
- **Kind:** Topic
- **Path:** ReportingCloud > SDKs > PHP
- **4331 words**
- **Web URL:** https://docs.textcontrol.com/reporting-cloud/sdks/php/
- **LLMs URL:** https://docs.textcontrol.com/reporting-cloud/sdks/php/llms.txt
- **LLMs-Full URL:** https://docs.textcontrol.com/reporting-cloud/sdks/php/llms-full.txt

---

PHP applications reach ReportingCloud through the Composer package `textcontrol/textcontrol-reportingcloud`, the only SDK with a release after 2019. Its `ReportingCloud` class wraps the endpoints of the Web API in methods that take PHP arrays and file names and return binary strings or arrays. What follows covers the package and its PHP version, the options of the class, a merge example, the methods, the error handling, the demo scripts and the module for Laminas applications.

[PHP](https://docs.textcontrol.com/reporting-cloud/getting-started/php/llms-full.txt) in Getting Started builds a first project with the package step by step.

### Package and Requirements

| Package | Version | Released | PHP | Dependencies |
|---|---|---|---|---|
| [textcontrol/textcontrol-reportingcloud](https://packagist.org/packages/textcontrol/textcontrol-reportingcloud) | 4.0.5 | June 27, 2024 | 8.3 or a later 8.x version, with the extensions `dom`, `json` and `libxml` | `guzzlehttp/guzzle` 7, `ctw/ctw-http` 4, `psr/container` 1 or 2 |

The PHP version is the requirement in the package's *composer.json*, which Composer enforces; the README of version 4.0.5 still names PHP 8.1 and 8.2. [Requirements](https://docs.textcontrol.com/reporting-cloud/installation/requirements/#php) lists the releases for older PHP versions. Install the package with Composer in the folder of your project, and load Composer's autoloader in your scripts:

```bash
composer require textcontrol/textcontrol-reportingcloud:^4.0
```

[Installing an SDK](https://docs.textcontrol.com/reporting-cloud/installation/sdks/#php) has the details and a first call that checks the installation.

#### Older Packages and Namespaces

Until the current package's release 4.0.0 of September 2023, the SDK was published as `textcontrol/txtextcontrol-reportingcloud`, whose last releases on Packagist, 4.0.0 to 4.0.6, are dated July 7, 2022. Packagist marks that package as abandoned in favor of `textcontrol/textcontrol-reportingcloud`, and its repository, TextControl/txtextcontrol-reportingcloud-php, is archived. The old package has its classes in the namespace `TxTextControl\ReportingCloud`, the current one in `TextControl\ReportingCloud`: samples that import `TxTextControl\ReportingCloud\ReportingCloud` were written for the old package and need the new namespace.

### Create an Instance

The constructor of `ReportingCloud` takes an array of options. Each option also has a setter method:

| Option | Setter | Default | Description |
|---|---|---|---|
| `api_key` | `setApiKey` | none | The API key, sent as `ReportingCloud-APIKey` with every request |
| `username`, `password` | `setUsername`, `setPassword` | none | Credentials for Basic authentication, used when no API key is set; deprecated since version 3.0 |
| `base_uri` | `setBaseUri` | `https://api.reporting.cloud` | The base URL of the Web API |
| `version` | `setVersion` | `v1` | The version part of every endpoint path |
| `timeout` | `setTimeout` | `120` | The timeout of a request in seconds |
| `test` | `setTest` | `false` | Adds `test=true` to every request: the documents carry a "TEST MODE" watermark, and the runs don't count against the document quota, except merge and find and replace on a trial account |
| `debug` | `setDebug` | `false` | Turns on the debug output of the HTTP client |

The class creates its HTTP client with the credentials, `base_uri`, `timeout` and `debug` at the first request and keeps it: set these options before the first request, because a setter called later has no effect. `setTest` and `setVersion` apply to every request. Without an API key, user name and password, the first request throws an `InvalidArgumentException`. When `base_uri` isn't set, the class reads the base URL from the PHP constant or environment variable `REPORTING_CLOUD_BASE_URI` and accepts it only if its host ends with `api.reporting.cloud`. A Free account can't use the `test` parameter; see [Test Mode](https://docs.textcontrol.com/reporting-cloud/overview/licensing/#test-mode). [API Keys](https://docs.textcontrol.com/reporting-cloud/installation/api-keys/llms-full.txt) shows how to create a key, and [Authentication](https://docs.textcontrol.com/reporting-cloud/document-processing/authentication/llms-full.txt) explains both kinds of credentials.

### Merge a Template

The following script merges *sample\_invoice.tx*, the demo template of every trial account, with one invoice record and saves *invoice.pdf*. It reads the API key from the environment variable `REPORTINGCLOUD_API_KEY`. Save it as *merge.php* in the folder where you ran `composer require`:

```php
<?php

declare(strict_types=1);

require_once __DIR__ . '/vendor/autoload.php';

use TextControl\ReportingCloud\Exception\RuntimeException;
use TextControl\ReportingCloud\ReportingCloud;

// Send the API key with every request
$reportingCloud = new ReportingCloud([
    'api_key' => (string) getenv('REPORTINGCLOUD_API_KEY'),
]);

// One record with the fields and the item block of sample_invoice.tx
$mergeData = [
    [
        'invoice_no'         => '778723',
        'billto_name'        => 'Joey Montana',
        'billto_companyname' => 'Montana, LLC',
        'item'               => [
            ['qty' => '1', 'item_no' => '1', 'item_description' => 'Item description 1', 'item_total' => '2130.40'],
            ['qty' => '1', 'item_no' => '2', 'item_description' => 'Item description 2', 'item_total' => '5543'],
        ],
        'total'              => '8210.538',
    ],
];

try {
    // Merge the stored template and return the documents as binary strings
    $documents = $reportingCloud->mergeDocument(
        $mergeData,
        ReportingCloud::FILE_FORMAT_PDF,
        templateName: 'sample_invoice.tx',
        mergeSettings: ['document_title' => 'Invoice 778723'],
    );

    file_put_contents('invoice.pdf', $documents[0]);
    echo 'invoice.pdf has been written.', PHP_EOL;
} catch (RuntimeException $exception) {
    // The code is the HTTP status code of the failed request
    echo $exception->getCode(), ': ', $exception->getMessage(), PHP_EOL;
}
```

Run it with `php merge.php`. The code works as follows:

- `$mergeData` is a list of records. Each record is an associative array whose keys are the merge field names, and a nested list such as `item` fills a merge block. [Merge Data](https://docs.textcontrol.com/reporting-cloud/mail-merge/data-sources/llms-full.txt) describes the structure.
- `mergeDocument` sends the request to [POST /v1/document/merge](https://docs.textcontrol.com/reporting-cloud/reference/web-api/document/merge/post/llms-full.txt). Its parameters are `$mergeData`, `$returnFormat`, `$templateName`, `$templateFilename`, the path of a local template to send instead of a stored one, `$append` and `$mergeSettings`. The named arguments skip the parameters the example doesn't need.
- The method decodes the Base64 strings of the response and returns an array of binary strings, one for each created document. `$append` is `false` by default, and the method sends the parameter only when it is `true`. The service appends the records of a request without it, so the array holds one document whatever `$append` is; to get one per record, call `mergeDocument` once per record.
- The return format is one of the class constants `FILE_FORMAT_PDF`, `FILE_FORMAT_PDFA`, `FILE_FORMAT_DOCX`, `FILE_FORMAT_DOC`, `FILE_FORMAT_RTF`, `FILE_FORMAT_HTML`, `FILE_FORMAT_TX` and `FILE_FORMAT_TXT`.

#### Merge Settings

`$mergeSettings`, and `$documentSettings` of `appendDocument`, take snake-case keys that the SDK renames for the Web API: `author`, `creation_date`, `creator_application`, `culture`, `document_subject`, `document_title`, `last_modification_date`, `merge_html`, `remove_empty_blocks`, `remove_empty_fields`, `remove_empty_images`, `remove_trailing_whitespace` and `user_password`. `$documentSettings` uses only the seven keys that set document properties, `author`, the two dates, `creator_application`, `document_subject`, `document_title` and `user_password`, and ignores the others. The two dates are Unix timestamps, such as the result of `time()`. `culture` must be one of the culture names in the SDK's *data/cultures.php*, such as `de-DE`. The SDK has no key for `removeEmptyLines`. [Merge Settings](https://docs.textcontrol.com/reporting-cloud/mail-merge/settings/llms-full.txt) explains what each setting does.

### ReportingCloud Methods

Most methods that send a document read it from a local file, and the methods that return documents or images return binary strings. Arrays in the results have snake-case keys, such as `template_name`.

| Method | Web API endpoint | Returns |
|---|---|---|
| `mergeDocument` | [POST /v1/document/merge](https://docs.textcontrol.com/reporting-cloud/reference/web-api/document/merge/post/llms-full.txt) | An array of documents |
| `appendDocument` | [POST /v1/document/append](https://docs.textcontrol.com/reporting-cloud/reference/web-api/document/append/post/llms-full.txt) | One document combined from files, each given as `filename` and `divider` (a `DOCUMENT_DIVIDER_*` constant) |
| `convertDocument` | [POST /v1/document/convert](https://docs.textcontrol.com/reporting-cloud/reference/web-api/document/convert/post/llms-full.txt) | The document in the return format |
| `findAndReplaceDocument` | [POST /v1/document/findandreplace](https://docs.textcontrol.com/reporting-cloud/reference/web-api/document/findandreplace/post/llms-full.txt) | The document with the text replaced |
| `getDocumentThumbnails` | [POST /v1/document/thumbnails](https://docs.textcontrol.com/reporting-cloud/reference/web-api/document/thumbnails/post/llms-full.txt) | An array of images, one per page |
| `uploadTemplate`, `uploadTemplateFromBase64` | [POST /v1/templates/upload](https://docs.textcontrol.com/reporting-cloud/reference/web-api/templates/upload/post/llms-full.txt) | `true`; the first takes a file name and stores the file under its name |
| `getTemplateList` | [GET /v1/templates/list](https://docs.textcontrol.com/reporting-cloud/reference/web-api/templates/list/get/llms-full.txt) | The templates with `template_name`, `modified` and `size` |
| `getTemplateCount` | [GET /v1/templates/count](https://docs.textcontrol.com/reporting-cloud/reference/web-api/templates/count/get/llms-full.txt) | An integer |
| `templateExists` | [GET /v1/templates/exists](https://docs.textcontrol.com/reporting-cloud/reference/web-api/templates/exists/get/llms-full.txt) | A Boolean |
| `getTemplateInfo` | [GET /v1/templates/info](https://docs.textcontrol.com/reporting-cloud/reference/web-api/templates/info/get/llms-full.txt) | The merge fields and merge blocks of the template |
| `getTemplatePageCount` | [GET /v1/templates/pagecount](https://docs.textcontrol.com/reporting-cloud/reference/web-api/templates/pagecount/get/llms-full.txt) | An integer |
| `getTemplateThumbnails` | [GET /v1/templates/thumbnails](https://docs.textcontrol.com/reporting-cloud/reference/web-api/templates/thumbnails/get/llms-full.txt) | An array of images, one per page |
| `downloadTemplate` | [GET /v1/templates/download](https://docs.textcontrol.com/reporting-cloud/reference/web-api/templates/download/get/llms-full.txt) | The template |
| `deleteTemplate` | [DELETE /v1/templates/delete](https://docs.textcontrol.com/reporting-cloud/reference/web-api/templates/delete/delete/llms-full.txt) | `true` |
| `getAccountSettings` | [GET /v1/account/settings](https://docs.textcontrol.com/reporting-cloud/reference/web-api/account/settings/get/llms-full.txt) | The quotas, their usage and the serial number |
| `getApiKeys`, `createApiKey`, `deleteApiKey` | [GET /v1/account/apikeys](https://docs.textcontrol.com/reporting-cloud/reference/web-api/account/apikeys/get/llms-full.txt), [PUT](https://docs.textcontrol.com/reporting-cloud/reference/web-api/account/apikey/put/llms-full.txt) and [DELETE /v1/account/apikey](https://docs.textcontrol.com/reporting-cloud/reference/web-api/account/apikey/delete/llms-full.txt) | The keys, the new key or `true` |
| `getFontList` | [GET /v1/fonts/list](https://docs.textcontrol.com/reporting-cloud/reference/web-api/fonts/list/get/llms-full.txt) | The font names |
| `proofingCheck` | [GET /v1/proofing/check](https://docs.textcontrol.com/reporting-cloud/reference/web-api/proofing/check/get/llms-full.txt) | The misspelled words |
| `getAvailableDictionaries` | [GET /v1/proofing/availabledictionaries](https://docs.textcontrol.com/reporting-cloud/reference/web-api/proofing/availabledictionaries/get/llms-full.txt) | The dictionary names |
| `getProofingSuggestions` | [GET /v1/proofing/suggestions](https://docs.textcontrol.com/reporting-cloud/reference/web-api/proofing/suggestions/get/llms-full.txt) | Suggestions for a word, 10 at most by default |
| `getTrackedChanges` | [POST /v1/processing/review/trackedchanges](https://docs.textcontrol.com/reporting-cloud/reference/web-api/processing/review-trackedchanges/post/llms-full.txt) | The tracked changes of a document |
| `removeTrackedChange` | [POST /v1/processing/review/removetrackedchange](https://docs.textcontrol.com/reporting-cloud/reference/web-api/processing/review-removetrackedchange/post/llms-full.txt) | The document with the change accepted or rejected |

The SDK has no method for [GET /v1/document/share](https://docs.textcontrol.com/reporting-cloud/reference/web-api/document/share/get/llms-full.txt). The [ReportingCloud PHP SDK API documentation](https://textcontrol.github.io/textcontrol-reportingcloud/docs-api/) lists the parameters of every method.

### Errors

The exceptions of the SDK implement `TextControl\ReportingCloud\Exception\ExceptionInterface`:

- **`InvalidArgumentException`** is thrown before a request is sent, when an argument fails a check: a template name with a path or an unsupported file extension, a return format or culture the SDK doesn't know, a zoom factor out of range, a file that doesn't exist or missing credentials.
- **`RuntimeException`** is thrown when the request fails. Its code is the HTTP status code, or `0` when the server can't be reached, and its message names the request and contains the response body, cut off after 120 characters.

[Errors and Status Codes](https://docs.textcontrol.com/reporting-cloud/document-processing/errors/llms-full.txt) lists the status codes and their causes, and its section [Handle Errors in the SDKs](https://docs.textcontrol.com/reporting-cloud/document-processing/errors/#handle-errors-in-the-sdks) tells the causes apart in code.

### Demo Scripts

The package contains a *demo* folder with a script for each task, such as *merge-document-basic.php*, *merge-document-image.php*, *append-document-basic.php*, *convert-document-docx-to-pdf.php*, *template-management.php*, *manage-api-keys.php* and *tracked-changes.php*. The scripts read the API key from the PHP constant or environment variable `REPORTING_CLOUD_API_KEY`, use the sample files of the package's *resource* folder and write their results to its *output* folder. Six of them, *merge-document-basic.php* among them, set the `test` option, so their documents carry the "TEST MODE" watermark, and they fail with a Free account, which can't use it. *manage-api-keys.php* deletes every API key of the account except the one it runs with. *instantiation.php* shows how to create and configure an instance with an API key, through the constructor options or the setter methods.

### Laminas Module

For Laminas MVC applications, the package [textcontrol/textcontrol-laminas-reportingcloud](https://packagist.org/packages/textcontrol/textcontrol-laminas-reportingcloud), version 5.0.6 of June 27, 2024, registers the SDK in the service manager. It needs PHP 8.3 or 8.4 and version 3.3 or a later version 3 of `laminas/laminas-mvc`: the module allows any PHP 8 version from 8.3, but 3.8.0, the newest release of `laminas/laminas-mvc`, supports PHP 8.4 at most, so Composer can't install the module on PHP 8.5. It requires the PHP SDK as `^2.0`, so Composer installs release 2.0.0 of `textcontrol/textcontrol-reportingcloud`, which Packagist lists with the same source commit as 4.0.4.

1. Install the module with Composer:

    ```bash
    composer require textcontrol/textcontrol-laminas-reportingcloud
    ```
2. Copy *vendor/textcontrol/textcontrol-laminas-reportingcloud/config/reportingcloud.local.php.dist* to *config/autoload/reportingcloud.local.php* and enter your API key:

    ```php
    <?php

    return [
        'reportingcloud' => [
            'credentials' => [
                'api_key' => '<API key>',
            ],
        ],
    ];
    ```
3. Add `'TextControl\Laminas\ReportingCloud'` to the module list in *config/modules.config.php*.

The module registers the service `ReportingCloud` in the service manager, which your factories get with `$container->get('ReportingCloud')`, and a controller plugin and a view helper, both called with `$this->reportingCloud()`. Each returns a `TextControl\ReportingCloud\ReportingCloud` instance.

### API Documentation and Source

- **API documentation.** The [ReportingCloud PHP SDK API documentation](https://textcontrol.github.io/textcontrol-reportingcloud/docs-api/) describes the classes of the namespace `TextControl\ReportingCloud`.
- **Source code.** The repositories [TextControl/textcontrol-reportingcloud](https://github.com/TextControl/textcontrol-reportingcloud) and [TextControl/textcontrol-laminas-reportingcloud](https://github.com/TextControl/textcontrol-laminas-reportingcloud) hold the SDK and the module under the BSD-3-Clause license, with a changelog and unit tests. Both were last changed on November 27, 2025, when their development dependencies were updated; the code is that of the releases of June 27, 2024.

### Related Pages

- [SDKs](https://docs.textcontrol.com/reporting-cloud/sdks/llms-full.txt): the SDKs compared, with their status.
- [Installing an SDK](https://docs.textcontrol.com/reporting-cloud/installation/sdks/llms-full.txt): add the package with Composer.
- [PHP](https://docs.textcontrol.com/reporting-cloud/getting-started/php/llms-full.txt): a first project that merges a template to PDF.
- [Authentication](https://docs.textcontrol.com/reporting-cloud/document-processing/authentication/llms-full.txt): API keys and Basic authentication.
- [Web API](https://docs.textcontrol.com/reporting-cloud/reference/web-api/llms-full.txt): the endpoints the methods call.

---

## Nearby

- **Previous:** [.NET](https://docs.textcontrol.com/reporting-cloud/sdks/dotnet/llms-full.txt)
- **Next:** [Java](https://docs.textcontrol.com/reporting-cloud/sdks/java/llms-full.txt)
