截取laravel 5模型保存以进行唯一约束检查​​

时间:2016-02-15 13:18:55

标签: php laravel unique

在保存条目之前,我要检查3列唯一约束。

在我的情况下,对于product_id,product_attribute_id和product_option值,条目是唯一的。

例如产品1234尺寸L应该只有一个条目,1234颜色橙色应该只有一个条目。

当我在测试中加倍输入“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);

}

2 个答案:

答案 0 :(得分:1)

要实现您所寻找的目标并采用正确的Laravel方式,您应该利用模型事件,如下:

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

saving会拦截模型的createsave操作。

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

答案 1 :(得分:0)

知道了,基本上是假的......

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

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;

}