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 useAdapterInterface
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>