Beartropy Tables
Using Models
Define the $model property to enable Eloquent mode instead of the data() method.
Basic Eloquent Setup
Set public $model = User::class to enable Eloquent mode. This gives you automatic server-side pagination, searching, and sorting directly on the database.
Eager Loading: Define public $with to preload relationships and avoid N+1 query issues.
1class UsersTable extends YATBaseTable 2{ 3 // Enable Eloquent mode by defining the model 4 public $model = User::class; 5 6 // Eager load relationships to avoid N+1 issues 7 public $with = ['role', 'settings']; 8 9 public function columns(): array {10 return [11 // Use dot notation to access related data12 Column::make('Role', 'role.name'),13 14 // Search works automatically on related columns15 Column::make('Email', 'email'),16 ];17 }18}
Model vs data()
$model is defined, you don't need the data() method. The table queries the model automatically. Use data() only for array/collection-based tables.
Relationships
Access related model data using dot notation and eager loading.
Relationship Types
- BelongsTo / HasOne: Use dot notation directly (e.g.,
role.name,profile.bio). - HasMany: Use
customData()to extract specific values from a collection (e.g., getting a setting from a settings collection).
Always eager load
public $with = ['relation'] or public array $with = ['relation'] for every relationship you access in columns. This prevents N+1 queries and significantly improves performance.
Advanced Column Logic
Custom sorting and searching for computed columns and complex relationships.
Custom Sort & Search
For columns that don't map directly to a database column, pass closures to sortable() and searchable() for full query builder control.
1Column::make('Theme', 'theme_setting') 2 ->customData(fn($row) => $row->settings->firstWhere('key', 'theme')?->value) 3 ->sortable(function($query, $direction) { 4 $query->orderBy( 5 UserSetting::select('value') 6 ->whereColumn('user_settings.user_id', 'users.id') 7 ->where('key', 'theme'), 8 $direction 9 );10 })11 ->searchable(function($query, $term) {12 $query->orWhereHas('settings', function($q) use ($term) {13 $q->where('key', 'theme')->where('value', 'like', "%$term%");14 });15 });
Filter Relationships
Two approaches for filtering by related model data.
Custom Filter Logic
->query(callable $callback) — Override default filter logic for full control. When using the callback, the default filtering is skipped entirely.
1FilterString::make('Name')2 ->query(function($query, $value) {3 $query->where('custom_col', 'like', "%$value%")4 ->orWhere('other_col', 'like', "%$value%");5 })
Relationship Filters
Dot Notation: If the Eloquent relationship exists, use dot notation (e.g., profile.bio) and the table handles joins automatically.
Custom Query: For complex relationships (like filtering a specific key in a HasMany), use the query() callback.
1// Dot notation — auto-handled relation join 2FilterSelect::make('Bio', \App\Models\Profile::distinct()->pluck('bio')->toArray(), 'profile.bio'), 3 4// Custom query — for complex relationship filtering 5FilterSelect::make('Theme', UserSetting::where('key','theme')->distinct()->pluck('value')->toArray(), 'theme_setting') 6 ->query(function($query, $value, $filter) { 7 $query->whereHas('settings', function($q) use ($value) { 8 $q->where('key', 'theme')->where('value', 'like', "%$value%"); 9 });10 })
Complete Example
A playground table with eager-loaded relationships, dot-notation columns, and relationship filters.
RelationshipUsersTable.php
This example eager-loads three relationships (profile, plataforma, settings), uses dot notation for columns, and implements custom query filters for related data.
1use App\Models\User; 2use Beartropy\Tables\Classes\Columns\Column; 3use Beartropy\Tables\Classes\Columns\DateColumn; 4use Beartropy\Tables\Classes\Filters\FilterSelect; 5use Beartropy\Tables\Classes\Filters\FilterString; 6use Beartropy\Tables\YATBaseTable; 7 8class RelationshipUsersTable extends YATBaseTable 9{10 public $model = User::class;11 12 public array $with = ['profile', 'plataforma', 'settings'];13 14 public function columns(): array15 {16 return [17 Column::make('Name', 'name')->sortable()->searchable(),18 Column::make('Email', 'email')->sortable()->searchable(),19 Column::make('Platform', 'plataforma.name')20 ->sortable(false)->searchable(),21 Column::make('Bio', 'profile.bio')22 ->sortable(false)->searchable(),23 Column::make('Settings')->sortable(false)->searchable(false),24 DateColumn::make('Created', 'created_at')25 ->outputFormat('M d, Y'),26 ];27 }28 29 public function filters(): array30 {31 $plataformas = \App\Models\Plataforma::pluck('name', 'id')->toArray();32 33 return [34 FilterString::make('Name', 'name'),35 FilterSelect::make('Platform', $plataformas)36 ->query(function ($query, $value) {37 $query->whereHas('plataforma', function ($q) use ($value) {38 $q->where('id', $value);39 });40 }),41 FilterString::make('Bio')42 ->query(function ($query, $value) {43 $query->whereHas('profile', function ($q) use ($value) {44 $q->where('bio', 'like', "%{$value}%");45 });46 }),47 ];48 }49 50 public function settings(): void51 {52 $this->setPerPageDefault(15);53 }54}