【问题标题】:Laravel 5: How to use firstOrNew with additional relationship fieldsLaravel 5:如何将 firstOrNew 与其他关系字段一起使用
【发布时间】:2017-04-16 03:16:34
【问题描述】:

我有一个允许用户保存和创建自行车旅行的 CMS。每个自行车之旅也有类别,这些类别是使用 Laravel 的多对多关系使用中间数据透视表定义的。在保存游览时,我们不知道游览是正在编辑的现有游览还是新游览。

认为我应该使用 Laravel 的 firstOrNew 方法来保存游览,并使用 sync 方法来保存类别。但是,所有教程都非常简单地给出了将单个对象传递给函数的示例,如下所示:

$tour = Tour::firstOrNew($attributes);

但是当我的$attributes 还包含额外的内容时会发生什么,例如链接到关系表的类别,并且我需要在下一步中保存这些内容?例如this very good tutorial 给出了以下示例:

$categories = [7, 12, 52, 77];

$tour = Tour::find(2);

$tour->categories()->sync($categories);

但是,如果类别数据与游览其余部分的数据捆绑在一起,而不是使用 find 我需要使用 firstOrNew 来创建游览,会发生什么?我应该在实例化游览时将类别保留在$attributes 中,然后运行sync,然后在保存游览之前取消设置,还是...?有没有更好的方法来实现这一点?

编辑: 需要明确的是,我的示例中的 $attributes 变量本质上是捆绑在一起的旅游对象数据 - 就像 Laravel/Eloquent 系统会使用 belongsToMany 从事务中返回它一样方法 - 用户随后进行修改)。即:这是它包含的内容的快照:

array (
  'id' => 1,
  'uid' => '03ecc797-f47e-493a-a85d-b5c3eb4b9247',
  'active' => 1,
  'code' => '2-0',
  'title' => 'Tour Title',
  'url_title' => 'tour_title',
  'distance_from' => 20,
  'distance_to' => 45,
  'price_from' => '135.00',
  'price_to' => '425.00',
  'created_at' => '2013-12-31 15:23:19',
  'updated_at' => '2015-07-24 16:02:50',
  'cats' => // This is not a column name!
  array (
    0 => 1,
    1 => 7
  ),
)

所有这些属性都是我的 tours 表中的列名,除了 cat,它通过 hasMany 关系引用另一个表。是否需要手动取消设置才能设置此对象类并使用$tour->save 保存?

我正在寻找最干净最 Laravel 的方式来做到这一点?

EDIT2:以下是 Tours 模型中定义的关系:

class Tour extends Model
{

    protected $guarded = [];

    public function cats(){
        return $this->belongsToMany('App\TourCategory', 'tour_cat_assignments', 'tour_id', 'cat_id');
    }
}

【问题讨论】:

  • 不确定我是否明白你的意思。但是既然你没有提到它......你试过hydratefill吗?
  • 从来没有听说过这两个,看起来很有希望-谢谢!
  • 及时通知我们!

标签: laravel laravel-5


【解决方案1】:

您需要定义 Tour 模型的 $fillable 属性来告诉 eloquent 在使用批量分配时要考虑哪些属性,这样它就会默默地忽略类别相关的属性。例如。

<?php
 namespace App;
 use Illuminate\Database\Eloquent\Model;

class Tour extends Model {
     protected $fillable = ['name'] //... other attributes which are part of this model only and laravel will consider only these attributes and ignore category related attributes which you can consider later use.
}

【讨论】:

  • " 它会默默地忽略与类别相关的属性" 不,我收到 Column not found: 1054 Unknown column 错误,因为模型的数据库表中不是列名的所有属性。
  • 确保您的可填充数组仅包含 tours 表可用的列
  • 我怀疑你只是误会了我。如果我尝试创建一个新对象并将其保存到包含不是列名的属性的数据库中,则会收到未找到列的错误。将所有列名的列表放在 $fillable 数组中没有区别....
  • 如果您使用模型进行插入,请不要使用数据库对象进行插入,它将考虑可填充属性,并且仅在批量分配时填充这些值。
  • 我正在创建适当的 eloquent 模型并对其调用 save,即:$tour = new Tour($attributes); $tour-&gt;save(); 如果 $attributes 包含不是列名的属性,我会收到错误 - 即使列出所有列名在 Tour 模型中的 $fillable 数组中。我正在使用 Laravel 5.3。
【解决方案2】:

您可以使用 firstOrCreate。数据实际上是使用这种方法持久化的。

$categories = [7, 12, 52, 77];
$tour = Tour::firstOrCreate($attributes)->cats()->sync($categories);

必须确保这些字段是可批量分配的,以便能够使用 firstOrCreate 方法。因此,要么在 $fillable 属性中设置字段名,要么将其放入 Tour 模型中:

protected $guarded = [];

【讨论】:

  • 不,抱歉,这会触发Column not found: 1054 Unknown column 'categories' in 'where clause'- 这是我问题的症结所在;我需要先从$attributes 数组中取消设置类别吗?正如我所说,所有这些数据都捆绑到 $attributes 中(这实际上是游览对象,就像 Laravel 使用 belongsToMany 方法从数据库中返回它一样 - 用户随后进行修改)
  • 请发布Tour模型中定义的关系
【解决方案3】:

由于您提到了“CMS”和“用户的后续修改”,我猜您是从 Form 获取属性,这意味着您将获得 Request 对象/集合。
如果是这种情况,那么您可以尝试

$tour = Tour::firstOrCreate($request->except('cats'));  
$categories = [];
foreach($request->get('cats') as $key=>$value){  
    $categories[] = $value;
}
$tour->cats()->sync($categories);  

但是,如果您的 $attributes 我们按照您的 EDIT 构造为一个数组(可能对表单数据进行了一些操作),那么在这种情况下您可以尝试:

$tour = Tour::firstOrCreate(array_except($attributes, ['cats']);  
$categories = [];
foreach($attributes['cats'] as $key=>$value){
    $categories[] = $value;
}
$tour->cats()->sync($categories);  

无论如何,您必须在模型的$fillable 属性中声明大量可分配字段,即Tour

希望这会有所帮助。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2015-06-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-03-26
    • 1970-01-01
    • 2021-10-03
    • 1970-01-01
    相关资源
    最近更新 更多