Laravel验证:检测两列是否存在反向关联值的实现方案
Absolutely! You can pull this off in Laravel with a custom validation rule—this is exactly the kind of specific business logic that custom rules are built for. Here's a step-by-step breakdown to implement it:
Step 1: Create a Custom Validation Rule
First, generate a new rule class using Laravel's Artisan command:
php artisan make:rule ReverseAssociationCheck
Step 2: Implement the Validation Logic
Open the generated app/Rules/ReverseAssociationCheck.php file and update the passes method to check for reverse associations. The core logic is:
- Grab the incoming
frame_idand convertextra_frame_idinto an array (handling both comma-separated strings like "1,4" and raw arrays). - Query your table to check if any existing record meets two conditions:
- The record's
frame_idis one of the values in the incomingextra_frame_idlist. - That same record's
extra_frame_idcontains the incomingframe_id.
- The record's
Here's the complete code:
<?php namespace App\Rules; use Illuminate\Contracts\Validation\Rule; use Illuminate\Support\Facades\DB; class ReverseAssociationCheck implements Rule { /** * Determine if the validation rule passes. * * @param string $attribute * @param mixed $value * @return bool */ public function passes($attribute, $value) { // Get the incoming frame ID from the request $currentFrameId = request()->input('frame_id'); // Convert extra_frame_id to an array (supports both strings and arrays) $extraFrameIds = is_array($value) ? $value : explode(',', $value); // Check for existing reverse associations $hasReverseMatch = DB::table('your_table_name') // Look for records where frame_id is in our incoming extra_frame_ids ->whereIn('frame_id', $extraFrameIds) // And that record's extra_frame_id contains our current frame_id ->whereRaw('FIND_IN_SET(?, extra_frame_id)', [$currentFrameId]) ->exists(); // Return false to trigger validation error if a reverse association exists return !$hasReverseMatch; } /** * Get the validation error message. * * @return string */ public function message() { return 'A reverse association already exists between the provided frame_id and one of the extra_frame_ids.'; } }
Adjustments for Different Storage Formats:
If your
extra_frame_idis stored as a JSON array instead of a comma-separated string, replace thewhereRawline with a JSON-specific check:->whereJsonContains('extra_frame_id', (string)$currentFrameId)(Cast to string if your JSON array stores string values instead of integers.)
Don't forget to replace
your_table_namewith the actual name of your database table.
Step 3: Use the Custom Rule in Validation
Now apply the rule in your controller validation or a form request class. For example, in a form request:
public function rules() { return [ 'frame_id' => 'required|integer', // Add `exists:` rule if frame_id references another table 'extra_frame_id' => [ 'required', new ReverseAssociationCheck(), ], ]; }
This will trigger a validation error exactly as you described: if there's already a record with frame_id=1 and extra_frame_id=2,5,7, submitting a new record with frame_id=5 and extra_frame_id=1,4 will fail validation.
内容的提问来源于stack exchange,提问作者Pratik

