Skip to content

Tablas y columnas ​

Las columnas definen qué se muestra en el listado de un Resource. Se declaran dentro de columns():

php
public function columns(): array
{
    return [
        Column::make('title')->sortable()->searchable(),
        Column::make('is_published')->as('boolean')->sortable(),
        Column::make('published_at')->as('date')->displayFormat('d/m/Y')->sortable(),
        Column::make('status')
            ->as('badge')
            ->value(fn (Post $post): string => $post->is_published ? 'Published' : 'Draft')
            ->color(fn (Post $post): string => $post->is_published ? 'success' : 'gray'),
    ];
}

API de Column ​

MétodoDescripción
make(string $name)El nombre del atributo en el modelo Eloquent (o el nombre lógico, si usas value()).
label(string $label)Etiqueta de la cabecera. Por defecto, Str::headline($name).
as(string $type)Cómo se renderiza la celda en el frontend: text (por defecto), boolean, date, badge…
sortable(bool $sortable = true)Permite ordenar el listado por esta columna.
hiddenByDefault(bool $hidden = true)Oculta por defecto; el usuario puede mostrarla desde el selector de columnas y elegir el orden desde el propio listado.
displayFormat(string $format)Formato de visualización cuando as('date') (sintaxis date() de PHP).
value(Closure $callback)Sustituye el valor de la celda por un valor calculado. Recibe el modelo completo, no solo el atributo.
color(Closure $callback)Color de la celda (relevante sobre todo para as('badge')). Recibe el modelo completo.
circular(bool $circular = true)Renderiza el valor de una columna as('image') como un avatar circular. No hace nada en el resto de tipos.
url(Closure $callback)Resuelve un enlace por fila. Recibe el modelo y devuelve la URL, o null para dejar esa fila sin enlace.
searchable(bool $searchable = true, ?Closure $using = null, ?Closure $refine = null)Incluye la columna en la búsqueda de texto libre del listado. Con using, sustituye el LIKE por defecto, y con refine, afina el resultado en PHP (véase «Búsqueda a medida»).

Una columna as('boolean') se renderiza como un icono (✓/✗), no como el texto «Yes»/«No» codificado en inglés.

Columnas con imagen y enlace ​

php
Column::make('cover_path')
    ->as('image')
    ->circular()
    ->url(fn (Post $post): ?string => $post->cover_path === null ? null : "/storage/{$post->cover_path}")
    ->hiddenByDefault()

El callback de url() recibe el registro Eloquent y devuelve el enlace. El resultado se añade a cada fila como {columna}_url, de la misma manera que el color resuelto de una columna badge se añade como {columna}_color, no se sirve como propiedad del schema, se calcula por fila.

Búsqueda a medida ​

Por defecto, searchable() compara el término de búsqueda del índice contra la columna con un LIKE sencillo. Pásale using para columnas que no se pueden comparar así, una columna virtual, o una cifrada:

php
Column::make('author')
    ->value(fn (Post $post): ?string => $post->author?->name)
    ->searchable(using: fn (Builder $query, string $term): Builder => $query->whereHas(
        'author',
        fn (Builder $author) => $author->where('name', 'like', "%{$term}%")
    ))

La closure recibe un query builder anidado nuevo y el término de búsqueda en crudo; debe mutar el builder que recibe en lugar de devolver otro distinto, porque el where(Closure) de Laravel descarta lo que le devuelvas.

Búsquedas que SQL solo puede estrechar ​

Una columna cifrada, por ejemplo, no se puede comparar con LIKE, pero sí se puede indexar por un prefijo. Con refine, using solo estrecha los candidatos y refine decide en PHP cuáles coinciden:

php
Column::make('name')->searchable(
    using: fn (Builder $query, string $term): Builder => $query->where('name_index', 'like', mb_substr($term, 0, 3).'%'),
    refine: fn (Student $student, string $term): bool => str_contains(mb_strtolower($student->name), mb_strtolower($term)),
)

using se ejecuta en SQL y da como máximo 500 candidatos. refine recibe cada candidato y el término, y devuelve si coincide. Los candidatos que pasan se combinan con el resto de columnas buscables del listado.

Columnas calculadas ​

value() y color() reciben el registro Eloquent entero, no un simple $record->$name: una columna «lógica» que no corresponde a ningún atributo es tan válida como una directa. El ejemplo de status de arriba no lee ninguna columna status de la base de datos, la calcula a partir de is_published.

php
Column::make('status')
    ->as('badge')
    ->value(fn (Post $post): string => $post->is_published ? 'Published' : 'Draft')
    ->color(fn (Post $post): string => $post->is_published ? 'success' : 'gray')

Vista de solo lectura ​

Cuando un Resource tiene una ViewAction, Arrel reutiliza columns() para renderizar la vista de detalle del registro, con el mismo as(), value() y color() de cada columna. Para agruparlas en secciones con título, declara infolist(). Una entrada vacía se muestra como un guion.