PHP code example of gtcesar / filament-expandable-table

1. Go to this page and download the library: Download gtcesar/filament-expandable-table library. Choose the download type require.

2. Extract the ZIP file and open the index.php.

3. Add this code to the index.php.
    
        
<?php
require_once('vendor/autoload.php');

/* Start to develop here. Best regards https://php-download.com/ */

    

gtcesar / filament-expandable-table example snippets




// app/Filament/Tables/OrderItemsTable.php

namespace App\Filament\Tables;

use App\Models\OrderItem;
use Filament\Tables\Actions\DeleteAction;
use Filament\Tables\Actions\EditAction;
use Filament\Tables\Columns\TextColumn;
use Filament\Tables\Filters\SelectFilter;
use Filament\Tables\Table;
use Illuminate\Database\Eloquent\Model;
use Tibras\ExpandableTable\Contracts\HasExpandedTable;

class OrderItemsTable implements HasExpandedTable
{
    public function table(Table $table, Model $record): Table
    {
        // $record is the parent row (the Order).
        // Use $record->id to fetch only the items belonging to that order.
        return $table
            ->query(
                OrderItem::query()->where('order_id', $record->id)
            )
            ->columns([
                TextColumn::make('product_name')
                    ->label('Product')
                    ->searchable()
                    ->sortable(),
                TextColumn::make('quantity')
                    ->label('Qty')
                    ->sortable(),
                TextColumn::make('unit_price')
                    ->label('Unit Price')
                    ->money('USD')
                    ->sortable(),
                TextColumn::make('status')
                    ->label('Status')
                    ->badge(),
            ])
            ->filters([
                SelectFilter::make('status')
                    ->label('Status')
                    ->options([
                        'pending'   => 'Pending',
                        'shipped'   => 'Shipped',
                        'delivered' => 'Delivered',
                    ]),
            ])
            ->actions([
                EditAction::make(),
                DeleteAction::make(),
            ])
            ->paginated([5, 10, 25])
            ->defaultSort('product_name');
    }
}



// app/Filament/Resources/OrderResource/Pages/ListOrders.php

namespace App\Filament\Resources\OrderResource\Pages;

use App\Filament\Resources\OrderResource;
use App\Filament\Tables\OrderItemsTable;
use Filament\Resources\Pages\ListRecords;
use Tibras\ExpandableTable\Actions\ExpandAction;

class ListOrders extends ListRecords
{
    protected static string $resource = OrderResource::class;

    protected function getTableActions(): array
    {
        return [
            ExpandAction::make()
                ->detailComponent(OrderItemsTable::class),
            // Other actions (EditAction, DeleteAction, etc.) can go here too.
        ];
    }
}

ExpandAction::make()
    ->detailComponent(OrderItemsTable::class)
    ->startExpanded(fn (Order $record): bool => $record->is_latest),

->startExpanded()  // equivalent to ->startExpanded(true)

interface HasExpandedTable
{
    public function table(Table $table, Model $record): Table;
}

ExpandAction::make()
    ->detailComponent(fn (Order $record): string => match ($record->type) {
        'wholesale' => WholesaleItemsTable::class,
        default     => OrderItemsTable::class,
    }),



// app/Filament/Tables/OrderItemsTable.php

namespace App\Filament\Tables;

use App\Models\OrderItem;
use Filament\Tables\Actions\DeleteAction;
use Filament\Tables\Actions\EditAction;
use Filament\Tables\Columns\TextColumn;
use Filament\Tables\Filters\SelectFilter;
use Filament\Tables\Table;
use Illuminate\Database\Eloquent\Model;
use Tibras\ExpandableTable\Contracts\HasExpandedTable;

class OrderItemsTable implements HasExpandedTable
{
    public function table(Table $table, Model $record): Table
    {
        // $record é a linha da tabela PAI (o Pedido).
        // Use $record->id para buscar apenas os itens daquele pedido.
        return $table
            ->query(
                OrderItem::query()->where('order_id', $record->id)
            )
            ->columns([
                TextColumn::make('product_name')
                    ->label('Produto')
                    ->searchable()
                    ->sortable(),
                TextColumn::make('quantity')
                    ->label('Qtd')
                    ->sortable(),
                TextColumn::make('unit_price')
                    ->label('Preço Un.')
                    ->money('BRL')
                    ->sortable(),
                TextColumn::make('status')
                    ->label('Status')
                    ->badge(),
            ])
            ->filters([
                SelectFilter::make('status')
                    ->label('Status')
                    ->options([
                        'pending'   => 'Pendente',
                        'shipped'   => 'Enviado',
                        'delivered' => 'Entregue',
                    ]),
            ])
            ->actions([
                EditAction::make(),
                DeleteAction::make(),
            ])
            ->paginated([5, 10, 25])
            ->defaultSort('product_name');
    }
}



// app/Filament/Resources/OrderResource/Pages/ListOrders.php

namespace App\Filament\Resources\OrderResource\Pages;

use App\Filament\Resources\OrderResource;
use App\Filament\Tables\OrderItemsTable;
use Filament\Resources\Pages\ListRecords;
use Tibras\ExpandableTable\Actions\ExpandAction;

class ListOrders extends ListRecords
{
    protected static string $resource = OrderResource::class;

    protected function getTableActions(): array
    {
        return [
            ExpandAction::make()
                ->detailComponent(OrderItemsTable::class),
            // Outras ações (EditAction, DeleteAction, etc.) podem ficar aqui também.
        ];
    }
}

ExpandAction::make()
    ->detailComponent(OrderItemsTable::class)
    ->startExpanded(fn (Order $record): bool => $record->is_latest),

->startExpanded()  // equivalente a ->startExpanded(true)

interface HasExpandedTable
{
    public function table(Table $table, Model $record): Table;
}

ExpandAction::make()
    ->detailComponent(fn (Order $record): string => match ($record->type) {
        'wholesale' => WholesaleItemsTable::class,
        default     => OrderItemsTable::class,
    }),

┌─────────────────────────────────────────────────────────┐
│  # │ Customer       │ Total    │ Status   │      [+]    │
├─────────────────────────────────────────────────────────┤
│  1 │ John Smith     │ $120.00  │ Paid     │      [+]    │
├─────────────────────────────────────────────────────────┤
│    ↳ Items for Order #1                                  │
│    ┌──────────────────┬──────┬────────────────────────┐ │
│    │ Product          │ Qty  │ Unit Price             │ │
│    ├──────────────────┼──────┼────────────────────────┤ │
│    │ Blue T-Shirt (M) │  2   │ $ 30.00                │ │
│    │ Slim Jeans       │  1   │ $ 60.00                │ │
│    └──────────────────┴──────┴────────────────────────┘ │
├─────────────────────────────────────────────────────────┤
│  2 │ Mary Johnson    │ $200.00  │ Pending  │      [+]    │
└─────────────────────────────────────────────────────────┘
bash
php artisan filament:publish --views

resources/views/vendor/filament-tables/index.blade.php
bash
php artisan filament:publish --views

resources/views/vendor/filament-tables/index.blade.php