如何投射雄辩的枢轴参数?

时间:2015-05-13 22:50:03

标签: php laravel laravel-5 eloquent

我有以下有关系的雄辩模型:

class Lead extends Model 
{
    public function contacts() 
    {
        return $this->belongsToMany('App\Contact')
                    ->withPivot('is_primary');
    }
}

class Contact extends Model 
{
    public function leads() 
    {
        return $this->belongsToMany('App\Lead')
                    ->withPivot('is_primary');
    }
}

数据透视表包含一个额外的参数(is_primary),用于将关系标记为主要关系。目前,当我查询联系人时,我看到这样的回报:

{
    "id": 565,
    "leads": [
        {
            "id": 349,
             "pivot": {
                "contact_id": "565",
                "lead_id": "349",
                "is_primary": "0"
             }
        }
    ]
}

有没有办法将is_primary转换为布尔值?我尝试将其添加到两个模型的$casts数组中,但这并没有改变任何内容。

5 个答案:

答案 0 :(得分:23)

Laravel 5.4.14 中,此问题已得到解决。您可以定义自定义透视模型,并告知您的关系在定义时使用此自定义模型。请参阅定义自定义中间表模型标题下的the documentation

要执行此操作,您需要创建一个类来表示您的数据透视表,并让它扩展a=unique(A{2},'stable'); b=cellfun(@(x) sum(ismember(A{2},x)),a); 类。在此课程中,您可以定义Illuminate\Database\Eloquent\Relations\Pivot属性。

$casts

然后,您可以使用<?php namespace App; use Illuminate\Database\Eloquent\Relations\Pivot; class CustomPivot extends Pivot { protected $casts = [ 'is_primary' => 'boolean' ]; } 关系中的using方法告诉Laravel您希望枢轴使用指定的自定义透视模型。

BelongsToMany

现在,只要您使用<?php namespace App; use Illuminate\Database\Eloquent\Model; class Lead extends Model { public function contacts() { return $this->belongsToMany('App\Contact')->using('App\CustomPivot'); } } 访问数据透视表,就会发现它是自定义数据透视表类的一个实例,应该尊重->pivot属性。

2017年6月1日更新

@cdwyer关于使用通常的$casts / sync / attach方法更新数据透视表的评论中提出的问题预计将在Laravel 5.5中修复,这是由于将于下个月(2017年7月)发布。

请参阅this bug report底部的Taylor评论和他的提交,解决问题here

答案 1 :(得分:11)

由于这是数据透视表的一个属性,因此使用Lead属性不会对ContactPivot模型起作用。

但是,您可以尝试使用定义了$casts属性的自定义Pivot模型。有关自定义透视模型的文档为here。基本上,您使用自定义项创建新的Lead模型,然后更新ContactPivot模型以使用此自定义Pivot模型而不是基础模型。< / p>

首先,创建扩展基本Pivot模型的自定义<?php namespace App; use Illuminate\Database\Eloquent\Relations\Pivot; class PrimaryPivot extends Pivot { protected $casts = ['is_primary' => 'boolean']; } 模型:

newPivot()

现在,覆盖LeadContact模型上的class Lead extends Model { public function newPivot(Model $parent, array $attributes, $table, $exists) { return new \App\PrimaryPivot($parent, $attributes, $table, $exists); } } class Contact extends Model { public function newPivot(Model $parent, array $attributes, $table, $exists) { return new \App\PrimaryPivot($parent, $attributes, $table, $exists); } } 方法:

{{1}}

答案 2 :(得分:3)

好消息!泰勒已经修复了这个错误:

https://github.com/laravel/framework/issues/10533

在Laravel 5.1或更高版本中,您可以使用点表示法进行枢轴投射:

{{1}}

答案 3 :(得分:2)

上面@patricus提供的答案是完全正确的,但是,如果像我一样你也希望从数据透视表中的JSON编码字符串中删除,那么请继续阅读。< / p>

问题

我相信Laravel在这个阶段有一个错误。问题是当您实例化一个数据透视模型时,它使用本机的Illuminate-Model setAttributes方法将数据透视记录表的值“复制”到数据透视模型。

这对于大多数属性都很好,但是当它看到$casts数组包含JSON样式的强制转换时会变得很粘 - 它实际上是对数据进行双重编码。

解决方案

我克服这个问题的方法如下:

<强> 1。设置自己的Pivot基类,从中扩展您的数据透视子类(稍后详细介绍)

<强> 2。在新的Pivot基类中,重新定义setAttribute方法,注释掉处理JSON-castable属性的行

class MyPivot extends Pivot {
  public function setAttribute($key, $value)
  {
    if ($this->hasSetMutator($key))
    {
      $method = 'set'.studly_case($key).'Attribute';

      return $this->{$method}($value);
    }
    elseif (in_array($key, $this->getDates()) && $value)
    {
      $value = $this->fromDateTime($value);
    }

    /*
    if ($this->isJsonCastable($key))
    {
      $value = json_encode($value);
    }
    */

    $this->attributes[$key] = $value;
  }
}

这突出显示了isJsonCastable方法调用的删除,对于您已投放为truejsonarray的所有属性,此调用将返回object或你的whizzy pivot子类中的collection

第3。使用某种有用的命名约定创建您的数据透视子类(我做{PivotTable}Pivot,例如FeatureProductPivot)

<强> 4。在基础模型类中,将newPivot方法覆盖更改/创建为更有用的内容

我的样子如下:

public function newPivot(Model $parent, array $attributes, $table, $exists)
{
  $class = 'App\Models\\' . studly_case($table) . 'Pivot';

  if ( class_exists( $class ) )
  {
    return new $class($parent, $attributes, $table, $exists);
  }
  else
  {
    return parent::newPivot($parent, $attributes, $table, $exists);
  }
}

然后只需确保您的模型从您的基础模型扩展,并创建您的数据透视表“模型”以适合您的命名约定,并且您将在数据库的出路上对数据透视表列进行JSON转换!< / p>

注意:这尚未经过全面测试,可能无法保存回数据库。

答案 4 :(得分:1)

我必须添加一些额外的检查才能使保存和加载功能在Laravel 5中正常工作。

class BasePivot extends Pivot
{
    private $loading = false;

    public function __construct(Model $parent, array $attributes, $table, $exists)
    {
        $this->loading = true;
        parent::__construct($parent, $attributes, $table, $exists);
        $this->loading = false;
    }

    public function setAttribute($key, $value)
    {
        // First we will check for the presence of a mutator for the set operation
        // which simply lets the developers tweak the attribute as it is set on
        // the model, such as "json_encoding" an listing of data for storage.
        if ($this->hasSetMutator($key)) {
            $method = 'set'.Str::studly($key).'Attribute';

            return $this->{$method}($value);
        }

        // If an attribute is listed as a "date", we'll convert it from a DateTime
        // instance into a form proper for storage on the database tables using
        // the connection grammar's date format. We will auto set the values.
        elseif ($value && (in_array($key, $this->getDates()) || $this->isDateCastable($key))) {
            $value = $this->fromDateTime($value);
        }

        /**
         * @bug
         * BUG, double casting
         */
        if (!$this->loading && $this->isJsonCastable($key) && ! is_null($value)) {
            $value = $this->asJson($value);
        }


        $this->attributes[$key] = $value;

        return $this;
    }
}