首页 > 解决方案 > 雄辩的急切加载关系

问题描述

StackOverflow的各位好人,祝大家有个美好的一天(˘⌣˘)♡(˘⌣˘)

我是 Laravel 的新手,目前正在学习雄辩的关系(hasMany)

很抱歉这篇文章太长无法阅读,但我想澄清我在遇到问题之前所做的每一步,如果我的英语不好也很抱歉(⁄ ⁄•⁄ω⁄•⁄ ⁄)

所以我们开始

在我的用户模型中

public function posts() {
    // A user can have many posts
    return $this->hasMany('App\Post');
}

在我的 Post 模型中

public function owner()
{
    // A post belongs to a user
    return $this->belongsTo('App\User', 'user_id');
}

在我的帖子表中,我有 3 条简单的记录

|----------------------------------------------------------|
| id |   user_id |   body          |    ...    |   ...     |
|  1 |   1       |   My first post |    ...    |   ...     |
|  2 |   1       |   Second post   |    ...    |   ...     |
|  3 |   1       |   Another post  |    ...    |   ...     |

然后假设,我们想查看 id = 1 的用户以及他们创建的所有帖子,所以我使用下面的代码:

// AccountController
public function profile($id)
{
    $user = App\User::with('posts')->findOrFail($id);
    return $user;
}

// Will return data:
{
    "id": 1,
    "name": "Prof. Angela Runte Jr.",
    "email": "mborer@example.org",
    ...
    "posts": [
        {
            "id": 1,
            "user_id": 1,
            "body": "My first post",
            ...
        },
        {
            "id": 1,
            "user_id": 1,
            "body": "Second post",
            ...
        },
        {
            "id": 1,
            "user_id": 1,
            "body": "Another post",
            ...
        }
}

在 Blade 视图中,我可以简单地获取如下数据:

// in profile.blade.php

$user->name
$user->...

@foreach($user->posts as $post)
// Show each post data
@endforeach

它以我想要的方式完美运行,感谢 Taylor Otwell 创建了一个惊人的框架 (´• ω •`) ♡</p>

然后我脑子里有了一个想法,让我们做一个用户可以向其他用户发帖的功能,为什么不呢?我们开始做吧!(✧ω✧)

因此,在我的 Post 迁移中,我更改了表架构:

从:

// Before
$table->foreign('user_id')->references('id')->on('users')->onDelete('cascade');
$table->unsignBigInteger('user_id');

$table->text('body');
$table->timestamps();

至:

// After
$table->foreign('user_id')->references('id')->on('users')->onDelete('cascade');
$table->unsignedBigInteger('user_id');

// New column: nullable()
$table->foreign('for_id')->references('id')->on('users')->onDelete('cascade');
$table->unsignedBigInteger('for_id')->nullable();

$table->text('body');
$table->timestamps();

如您所见,我将 nullable() 放在“for_id”列中

换句话说,如果 for_id 为空,则该帖子仅属于发布该帖子的用户

否则,帖子属于发布帖子的用户以及预期用户 (for_id)。

然后在那之后,我跑

// I only use UserSeeder (wanna keep it simple tho)
php artisan migrate:fresh --seed

现在我们有 2 个 id = 1 和 2 的用户(耶!)

|----------------------------------------------------------------------------------------|
| id |   name                    |   email                     |    ...     |    ...     |
|  1 |   Camden Kulas            |   lemke.fabian@example.net  |    ...     |    ...     |
|  2 |   Mrs. Roberta Stroman    |   ybartoletti@example.com   |    ...     |    ...     |

让我们使用 tinker 创建虚拟数据

php artisan tinker
>> $user = App\User::first();
=> App\User {#3910
       id: 1,
       name: "Camden Kulas",
       email: "lemke.fabian@example.net",
       ...
   }
>> $user->posts()->create(['body' => 'New first post']);
=> App\Post {#4120
       body: "New first post",
       user_id: 1,
       updated_at: "2020-08-30 03:42:43",
       created_at: "2020-08-30 03:42:43",
       id: 1,
   }

// we create one for Mrs. Roberta Stroman (user with id #2)
>> $user->posts()->create(['for_id' => 2, 'body' => 'Hello there']);
=> App\Post {#3912
       for_id: 2,
       body: "Hello there",
       user_id: 1,
       updated_at: "2020-08-30 03:44:18",
       created_at: "2020-08-30 03:44:18",
       id: 2,
   }

所以现在我们的帖子表中有 2 条记录

|--------------------------------------------------------------------|
| id |   user_id |   for_id        |   body              |   ...     |
|  1 |   1       |   NULL          |   New first post    |   ...     |
|  2 |   1       |   2             |   Hello there       |   ...     |

我们仍然在用户 ID #1

>> $user->posts

=> Illuminate\Database\Eloquent\Collection {#4120
       all: [
           App\Post {#4125
               id: 1,
               user_id: 1,
               for_id: null,
               body: "New first post",
               ...
           },
           App\Post {#4128
               id: 2,
               user_id: 1,
               for_id: 2,
               body: "Hello there",
               ...
           },
       ],
   }

( ̄ω ̄) 好的,到这里为止,一切正常,让我们尝试使用用户 ID #2

在我看来,我想获取用户 id #2,以及所有由 id #2发布的帖子,以及其他人为 id #2 发布的所有帖子

>> $user = App\User::find(2);
=> App\User {#4121
       id: 2
       name: "Mrs. Roberta Stroman",
       email: "ybartoletti@example.com",
       ...
   }
>> $user->posts
=> Illuminate\Database\Eloquent\Collection {#4067
       all: [],
   }

Σ(°ロ°) 帖子是空的,为什么它是空的?

ఠ ͟ಠ 然后我尝试使用 with()

>> $user = App\User::with('posts')->find(2);
=> App\User {#4120
       id: 2,
       name: "Mrs. Roberta Stroman",
       email: "ybartoletti@example.com",
       ...
       posts: Illuminate\Database\Eloquent\Collection {#4123
           all: [],
       },
   }

(ꐦ°᷄д°᷅) 什么??为什么帖子还是空的?щ(ºДºщ)

所以,找了好几天,还是不知道怎么解决(。╯︵╰。)

然后我试图改变我的用户模型:posts() 函数

从:

public function posts()
{
    // A post belongs to a user
    return $this->hasMany('App\Post');
}

至:

public function posts()
{
    // In my logic like:
    // Hey I want to fetch all posts that made by this user, **or where all posts that created by others for this user**
    // Make sense in human language right?
    return $this->hasMany('App\Post', 'user_id')->orWhere('posts.for_id', $this->id);
}

我退出了修补程序,然后再次重新进入修补程序

>> $user = App\User::first();
// return user id #1

>> $user->posts
// works fine, return all posts

(ಠ益ಠ) 现在我面临其他问题

>> $user = App\User::with('posts')->first(); // notice that I'm using with()

// tinker return the desired user, and also return ONLY one post

>> App\User {#4123
       id: 1,
       name: "Camden Kulas",
       email: "lemke.fabian@example.net",
       ....
       posts: Illuminate\Database\Eloquent\Collection {#4130
           all: [
               App\Post {#4128
                   id: 1,
                   user_id: 1,
                   for_id: null,
                   body: "New first post",
                   created_at: "2020-08-30 03:42:43",
                   updated_at: "2020-08-30 03:42:43",
               },

               // where is the second post?
           ],
       },
   }

然后我尝试使用用户 ID #2 更改修补会话

>> $user = App\User::find(2);
// return user id #2

>> $user = App\User::with('posts')->find(2);
// return user id #2, but no post (only array all)

所以不用再写了,我想问的问题

[#1] 为什么用户 #1 只获取一个帖子,同时他创建了 2 个帖子?

一篇没有 for_id (NULL) 的帖子,第二篇有 for_id 的帖子

[#2] 如何让用户 id #2 获取他们所有的帖子,以及为他们创建的帖子?

因为用户模型中的恕我直言 posts() 函数,对我来说非常有意义,但它不起作用

如有解释不清楚,会及时编辑

提前致谢

更新

我发现我可以通过这种方式简单地获取用户 X 的所有帖子和用户 X 的所有帖子:

$user = App\User::find(X);
$posts = $user->posts()->orWhere('for_id', X)->get();
return [
    'user' => $user,
    'posts => $posts
];

所以现在我想到了这个问题:

如何将 with() 用于 $posts?

// Like this
$user = App\User::with('allposts')->find(X);
// Return user X and all posts made by X and posted to user X

// So I can simply get data in view like this:

@foreach ($user->allposts as $post)
// Loop all posts by user X and for user X
@endforeach

标签: laraveleloquenteloquent-relationship

解决方案


推荐阅读