【问题标题】:Intercepting laravel 5 model save for unique constraint check拦截 laravel 5 模型保存以进行唯一约束检查
【发布时间】:2016-02-15 13:18:55
【问题描述】:

在保存条目之前,我有一个 3 列的唯一限制要检查。

在我的例子中,product_id、product_attribute_id 和 product_option 值的条目是唯一的。

例如产品 1234 Size L 应该只有一个条目,1234 Color Orange 应该只有一个条目。

当我在测试中加倍输入“1-7-Fuscha Baby”时,我会正确收到错误

Integrity constraint violation: 
1062 Duplicate entry '1-7-Fuscha Baby' for key 'p_a_v' 
(SQL: insert into `product_options` (`product_attribute_id`, `value`, `product_id`, `updated_at`, `created_at`) 
values (1, Fuscha Baby, 7, 2016-02-15 13:06:27, 2016-02-15 13:06:27))

所以现在我需要绕过创建该条目

在 ProductOption 模型上,我重写了 save 方法来添加检查。这是破坏的部分,无法弄清楚正确的语法。

public function save()
{
    // before save code - Check for a unique value....
    //

    $product_option = ProductOption::where('product_id', $this->product_id)
        ->where('value' ,$this->value)
        ->where('product_attribute_id',$this->product_attribute_id)
        ->first()
    ;

    if($product_option)
    {
        //i have the constraint violation, now how do I tell laravel to use $product_option instead of $this?
        //return  $product_option;  messy error 1
        //return  $product_option->id; messy error 2
        //$this = $product_option; sytnax error
        //return; I think this works with the plain old save() call, but not for saveMany()
        //$this->exists = true; //works for save(), fails for saveMany()

    }

    parent::save();
    // after save code
}

此外,这应该适用于 saveMany 调用:

public function saveOptionsArray($product_options)
{
    /*
        $product_options = [
            ['name' => 1, 'value' =>'Pink'],
            ['name' => 'Color', 'value' =>'Yellow'],
            ['name' => 'Color', 'value' =>'Yellow'], //constraint violation
            ['name' => 'Size', 'value' =>'1'],
            ['name' => 'Size', 'value' =>'2'],
            ['name' => 'Size', 'value' =>'3'],
            ];
    */
    $options = [];
    foreach ($product_options as $product_option)
    {
        $option = new ProductOption();
        $option->product_attribute_id = $product_option['name'];
        $option->value = $product_option['value'];
        //$option = $option->checkBeforeSave(); //same as the save() pre-check above.. didn't work out too well
        $options[] = $option;
    }

    return $this->options()->saveMany($options);

}

【问题讨论】:

    标签: php laravel unique


    【解决方案1】:

    要以正确的 Laravel 方式实现您正在寻找的东西,您应该利用模型事件,例如:

    public static function boot()
    {
        static::saving(function($model)
        {
            //run your logic here
        });
    }
    

    saving 将拦截模型的 createsave 操作。

    此代码应放在模型中。稍后您可以将其扩展并提取到模型观察者。

    【讨论】:

    • 好的,我明白了,但是你认为这比我描述的在模型中覆盖保存更容易理解吗?看起来我实现它的方式在任何事件发生之前就已经存在了。
    • 有很多不同的钩子,savingsavedcreatingupdateddeletingrestoring等请看这里stackoverflow.com/a/28620785/2094178
    【解决方案2】:

    知道了,基本返回false……

    但是,如果字符串太长,代码又会失败,所以我也会传递我的截断器......

    public function save(array $options = [])
    {
        // before save code - Check for a unique value....
        // before check for unique, the value will truncate causing another issue...
    
        $product_option = ProductOption::where('product_id', $this->product_id)
            ->where('value' ,$this->truncateString('value'))
            ->where('product_attribute_id',$this->product_attribute_id)
            ->first()
        ;
        if($product_option)
        {
            return false;
        }
    
        parent::save();
        // after save code
    }
    

    截断器将从数据库中读取最大长度并在输入导致另一个约束违规之前截断您的输入

    public function truncateString($column)
    {
        $max_length =  DB::connection()->getDoctrineColumn($this->getTable(), $column)->getLength();
        $this->$column  = substr ( $this->$column , 0 ,$max_length );
        return $this->$column;
    
    }
    

    【讨论】:

      猜你喜欢
      • 2018-08-16
      • 2020-04-10
      • 2015-09-20
      • 1970-01-01
      • 2011-06-10
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多