MAD Lab
/
Tutor > Listagens e tabelas > Formatação e totais

Formatação e totais

Listagens e tabelas

mad-col (formatters) mad-data-row totais agrupamento
mad-data-row não é uma tag autoral
O catálogo lista mad-data-row nesta página, mas ela não existe como tag Blade pra escrever — é o nome do partial interno que o MadDataGrid usa pra renderizar cada <tr> (inclusive na atualização parcial via manageRow()/removeRow()). Não há atributo/prop pra declará-la diretamente no Blade; reportado como limitação/imprecisão do catálogo nesta versão do framework.
Formatadores de coluna

prefix, badge, date e money — direto nos atributos do mad-col.

Visible columns
Código
Estado
Data
Valor
1 Enviado 11/03/2026 R$ 2.358,46
2 Cancelado 18/03/2026 R$ 747,15
3 Entregue 26/10/2025 R$ 7.424,20
4 Entregue 15/12/2025 R$ 8.578,21
5 Em separação 25/05/2026 R$ 4.406,22
6 Enviado 04/07/2026 R$ 2.329,41
7 Cancelado 19/06/2026 R$ 4.309,89
8 Entregue 04/03/2026 R$ 325,31
resources/views/tutor/examples/grids-formatacao/formatadores.blade.php
<mad-grid model="TutorDemoPedido" per-page="8">
    <mad-columns>
        <mad-col field="id" label="Código" width="100" prefix="#" sort />
        <mad-col field="estado_id" label="Estado" width="130"
            badge="1:info:Novo|2:warning:Em separação|3:primary:Enviado|4:success:Entregue|5:danger:Cancelado" />
        <mad-col field="dt_pedido" label="Data" width="110" center date="d/m/Y" sort />
        <mad-col field="valor_total" label="Valor" width="140" right money="R$" sort />
    </mad-columns>
</mad-grid>
Transform customizado

Callable PHP formata o valor exibido — com e sem HTML.

Visible columns
Cod.
Descrição (truncada)
Cliente (via $row->__record)
Faixa de valor
Valor
1 Pedido #1 João Gomes (Caxias do Sul/RS) Alto R$ 2.358,46
2 Pedido #2 Mariana Almeida (Recife/PE) Médio R$ 747,15
3 Pedido #3 Vanessa Gomes (Vitória/ES) Alto R$ 7.424,20
4 Pedido #4 Otávio Gomes (Goiânia/GO) Alto R$ 8.578,21
5 Pedido #5 Fábio Souza (Uberlândia/MG) Alto R$ 4.406,22
6 Pedido #6 Carla Almeida (Rio de Janeiro/RJ) Alto R$ 2.329,41
7 Pedido #7 João Gomes (Caxias do Sul/RS) Alto R$ 4.309,89
8 Pedido #8 Mariana Almeida (Recife/PE) Médio R$ 325,31
resources/views/tutor/examples/grids-formatacao/transform.blade.php
<mad-grid model="TutorDemoPedido" per-page="8">
    <mad-columns>
        <mad-col field="id" label="Cod." width="70" sort />
        <mad-col field="descricao" label="Descrição (truncada)"
            transform="TutorGridsFormatacao::truncarDescricao" />
        <mad-col field="cliente_id" label="Cliente (via $row->__record)"
            transform="TutorGridsFormatacao::colClienteCidade" />
        <mad-col field="valor_total" label="Faixa de valor" width="150"
            transform="TutorGridsFormatacao::faixaValor" html />
        <mad-col field="valor_total" label="Valor" width="130" right money="R$" />
    </mad-columns>
</mad-grid>
app/control/Tutor/TutorGridsFormatacao.php
/** Transform de COLUNA com HTML (precisa do atributo `html` no <mad-col>). */
public static function faixaValor(mixed $value, object $row): string
{
    $valor = (float) $value;

    [$variant, $texto] = match (true) {
        $valor >= 1000 => ['success', 'Alto'],
        $valor >= 300  => ['warning', 'Médio'],
        default        => ['secondary', 'Baixo'],
    };

    return sprintf(
        '<span class="mad-badge mad-badge-%s">%s</span>',
        htmlspecialchars($variant, ENT_QUOTES),
        htmlspecialchars($texto, ENT_QUOTES)
    );
}
Totais no rodapé

total=&quot;sum|avg|count&quot; agrega a coluna inteira no rodapé.

Visible columns
Cod.
Descrição
Valor
Média
1 Pedido #1 R$ 2.358,46 R$ 2.358,46
2 Pedido #2 R$ 747,15 R$ 747,15
3 Pedido #3 R$ 7.424,20 R$ 7.424,20
4 Pedido #4 R$ 8.578,21 R$ 8.578,21
5 Pedido #5 R$ 4.406,22 R$ 4.406,22
6 Pedido #6 R$ 2.329,41 R$ 2.329,41
7 Pedido #7 R$ 4.309,89 R$ 4.309,89
8 Pedido #8 R$ 325,31 R$ 325,31
9 Pedido #9 R$ 6.631,58 R$ 6.631,58
10 Pedido #10 R$ 10.761,97 R$ 10.761,97
10 R$ 4.787,24 R$ 4.787,24
resources/views/tutor/examples/grids-formatacao/totais.blade.php
<mad-grid model="TutorDemoPedido" per-page="10" sticky>
    <mad-columns>
        <mad-col field="id" label="Cod." width="70" total="count" />
        <mad-col field="descricao" label="Descrição" />
        <mad-col field="valor_total" label="Valor" width="140" right money="R$" total="sum" />
        <mad-col field="valor_total" label="Média" width="130" right money="R$" total="avg" />
    </mad-columns>
</mad-grid>
Agrupamento com subtotal

group-by + group-mask + group-total. O mask usa só o campo cru (categoria_id) — uma seta de relação dentro do valor do atributo quebra o parser da tag do grid (ver comentário no código-fonte do exemplo).

Visible columns
Cod.
Descrição
Data
Valor
Categoria 2 2 Valor: R$ 6.668,35
1 Pedido #1 11/03/2026 R$ 2.358,46
7 Pedido #7 19/06/2026 R$ 4.309,89
R$ 6.668,35
Categoria 5 1 Valor: R$ 747,15
2 Pedido #2 18/03/2026 R$ 747,15
R$ 747,15
Categoria 1 1 Valor: R$ 7.424,20
3 Pedido #3 26/10/2025 R$ 7.424,20
R$ 7.424,20
Categoria 7 2 Valor: R$ 15.209,79
4 Pedido #4 15/12/2025 R$ 8.578,21
9 Pedido #9 23/02/2026 R$ 6.631,58
R$ 15.209,79
Categoria 4 2 Valor: R$ 4.731,53
5 Pedido #5 25/05/2026 R$ 4.406,22
8 Pedido #8 04/03/2026 R$ 325,31
R$ 4.731,53
Categoria 8 1 Valor: R$ 2.329,41
6 Pedido #6 04/07/2026 R$ 2.329,41
R$ 2.329,41
Categoria 6 1 Valor: R$ 10.761,97
10 Pedido #10 08/03/2026 R$ 10.761,97
R$ 10.761,97
R$ 47.872,40
resources/views/tutor/examples/grids-formatacao/agrupamento.blade.php
@php
    // group-by/group-mask/group-total só existem no modo "self" (via
    // _renderInlineGrid()) — o modo zero-PHP (grid com model= direto na tag)
    // NUNCA aplica agrupamento (mount()/_renderFromConfig() não copiam esses
    // campos do config pra a instância). Por isso este exemplo (só ele, nesta
    // página) precisa do self + do fix de $__component: o partial é
    // incluído dentro do componente Blade nativo tutor-demo (escopo isolado)
    // e o modo self compila pra uma chamada em cima da variável LEXICAL
    // $__component, que não atravessa esse aninhamento sozinha.
    // NUNCA escreva o texto literal da tag grid+self dentro de um comentário
    // neste arquivo: o compilador de tags do MAD é regex-based e não entende
    // comentário PHP — ele casaria a abertura aqui no comentário com o
    // fechamento real lá embaixo (bug real, já pego em produção neste lote).
    //
    // group-mask NÃO pode ter "->" dentro do valor do atributo (ex.: um mask
    // tipo "{relacao->campo}"): confirmado em tinker que o "seta" de
    // ->campo tem um ">" que o regex externo da tag do grid (que só para
    // no PRIMEIRO ">" que encontra) interpreta como o fechamento da própria
    // tag — o atributo group-mask vira um bool solto (true) em vez de string, e
    // (string) true = "1" acaba sendo o mask literal usado (grupo mostra
    // "1" pra TODO mundo). Por isso o mask abaixo usa só o campo cru
    // ({categoria_id}), igual ao padrao ja usado noutras telas do projeto.
    $__component = \Mad\Component\MadRenderContext::getComponent();
@endphp
<mad-grid self per-page="10" sticky
    group-by="categoria_id" group-mask="Categoria {categoria_id}" group-total>
    <mad-columns>
        <mad-col field="id" label="Cod." width="70" />
        <mad-col field="descricao" label="Descrição" />
        <mad-col field="dt_pedido" label="Data" width="110" date="d/m/Y" />
        <mad-col field="valor_total" label="Valor" width="140" right money="R$" total="sum" />
    </mad-columns>
</mad-grid>
Código-fonte completo da página
app/control/Tutor/TutorGridsFormatacao.php
<?php

namespace App\Control\Tutor;

use App\Models\TutorDemo\TutorDemoPedido;
use App\Support\Tutor\TutorDemoSeed;
use Mad\Grid\MadDataGrid;

/**
 * TutorGridsFormatacao — formatadores de <mad-col> (money/date/badge), transform
 * custom (com e sem HTML, com e sem relação via $row->__record), totais de
 * rodapé (total="sum") e agrupamento com subtotal (group-by/group-mask/group-total).
 *
 * ESTENDE MadDataGrid (não TutorPage): descoberto na prática (renderização real
 * via tinker, não só leitura de doc) que `<mad-grid model="...">` (modo
 * zero-PHP) NUNCA aplica groupBy/groupMask/groupTotal — MadGrid::mount()/
 * _renderFromConfig() só copiam model/database/perPage/actionSide/exportable/
 * searchable/defaultSort do config pro componente; agrupamento só existe em
 * MadDataGrid::_renderInlineGrid() (`<mad-grid self>`), que por sua vez só
 * existe numa subclasse de verdade. Os outros 4 exemplos desta página (que
 * não precisam de agrupamento) continuam em modo zero-PHP normalmente.
 *
 * Gotcha de nesting: `<mad-grid self>` compila para `$__component->
 * _renderInlineGrid(...)` — variável LEXICAL, não resolvida via
 * MadRenderContext. Como cada exemplo é um partial incluído dentro do
 * componente Blade <x-tutor-demo> (escopo isolado — confirmado empiricamente
 * com um teste descartável via tinker), $__component não sobrevive até lá.
 * O fix (mesmo usado por TutorGridsFiltros): reatribuir
 * `$__component = \Mad\Component\MadRenderContext::getComponent();` no TOPO
 * do partial que usa <mad-grid self> — esse helper é resolvido via um stack
 * estático (push/pop em MadComponent::render()), não por escopo léxico, então
 * atravessa qualquer aninhamento de componentes Blade.
 */
class TutorGridsFormatacao extends MadDataGrid
{
    protected static string $wrapper = self::INTERNAL;

    protected string $model    = TutorDemoPedido::class;
    protected string $database = 'business';
    protected array  $with     = ['cliente', 'estado'];

    public function mount(array $params = []): void
    {
        TutorDemoSeed::ensure();
        parent::mount($params);
    }

    // ── Transforms de coluna ──────────────────────────────────────────────
    // Assinatura: (mixed $value, object $row[, array $rowArr]) — 2o arg é
    // stdClass (cast do row), NUNCA array. Ver grid-datagrid.md.

    /** Transform de COLUNA com HTML (precisa do atributo `html` no <mad-col>). */
    public static function faixaValor(mixed $value, object $row): string
    {
        $valor = (float) $value;

        [$variant, $texto] = match (true) {
            $valor >= 1000 => ['success', 'Alto'],
            $valor >= 300  => ['warning', 'Médio'],
            default        => ['secondary', 'Baixo'],
        };

        return sprintf(
            '<span class="mad-badge mad-badge-%s">%s</span>',
            htmlspecialchars($variant, ENT_QUOTES),
            htmlspecialchars($texto, ENT_QUOTES)
        );
    }

    /** Transform de COLUNA em texto puro (sem `html` — o retorno é escapado normalmente). */
    public static function truncarDescricao(mixed $value, object $row): string
    {
        $texto = (string) $value;

        return $texto !== '' ? mb_strimwidth($texto, 0, 24, '…') : '-';
    }

    /**
     * Transform de coluna de RELAÇÃO — o model Eloquent não tem render('{rel->campo}')
     * como o Record legado, então uma coluna calculada a partir de uma relação
     * usa transform + `$row->__record` (a instância Eloquent real da linha) em
     * vez de tentar ler a relação a partir do array normalizado.
     */
    public static function colClienteCidade(mixed $value, object $row): string
    {
        $cliente = $row->__record->cliente ?? null;

        return $cliente ? "{$cliente->nome} ({$cliente->cidade}/{$cliente->uf})" : '—';
    }

    protected function view(): string|array
    {
        return 'tutor.grids.formatacao';
    }
}
resources/views/tutor/grids/formatacao.blade.php
<x-tutor-page page="grids_formatacao">
    <mad-callout type="warning" title="mad-data-row não é uma tag autoral" icon="triangle-alert">
        O catálogo lista <code>mad-data-row</code> nesta página, mas ela não existe
        como tag Blade pra escrever — é o nome do partial interno que o
        MadDataGrid usa pra renderizar cada <code>&lt;tr&gt;</code> (inclusive na
        atualização parcial via <code>manageRow()</code>/<code>removeRow()</code>).
        Não há atributo/prop pra declará-la diretamente no Blade; reportado
        como limitação/imprecisão do catálogo nesta versão do framework.
    </mad-callout>

    <x-tutor-demo demo="tutor.examples.grids-formatacao.formatadores"
        title="Formatadores de coluna" desc="prefix, badge, date e money — direto nos atributos do mad-col." />

    <x-tutor-demo demo="tutor.examples.grids-formatacao.transform"
        title="Transform customizado" desc="Callable PHP formata o valor exibido — com e sem HTML."
        php="TutorGridsFormatacao::faixaValor" />

    <x-tutor-demo demo="tutor.examples.grids-formatacao.totais"
        title="Totais no rodapé" desc="total=&quot;sum|avg|count&quot; agrega a coluna inteira no rodapé." />

    <x-tutor-demo demo="tutor.examples.grids-formatacao.agrupamento"
        title="Agrupamento com subtotal" desc="group-by + group-mask + group-total. O mask usa só o campo cru (categoria_id) — uma seta de relação dentro do valor do atributo quebra o parser da tag do grid (ver comentário no código-fonte do exemplo)." />
</x-tutor-page>