Custom Adapter

A custom adapter is used when the available adapters do not support your specific data source. It follows the AdapterInterface and ensures that your data is properly mapped to an HTML table format.

Why Create a Custom Adapter?

  • You have a unique data format (e.g., an API response, XML, or a proprietary database).
  • You need a specialized way to extract column headers and rows.
  • You want more control over how data is processed before rendering into a table.

Key Considerations

  • The adapter does not render the table; it only prepares data for the TableGenerator.
  • Extend the AbstractAdapter rather than use AdapterInterface directly
  • Ensure data transformation is efficient, especially for large datasets.
  • update the Paginator settings within the adapter.

Creating a Custom Adapter Example

Let's say you have a JSON API response that contains table data, and you want to create a custom adapter to convert it into a table format.

1. Define the JSON Data Source

Here's an example of JSON data you might receive from an API:

{
    "status": "success",
    "data": [
        { "id": 1, "name": "John Doe", "email": "john@example.com" },
        { "id": 2, "name": "Jane Doe", "email": "jane@example.com" },
        { "id": 3, "name": "Alice Smith", "email": "alice@example.com" }
    ]
}

2. Create the Custom Adapter

Your adapter must implement AdapterInterface and extract the headers (Thead) and rows (Tbody).

use Ucscode\HtmlComponent\TableGenerator\Abstraction\AbstractAdapter;
use Ucscode\HtmlComponent\TableGenerator\Component\Section\Tr;
use Ucscode\HtmlComponent\TableGenerator\Component\Th;
use Ucscode\HtmlComponent\TableGenerator\Component\Td;
use Ucscode\HtmlComponent\TableGenerator\Collection\TrCollection;

class JsonApiAdapter extends AbstractAdapter
{
    protected array $columns;
    protected array $rows;

    protected function initialize(): void
    {
        // verify that the input is a string
        if (!is_string($this->data)) {
            throw new \InvalidArgumentException('Argument 1 must be a valid JSON string');
        }

        // convert json into an array
        $decoded = json_decode($this->data, true);

        // verify that the data matches the expected api response
        if (!$decode || !isset($decoded['status'], $decoded['data']) || !is_array($decoded['data'])) {
            throw new \InvalidArgumentException("Invalid API response format.");
        }

        // extract rows and infer column headers dynamically
        $this->rows = $decoded['data'];
        $this->columns = !empty($this->rows) ? array_keys($this->rows[0]) : [];

        // update pagination
        $this->paginator->setTotalItems(count($this->columns));
    }

    public function getTheadTr(): Tr
    {
        // create a Tr component
        $tr = new Tr();

        foreach ($this->columns as $columnName) {
            // capitalize the column name
            $columnData = ucwords(str_replace('_', ' ', $col));

            // create a new Th instance
            $th = new Th($columnData);

            // append the Th component to the Tr
            $tr->addCell($th);
        }

        return $tr;
    }

    public function getTbodyTrCollection(): TrCollection
    {
        // create a new TrCollection instance
        $trCollection = new TrCollection();

        // Filter the result based on pagination
        $rowsToRender = array_slice(
            $this->rows, // the data to paginate
            $this->pagination->getCurrentPageOffset(), // start from the current page offset
            $this->pagination->getItemsPerPage(), // limit number of data per page
        );

        foreach ($rowsToRender as $row) {
            // $row = {"id": 1...}
            $tr = new Tr();

            foreach ($row as $data) {
                // $data example: 1, John Doe, john@example.com, ...
                $td = new Td($data);
                // Add the Td component to the Tr
                $tr->addCell($td);
            }

            // add each Tr component to the collection
            $trCollection->add($tr);
        }

        return $trCollection;
    }
}

3. Using the Custom Adapter

Now, let's use this adapter with TableGenerator:

$jsonData = '{
    "status": "success",
    "data": [
        { "id": 1, "name": "John Doe", "email": "john@example.com" },
        { "id": 2, "name": "Jane Doe", "email": "jane@example.com" },
        { "id": 3, "name": "Alice Smith", "email": "alice@example.com" }
    ]
}';

$adapter = new JsonApiAdapter($jsonData);
$table = new TableGenerator($adapter);

echo $table->render();

4. Expected Output

<table>
    <thead>
        <tr>
            <th>ID</th>
            <th>Name</th>
            <th>Email</th>
        </tr>
    </thead>
    <tbody>
        <tr>
            <td>1</td>
            <td>John Doe</td>
            <td>john@example.com</td>
        </tr>
        <tr>
            <td>2</td>
            <td>Jane Doe</td>
            <td>jane@example.com</td>
        </tr>
    </tbody>
</table>
Source Code
If you find this project useful, consider leaving a on GitHub! Thank you!