Be part of JetBrains PHPverse 2026 on June 9 – a free online event bringing PHP devs worldwide together.

MoshaxDev's avatar

Rule in filamentphp

I really need help. I am using FilamentPHP and I have two tables: one for residential complexes and another for residential units. There is a relationship between the two, such that each residential complex can have a number of residential units.

The problem now is that when adding a residential unit, for example, to the John complex and the unit number is 10, I added a validation code to ensure that the John residential complex does not contain a residential unit with the same number. This means that if the user adds two units with the number (10), an error should appear indicating that there is a residential unit with the same number.

However, if the user adds the unit number (10) to a residential complex named Yara, for example, the record is added successfully because the unit number is not repeated.

I am currently learning and I wanted to create a complex application and it seems that I have encountered a major obstacle along the way.

My Resources :

<?php

namespace App\Filament\Resources;

use Closure;
use Filament\Forms;
use Filament\Tables;
use App\Models\Region;
use Filament\Forms\Form;
use Filament\Tables\Table;
use App\Models\ResidentialUnit;
use Filament\Resources\Resource;
use App\Models\ResidentialComplex;
use Filament\Forms\Components\Select;
use Filament\Forms\Components\Toggle;
use Filament\Forms\Components\TextInput;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\SoftDeletingScope;
use App\Filament\Resources\ResidentialUnitResource\Pages;
use App\Filament\Resources\ResidentialUnitResource\RelationManagers;

class ResidentialUnitResource extends Resource
{
    protected static ?string $model = ResidentialUnit::class;

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

    public static function form(Form $form): Form
    {
        return $form
            ->schema([
                Select::make('residential_complex_id')
                    ->label('اسم المجمع')
                    ->required()
                    ->options(ResidentialComplex::all()->pluck('name', 'id'))
                    ->searchable(),
                TextInput::make('number')
                    ->label('رقم الوحده')
                    ->required()
                    ->alphaNum()
                    ->maxLength(3)
                    ->rule(static function (Forms\Get $get, Forms\Components\Component $component): Closure {
                        return static function (string $attribute, $value, Closure $fail) use ($get, $component) {
                            try {
                                // Get the selected residential complex
                                $residentialComplexId = $component->getFormData()['residential_complex_id'];

                                // Check if there is any existing unit with the same number in the selected residential complex
                                $existingUnit = ResidentialUnit::where('residential_complex_id', $residentialComplexId)
                                    ->where('number', $value)
                                    ->exists();

                                if ($existingUnit) {
                                    $fail('وحدة سكنية أخرى بنفس الرقم (' . $value . ') موجودة بالفعل في هذا المجمع.');
                                }
                            } catch (\Exception $e) {
                                // Log the error
                                \Illuminate\Support\Facades\Log::error($e->getMessage());
                                // You can handle the response according to your application's requirements here
                            }
                        };
                    }),
                TextInput::make('rooms_count')
                    ->numeric()
                    ->label('عدد الغرف')
                    ->required()
                    ->minLength(0)
                    ->rules([
                        'min:1', // Ensure that the value is not less than 1
                        'max:400', // Ensure that the value is not more than 400
                    ]),
                TextInput::make('kitchens_count')
                    ->numeric()
                    ->label('عدد المطابخ')
                    ->required()
                    ->minLength(0)
                    ->rules([
                        'min:1', // Ensure that the value is not less than 1
                        'max:3', // Ensure that the value is not more than 3
                    ]),
                TextInput::make('majlis_count')
                    ->numeric()
                    ->label('عدد المجالس')
                    ->required()
                    ->minLength(0)
                    ->rules([
                        'min:1', // Ensure that the value is not less than 1
                        'max:3', // Ensure that the value is not more than 3
                    ]),
                TextInput::make('bathrooms_count')
                    ->numeric()
                    ->label('عدد الحمامات')
                    ->required()
                    ->minLength(0)
                    ->rules([
                        'min:1', // Ensure that the value is not less than 1
                        'max:3', // Ensure that the value is not more than 3
                    ]),
                Toggle::make('has_front_yard')
                    ->label('يوجد فناء أمامي'),
                Toggle::make('has_back_yard')
                    ->label('يوجد فناء خلفي'),
                Select::make('type')
                    ->label('النوع')
                    ->options([
                        'apartment' => 'دور',
                        'villa' => 'فيلا',
                    ])
                    ->placeholder('اختر النوع')
                    ->required()
                    ->native(false),
                Select::make('status')
                    ->label('الحالة')
                    ->options([
                        'occupied' => 'مسكونة',
                        'vacant' => 'شاغرة',
                    ])
                    ->placeholder('اختر الحالة')
                    ->required()
                    ->native(false),
            ]);
    }






    public static function table(Table $table): Table
    {
        return $table
            ->columns([
                //
            ])
            ->filters([
                //
            ])
            ->actions([
                Tables\Actions\EditAction::make(),
            ])
            ->bulkActions([
                Tables\Actions\BulkActionGroup::make([
                    Tables\Actions\DeleteBulkAction::make(),
                ]),
            ]);
    }

    public static function getRelations(): array
    {
        return [
            //
        ];
    }

    public static function getPages(): array
    {
        return [
            'index' => Pages\ListResidentialUnits::route('/'),
            'create' => Pages\CreateResidentialUnit::route('/create'),
            'edit' => Pages\EditResidentialUnit::route('/{record}/edit'),
        ];
    }

    public static function getModelLabel(): string
    {
        return "وحده سكنيه";
    }
    public static function getPluralLabel(): ?string
    {
        return "الوحدات السكنيه";
    }
}

0 likes
2 replies
LaryAI's avatar
Level 58

To solve the issue of ensuring that a residential unit number is unique within a residential complex, you can use a custom validation rule within the TextInput component for the number field. The rule should check if a unit with the same number already exists within the selected residential complex.

Here's how you can modify the TextInput component for the number field to include this validation:

TextInput::make('number')
    ->label('رقم الوحده')
    ->required()
    ->alphaNum()
    ->maxLength(3)
    ->unique(ResidentialUnit::class, 'number', function ($query, $get) {
        // Get the selected residential complex id from the form data
        $residentialComplexId = $get('residential_complex_id');
        // If we are updating an existing unit, exclude it from the uniqueness check
        $ignoreId = $get('id');
        return $query
            ->where('residential_complex_id', $residentialComplexId)
            ->when($ignoreId, function ($query, $ignoreId) {
                return $query->where('id', '!=', $ignoreId);
            });
    })
    ->rule('required')
    ->errorMessage('وحدة سكنية أخرى بنفس الرقم موجودة بالفعل في هذا المجمع.');

In this code, the unique method is used to define a custom query for the uniqueness check. The closure passed to the unique method receives the query builder instance and the $get closure, which can be used to access the form data. We use the $get closure to retrieve the residential_complex_id from the form data and apply it to the query to ensure the uniqueness check is scoped to the selected residential complex.

Additionally, if we are editing an existing unit, we want to exclude it from the uniqueness check. We can do this by using the when method on the query builder, which conditionally applies a given callback based on the truthiness of the first argument. In this case, if $ignoreId is provided, we exclude the current unit from the uniqueness check.

Make sure to replace 'number' and 'residential_complex_id' with the actual column names used in your ResidentialUnit model if they are different.

This solution should ensure that when a user tries to add or update a residential unit, the unit number is unique within the selected residential complex.

MoshaxDev's avatar

@LaryAI I encountered this error when adding a new record to test for duplication or not.

An attempt was made to evaluate a closure for [Filament\Forms\Components\TextInput], but [$query] was unresolvable.

Please or to participate in this conversation.