# Translation strategy

{% hint style="success" %}
This is the official documentation of the `forestadmin/laravel-forestadmin` v2+ and `forestadmin/symfony-forestadmin` PHP agents.
{% endhint %}

### Steps

Creating a custom data source will require you to work on the 3 following steps:

1. Declare the structure of the data
2. Declare the API capabilities
3. Code a translation layer

### Minimal example

```php
<?php

use ForestAdmin\AgentPHP\DatasourceToolkit\Collection;
use ForestAdmin\AgentPHP\DatasourceToolkit\Components\Caller;
use ForestAdmin\AgentPHP\DatasourceToolkit\Components\Contracts\DatasourceContract;
use ForestAdmin\AgentPHP\DatasourceToolkit\Components\Query\Aggregation;
use ForestAdmin\AgentPHP\DatasourceToolkit\Components\Query\Filters\Filter;
use ForestAdmin\AgentPHP\DatasourceToolkit\Components\Query\Projection\Projection;
use ForestAdmin\AgentPHP\DatasourceToolkit\Schema\ColumnSchema;
use GuzzleHttp\Client;
// The real work is in writing this module
// Expect a full featured query translation module to be over 1000 LOCs
use QueryGenerator;

class MyCollection extends Collection
{
    public function __construct(DatasourceContract $datasource)
    {
        parent::__construct(
            $datasource,
            'MyCollection'
        );

        $this->addField('id', new ColumnSchema(
            columnType: 'Number',
            // As we are using the query translation strategy => define capabilities
            filterOperators: [], // field is not filterable
            isPrimaryKey: true,
            isReadOnly: true,  // field is readonly
            isSortable: false // field is not sortable
        ));

        $this->addField('title', new ColumnSchema(
            columnType: 'String',
            filterOperators: [],
            isPrimaryKey: false,
            isReadOnly: true,
            isSortable: false
        ));

        $this->client = new Client([
            'base_uri' => 'https://my-api/',
            'timeout'  => 5.0,
        ]);
    }

    public function list(Caller $caller, Filter $filter, Projection $projection): array
    {
        $params = QueryGenerator::generateListQueryString($filter, $projection);

        try {
            $response = $this->client->get('my-collection', [
                'query' => $params,
            ]);

            $body = json_decode($response->getBody()->getContents(), true);

            return $body['items'] ?? [];
        } catch (\Exception $e) {
            throw new \RuntimeException('Failed to fetch items: ' . $e->getMessage());
        }
    }

    public function aggregate(Caller $caller, Filter $filter, Aggregation $aggregation, ?int $limit = null)
    {
        $params = QueryGenerator::generateAggregateQueryString($filter, $aggregation, $limit);

        try {
            $response = $this->client->get('my-collection', [
                'query' => $params,
            ]);

            $body = json_decode($response->getBody()->getContents(), true);

            return $body['items'] ?? [];
        } catch (\Exception $e) {
            throw new \RuntimeException('Failed to fetch items: ' . $e->getMessage());
        }
    }
}
```

```php
<?php

use Collections\MyCollection;
use ForestAdmin\AgentPHP\DatasourceToolkit\DataSource;

class MyDataSource extends DataSource
{
    public function __construct()
    {
        parent::__construct();
        $this->addCollection(new MyCollection($this)); // List of your collections
    }

```

```php
<?php

use ForestAdmin\AgentPHP\Agent\Builder\AgentFactory;

return static function () {
    $dataSource = new MyDataSource();
    $agent = new AgentFactory([]);
    $agent->addDatasource($dataSource);

    return $dataSource;
};
```

### Read more

Implementing a data source using the "query translation" strategy is an advanced concept: you will need to have a deep understanding of Forest Admin internals.

This strategy is a good match when writing data sources for full-featured databases.

Before starting, it is highly advised to read and understand the following sections:

* [Data Model Typing](/developer-guide-agents-php/under-the-hood/data-model/typing.md)
* [Data Model Relationships](/developer-guide-agents-php/under-the-hood/data-model/relationships.md)
* [Query interface](/developer-guide-agents-php/data-sources/getting-started/queries.md)
* [Fields and projections](/developer-guide-agents-php/data-sources/getting-started/queries/fields-projections.md)
* [Filters](/developer-guide-agents-php/data-sources/getting-started/queries/filters.md)
* [Aggregations](/developer-guide-agents-php/data-sources/getting-started/queries/aggregations.md)


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://docs.forestadmin.com/developer-guide-agents-php/data-sources/custom/translation.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
