MAD Lab
/
Tutor > Campos de formulário > Uploads

Uploads

Campos de formulário

mad-file-field mad-multi-file-field mad-attachments mad-attach-btn
Arquivo único

mad-file-field: um arquivo por campo, storage disk ou db.

Clique para enviar ou arraste aqui .pdf,.doc,.docx · Máx. 10MB
Baixar

mad-file-field puro — nível demo, sem storage: o arquivo não é gravado em disco/banco nesta página.

resources/views/tutor/examples/forms-uploads/arquivo-unico.blade.php
<mad-file-field name="contrato_demo" label="Contrato (arquivo único)"
    accept=".pdf,.doc,.docx" max-size="10MB"
    hint="mad-file-field puro — nível demo, sem storage: o arquivo não é gravado em disco/banco nesta página." />
Múltiplos arquivos

mad-multi-file-field: vários arquivos, mode=comma ou mode=table.

Anexos (múltiplos arquivos)
Arraste arquivos aqui ou clique para selecionar Máx. 5 arquivo(s)

mode=comma (padrão): vários arquivos no mesmo campo. Para 1 linha por arquivo numa tabela filha, use mode=table (model + foreign-key).

resources/views/tutor/examples/forms-uploads/multiplos-arquivos.blade.php
<mad-multi-file-field name="anexos_demo" label="Anexos (múltiplos arquivos)"
    accept=".pdf,.png,.jpg" :max-files="5"
    hint="mode=comma (padrão): vários arquivos no mesmo campo. Para 1 linha por arquivo numa tabela filha, use mode=table (model + foreign-key)." />
Botão compacto

mad-attach-btn: mesma API de storage do multi-file, visual de paperclip pra toolbar.

Nova mensagem

Botão compacto (ícone paperclip) — mesma API de storage do mad-multi-file-field, pensado para toolbar de chat/reply.

resources/views/tutor/examples/forms-uploads/attach-btn.blade.php
{{-- mad-attach-btn não tem prop hint/label — o rótulo/dica aqui é markup ao redor. --}}
<div class="mad-field">
    <label class="mad-label">Anexar na conversa</label>
    <div style="display:flex; align-items:center; gap:8px;">
        <span>Nova mensagem</span>
        <mad-attach-btn name="anexo_chat_demo" accept="image/*,.pdf" multiple :max-files="3" />
    </div>
    <p class="mad-field-hint">Botão compacto (ícone paperclip) — mesma API de storage do mad-multi-file-field, pensado para toolbar de chat/reply.</p>
</div>
Ação wire

mad-form com submit real — dispara TutorFormsUploads::onUploadDemo, que lê os arquivos crus de $_FILES e mostra nome/tamanho no toast (sem persistir).

Clique para enviar ou arraste aqui .pdf,.png,.jpg · Máx. 10MB
Baixar

Anexos (múltiplos)
Arraste arquivos aqui ou clique para selecionar Máx. 3 arquivo(s)

resources/views/tutor/examples/forms-uploads/wire-submit.blade.php
<mad-form submit="onUploadDemo">
    <mad-form-grid :cols="2">
        <mad-file-field name="arquivo_unico_wire" label="Arquivo (único)"
            accept=".pdf,.png,.jpg" max-size="10MB" />
        <mad-multi-file-field name="anexos_wire" label="Anexos (múltiplos)"
            accept=".pdf,.png,.jpg" :max-files="3" />
    </mad-form-grid>
    <mad-form-actions align="right">
        <mad-btn type="submit" variant="primary" icon="upload">Enviar (onUploadDemo)</mad-btn>
    </mad-form-actions>
</mad-form>
app/control/Tutor/TutorFormsUploads.php
public function onUploadDemo(): MadResponse
{
    $unico = MadUploadIngest::filesFor('arquivo_unico_wire');
    $multi = MadUploadIngest::filesFor('anexos_wire');

    $partes = [];

    if ($unico !== []) {
        $f = $unico[0];
        $partes[] = "arquivo_unico_wire={$f['name']} (" . $this->formatBytes((int) $f['size']) . ')';
    }

    if ($multi !== []) {
        $total = array_sum(array_column($multi, 'size'));
        $partes[] = count($multi) . ' anexo(s) em anexos_wire, ' . $this->formatBytes((int) $total) . ' no total';
    }

    $resumo = $partes !== [] ? implode(' | ', $partes) : 'nenhum arquivo selecionado';

    return (new MadResponse())
        ->toast("Upload recebido: {$resumo}", 'success', 'onUploadDemo');
}
mad-attachments não dá pra demonstrar ao vivo aqui
mad-attachments exige model + foreign-key apontando pra um registro PAI que já existe no banco — ele resolve sozinho o id do registro a partir da tela atual e lista/envia/apaga anexos reais daquele registro. O MAD Lab é uma página de exemplos sem estado (sem registro persistido nem tabela de anexos própria), então demonstrar esse componente ao vivo exigiria sair do escopo de "showcase de campos" — precisaria de uma tabela filha nova (migration/model), um registro pai fixo e trait extra, o que não cabe no nível demo desta página (ver relatório do lote).

Sintaxe de referência (numa tela de detalhe real, com o registro já salvo):
<mad-attachments model="TicketAttachments" foreign-key="ticket_id" folder="uploads/tickets" />
Código-fonte completo da página
app/control/Tutor/TutorFormsUploads.php
<?php

namespace App\Control\Tutor;

use App\Support\Tutor\TutorPage;
use Mad\Form\MadForm;
use Mad\Http\MadResponse;
use Mad\Service\MadUploadIngest;

/**
 * TutorFormsUploads — página "Uploads" do catálogo (grupo forms).
 *
 * Cobre mad-file-field, mad-multi-file-field e mad-attach-btn com demos
 * vivas. mad-attachments fica documentado via callout na view — ele exige
 * model+foreign-key apontando pra um registro PAI já persistido (resolve o
 * id sozinho a partir da tela), o que não existe numa página de exemplos sem
 * estado como esta (ver relatório final do lote).
 *
 * Nível demo: nenhum arquivo é gravado em disco/banco. onUploadDemo() lê os
 * arquivos crus de $_FILES via MadUploadIngest::filesFor() (mesmo helper que
 * o framework usa internamente antes de gravar) só para exibir nome/tamanho
 * no toast — sem storage, sem form->save() num registro.
 */
class TutorFormsUploads extends TutorPage
{
    protected string $catalogKey = 'forms_uploads';

    public MadForm $form;

    public function mount(array $params = []): void
    {
        $this->form = new MadForm('tutor_forms_uploads');
    }

    public function onUploadDemo(): MadResponse
    {
        $unico = MadUploadIngest::filesFor('arquivo_unico_wire');
        $multi = MadUploadIngest::filesFor('anexos_wire');

        $partes = [];

        if ($unico !== []) {
            $f = $unico[0];
            $partes[] = "arquivo_unico_wire={$f['name']} (" . $this->formatBytes((int) $f['size']) . ')';
        }

        if ($multi !== []) {
            $total = array_sum(array_column($multi, 'size'));
            $partes[] = count($multi) . ' anexo(s) em anexos_wire, ' . $this->formatBytes((int) $total) . ' no total';
        }

        $resumo = $partes !== [] ? implode(' | ', $partes) : 'nenhum arquivo selecionado';

        return (new MadResponse())
            ->toast("Upload recebido: {$resumo}", 'success', 'onUploadDemo');
    }

    private function formatBytes(int $bytes): string
    {
        if ($bytes < 1024) {
            return "{$bytes} B";
        }
        if ($bytes < 1024 * 1024) {
            return round($bytes / 1024, 1) . ' KB';
        }

        return round($bytes / (1024 * 1024), 1) . ' MB';
    }
}
resources/views/tutor/forms/uploads.blade.php
<x-tutor-page page="forms_uploads">
    <x-tutor-demo demo="tutor.examples.forms-uploads.arquivo-unico"
        title="Arquivo único" desc="mad-file-field: um arquivo por campo, storage disk ou db." />

    <x-tutor-demo demo="tutor.examples.forms-uploads.multiplos-arquivos"
        title="Múltiplos arquivos" desc="mad-multi-file-field: vários arquivos, mode=comma ou mode=table." />

    <x-tutor-demo demo="tutor.examples.forms-uploads.attach-btn"
        title="Botão compacto" desc="mad-attach-btn: mesma API de storage do multi-file, visual de paperclip pra toolbar." />

    <x-tutor-demo demo="tutor.examples.forms-uploads.wire-submit"
        title="Ação wire" desc="mad-form com submit real — dispara TutorFormsUploads::onUploadDemo, que lê os arquivos crus de $_FILES e mostra nome/tamanho no toast (sem persistir)."
        php="TutorFormsUploads::onUploadDemo" />

    <mad-callout type="warning" title="mad-attachments não dá pra demonstrar ao vivo aqui" icon="triangle-alert">
        mad-attachments exige <code>model</code> + <code>foreign-key</code> apontando pra um registro PAI que já
        existe no banco — ele resolve sozinho o id do registro a partir da tela atual e lista/envia/apaga anexos
        reais daquele registro. O MAD Lab é uma página de exemplos sem estado (sem registro persistido nem
        tabela de anexos própria), então demonstrar esse componente ao vivo exigiria sair do escopo de "showcase
        de campos" — precisaria de uma tabela filha nova (migration/model), um registro pai fixo e trait extra,
        o que não cabe no nível demo desta página (ver relatório do lote).
        <br><br>
        Sintaxe de referência (numa tela de detalhe real, com o registro já salvo):
        <br>
        <code>&lt;mad-attachments model="TicketAttachments" foreign-key="ticket_id" folder="uploads/tickets" /&gt;</code>
    </mad-callout>
</x-tutor-page>