首页 文章

更新附加/分离Eloquent关系的时间戳

提问于
浏览
4

我正在使用Laravel 4,有2个型号:

class Asset extends \Eloquent {
    public function products() {
        return $this->belongsToMany('Product');
    }
}

class Product extends \Eloquent {
    public function assets() {
        return $this->belongsToMany('Asset');
    }
}

Product 上有标准时间戳( created_atupdated_at ),当我附加/分离 Asset 时,我想更新 Productupdated_at 字段 .

我在 Asset 模型上尝试过这个:

class Asset extends \Eloquent {
    public function products() {
        return $this->belongsToMany('Product')->withTimestamps();
    }
}

......但这根本没有做任何事情(显然) . Edit :显然这是为了更新数据透视表上的时间戳,而不是在关系表上更新它们(即更新 assets_products.updated_at ,而不是 products.updated_at ) .

然后我在 Asset 模型上尝试了这个:

class Asset extends \Eloquent {
    protected $touches = [ 'products' ];

    public function products() {
        return $this->belongsToMany('Product');
    }
}

...哪个有效,但随后打破我的种子_1155000_因为显然Laravel试图在关系上调用 ->touchOwners() 而不检查它是否是 null

PHP致命错误:在1583行的/projectdir/vendor/laravel/framework/src/Illuminate/Database/Eloquent/Model.php中调用未定义的方法Illuminate \ Database \ Eloquent \ Collection :: touchOwners()

我用来添加/删除 Asset 的代码是这样的:

Product::find( $validId )->assets()->attach( $anotherValidId );
Product::find( $validId )->assets()->detach( $anotherValidId );

我哪里错了?

3 回答

  • 1

    您可以使用 touch 方法手动执行此操作:

    $product = Product::find($validId);
    $product->assets()->attach($anotherValidId);
    $product->touch();
    

    但是,如果您不希望每次都以这种方式在 Product 模型中简化此创建方法时手动执行此操作:

    public function attachAsset($id)
    {
        $this->assets()->attach($id);
        $this->touch();
    }
    

    现在你可以这样使用它:

    Product::find($validId)->attachAsset($anotherValidId);
    

    你当然可以为分离行动做同样的事情 .

    而且我注意到你有一个关系 belongsToMany 和另一个 hasMany - 两者都应该是 belongsToMany 因为它是多对多的关系

    EDIT

    如果您想在许多模型中使用它,您可以使用以下方法创建特征或创建另一个扩展Eloquent的基类:

    public function attach($id, $relationship =  null)
    {
        $relationship = $relationship ?: $this->relationship;
        $this->{$relationship}()->attach($id);
        $this->touch();
    }
    

    现在,如果您需要此功能,您只需要从另一个基类(或使用特征)扩展,现在您可以向 Product 类添加一个额外属性:

    private $relationship = 'assets';
    

    现在您可以使用:

    Product::find($validId)->attach($anotherValidId);
    

    要么

    Product::find($validId)->attach($anotherValidId, 'assets');
    

    如果您需要通过更新 updated_at 字段附加数据 . 当然,你需要重复分离 .

  • 3

    code source中,您需要在创建相关模型的新实例时将 $touch 设置为false:

    Asset::create(array(),array(),false);
    

    或使用:

    $asset = new Asset;
    // ... 
    $asset->setTouchedRelations([]);
    $asset->save();
    
  • 1

    解决方案:

    创建一个扩展Eloquent的 BaseModel ,对 create 方法进行简单调整:

    BaseModel.php

    class BaseModel extends Eloquent {
        /**
         * Save a new model and return the instance, passing along the
         * $options array to specify the behavior of 'timestamps' and 'touch'
         *
         * @param  array  $attributes
         * @param  array  $options
         * @return static
         */
        public static function create(array $attributes, array $options = array())
        {
            $model = new static($attributes);
            $model->save($options);
            return $model;
        }
    }
    

    AssetProduct 模型(以及其他模型,如果需要)扩展 BaseModel 而不是 Eloquent ,并设置 $touches 属性:

    Asset.php (和其他型号):

    class Asset extends BaseModel {
        protected $touches = [ 'products' ];
        ...
    

    In your seeders ,将 create 的第二个参数设置为一个数组,该数组将 'touch' 指定为 false

    Asset::create([...],['touch' => false])
    

    说明:

    Eloquent的save() method接受一个(可选的)选项数组,您可以在其中指定两个标志: 'timestamps''touch' . 如果 touch 设置为 false ,那么无论您使用哪种 $touches 属性,Eloquent都不会触及相关模型 .

    问题是Eloquent的create() method不接受传递给 save() 的任何选项 . 通过扩展Eloquent(使用 BaseModel )接受 $options 数组作为第二个属性,并将其传递给 save() ,您现在可以在所有扩展 BaseModel 的模型上调用 create() 时使用这两个选项 .

    请注意 $options 数组是可选的,因此这样做不会破坏您在代码中对 create() 的任何其他调用 .

相关问题