laravel-10laravel-filamentfilamentphp

Filament PHP v3 how to show multiple table data on single resource view page?


I am currently work student management project using FilamentPHP v3. Before I make this post I already research on filament documentation and youtube but still not found how to solve it. For now I already succeed to create new student(student table) with parent detail(student_parent table). The issue i have here is if I click the view button or edit button it does not show the parent detail. I do not want to use relation manager for this purpose because i want to stick with same design as form. Please help me how to make it show on view and edit page.

here the StudentResource code

<?php

namespace App\Filament\Resources;

use App\Filament\Resources\StudentResource\Pages;
use App\Filament\Resources\StudentResource\RelationManagers;
use App\Models\Student;
use App\Models\StudentParent;
use Filament\Forms;
use Filament\Forms\Form;
use Filament\Resources\Resource;
use Filament\Tables;
use Filament\Tables\Table;
use Illuminate\Database\Eloquent\Model;

class StudentResource extends Resource
{
    protected static ?string $model = Student::class;

    protected static ?string $navigationIcon = 'heroicon-o-users';

    protected static ?string $navigationLabel = 'Student';

    protected static ?string $modelLabel = 'Student';

    protected static ?string $navigationGroup = 'Student Management';

    public static function form(Form $form): Form
    {
        return $form
            ->schema([

                Forms\Components\Fieldset::make('Student Information')
                    ->schema([
                        Forms\Components\Select::make('student_code_id')
                        ->label('Kod Pelajar')
                        ->relationship('studentCode', 'code_name')
                        ->required()
                        ->reactive() // Ensure the component reacts immediately
                        ->afterStateUpdated(function ($state, callable $set) {
                            if ($state) {
                                // Update code_no when student_code_id changes
                                $set('code_no', Student::getNextCodeNo($state));
                            }
                        }),

                        Forms\Components\TextInput::make('code_no')
                            ->label('Nombor Kod Pelajar')
                            ->disabled(), // This field is shown but disabled

                        // Add a hidden field to store the actual code_no value
                        Forms\Components\Hidden::make('code_no')
                            ->default(fn (callable $get) => Student::getNextCodeNo($get('student_code_id'))),


                        Forms\Components\Select::make('student_subcode_id')
                            ->label('Subkod Pelajar')
                            ->relationship('studentSubcode', 'subcode_name')
                            ->required()
                            ->reactive() // Ensure the component reacts immediately
                            ->afterStateUpdated(function ($state, callable $set) {
                                if ($state) {
                                    // Update subcode_no when student_subcode_id changes
                                    $set('subcode_no', Student::getNextSubcodeNo($state));
                                }
                            }),

                        Forms\Components\TextInput::make('subcode_no')
                            ->label('Nombor Subkod Pelajar')
                            ->disabled(), // This field is shown but disabled

                        // Add a hidden field to store the actual subcode_no value
                        Forms\Components\Hidden::make('subcode_no')
                            ->default(fn (callable $get) => Student::getNextSubcodeNo($get('student_subcode_id'))),


                        Forms\Components\Select::make('student_type_id')
                            ->label('Status Belajar')
                            ->relationship('studentType', 'type_name')
                            ->required(),

                        Forms\Components\Select::make('student_session_id')
                            ->label('Sesi Pelajar')
                            ->relationship('studentSession', 'session_name')
                            ->required(),

                        Forms\Components\Select::make('student_category_id')
                            ->label('Kategori Pelajar')
                            ->relationship('studentCategory', 'category_name')
                            ->required(),

                        Forms\Components\TextInput::make('batch')
                            ->label('Batch')
                            ->numeric()
                            ->required(),

                        Forms\Components\TextInput::make('fullname')
                            ->extraInputAttributes(['onChange' => 'this.value = this.value.toUpperCase()'])
                            ->label('Nama Penuh')
                            ->required(),

                        Forms\Components\Textarea::make('address')
                            ->extraInputAttributes(['onChange' => 'this.value = this.value.toUpperCase()'])
                            ->label('Alamat')
                            ->required(),

                        Forms\Components\TextInput::make('postcode')
                            ->label('Poskod')
                            ->required(),

                        Forms\Components\TextInput::make('city')
                            ->extraInputAttributes(['onChange' => 'this.value = this.value.toUpperCase()'])
                            ->label('Bandar')
                            ->required(),

                        Forms\Components\TextInput::make('state')
                            ->extraInputAttributes(['onChange' => 'this.value = this.value.toUpperCase()'])
                            ->label('Negeri')
                            ->required(),

                        Forms\Components\TextInput::make('nric')
                            ->label('Nombor Kad Pengenalan')
                            ->required()
                            ->maxLength(12)
                            ->unique(),

                        Forms\Components\DatePicker::make('date_of_birth')
                            ->label('Tarikh Lahir')
                            ->required(),

                        Forms\Components\DatePicker::make('date_of_admit')
                            ->label('Daftar Pada'),
                            // ->required(),
                    ])
                    ->columns(2),
                

                Forms\Components\Fieldset::make('Father Information')
                    ->schema([
                        Forms\Components\TextInput::make('father_name')
                        ->extraInputAttributes(['onChange' => 'this.value = this.value.toUpperCase()'])
                        ->label('Nama Ayah'),
                        
                        Forms\Components\TextInput::make('father_nric')
                            ->label('Nombor Kad Pengenalan')
                            ->maxLength(12),
                            // ->unique(),

                        Forms\Components\TextInput::make('father_age')
                            ->label('Umur Ayah')
                            ->numeric(),

                        Forms\Components\TextInput::make('father_phone')
                            ->label('Nombor Telefon Ayah')
                            ->tel(),

                        Forms\Components\TextInput::make('father_email')
                            ->label('Email Ayah')
                            ->email(),

                        Forms\Components\TextInput::make('father_occupation')
                            ->extraInputAttributes(['onChange' => 'this.value = this.value.toUpperCase()'])
                            ->label('Pekerjaan Ayah'),

                        Forms\Components\TextInput::make('father_gross_salary')
                            ->label('Gaji Kasar Ayah')
                            ->numeric(),

                        Forms\Components\TextInput::make('father_net_salary')
                            ->label('Gaji Bersih Ayah')
                            ->numeric(),
                        ])
                    ->columns(3),

                Forms\Components\Fieldset::make('Mother Information')
                ->schema([
                    Forms\Components\TextInput::make('mother_name')
                    ->extraInputAttributes(['onChange' => 'this.value = this.value.toUpperCase()'])
                    ->label('Nama Ibu'),

                    Forms\Components\TextInput::make('mother_nric')
                            ->label('Nombor Kad Pengenalan')
                            ->maxLength(12),
                            // ->unique(),

                    Forms\Components\TextInput::make('mother_age')
                        ->label('Umur Ibu')
                        ->numeric(),

                    Forms\Components\TextInput::make('mother_phone')
                        ->label('Nombor Telefon Ibu')
                        ->tel(),

                    Forms\Components\TextInput::make('mother_email')
                        ->label('Emel Ibu')
                        ->email(),

                    Forms\Components\TextInput::make('mother_occupation')
                        ->extraInputAttributes(['onChange' => 'this.value = this.value.toUpperCase()'])
                        ->label('Pekerjaan Ibu'),

                    Forms\Components\TextInput::make('mother_gross_salary')
                        ->label('Gaji Kasar Ibu')
                        ->numeric(),

                    Forms\Components\TextInput::make('mother_net_salary')
                        ->label('Gaji Bersih Ibu')
                        ->numeric(),
                    ])
                ->columns(3),
                
                Forms\Components\Fieldset::make('Emergency Information')
                ->schema([
                    Forms\Components\TextInput::make('emergency_contact_name')
                    ->extraInputAttributes(['onChange' => 'this.value = this.value.toUpperCase()'])
                    ->label('Nama Kecemasan')
                    ->required(),

                    Forms\Components\TextInput::make('emergency_contact_nric')
                            ->label('Nombor Kad Pengenalan')
                            ->maxLength(12),
                            // ->unique(),

                    Forms\Components\TextInput::make('emergency_contact_phone')
                        ->label('Nombor Telefon Kecemasan')
                        ->tel()
                        ->required(),

                    Forms\Components\TextInput::make('emergency_contact_relation')
                        ->extraInputAttributes(['onChange' => 'this.value = this.value.toUpperCase()'])
                        ->label('Hubungan')
                        ->required(),

                    Forms\Components\TextInput::make('emergency_contact_gross_salary')
                        ->label('Gaji Kasar')
                        ->numeric(),
                        // ->required(),

                    Forms\Components\TextInput::make('emergency_contact_net_salary')
                        ->label('Gaji Bersih')
                        ->numeric(),
                        // ->required(),
                    ])
                ->columns(3),
                
            ]);
    }

    public static function table(Table $table): Table
{
    return $table
        ->columns([
            Tables\Columns\TextColumn::make('studentCode.code_name')
                ->label('Kod')
                ->searchable(),

            Tables\Columns\TextColumn::make('studentSubcode.subcode_name')
                ->label('Subkod')
                ->searchable(),

            Tables\Columns\TextColumn::make('studentType.type_name')
                ->label('Status Belajar')
                ->searchable(),

            Tables\Columns\TextColumn::make('studentSession.session_name')
                ->label('Sesi')
                ->searchable(),

            Tables\Columns\TextColumn::make('studentCategory.category_name')
                ->label('Kategori')
                ->searchable(),

            Tables\Columns\TextColumn::make('batch')
                ->label('Batch')
                ->searchable(),

            Tables\Columns\TextColumn::make('fullname')
                ->label('Nama Penuh')
                ->searchable(),

            Tables\Columns\TextColumn::make('address')
                ->label('Alamat')
                ->searchable(),

            Tables\Columns\TextColumn::make('nric')
                ->label('Kad Pengenalan')
                ->searchable(),
        ])
        ->filters([
            Tables\Filters\SelectFilter::make('student_type_id')
                ->label('Status Belajar')
                ->relationship('studentType', 'type_name'),

            Tables\Filters\SelectFilter::make('student_session_id')
                ->label('Sesi Pelajar')
                ->relationship('studentSession', 'session_name'),

            Tables\Filters\SelectFilter::make('student_category_id')
                ->label('Kategori Pelajar')
                ->relationship('studentCategory', 'category_name'),

            Tables\Filters\Filter::make('batch')
                ->label('Batch')
                ->form([
                    Forms\Components\TextInput::make('batch')
                        ->label('Batch')
                        ->numeric(),
                ]),
        ])
        ->actions([
            Tables\Actions\ViewAction::make(),
            Tables\Actions\EditAction::make(),
        ])
        ->bulkActions([
            Tables\Actions\BulkActionGroup::make([
                Tables\Actions\DeleteBulkAction::make(),
            ]),
        ]);
}

    public static function getRelations(): array
    {
        return [
            // RelationManagers\ParentRelationManager::class,
        ];
    }

    public static function getPages(): array
    {
        return [
            'index' => Pages\ListStudents::route('/'),
            'create' => Pages\CreateStudent::route('/create'),
            'view' => Pages\ViewStudent::route('/{record}'),
            'edit' => Pages\EditStudent::route('/{record}/edit'),
        ];
    }

    public static function handleStudentCreation(array $data): Model
    {
        // Insert the student
        $student = static::getModel()::create($data);

        // Create a new StudentParent model instance
        $guardian = new StudentParent();
        $guardian->student_id = $student->id; // Set to the ID of the newly created student
        $guardian->father_name = $data['father_name'] ?? null;
        $guardian->father_nric = $data['father_nric'] ?? null;
        $guardian->father_age = $data['father_age'] ?? null;
        $guardian->father_phone = $data['father_phone'] ?? null;
        $guardian->father_email = $data['father_email'] ?? null;
        $guardian->father_occupation = $data['father_occupation'] ?? null;
        $guardian->father_gross_salary = $data['father_gross_salary'] ?? null;
        $guardian->father_net_salary = $data['father_net_salary'] ?? null;
        $guardian->mother_name = $data['mother_name'] ?? null;
        $guardian->mother_nric = $data['mother_nric'] ?? null;
        $guardian->mother_age = $data['mother_age'] ?? null;
        $guardian->mother_phone = $data['mother_phone'] ?? null;
        $guardian->mother_email = $data['mother_email'] ?? null;
        $guardian->mother_occupation = $data['mother_occupation'] ?? null;
        $guardian->mother_gross_salary = $data['mother_gross_salary'] ?? null;
        $guardian->mother_net_salary = $data['mother_net_salary'] ?? null;
        $guardian->emergency_contact_name = $data['emergency_contact_name'] ?? null;
        $guardian->emergency_contact_nric = $data['emergency_contact_nric'] ?? null;
        $guardian->emergency_contact_phone = $data['emergency_contact_phone'] ?? null;
        $guardian->emergency_contact_relation = $data['emergency_contact_relation'] ?? null;
        $guardian->emergency_contact_gross_salary = $data['emergency_contact_gross_salary'] ?? null;
        $guardian->emergency_contact_net_salary = $data['emergency_contact_net_salary'] ?? null;

        // Save the StudentParent model
        $guardian->save();

        return $student;
    }
}

here relationship on Student Model.

public function parent()
{
    return $this->hasOne(StudentParent::class, 'student_id', 'id');

}

here relationship on StudentParent Model.

<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;

class StudentParent extends Model
{
    use HasFactory;

    protected $fillable = [
        'student_id',
        'father_name',
        'father_nric',
        'father_age',
        'father_phone',
        'father_email',
        'father_occupation',
        'father_gross_salary',
        'father_net_salary',
        'mother_name',
        'mother_nric',
        'mother_age',
        'mother_phone',
        'mother_email',
        'mother_occupation',
        'mother_gross_salary',
        'mother_net_salary',
        'emergency_contact_name',
        'emergency_contact_nric',
        'emergency_contact_phone',
        'emergency_contact_relation',
        'emergency_contact_gross_salary',
        'emergency_contact_net_salary',
    ];

    public function user()
    {
        return $this->belongsTo(User::class);
    }

    public function student()
    {
        return $this->belongsTo(Student::class);
    }

}

this is my screenshot of the issue:

enter image description here

enter image description here


Solution

  • I think it will be simple if you use relationship on the form like this

    Forms\Components\Group::make()
        ->relationship('parent')
        ->schema([
            TextInput::make('father_name')
                ->required(),
            // etc
        ]);
    

    But if you still want to use the form like before, you can customize the data before filling the form on the view page by customize mutateFormDataBeforeFill function:

    protected function mutateFormDataBeforeFill(array $data): array
    {
        $guardian = $this->getRecord()->parent;
    
        foreach($guardian->attributesToArray() as $key => $value) {
            $data[$key] = $value;
        }
    
        return $data;
    }
    

    Ref:

    1. Filament - Customizing data before filling the form