Milk Admin

ArrayDB with Models and Builders

Revision: 2026/01/20

This guide shows how to use ArrayDB with Models and Builders.

Note: ArrayDB is in-memory and uses the Get::arrayDb() singleton. Data should be populated (or repopulated) at the start of each request.

1) Populate ArrayDB in the module

ArrayDB is a singleton accessible with Get::arrayDb(), so in-memory data can be initialized anywhere (modules, services, bootstrap, controller). Seeding must happen before using Models or Builders, so they find tables already populated.

use App\Get;

$db = Get::arrayDb();

if (!in_array('documentation_products', $db->getTables(), true)) {
    $db->addTable('documentation_products', [
        ['ID_PRODUCT' => 1, 'NAME' => 'Notebook', 'CATEGORY' => 'Electronics', 'PRICE' => 999.90, 'STATUS' => 'ACTIVE'],
        ['ID_PRODUCT' => 2, 'NAME' => 'Mouse', 'CATEGORY' => 'Electronics', 'PRICE' => 24.50, 'STATUS' => 'ACTIVE'],
        ['ID_PRODUCT' => 3, 'NAME' => 'Desk', 'CATEGORY' => 'Office', 'PRICE' => 189.00, 'STATUS' => 'INACTIVE'],
    ], 'ID_PRODUCT');
}
Note: data configuration can be done anywhere in the site. If you need persistence, you can serialize data to a file and reload it on startup (optional capability).

2) Configure the Model for ArrayDB

In the Model, set the table and enable the ArrayDB connection with db('array'). The rest of the configuration is the same as standard Models.

namespace Local\Modules\DocumentationProducts;

use App\Abstracts\AbstractModel;

class DocumentationProductsModel extends AbstractModel
{
    protected function configure($rule): void
    {
        $rule->table('documentation_products')
            ->id('ID_PRODUCT')
            ->db('array')
            ->title('NAME', 100)->label('Name')->required()
            ->string('CATEGORY', 50)->label('Category')
            ->decimal('PRICE', 10, 2)->label('Price')
            ->string('STATUS', 10)->label('Status');
    }
}

3) Module with table and chart

Builders work with ArrayDB like any other database. Here we show a table and a chart on the same page. For JSON reloads, change the builder action with setRequestAction() and handle that action in the controller/module.

use App\Attributes\RequestAction;
use App\Response;
use Builders\{TableBuilder, ChartBuilder};

private const TABLE_ID = 'idTableDocumentationProducts';
private const CHART_ID = 'idChartDocumentationProducts';
private const TABLE_ACTION = 'documentation-products-table';
private const CHART_ACTION = 'documentation-products-chart';

#[RequestAction('home')]
public function home(): void
{
    $table = $this->buildTable(self::TABLE_ID);
    $chart = $this->buildChart(self::CHART_ID);

    $this->respondPartial([
        'table_id' => [self::TABLE_ID => fn() => $table->getResponse()],
        'chart_id' => [self::CHART_ID => fn() => $chart->getResponse()],
    ]);

    $response = $this->getCommonData();
    $response['table_html'] = $table->render();
    $response['chart_html'] = $chart->render();

    Response::render(__DIR__ . '/Views/DocumentationProductsView.php', $response);
}

#[RequestAction(self::TABLE_ACTION)]
public function tableJson(): void
{
    $response = $this->buildTable(self::TABLE_ID)->getResponse();
    Response::htmlJson($response);
}

#[RequestAction(self::CHART_ACTION)]
public function chartJson(): void
{
    $response = $this->buildChart(self::CHART_ID)->getResponse();
    Response::htmlJson($response);
}

To update the table via JSON, the client sends: ?page=documentation-products&action=documentation-products-table&table_id=idTableDocumentationProducts. The same pattern applies to the chart using action=documentation-products-chart and chart_id.

On this documentation page the action is: ?page=docs&action=arraydb-models-builders-table&table_id=idTableDocumentationProductsExample.

View: table and chart visible

In the page template, just print the two HTML outputs generated by the builders.

<?php
// DocumentationProductsView.php
?>
<div class="container py-3">
    <div class="row g-3">
        <div class="col-12 col-lg-6">
            <h4 class="mb-2">Chart</h4>
            <?php echo $chart_html ?? ''; ?>
        </div>
        <div class="col-12 col-lg-6">
            <h4 class="mb-2">Table</h4>
            <?php echo $table_html ?? ''; ?>
        </div>
    </div>
</div>

Real table example (TableBuilder)

This table is generated by TableBuilder::render() using ArrayDB.

Loading...
1 Notebook Electronics 999.9 ACTIVE
2 Mouse Electronics 24.5 ACTIVE
3 Desk Office 189 INACTIVE
Tip: you can use ListBuilder instead of TableBuilder with the same rules. The model stays the same, only the builder changes.

4) Configure table and chart

The table and chart share the same ArrayDB model. Set the action for JSON reloads with setRequestAction().

private function buildTable(string $table_id): TableBuilder
{
    return TableBuilder::create($this->model, $table_id)
        ->setRequestAction(self::TABLE_ACTION)
        ->field('NAME')->label('Name')
        ->field('CATEGORY')->label('Category')
        ->field('PRICE')->label('Price')
        ->field('STATUS')->label('Status');
}

private function buildChart(string $chart_id): ChartBuilder
{
    return ChartBuilder::create($this->model, $chart_id)
        ->setRequestAction(self::CHART_ACTION)
        ->select(['CATEGORY AS label', 'SUM(PRICE) AS value'])
        ->structure([
            'label' => ['label' => 'Category', 'axis' => 'x'],
            'value' => ['label' => 'Total', 'axis' => 'y'],
        ])
        ->groupBy('CATEGORY')
        ->orderBy('label', 'ASC');
}

5) Filters and queries

Builder filters and model queries work the same way. Example with a column filter:

$tableBuilder->filter('only_active', function($query, $value) {
    if ($value === 'ACTIVE') {
        $query->where('STATUS = ?', ['ACTIVE']);
    }
});
Loading...