Links

Query interface

To connect to different backends, Forest Admin abstracts away their differences.
Each one of the available data sources "speaks" the language of the API it is targeting from one side and exposes the Forest Admin Query Interface on the other one.
This API is by far not a full-featured ORM: its objective is to be "just enough" to fuel Forest Admin.
Writing an abstraction layer is full of compromises: small enough so that it can be written on top of APIs which may not be very capable but large enough so that all Forest Admin features can be implemented on top of them.

When to use it?

When customizing your Forest Admin with custom code (creating new actions, fields, ...), you can either access your data using the Forest Admin Query Interface or using the native driver. It makes no difference for the admin panel.
-
Forest Admin Query Interface
Native Driver
Learning curve
Use the same query interface for any SaaS
Different API for each database / SaaS
Differentiating features
Can make cross data-source requests
Use all features of the underlying API

Example

This example shows the same segment implemented using both methods.
Using the forest admin query interface:
use ForestAdmin\AgentPHP\DatasourceCustomizer\CollectionCustomizer;
use ForestAdmin\AgentPHP\DatasourceCustomizer\Context\CollectionCustomizationContext;
use ForestAdmin\AgentPHP\DatasourceToolkit\Components\Query\Aggregation;
use ForestAdmin\AgentPHP\DatasourceToolkit\Components\Query\Filters\Filter;
use ForestAdmin\AgentPHP\DatasourceToolkit\Components\Query\ConditionTree\Operators;
$forestAgent->customizeCollection(
'Customer',
function (CollectionCustomizer $builder) {
$builder->addSegment(
'mySegment',
function (CollectionCustomizationContext $context) {
$rows = $context->getDatasource()->getCollection('Order')->aggregate(
new Filter(),
new Aggregation(operation: 'Count', groups: [['field' => 'category_id']]),
10
);
return [
'field' => 'id',
'operator' => Operators::IN,
'value' => array_map(fn ($r) => $r['product_id'], $rows)
];
}
);
}
);
Using a native driver:
use ForestAdmin\AgentPHP\DatasourceCustomizer\CollectionCustomizer;
use ForestAdmin\AgentPHP\DatasourceCustomizer\Context\CollectionCustomizationContext;
use ForestAdmin\AgentPHP\DatasourceToolkit\Components\Query\Aggregation;
use ForestAdmin\AgentPHP\DatasourceToolkit\Components\Query\Filters\Filter;
use ForestAdmin\AgentPHP\DatasourceToolkit\Components\Query\ConditionTree\Operators;
$client = new PDO('pgsql:host=localhost;dbname=myDb;', 'username', 'password');
$forestAgent->customizeCollection(
'Customer',
function (CollectionCustomizer $builder) {
$builder->addSegment(
'highPrice',
function (CollectionCustomizationContext $context) {
$query = $client->prepare(
'SELECT product_id, COUNT(*) FROM orders
GROUP BY product_id
ORDER BY count DESC
LIMIT 10;'
);
$query->execute();
$rows = $query->fetchAll(PDO::FETCH_ASSOC);
return [
'field' => 'id',
'operator' => Operators::IN,
'value' => array_map(fn ($r) => $r['product_id'], $rows)
];
}
);
}
);

Interface

All parameters are explained in depth on the following pages:
use ForestAdmin\AgentPHP\DatasourceToolkit\Components\Caller;
use ForestAdmin\AgentPHP\DatasourceToolkit\Components\Charts\Chart;
use Illuminate\Support\Collection as IlluminateCollection;
interface DatasourceContract
{
/** Retrieve list of all collection within the data source */
public function getCollections(): IlluminateCollection;
/** Retrieve list of all charts within the data source */
public function getCharts(): IlluminateCollection;
/** Get collection by name */
public function getCollection(string $name): CollectionContract;
/** Add collection to the data source */
public function addCollection(CollectionContract $collection): void;
/** Render the chart given by name */
public function renderChart(Caller $caller, string $name): Chart|array;
}
use ForestAdmin\AgentPHP\DatasourceToolkit\Components\Caller;
use ForestAdmin\AgentPHP\DatasourceToolkit\Components\Query\Aggregation;
use ForestAdmin\AgentPHP\DatasourceToolkit\Components\Query\Filters\Filter;
use ForestAdmin\AgentPHP\DatasourceToolkit\Components\Query\Filters\PaginatedFilter;
use ForestAdmin\AgentPHP\DatasourceToolkit\Components\Query\Projection\Projection;
interface CollectionContract
{
public function getDataSource(): DatasourceContract;
public function getName(): string;
/** Execute the action given by name */
public function execute(Caller $caller, string $name, array $formValues, ?Filter $filter = null);
/** Get the form of the action given by name */
public function getForm(Caller $caller, string $name, ?array $formValues = null, ?Filter $filter = null): array;
/** Create new records */
public function create(Caller $caller, array $data);
/** List records matching filter */
public function list(Caller $caller, PaginatedFilter $filter, Projection $projection): array;
/** Update records matching filter */
public function update(Caller $caller, Filter $filter, array $patch);
/** Delete records matching filter */
public function delete(Caller $caller, Filter $filter): void;
/** Compute aggregated version of records matching filter */
public function aggregate(Caller $caller, Filter $filter, Aggregation $aggregation, ?int $limit = null, ?string $chartType = null);
/** Render chart for a given record */
public function renderChart(Caller $caller, string $name, array $recordId);
}