PHPackages                             tobento/service-table - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. [Utility &amp; Helpers](/categories/utility)
4. /
5. tobento/service-table

ActiveLibrary[Utility &amp; Helpers](/categories/utility)

tobento/service-table
=====================

Building HTML tables easily.

2.0(5mo ago)0169MITPHPPHP &gt;=8.4

Since Oct 26Pushed 5mo ago1 watchersCompare

[ Source](https://github.com/tobento-ch/service-table)[ Packagist](https://packagist.org/packages/tobento/service-table)[ Docs](https://www.tobento.ch)[ RSS](/packages/tobento-service-table/feed)WikiDiscussions 2.x Synced today

READMEChangelog (7)Dependencies (3)Versions (9)Used By (0)

Table Service
=============

[](#table-service)

The Table Service provides a way for building tables easily.

Table of Contents
-----------------

[](#table-of-contents)

- [Getting started](#getting-started)
    - [Requirements](#requirements)
    - [Highlights](#highlights)
    - [Screenshots](#screenshots)
    - [Simple Example](#simple-example)
- [Documentation](#documentation)
    - [Create Table](#create-table)
    - [Create Rows](#create-rows)
    - [Create Row](#create-row)
    - [Row Methods](#row-methods)
    - [Custom Row](#custom-row)
    - [Table Attributes](#table-attributes)
    - [Render Table](#render-table)
        - [Default Renderer](#default-renderer)
        - [Table Renderer](#table-renderer)
        - [Custom Renderer](#custom-renderer)
- [Credits](#credits)

---

Getting started
===============

[](#getting-started)

Add the latest version of the Table service project running this command.

```
composer require tobento/service-table

```

Requirements
------------

[](#requirements)

- PHP 8.4 or greater

Highlights
----------

[](#highlights)

- Framework-agnostic, will work with any project
- Decoupled design
- Customize rendering

Screenshots
-----------

[](#screenshots)

[![](demo/tables.jpg)](demo/tables.jpg)

Simple Example
--------------

[](#simple-example)

```
use Tobento\Service\Table\Table;

$table = new Table('products');

$table->row([
    'sku' => 'Sku',
    'title' => 'Title',
    'description' => 'Description',
    'price' => 'Price',
])->heading();

$table->row([
    'sku' => 'shirt',
    'title' => 'Shirt',
    'description' => 'A nice shirt in blue color.',
    'price' => 19.99,
]);
```

**Render the table**

```

// or just

```

**Both tables from above will produce the following output**

```

        Sku
        Title
        Description
        Price

        shirt
        Shirt
        A nice shirt in blue color.
        19.99

```

Documentation
=============

[](#documentation)

Create Table
------------

[](#create-table)

```
use Tobento\Service\Table\Table;
use Tobento\Service\Table\TableInterface;
use Tobento\Service\Table\Renderer;

$table = new Table(
    name: 'products',
    columns: ['title', 'description'], // The columns to render only.
    renderer: new Renderer(),
);

var_dump($table instanceof TableInterface);
// bool(true)

// Get the name of the table:
var_dump($table->name());
// string(8) "products"
```

### With Methods

[](#with-methods)

You might change some data or implentation by the following "with methods" returning a new instance.

**withColumns**

```
use Tobento\Service\Table\Table;

$table = new Table('products');

$newTable = $table->withColumns(['sku', 'title']);

var_dump($table === $newTable);
// bool(false)
```

**withRenderer**

```
use Tobento\Service\Table\Table;
use Tobento\Service\Table\Renderer;

$table = new Table('products');

$newTable = $table->withRenderer(new Renderer());

var_dump($table === $newTable);
// bool(false)
```

Create Rows
-----------

[](#create-rows)

**Creating rows from array items**

```
use Tobento\Service\Table\Table;

$table = new Table('products');

$table->rows([
    [
        'sku' => 'shirt',
        'title' => 'Shirt',
        'description' => 'A nice shirt in blue color.',
        'price' => 19.99,
    ],
    [
        'sku' => 'cap',
        'title' => 'Cap',
        'description' => 'A nice cap.',
        'price' => 11.99,
    ],
]);
```

**Using a callback for creating rows**

You may use a callback for creating rows if you provide an array of objects for instance or want to create only specific row columns.

```
use Tobento\Service\Table\Table;
use Tobento\Service\Table\Row;

class Product
{
    public function __construct(
        protected string $title,
        protected float $price,
    ) {}

    public function title(): string
    {
        return $this->title;
    }

    public function price(): float
    {
        return $this->price;
    }
}

$table = new Table('products');

$table->rows([
    new Product('Shirt', 19.99),
    new Product('Cap', 11.99),
], function(Row $row, Product $product): void {
    $row->column(key: 'title', text: $product->title());
    $row->column(key: 'price', text: $product->price(), attributes: ['data-foo' => 'value']);
});
```

Create only specific row columns from an array of items:

```
$table = new Table('products');

$table->rows([
    [
        'sku' => 'shirt',
        'title' => 'Shirt',
        'description' => 'A nice shirt in blue color.',
        'price' => 19.99,
    ],
    [
        'sku' => 'cap',
        'title' => 'Cap',
        'description' => 'A nice cap.',
        'price' => 11.99,
    ],
], function(Row $row, array $item): void {
    $row->column(key: 'title', text: $item['title']);
    $row->column(key: 'price', text: $item['price'], attributes: ['data-foo' => 'value']);
});
```

Create Row
----------

[](#create-row)

**Creating a row from an array**

```
use Tobento\Service\Table\Table;

$table = new Table('products');

$table->row([
    'sku' => 'shirt',
    'title' => 'Shirt',
    'description' => 'A nice shirt in blue color.',
    'price' => 19.99,
]);
```

**Using a callback for creating row columns**

You may use a callback for creating row columns if you provide an object.

```
use Tobento\Service\Table\Table;
use Tobento\Service\Table\Row;

class Product
{
    public function __construct(
        protected string $title,
        protected float $price,
    ) {}

    public function title(): string
    {
        return $this->title;
    }

    public function price(): float
    {
        return $this->price;
    }
}

$table = new Table('products');

$table->row(
    new Product('Shirt', 19.99),
    function(Row $row, Product $product): void {
        $row->column(key: 'title', text: $product->title())
            ->column(key: 'price', text: $product->price(), attributes: ['data-foo' => 'value']);
    }
);
```

Row Methods
-----------

[](#row-methods)

**Heading**

You may mark the row as a heading.

```
use Tobento\Service\Table\Table;

$table = new Table('products');

$table->row([
    'title' => 'Title',
    'description' => 'Description',
])->heading();
```

**Id**

You may give the row an id to fetch it later.

```
use Tobento\Service\Table\Table;

$table = new Table('products');

$table->row([
    'title' => 'Title',
    'description' => 'Description',
])->id('header');

$headerRow = $table->getRow('header');
```

**Each**

You may use the each method to create the row columns.

```
use Tobento\Service\Table\Table;
use Tobento\Service\Table\Row;

$item = [
    'sku' => 'shirt',
    'title' => 'Shirt',
    'description' => 'A nice shirt in blue color.',
    'price' => 19.99,
];

$table = new Table('products');

$table->row()
      ->each($item, function(Row $row, $value, $key): void {
            $row->column(key: $key, value: $value);
      });
```

**When**

The when method will execute the given callback when the first argument given to the method evaluates to true.

```
use Tobento\Service\Table\Table;
use Tobento\Service\Table\Row;

$table = new Table('products');

$table->row()
      ->when(true, function(Row $row): void {
          $row->column('actions', 'Actions');
      });
```

**Html**

You may mark columns as html, indicating that no escaping is done.

```
use Tobento\Service\Table\Table;

$table = new Table('products');

$table->row([
    'sku' => 'shirt',
    'title' => 'Shirt',
    'description' => 'A nice shirt in blue color.',
    'price' => 19.99,
])->html('description');
```

**PependHtml / AppendHtml**

You may prepend and append html to the row.

```
use Tobento\Service\Table\Table;

$table = new Table('products');

$table->row([
    'sku' => '',
    'title' => '',
])->html('sku')
  ->html('title')
  ->prependHtml('')
  ->appendHtml('');
```

**Column**

You may use the column method to add a column.

```
use Tobento\Service\Table\Table;

$table = new Table('products');

$table->row()
      ->column(key: 'sku', text: 'Sku')
      ->column(key: 'title', text: 'Title', attributes: ['data-foo' => 'Foo']);
```

Custom Row
----------

[](#custom-row)

You may use the addRow method to pass a custom row.

```
use Tobento\Service\Table\Table;
use Tobento\Service\Table\RowInterface;

$table = new Table('products');

// must implement RowInterface
$customRow = new CustomRow();

$table->addRow($customRow);
```

### Table Attributes

[](#table-attributes)

You may set table attributes which will be rendered depending on the renderer.

```
use Tobento\Service\Table\Table;

$table = new Table('products');
$table->attributes(['data-foo' => 'value']);

$attributes = $table->getAttributes();
// ['data-foo' => 'value']
```

### Render Table

[](#render-table)

There are different ways of rendering the table depending on your needs.

#### Default Renderer

[](#default-renderer)

The default renderer generates the table using `` elements and calculates the columns size automatically.

```
use Tobento\Service\Table\Table;
use Tobento\Service\Table\Renderer;

$table = new Table(
    name: 'products',
    renderer: new Renderer(),
);

$table->attributes(['data-id' => 'value']);

$table->row([
    'sku' => 'Sku',
    'title' => 'Title',
    'description' => 'Description',
    'price' => 'Price',
])->heading();

$table->row([
    'sku' => 'shirt',
    'title' => 'Shirt',
    'description' => 'A nice shirt in blue color.',
    'price' => 19.99,
])->attributes(['data-row' => 'name']);

echo $table;
```

Outputs:

```

        Sku
        Title
        Description
        Price

        shirt
        Shirt
        A nice shirt in blue color.
        19.99

```

#### Table Renderer

[](#table-renderer)

The table renderer generates the table using the `` HTML element.

```
use Tobento\Service\Table\Table;
use Tobento\Service\Table\TableRenderer;

$table = new Table(
    name: 'products',
    renderer: new TableRenderer(),
);

$table->attributes(['data-id' => 'value']);

$table->row([
    'sku' => 'Sku',
    'title' => 'Title',
    'description' => 'Description',
    'price' => 'Price',
])->heading();

$table->row([
    'sku' => 'shirt',
    'title' => 'Shirt',
    'description' => 'A nice shirt in blue color.',
    'price' => 19.99,
])->attributes(['data-row' => 'name']);

echo $table;
```

Outputs:

```

        Sku
        Title
        Description
        Price

        shirt
        Shirt
        A nice shirt in blue color.
        19.99

```

The `$table->row()->prependHtml()` and `$table->row()->appendHtml` methods will be ignored as it would produce invalid HTML!

#### Custom Renderer

[](#custom-renderer)

You might write your own renderer fitting your application.

```
use Tobento\Service\Table\RendererInterface;
use Tobento\Service\Table\TableInterface;

class CustomRenderer implements RendererInterface
{
    /**
     * Render the table.
     *
     * @param TableInterface $table
     * @return string
     */
    public function render(TableInterface $table): string
    {
        // create the your custom table ...

        return 'table';
    }
}
```

Credits
=======

[](#credits)

- [Tobias Strub](https://www.tobento.ch)
- [All Contributors](../../contributors)

###  Health Score

44

—

FairBetter than 92% of packages

Maintenance70

Regular maintenance activity

Popularity13

Limited adoption so far

Community7

Small or concentrated contributor base

Maturity72

Established project with proven stability

 Bus Factor1

Top contributor holds 100% of commits — single point of failure

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

###  Release Activity

Cadence

Every ~179 days

Recently: every ~32 days

Total

9

Last Release

172d ago

Major Versions

1.x-dev → 2.02025-10-01

PHP version history (2 changes)1.0.0PHP &gt;=8.0

2.0PHP &gt;=8.4

### Community

Maintainers

![](https://www.gravatar.com/avatar/055d6a1b5c2384bb179c75ab0b55914231d898fdc4dffeb30770f81200e52206?d=identicon)[TOBENTOch](/maintainers/TOBENTOch)

---

Top Contributors

[![tobento-ch](https://avatars.githubusercontent.com/u/16684832?v=4)](https://github.com/tobento-ch "tobento-ch (24 commits)")

---

Tags

packagetabletobento

###  Code Quality

TestsPHPUnit

Static AnalysisPsalm

Type Coverage Yes

### Embed Badge

![Health badge](/badges/tobento-service-table/health.svg)

```
[![Health](https://phpackages.com/badges/tobento-service-table/health.svg)](https://phpackages.com/packages/tobento-service-table)
```

###  Alternatives

[composer/composer

Composer helps you declare, manage and install dependencies of PHP projects. It ensures you have the right stack everywhere.

29.3k184.5M2.4k](/packages/composer-composer)[jean85/pretty-package-versions

A library to get pretty versions strings of installed dependencies

1.3k281.5M56](/packages/jean85-pretty-package-versions)[okipa/laravel-table

Generate tables from Eloquent models.

56852.7k](/packages/okipa-laravel-table)

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
