Own columns
When no format of the TextColumn fits, write a column type of your own, e.g. a progress bar.
php spark make:anvil-column Progressnamespace App\Columns;
use Anvil\Collection\Columns\Column;
final class Progress extends Column{ public function text(array|object $record): string { return $this->percent($record) . ' %'; }
public function html(array|object $record): string { $percent = $this->percent($record);
// Escape every value, also numbers: the code stays safe when it changes. return '<progress class="w-100" max="100" value="' . esc((string) $percent, 'attr') . '">' . esc($this->text($record)) . '</progress>'; }
public function exportValue(array|object $record): int { return $this->percent($record); }
private function percent(array|object $record): int { $value = $this->value($record);
return max(0, min(100, is_numeric($value) ? (int) $value : 0)); }}Progress::make('completion')->label('Done')->sortable(),Methods
Section titled “Methods”| Method | Purpose |
|---|---|
text($record) |
the value as plain text (required); used for search hits, titles, cards and – by default – exports |
html($record) |
the value as safe HTML for table and cards; default: escaped text(). Escape every value with esc() |
exportValue($record) |
value for exports; return numbers as numbers; default: text() or null |
prepare(Resource $resource, array $records) |
called once per page with the shown records before rendering, e.g. to load related data in one query (see CountColumn) |
value($record) |
the raw value: state() or the attribute of the column name |
render($record) |
final: html() plus link, icon and colour – what tables and cards show; use it in own card views |
All options of every column
come from Column and work unchanged: labels, sorting, searching,
state(), color(), icon(), description(), link().
html()must return safe HTML. Never put a value into markup withoutesc(): text content withesc($value), attributes withesc($value, 'attr')– as in the example, also for numbers that cannot contain markup today.- No inline styles or scripts: the Content Security Policy blocks them. Use classes of Bootstrap or of your own stylesheet.
- Load related data in
prepare(), not per row inhtml(). - Respect permissions: data from other tables must be read through their resource or with the same checks.
More on generators and own building blocks: Extending Anvil.