复合键的 Laravel 验证

Posted

技术标签:

【中文标题】复合键的 Laravel 验证【英文标题】:Laravel validation for composite key 【发布时间】:2021-09-30 07:54:50 【问题描述】:

我在插入或更新之前验证一个字段,但我想要验证的是,在我的表中使用外键而不是主键进行验证。 我的拍卖模式是:

class Auction extends Model

    use HasFactory;
    protected $fillable = [
        'auction_number',
        'title',
        'description',
        'image',
        'catelogue',
        'start_date',
        'end_date',
        'start_time',
        'end_time',
        'status'
    ];
    // public function auction_category()
    //     return $this->belongsTo(category::class,'category','id');
    // 

    public function lot()
        return $this->hasMany(Lot::class,'auction_id','id');
    

我的抽签模式是:

class Lot extends Model

    use HasFactory;
    protected $fillable = [
        'auction_id',
        'lot_number',
        'category',
        'description',
        'min_price',
        'max_price',
        'current_bid',
        'asking_bid',
        'thumbnail',
        'image',
        'sold',
        'closed'
    ];
    // public function seller()
    //     return $this->belongsTo(Seller::class,'seller_id','id');
    // 
    public function auctions()
        return $this->belongsTo(Auction::class,'auction_id','id');
    
    public function singlecategory()
        return $this->belongsTo(category::class,'category','id');
    

然后下面是我需要这些验证的批次控制器:

public function update(Request $request, Lot $admin_lot) 
    $this->validate(
    $request, 
    [   
        'auction'=> 'required',
        'lot_number'=> 'required|unique:lots,lot_number,'.$admin_lot->auction,
        'category' => 'required',
        'description'=> 'required|min:75',
        'min_price'=> 'required|numeric|regex:/[0-9][0-9]+/u',
        'max_price'=> 'required|numeric|regex:/[0-9][0-9]+/u',
        'image.*'=> 'sometimes|nullable|file|image',
    ],
    [   
        'auction.required'    => 'Please Select Auction Number, Thank you',
        'lot_number.required'      => 'Please Select Lot Number, Thank You.',
        'description.required' => 'Please Enter Description, Thank You.',
        'description.min' => 'Please Enter Minimum of 75 Characters In Description, Thank You.',
        'min_price.required'      => 'Please Enter Min price, Thank You.',
        'min_price.numeric'      => 'Please Enter a Valid Min price Without Any Special characters, Thank You.',
        'min_price.regex'      => 'Please Enter Valid Min Price, Thank You.',
        'max_price.required'      => 'Please Enter Max price, Thank You.',
        'max_price.numeric'      => 'Please Enter a Valid Max price Without Any Special characters, Thank You.',
        'max_price.regex'      => 'Please Enter Valid Max price, Thank You.',
        'image.image'      => 'Please Select Image, Thank You.',
        ]);
//then rest of my functions
if ($request->file('image')) 
            if (File::isDirectory(public_path($admin_lot->image))) 
                File::deleteDirectory(public_path($admin_lot->image));
                File::deleteDirectory(public_path($admin_lot->thumbnail));
                $hashpath = 'public/lot/images/lot_'.uniqid().'_'.time();
                $hashpaththumb = 'public/lot/thumbnail/lot_'.uniqid().'_'.time();
                foreach($request->file('image') as $imagefile)
                    if (!empty($imagefile)) 
                        $imagepath = $hashpath.'/'.'lot_'.uniqid().'_'.time().'.jpg';
                        $thumbnailpath = $hashpaththumb.'/'.'lot_'.uniqid().'_'.time().'.jpg';
                        $image = Image::make($imagefile)->resize(265,275)->encode('jpg');
                        $thumb = Image::make($imagefile)->resize(60,45)->encode('jpg');
                        Storage::put($imagepath, (string) $image->encode());
                        Storage::put($thumbnailpath, (string) $thumb->encode());
                    
                   
                $imageurl = Storage::url($hashpath);
                $thumburl = Storage::url($hashpaththumb);
            else
                $hashpath = 'public/lot/images/lot_'.uniqid().'_'.time();
                $hashpaththumb = 'public/lot/thumbnail/lot_'.uniqid().'_'.time();
                foreach($request->file('image') as $imagefile)
                    if (!empty($imagefile)) 
                        $imagepath = $hashpath.'/'.'lot_'.uniqid().'_'.time().'.jpg';
                        $thumbnailpath = $hashpaththumb.'/'.'lot_'.uniqid().'_'.time().'.jpg';
                        $image = Image::make($imagefile)->resize(265,275)->encode('jpg');
                        $thumb = Image::make($imagefile)->resize(60,45)->encode('jpg');
                        Storage::put($imagepath, (string) $image->encode());
                        Storage::put($thumbnailpath, (string) $thumb->encode());
                    
                   
                $imageurl = Storage::url($hashpath);
                $thumburl = Storage::url($hashpaththumb);            
            
        else

            $imageurl=$admin_lot->image;
            $thumburl =$admin_lot->thumbnail;
        
        $admin_lot->update([
            'auction_id'=> $request->auction,
            'lot_number'=> $request->lot_number,
            'category' => $request->category,
            'description'=> $request->description,
            'min_price'=> str_replace(',', '', $request->min_price),
            'max_price'=> str_replace(',', '', $request->max_price),
            'thumbnail'=> $thumburl,
            'image'=> $imageurl
        ]);

        $notification = array(
            'message' => 'Lot updated successfully!',
            'alert-type' => 'success'
        );
        return redirect()->back()->with($notification); 

从上面的代码中,拍卖是我存储在lots 表中的外键,而拍卖是表auctions 中的主键。所以我想要的是每次拍卖都有唯一的批号,例如:

auction 1 can have lot numbers 1,2,3,4, etc
auction 2 also can have 1,2,3,4,5 etc

但是从上述情况来看,拍卖 1 不能有重复的数字 1、2、3、4,因为它们已经被分配给同一个拍卖编号 1。那么我该如何为此添加验证,因为我尝试过的是例如验证主键:

auction 1 from above has the 1,2,3,4 and if I assign these to auction 2 then it gives an error saying it is already taken but the auction is different,

所以它必须将它们视为有效。那么我该怎么做呢,请有人帮我完成这件事

【问题讨论】:

批号存储逗号分隔? 没有一个又一个喜欢:aution 1 lot 1 和第二个 aution 1 lot 2 像这样 你能显示你的控制器代码吗? 请添加控制器和型号代码 在我的问题中,拍卖是拍卖的主键,这是我的地块表中的外键。所以在我的拍品表中,我可以进行任意数量的拍卖,对吧? 【参考方案1】:

您可以使用Rule::unique 来实现您的验证规则

$this->validate(
$request, 
[   
    'auction'=> 'required',
    'lot_number'=> ['required',
         Rule::unique('lots')->where(function($query) 
              $query->where('auction_id', '!=', $request->auction)
                    ->where('lot_number','!=',$request->lot_number);
         )            
     ],
    'category' => 'required',
    'description'=> 'required|min:75',
    'min_price'=> 'required|numeric|regex:/[0-9][0-9]+/u',
    'max_price'=> 'required|numeric|regex:/[0-9][0-9]+/u',
    'image.*'=> 'sometimes|nullable|file|image',
]
// other code

【讨论】:

女士,它不工作。但实际代码必须为插入功能工作,但它不工作它给我错误说批号已经被占用,但所占用的批号是另一个拍卖 您可以使用条件唯一规则。请参阅我编辑的答案。【参考方案2】:

你可以使用闭包laravel custom validation using closure

$auction = $request->input('auction');
$validated = $request->validate([
    'lot_number' => ['required',function($attribute, $value, $fail) use ($auction) 
        if(Lot::where('auction_id', $auction)->where('lot_number', $value)->exists())
            $fail('Given lot no. is already exists');
        
        
    ],
]);

【讨论】:

您的答案对于插入效果很好,但我们如何才能进行更新?你也可以告诉我吗?即使我不更改当前批号,编辑也会出错 我已经指导您如何使用闭包进行自定义验证。现在由您决定如何根据您的要求在闭包中​​定义更新逻辑。 对不起,我又问了一个愚蠢的问题。我通过另一个 where 条件实现了这一点,并在闭包的使用方法中传递了当前的批次 id。非常感谢,它适用于插入和另外一个在更新函数中排除当前 id 的条件

以上是关于复合键的 Laravel 验证的主要内容,如果未能解决你的问题,请参考以下文章

复合唯一密钥验证 - laravel

使用 Laravel Eloquent 使用复合键更新表

Laravel Eloquent hasOne 返回空

laravel验证外键个数不大于另一个表的id

Laravel 支付宝异步通知 419报错

Laravel中定义复合主键