# Campos

# Definir campos

Los campos definidos son utilizados tanto para la vista de listado de datos como para el formulario de creación / edición.
En el caso de la vista de listado el valor a mostrar se adapta, por ejemplo en campos de tipo imagen serán mostrados con una miniatura o campos de tipo checkbox podrán mostrados como Si / No.

Por ejemplo, si tenemos un modelo Country donde tenemos un campo name, podriamos representarlo como un campo de texto:

protected function fields(): array
{
    return [
        TextField::make('Nombre', 'name')
    ];
}

Para la vista de listado, se mostraría de la siguiente forma:

Vista listado

Para la vista de creación / edición, de la siguiente forma:

Vista detalle

Por regla general, el primer parámetro será el label que se mostrará.
El segundo parámetro corresponde al campo del modelo asociado o un nombre de relación para el caso de los BelongsTo y BelongsToMany.
El tercer parámetro opcional podría ser una función para un valor computado.

# Ordenar por campo

Puedes definir qué campos pueden ser utilizados para ordenar los datos en una vista de listado haciendo click en la cabecera mediante el modificador sortable().

TextField::make('Nombre', 'name')->sortable(),

# Campos disponibles

# TextField

Representa un input con el atributo type como text.

TextField::make('Nombre', 'name');

# EmailField

Es como un TextField, pero con el atributo type como email.

# UrlField

Es como un TextField, pero con el atributo type como url.
En la vista de listado se mostrará como un enlace.

# PasswordField

Es como un TextField, pero con el atributo type como password.
Por defecto no se muestra en la vista de listado de datos, sólo en la de creación / edición.

# NumberField

Representa un input con el atributo type como number.

NumberField::make('Nombre', 'name');

# Mínimo, máximo y step

Se puede definir el valor mínimo, máximo y el step mediante los modificadores min(), max() y step():

NumberField::make('Nombre', 'name')->min(2)->max(20)->step(2);

# SelectField

Representa un select y muestra un número de opciones a elegir.
Las opciones son definidas mediante la función options():

SelectField::make('Rol', 'role')->options([
    'admin' => 'Administrator',
    'user' => 'User'
])

La función options() también admite una Collection con clave => valor:

SelectField::make('País', 'country_id')->options(Country::query()->pluck('name', 'id'))

Por defecto se muestra un buscador, pero si se desea desactivar se puede hacer mediante el modificador searchable(false):

SelectField::make('Rol', 'role')->options([
    'admin' => 'Administrator',
    'user' => 'User'
])->searchable(false)

Relación con otra tabla (BelongsTo)

Si las opciones del campo corresponden a registros de otra tabla, se debe usar el tipo de campo BelongsTo

# Múltiples valores

Se puede seleccionar más de un valor mediante el modificador multiple().
Los valores serán devueltos y guardados separados por coma.

SelectField::make('Rol', 'role')->options([
    'admin' => 'Administrator',
    'user' => 'User'
])->multiple()

Relación con otra tabla mediante pivote (BelongsToMany)

Si las opciones del campo corresponden a registros de otra tabla, relacionados mediante una tabla pivote, se debe usar el tipo de campo BelongsToMany

En la vista de listado de datos, los valores múltiples se representarán por defecto separados por coma:

SelectMultipleList

Este separador puede ser cambiado por otro, mediante la función listSeparator():

SelectField::make('Rol', 'role')->options([
    'admin' => 'Administrator',
    'user' => 'User'
])->multiple()->listSeparator(' / ')

SelectMultipleList2

Incluso es posible utilizar html junto con el modificador valueAsHtml():

SelectField::make('Rol', 'role')->options([
    'admin' => 'Administrator',
    'user' => 'User'
])->multiple()->listSeparator('<br>')->valueAsHtml()

SelectMultipleList3

# CheckboxField

Representa un input con el atributo type como checkbox.

CheckboxField::make('Activo', 'active')

A la hora de guardar, si está marcado se representa como 1 y si no está marcado como 0.

# Valor a mostrar en listado de datos

Por defecto, en el listado de datos, si está marcado se muestra como Si y en caso contrario como No:

CheckboxYesNo

Se pueden modificar estos valores mediante los modificadores checkedValue() y nonCheckedValue():

 CheckboxField::make('Activo', 'active')->checkedValue('√')->nonCheckedValue('X')

CheckboxYesNoCustom

# FileField

Representa un input con el atributo type como file y se utiliza para subir uno o más archivos desde un formulario.

FileField::make('Archivo', 'file')

FileField1

Por defecto el archivo será subido a la carpeta storage.
Puede subirse a una subcarpeta en storage mediante la función onFolder():

FileField::make('Archivo', 'file')->onFolder('users')

Una vez subido, en la vista de formulario, se mostrará el nombre del archivo, con posibilidad de descargarlo y un botón para eliminar:
FileField2

# Múltiples archivos con hasMany

El campo se puede asociar a una relación hasMany del modelo, que haga referencia a una tabla donde se guarda el nombre del archivo.
Por ejemplo, tenemos un modelo Brand, con una relación files:

use Illuminate\Database\Eloquent\Model;

class Brand extends Model
{
    public function files()
    {
        return $this->hasMany(BrandFile::class);
    }
}

Y en base de datos una tabla brand_files:

id brand_id file
1 1 file1.jpg
1 1 file2.jpg

Teniendo en cuenta que el campo que hace referencia al archivo es file, el campo se configuraría de la siguiente forma:

FileField::make('Archivos', 'files')->hasMany('file')

FileField3

# Nombre personalizado

Puedes especificar un nombre en concreto para el archivo en vez del proporcionado por el sistema mediante la función filename().
Deberás especificar solamente el nombre sin la extensión, la cual será automáticamente aplicada basándose en el archivo original.

FileField::make('Archivo', 'file')->filename('MiArchivo')

# ImageField

El funcionamiento es idéntico al FileField, con la peculiaridad que sólo se admiten imágenes y se muestra una previsualización de la imagen:

ImageField::make('Logo', 'logo')

ImageField1

# Redimensionar imagen

Por defecto la imagen se sube sin ningún tipo de tratamiento, pero es posible reducir su tamaño.
Para ello tenemos la función resize, la cual admite 2 parámetros opcionales: ancho y alto.
Si sólo uno de los 2 parámetros se proporciona, se hará una redimensión proporcional.
Si ambos parámetros son especificados, se realizada un crop ajustando las dimensiones y manteniendo el aspect ratio.

// Redimensionar a 960px de ancho, con el alto proporcional
ImageField::make('Logo', 'logo')->resize(960),
// Redimensionar a 300px de alto, con el ancho proporcional
ImageField::make('Logo', 'logo')->resize(null, 300),
// Redimensionar a 500x500 manteniendo el aspect ratio
ImageField::make('Logo', 'logo')->resize(500, 500),

# Generar miniatura

Se puede generar una miniatura de la imagen, mediante la función thumbnail, con idéntico funcionamiento a la función resize:

// Generar miniatura de 100x100, manteniendo el aspect ratio
ImageField::make('Logo', 'logo')->thumbnail(100, 100)

Prefijo

La miniatura generada tendrá el mismo nombre de archivo que la principal, añadiendo al principio el prefijo t-.
Por ejemplo: t-image1.jpg.

Asimismo se pueden combinar las funciones resize y thumbnail:

// Redimensionar a 960px de ancho y generar miniatura de 100x100
ImageField::make('Logo', 'logo')->resize(960)->thumbnail(100, 100)

# Múltiples archivos con hasMany

El funcionamiento es idéntico al del FileField, con la particularidad que se mostrará una cuadrícula de imagenes.
Por ejemplo, tenemos un modelo Brand, con una relación images:

use Illuminate\Database\Eloquent\Model;

class Brand extends Model
{
    public function images()
    {
        return $this->hasMany(BrandImage::class);
    }
}

Y en base de datos una tabla brand_images:

id brand_id image
1 1 image1.jpg
1 1 image2.jpg

Teniendo en cuenta que el campo que hace referencia al archivo es image, el campo se configuraría de la siguiente forma:

FileField::make('Imagenes', 'images')->hasMany('image')

ImageField2

# BelongsTo

Es idéntico al SelectField, con la peculiaridad que va asociado a una relación en un modelo de Eloquent.
Se utiliza para relacionar el valor de un campo con un registro de otra tabla.
Para ello, en el modelo, deberá estar creada la relación de tipo BelongsTo:

namespace App\Models;

use Illuminate\Database\Eloquent\Model;

class Brand extends Model
{
    public function group()
    {
        return $this->belongsTo(Group::class);
    }
}

Como segundo parámetro se pasa el nombre de la relación, que coincide con el nombre de la función que contiene el BelongsToen el modelo:

BelongsTo::make('Grupo', 'group');

Automáticamente el sistema se encarga de extraer las opciones posibles y aplicarlas al SelectField.

BelongsTo

# Filtrar opciones

En ocasiones se necesita que las opciones cargadas mediante la relación BelongsTo no contenga todos los registros.
Para ello, se puede aplicar un filtro mediante la función filter(), la cual recibe la query (de tipo Illuminate\Database\Eloquent\Builder) sobre la que aplicar las condiciones:

BelongsTo::make('Grupo', 'group')->filter(function (Builder $query) {
    return $query->where('name', 'LIKE', 'Nuevo%');
})

# BelongsToMany

Es idéntico al SelectField múltiple, y al igual que el BelongsTo, va asociado a una relación en un modelo de Eloquent, concretamente del tipo BelongsToMany.

namespace App\Models;

use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsToMany;

class User extends Model
{
    public function projects(): BelongsToMany
    {
        return $this->belongsToMany(Project::class);
    }
}

Como segundo parámetro se pasa el nombre de la relación, que coincide con el nombre de la función que contiene el BelongsToManyen el modelo:

BelongsToMany::make('Proyectos', 'projects')

# Eliminar entidad relacionada

Siguiendo el ejemplo de arriba, si tenemos la relación projects en el modelo User, siendo que hay una tabla pivote, cuando intentemos eliminar un proyecto, el propio sistema está preparado para eliminar el registro de la tabla pivote, pero necesitaremos que la relación inversa esté definida, en este caso en el modelo Project:

class Project extends Model
{
    public function users(): BelongsToMany
    {
        return $this->belongsToMany(User::class);
    }
}

WARNING

Es importante para el funcionamiento que en la función que define la relación se especifique que el tipo que retorna es BelongsToMany

# Filtrar opciones

El funcionamiento es lo mismo que en el caso de filtrar opciones del BelongsTo, mediante la función filter().

# DateField

Representa un input preparado para trabajar con fechas (sin hora), mostrando un calendario donde seleccionar una fecha o rango de fechas.

DateField::make('Fecha', 'date')

DateField

# Textarea

Representa un textarea:

Textarea::make('Descripción', 'description')

Textarea

# HiddenField

Representa un input con atributo type como hidden.
Se puede usar en conjunto con la función default() para asignar un valor:

HiddenField::make('', 'type')->default(request()->input('type'))

Primer parámetro

Tener en cuenta que el primer parámetro es un string vacio.
Ya que el campo no se muestra en pantalla, no requiere ningún label, pero se necesita proveer ese parámetro aunque sea vacío o cualquier valor por compatibilidad con el resto de campos.

# CustomViewField

Puedes usarlo cuando quieres añadir una vista personalizada en vez de uno de los campos predefinidos.
Como primer parámetro se especifica el label.
Como segundo parámetro el nombre de la vista personalizada (con notación ::).
Como tercer parámetro (opcional), una función con los valores a devolver a la vista en caso de necesitarlos. Esta función recibirá en el primer parámetro un objeto de tipo Model con los datos del registro actual en casos de vista de edición.

CustomViewField::make('Países', 'backoffice::countries', function (Model $item) {
    $userCountries = $item->countries->pluck('id')->toArray();

    $countries = Country::query()->get(['id', 'name'])->map(function ($country) use ($userCountries) {
        $country->active = in_array($country->id, $userCountries);
        return $country;
    });

    return [
        'countries' => $countries
    ];
}),
<!-- resources/views/vendor/backoffice/connect.blade.php -->
<ul class="countries">
  @foreach ($countries as $country)
  <li class="{{ $country->active ? 'active' : '' }}">{{ $country->name }}</li>
  @endforeach
</ul>

@push('css')
<style>
  ul.countries {
    list-style: none;
    padding: 0 5px;
  }

  ul.countries li {
    padding-left: 8px;
    border-left: 4px solid #d97f76;
    margin: 10px 0;
  }

  ul.countries li.active {
    border-left: 4px solid #74bf9d;
  }
</style>
@endpush

CustomViewField

# Mostrar / ocultar campos

Para mostrar / ocultar campos se dispone de los siguientes modificadores:
hideOnList()
hideOnForm()
hideOnCreate()
hideOnEdit()

Vista de listado de datos
Los campos se convierten en columnas que, dependiendo del tipo de campo, se muestran con un formato determinado (por ejemplo, como texto en el caso de campos de texto o como miniatura de imagen en el caso de campos de imagen).
Si un campo no se desea que se muestre en ésta vista, se puede aplicar el modificador hideOnList():

protected function fields(): array
{
    return [
        TextField::make('Imagen', 'image')->hideOnList()
    ];
}

Vistas de creación y edición
Los campos son se muestran como controles de campos de texto, seleccionables, checkbox, etc, dependiendo del tipo de campo. Si un campo no se desea que se muestre en cualquiera de las 2 vistas, creación y edición, se puede aplicar el modificador hideOnForm():

protected function fields(): array
{
    return [
        TextField::make('Imagen', 'image')->hideOnForm()
    ];
}

Hay ocasiones en las que sólo se desea ocultar / mostrar en una única vista.
Para ello existen los modificadores hideOnCreate() y hideOnEdit().

# Readonly

Hay campos que en la vista de formulario no se permite que sean modificados y sólo son de carácter informativo.
Puedes hacerlo mediante el modificador readOnly():

TextField::make('Email', 'email')->readOnly()

# Valor por defecto

Se puede proporcionar un valor inicial a un campo mediante la función default():

TextField::make('Nombre', 'name')->default('Prueba')

# Valor computado

En ocasiones necesitamos mostrar un campo que puede ser la combinación de más de un campo, datos externos o una transformación.
Para ello, como tercer parámetro se puede pasar una función, la cual recibe un objeto de tipo Eloquent\Model, pudiendo accederse a todos sus campos:

TextField::make('Usuario', 'user_data', function (Model $item) {
    return $item->name . ' (' . $item->email . ')';
})

Computed

# Valor computado sin campo asociado

Se puede dar el caso que el campo sea simplemente informativo y no corresponda a ningún campo de la base de datos.
En ese caso, si el segundo parámetro se especifica a null, será ignorado al guardar y el campo no será editable:

TextField::make('Usuario', null, function (Model $item) {
    return $item->name . ' (' . $item->email . ')';
})

# Agrupar campos

En los formularios se puede realizar una agrupación lógica de ciertos campos, por ejemplo en el caso de un usuario, separar los datos generales (nombre, email) de otros datos.
Para ello existe el elemento GroupFields, donde el primer parámetro es el nombre de la sección y como segundo parámetro los campos que contiene:

protected function fields(): array
{
    return [
        GroupFields::make('Datos generales', [
            TextField::make('Nombre', 'name'),
            TextField::make('Email', 'email')
        ]),
        GroupFields::make('Otros datos', [
            CheckboxField::make('Es administrador', 'is_admin'),
            ImageField::make('Avatar', 'logo')
        ])
    ];
}

GroupFields

# Apilar campos

A veces se necesita agrupar campos que visualmente necesitan estar relacionados bajo la misma fila.
Para ello existe el elemento StackFields, donde el primer parámetro es el label de la fila y como segundo parámetro los campos que contiene:

protected function fields(): array
{
    return [
        StackFields::make('Fórmula', [
            TextField::make('Operador', 'operator'),
            TextField::make('Valor', 'value')
        ])
    ];
}

StackFields

# Apilar en bloque

Por defecto los campos se apilan en línea, pero se pueden apilar uno encima de otro mediante el modificador inBlock():







 



protected function fields(): array
{
    return [
        StackFields::make('Fórmula', [
            TextField::make('Operador', 'operator'),
            TextField::make('Valor', 'value')
        ])->inBlock()
    ];
}

StackFieldsBlock

# Texto de ayuda

Se puede mostrar un texto adicional o de ayuda junto al label mediante la función help.

protected function fields(): array
{
    return [
        TextField::make('Nombre', 'name'),
        TextField::make('Código ISO', 'iso_code')->help('Formato 3166-1. Ejemplo: ES')
    ];
}

Help

# Ignorar campo al guardar

En ocasiones queremos mostrar un campo de forma informativa, pero no queremos que se tenga en cuenta como campo a la hora de guardar en el modelo.
Por ejemplo si es un campo que viene de aplicar un join o un campo de tipo FileField que simplemente queremos guardar el archivo en disco pero asociarlo a ningún campo de la base de datos.
Para ello aplicaremos el modificador ignoreInSave():

FileField::make('Archivo', 'file')->ignoreInSave()