php 如何转换雄辩的透视参数?,

sh7euo9m  于 2023-11-16  发布在  PHP
关注(0)|答案(6)|浏览(151)

我有以下几个有关系的口才模型:

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');
    }
}

字符串
pivot表包含一个额外的参数(is_primary),它将关系标记为主要关系。目前,当我查询联系人时,我看到这样的返回:

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


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

qnyhuwrf

qnyhuwrf1#

Laravel 5.4.14中,此问题已得到解决。您可以定义自定义透视表模型,并在定义关系时告诉关系使用此自定义模型。请参阅文档,标题为 * 定义自定义中间表模型 *。
要做到这一点,你需要创建一个类来表示你的数据透视表,并让它扩展Illuminate\Database\Eloquent\Relations\Pivot类。在这个类上,你可以定义你的$casts属性。

<?php

namespace App;

use Illuminate\Database\Eloquent\Relations\Pivot;

class CustomPivot extends Pivot
{
    protected $casts = [
        'is_primary' => 'boolean'
    ];
}

字符串
然后,您可以在BelongsToMany关系上使用using方法来告诉Laravel您希望您的pivot使用指定的自定义pivot模型。

<?php

namespace App;

use Illuminate\Database\Eloquent\Model;

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


现在,每当您使用->pivot访问pivot时,您应该会发现它是自定义pivot类的示例,并且$casts属性应该被接受。

更新2017年6月1日

@cdwyer在评论中提出的关于使用通常的sync/attach/save方法更新pivot表的问题预计将在下个月(2017年7月)发布的Laravel 5.5中得到修复。
请参阅Taylor在this bug report底部的评论和他的提交,修复了here问题。

mbjcgjjk

mbjcgjjk2#

由于这是数据透视表上的一个属性,所以使用$casts属性在LeadContact模型上都不起作用。
但是,您可以尝试的一件事是使用定义了$casts属性的自定义Pivot模型。有关自定义pivot模型的文档在这里。基本上,您使用自定义创建了一个新的Pivot模型,然后更新LeadContact模型以使用此自定义Pivot模型而不是基本模型。
首先,创建您的自定义Pivot模型,它扩展了基础Pivot模型:

<?php namespace App;

use Illuminate\Database\Eloquent\Relations\Pivot;

class PrimaryPivot extends Pivot {
    protected $casts = ['is_primary' => 'boolean'];
}

字符串
现在,在LeadContact模型上覆盖newPivot()方法:

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);
    }
}

1u4esq0p

1u4esq0p3#

好消息!Tylor已经修复了这个bug:
https://github.com/laravel/framework/issues/10533
在Laravel 5.1或更高版本中,您可以使用点表示法进行枢轴转换:

protected $casts = [
    'id' => 'integer',
    'courses.pivot.course_id' => 'integer',
    'courses.pivot.active' => 'boolean'
]

字符串

llycmphe

llycmphe4#

上面@patricus提供的答案是绝对正确的,但是,如果你像我一样也想从数据透视表中的JSON编码字符串中获得好处,那么请继续阅读。
问题
我相信Laravel在这个阶段有一个bug。问题是当你示例化一个pivot模型时,它使用原生的Illuminate-Model setAttributes方法来“复制”pivot记录表的值到pivot模型。
这对于大多数属性来说都很好,但是当它看到$casts数组包含JSON风格的强制转换时就会变得棘手-它实际上对数据进行了双重编码。

解决方案

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

1.建立你自己的Pivot基类,从它扩展你的Pivot子类(稍后会有更多的介绍)
2.在新的Pivot基类中,重新定义setAttribute方法,注解掉处理JSON可铸造属性的行

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方法调用的删除,它将为您在出色的pivot子类中转换为jsonarrayobjectcollection的任何属性返回true

3.使用某种有用的命名约定创建pivot子类(我使用{PivotTable}Pivot,例如,pivotureProductPivot)
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转换!

注意:这还没有经过彻底的测试,保存回数据库可能会有问题。

dgtucam1

dgtucam15#

我不得不添加一些额外的检查,以使保存和加载功能在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;
    }
}

字符串

rmbxnbpk

rmbxnbpk6#

更简单的方法是在pivot关系函数上标记withCasts

public function teachers(): BelongsToMany
{
    return $this->belongsToMany(Teacher::class, 'section_teacher', 'section_id', 'teacher_id')
        ->withPivot(['id', 'role', 'created_at', 'updated_at'])
        ->withCasts([
            'role' => TeacherSectionRoleEnum::class,
        ]);
}

字符串

相关问题