Gwein

Gwein

Member Since 2 Months Ago

Experience Points
150
Total
Experience

4,850 experience to go until the next level!

In case you were wondering, you earn Laracasts experience when you:

  • Complete a lesson — 100pts
  • Create a forum thread — 50pts
  • Reply to a thread — 10pts
  • Leave a reply that is liked — 50pts
  • Receive a "Best Reply" award — 500pts
Lessons Completed
0
Lessons
Completed
Best Reply Awards
0
Best Reply
Awards
  • start your engines Created with Sketch.

    Start Your Engines

    Earned once you have completed your first Laracasts lesson.

  • first-thousand Created with Sketch.

    First Thousand

    Earned once you have earned your first 1000 experience points.

  • 1-year Created with Sketch.

    One Year Member

    Earned when you have been with Laracasts for 1 year.

  • 2-years Created with Sketch.

    Two Year Member

    Earned when you have been with Laracasts for 2 years.

  • 3-years Created with Sketch.

    Three Year Member

    Earned when you have been with Laracasts for 3 years.

  • 4-years Created with Sketch.

    Four Year Member

    Earned when you have been with Laracasts for 4 years.

  • 5-years Created with Sketch.

    Five Year Member

    Earned when you have been with Laracasts for 5 years.

  • school-in-session Created with Sketch.

    School In Session

    Earned when at least one Laracasts series has been fully completed.

  • welcome-newcomer Created with Sketch.

    Welcome To The Community

    Earned after your first post on the Laracasts forum.

  • full-time-student Created with Sketch.

    Full Time Learner

    Earned once 100 Laracasts lessons have been completed.

  • pay-it-forward Created with Sketch.

    Pay It Forward

    Earned once you receive your first "Best Reply" award on the Laracasts forum.

  • subscriber Created with Sketch.

    Subscriber

    Earned if you are a paying Laracasts subscriber.

  • lifer Created with Sketch.

    Lifer

    Earned if you have a lifetime subscription to Laracasts.

  • evangelist Created with Sketch.

    Laracasts Evangelist

    Earned if you share a link to Laracasts on social media. Please email [email protected] with your username and post URL to be awarded this badge.

  • chatty-cathy Created with Sketch.

    Chatty Cathy

    Earned once you have achieved 500 forum replies.

  • lara-veteran Created with Sketch.

    Laracasts Veteran

    Earned once your experience points passes 100,000.

  • 10k-strong Created with Sketch.

    Ten Thousand Strong

    Earned once your experience points hits 10,000.

  • lara-master Created with Sketch.

    Laracasts Master

    Earned once 1000 Laracasts lessons have been completed.

  • laracasts-tutor Created with Sketch.

    Laracasts Tutor

    Earned once your "Best Reply" award count is 100 or more.

  • laracasts-sensei Created with Sketch.

    Laracasts Sensei

    Earned once your experience points passes 1 million.

  • top-50 Created with Sketch.

    Top 50

    Earned once your experience points ranks in the top 50 of all Laracasts users.

Level 1
150 XP
Sep
13
1 month ago
Activity icon

Started a new Conversation Strange Eloquent Accessor

good morning/after/evening

I have a 3 model: User, Post, Comment

User.php

public function posts()
{
    return $this->hasMany(
        Post::class,
        'by_id'
        'id'
    );
}

Post.php

protected $appends = [
    'by' // Notice here I am using accessor for fetching the user who own the post (THIS IS JUST EXPERIMENT)
];

public function comments()
{
    // Morph Many
    return $this->morphMany(
        Comment::class,
        'commentable'
    );
}

// EXPERIMENTAL
public function getByAttribute()
{
    return User::find($this->attributes['by_id']);
}

Comment.php

public function by()
{
    return $this->belongsTo(
        User::class,
        'by_id',
        'id'
    );
}

public function commentable()
{
    return $this->morphTo();
}

In post table, I have 3 records

|---------------------------------------|
|  id  |  by_id  |  body  |  ...   |
|---------------------------------------|
|  1   |    1    |  ...   |  ...  |  ...  |
|  2   |    1    |  ...   |  ...  |  ...  |
|  3   |    1    |  ...   |  ...  |  ...  |

In comments table, I have 10 record

|----------------------------------------------------------------|
|  id  |  by_id  |  commentable_id  |  commentable_type  |  ...  |
|----------------------------------------------------------------|
|  1   |    2    |  1               |  App\Post          |  ...  |
|  2   |    3    |  1               |  App\Post          |  ...  |
|  3   |    4    |  2               |  App\Post          |  ...  |
|  ... |  ...    |  1               |  App\Post          |  ...  |
|  ... |  ...    |  2               |  App\Post          |  ...  |
|  ... |  ...    |  3               |  App\Post          |  ...  |
|  10  |  ...    |  1               |  App\Post          |  ...  |

In my profile route, I want to fetch all posts by that user, with 3 latest comments for each post, so I googled for few hours, but still couldn't find the answer, then I had idea in my mind, why not try accessor?

// So in my model Post.php
...
...

public function getRecentCommentsAttribute()
{
    // Get the 3 latest comment with relationship by (The owner of the comment)
    return $this->comments()->with('by')->orderBy('created_at', 'DESC')->get()->take(3);
}

Then I use conditional append() function for profile route, show 3 latest comment in profile, but paginate all comments on post.index route

$posts = Post::where('by_id', $x)->orderBy('created_at', 'DESC')
    ->get()
    ->each(function ($items) {
        $items->append('recent_comments'); // Notice here I'm appending the recentComments accessor
    }
);

It working perfectly like I want, fiuh...

Post #1
By: ...
3 latest comments

Post #2
By: ...
3 latest comments    

Post #3
By: ...
3 latest comments

...

But then when I try to look the query with \DB::enableQueryLog();

I don't see the query to fetch those 3 latest comments, nor the owner of the post (By accessor above)

It just return 1 query:

[
    {
        "query": "select * from `posts` where `posts`.`deleted_at` is null order by `created_at` desc",
        "bindings": [
             1
        ],
        "time": 2.72
    }
]

So my questions:

Why I'm not seeing any query for fetching those 3 latest comment and also query for fetching the owner of the post (By accessor above)

If there's any unclear explanation, just ask me, I will edit a.s.a.p

Sorry for bad english

Thanks in advance

Aug
30
2 months ago
Activity icon

Replied to Eloquent Relationship With() [Updated]

Thank you for your time sir @michaloravec

Activity icon

Replied to Eloquent Relationship With() [Updated]

I just updated my comment for you, it's possible?, If yes, how to achieve it?

If not, i guess we will be going like this:

$user = App\User::findOrFail(X);
$posts = $user->posts()->orWhere('for_id', 
$user->id)->get();
return view('search')->compact('user', 'posts');

If use code above, will it causing n+1 problem?

I'm really sorry if I'm asking too much

Activity icon

Replied to Eloquent Relationship With() [Updated]

Hello @michaloravec, I thank you for your answer, but that is not what I try to achieve

The thing is, posts() or with('posts') only return all posts that created by user X,

Example:

Public function searchUser($id)
{
    $selectedUser = App\User::with('posts')->findOrFail($id);
    return view('search')->compact('selectedUser);
}

In view

@foreach ($selectedUser->posts as $posts)
    // ....
@

This code will return selected user, and with all posts they made

I want a function just exactly like posts(), But fetch all posts that were made by selectedUser or posts by others for selectedUser

(What others posts to this selectedUser)

And inside view, I can use them exactly like this:

$user->posts as $posts

Not like this:

$user = App\User::findOrFail(X);
$posts = $user->posts()->orWhere('for_id', $user->id)->get();
return view('search')->compact('user', 'posts');
Activity icon

Replied to Eloquent Relationship With() [Updated]

I figured it out that I can simply get all posts by user X and all posts for user X with this way:

$user = App\User::find(X);

$posts = $user->posts()->orWhere('for_id', X)->get();


return [
    'user' => $user,
    'posts' => $posts
];

So now the question comes to my mind:

How to use with() for $posts?

// Like this

$user = App\User::with('allposts')->find(X);
// Return user X and all posts made by X and posted to user X (is it even possible?)

// 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
Activity icon

Replied to Eloquent Relationship With() [Updated]

Hello @mohammad_ranjbar49, that is what I'm tryng to achieve here

posts() only return all posts that were made by selected user

What I want is, fetch all posts that made by user X, and also posts that were made for user X

Aug
29
2 months ago
Activity icon

Started a new Conversation Eloquent Relationship With() [Updated]

Hello wonderful people of Laracast, I hope you all have a good day

I'm new to Laravel and currently learning about eloquent relationships (hasMany)

I'm sorry this post was too long to read, but I wanted to clarify every step I did until I ran into problems, and also sorry if my english is bad

So here we go

In my User model

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

In my Post model

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

In my Post Table, I have 3 simple records

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

And then let's say, we want to see the user with id = 1 with all posts they created, so I use the code below:

// 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": "[email protected]",
    ...
    "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",
            ...
        }
}

And in Blade view, I can simply get data like below:

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

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

It works perfectly the way I want, Thanks to Taylor Otwell for creating an amazing framework

And then I had an idea in my mind, let's make a feature where a user can post to other users, why not? Let's do it!

So in my Post migration, I change the table schema:

From:

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

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

To:

// 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();

As you can see, I put nullable() in column 'for_id'

In words, if for_id is empty then this post belongs only to the user who made the post

Otherwise the post belongs to the user who made the post, as well as the intended user (for_id).

Then after that, I run

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

And now we have 2 users with id = 1 and 2 (Yay!)

|-----------------------------------------------------------------------------------------------|
| id |  name                              |   email                                          
|  1 |  Camden Kulas               |   [email protected]
|  2 |  Mrs. Roberta Stroman |   [email protected]

Let's use tinker for creating dummy data

php artisan tinker

>> $user = App\User::first();
=> App\User {#3910
       id: 1,
       name: "Camden Kulas",
       email: "[email protected]",
       ...
     }
>> $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,
}

So now we have 2 record in our posts table

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

>> $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",
            ...
        },
    ],
}

Ok 'till here, all works fine, let's try with user id #2

In my mind, I want to get user id #2, and with all posts made by id # 2, and all posts from others for id # 2

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

The posts is empty, so why the hell it's empty?

Then I try to use with()

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

Why the posts still empty?

So, after searching and reading for days, still I couldn't figured it out how to solve this

And then I tried to change in my User model: the posts() function

From:

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

To:

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

I exited the tinker, then re-enter the tinker again

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

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

Now I am facing other problem

>> $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: "[email protected]",
        ...
        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?
        ],
    },
}

Then I try to change tinker session with user 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)

So without writing further, the questions I want to ask

[#1] Why user #1 only fetch one post, meanwhile he created 2 posts?

One post without for_id (NULL), and second post with for_id

[#2] How to make user id #2 to fetch all their posts, and also posts that created for them?

Because IMHO posts() function in User model, perfectly make sense for me, but it doesn't work

If there's any unclear explanation, it will edit in time

Thanks in advance