mad-avatar-field
Foto de perfil com layout circular compacto.
Campo de formulário específico para foto de perfil/usuário. Layout horizontal: círculo à esquerda, botões e dicas à direita. Auto-salva via form->save($record) igual ao <mad-image-field> e <mad-file-field>.
Use este componente em telas de perfil/configurações/cadastro de usuário. Para imagens gerais (produto, capa, banner) use <mad-image-field>. Para o componente de display (avatar circular em listas, headers), veja <mad-avatar> — são dois componentes distintos.
Props
| Prop | Tipo | Default | Descrição |
|---|---|---|---|
| name | string | '' |
Nome do campo (obrigatório) |
| label | string | '' |
Label superior |
| description | string | '' |
Texto secundário abaixo do label |
| value | string | '' |
Valor atual (path/URL/base64) |
| size | string | '96px' |
Diâmetro do círculo (normalizado por CssUnits::length — 96 vira 96px) |
| accept | string | 'image/png,image/jpeg' |
MIME types aceitos |
| max-size | string | '5MB' |
Tamanho máximo (KB, MB, GB) |
| btn-text | string | 'Trocar foto' |
Texto do botão de upload |
| btn-remove | string | 'Remover' |
Texto do botão de remover |
| removable | bool | true |
Habilita o botão de remover |
| storage | string | '' |
disk (filesystem) ou db (BLOB base64 no banco) |
| folder | string | 'uploads' |
Diretório destino (storage="disk") |
| name-column | string | '' |
Coluna para o nome original do arquivo |
| file-name | string | 'prefix' |
Modo do nome: prefix, unique, original, record |
| width | string | '' |
Largura CSS do wrapper (ex: '320px') |
| max-width | string | '' |
max-width CSS do wrapper |
| hint | string | '' |
Texto de ajuda |
| error | string | '' |
Mensagem de erro |
| required | bool | false |
Campo obrigatório |
| disabled | bool | false |
Campo desabilitado |
| attrs | string | '' |
Atributos HTML extras |
Upload simples (base64)
<mad-avatar-field name="foto" label="Foto de perfil" />
Storage automático (disco)
<mad-avatar-field name="photo" label="Profile photo"
description="Esta foto será exibida no seu perfil"
storage="disk" folder="uploads/avatars" name-column="photo_name"
accept="image/png,image/jpeg,image/webp" max-size="2MB" />
use Illuminate\Support\Facades\DB;
// Controller — zero código de arquivo
public function onSave(): MadResponse
{
DB::connection('business')->transaction(function () {
$user = SystemUsers::findOrNew($this->registroId);
$this->form->save($user);
// $user->photo = 'uploads/avatars/uniqid_foto.jpg'
// $user->photo_name = 'foto.jpg'
});
return (new MadResponse())->toast('Salvo!', 'success')->closeDrawer();
}
Onde o arquivo realmente é gravado
Com storage="disk" o componente não escreve no filesystem direto — todo o
I/O passa pelo Storage/Flysystem do Laravel (Mad\Service\MadUploadStorage):
- Disco default:
mad_uploads, declarado emconfig/filesystems.php, apontando parastorage/app/mad. - Para mandar os uploads para outro destino (S3, MinIO, etc), configure
MAD_UPLOAD_DISK(lido viaconfig('mad.uploads.disk')). O disco precisa existir emconfig/filesystems.php— apontar para um disco inexistente lança exception explícita no boot do upload. - O que vai para o banco é sempre o path relativo (ex.
uploads/avatars/652f_foto.jpg), nunca um caminho absoluto — por isso trocar o disco não invalida os registros já gravados. folderé validado em tempo de render porMadUploadPath::assertValidFolder()— path traversal (..) e caminho absoluto abortam o render com erro nomeando o campo, em vez de gravar fora da raiz.
O preview não aponta para o arquivo: o componente gera a URL por
mad_download_url($path), uma URL de download assinada servida pelo
MadDownloadController. Isso é o que permite o avatar funcionar igual com disco
local e com S3 privado — e é o motivo de nunca montar <img src="storage/...">
à mão para o valor do campo.
Storage automático (BLOB no banco)
<mad-avatar-field name="photo_blob" label="Foto"
storage="db" name-column="photo_name" />
// onEdit — extrair BLOB para tmp
$this->form->loadBlob($user, 'photo_blob', 'photo_name');
$this->form->fill($user);
// onSave
$this->form->save($user);
Com valor pré-carregado
<mad-avatar-field name="photo" label="Foto"
:value="$user->photo"
storage="disk" folder="uploads/avatars" />
Callback ao selecionar (mad:change)
Mesma API do mad-file-field / mad-image-field — recebe o path temporário.
<mad-avatar-field name="photo" label="Foto"
storage="disk" folder="uploads/avatars"
mad:change="onPhotoChange" />
public function onPhotoChange(string $tempPath): void
{
$size = getimagesize($tempPath);
$this->form->set('dimensoes', $size[0] . 'x' . $size[1]);
}
Dentro de form-section
<mad-form submit="onSave">
<mad-form-section title="Perfil" icon="user">
<mad-avatar-field name="photo" label="Foto de perfil"
description="JPG, PNG ou WebP. Máximo 2MB."
storage="disk" folder="uploads/avatars" name-column="photo_name"
accept="image/png,image/jpeg,image/webp" max-size="2MB" />
<mad-form-grid :cols="2">
<mad-input-field name="nome" label="Nome" required />
<mad-input-field name="email" label="Email" />
</mad-form-grid>
</mad-form-section>
<mad-form-actions>
<mad-btn type="submit" variant="primary" icon="save">Salvar</mad-btn>
</mad-form-actions>
</mad-form>
Quando usar avatar-field vs image-field
| Cenário | Usar |
|---|---|
| Foto de perfil de usuário / cadastro de pessoa | <mad-avatar-field> |
| Imagem de produto / capa / banner / qualquer imagem geral | <mad-image-field> |
| Precisa de crop, rotate, zoom, câmera | <mad-image-field> |
| Layout horizontal compacto (círculo + botão + dicas) | <mad-avatar-field> |
NUNCA fazer
{{-- ERRADO: usar mad-input-field type="file" para foto de perfil --}}
<mad-input-field name="photo" label="Foto" type="file" />
{{-- CERTO --}}
<mad-avatar-field name="photo" label="Foto" storage="disk" folder="uploads/avatars" />
{{-- ERRADO: usar mad-image-field para foto de perfil simples --}}
<mad-image-field name="photo" label="Foto" storage="disk" folder="uploads/avatars" />
{{-- CERTO: avatar-field tem o layout circular já pronto --}}
<mad-avatar-field name="photo" label="Foto" storage="disk" folder="uploads/avatars" />
{{-- ERRADO: código de arquivo manual no controller --}}
move_uploaded_file($_FILES['photo']['tmp_name'], $dest);
$user->photo = $dest;
{{-- CERTO: declarar storage e usar form->save --}}
{{-- Blade: <mad-avatar-field storage="disk" folder="uploads/avatars" /> --}}
$this->form->save($user);