12

Intro

Im havning some trubble getting the data on all the related elements. Im using Laravel as a REST backend service, exposing Json to the front-end javascript application.

Data structure

Consider I have the following tables:

+----------------+ +----------------+ +-------------+
|topics          | |posts           | |users        |
+----------------+ +----------------+ +-------------+
|id: int         | |id: int         | |id: int      |
|title: varchar  | |content: varchar| |name: varchar|
|content: varchar| |user_id: int    | +-------------+
|user_id: int    | |topic_id: int   |
+----------------+ +----------------+ 

A topic has 0 to many posts, and it has an author (user)

A post has one author (user)

UML: http://i58.servimg.com/u/f58/11/26/57/95/intrep10.png

Laravel Models

class User extends Eloquent {
    protected $table = 'users';

    public function topics() {
        reutrn $this->hasMany('Topic');
    }

    public function posts() {
        reutrn $this->hasMany('Post');
    }
}

class Topic extends Eloquent {
    protected $table = 'topics';

    public function posts() {
            return $this->hasMany('Post');
    }

    public function author() {
         return $this->hasOne('User', 'id');
    }
}

class Post extends Eloquent {
    protected $table = 'posts';

    public function topic() {
        return $this->belongsTo('Topic');
    }

    public function author() {
        return $this->hasOne('User', 'id');
    }
}

Controller

return Topic::where('id', '=', $topicId)
    ->with('author', 'posts.author')
    ->get();

Output

[{
    id: 1,
    title: "My Topic",
    content: "With opinions about the darkside",
    user_id: 1,
    created_at: "2014-03-06",
    updated_at: "2014-03-06",
    author: {
        id: 1,
        name: "JamesBond",
        created_at: "2014-03-06",
        updated_at: "2014-03-06",
    },
    posts: [{
        id: 1,
        content: "Reply 1 on topic 1",
        user_id: 1,
        created_at: "2014-03-06",
        updated_at: "2014-03-06",
        author: {
            id: 1,
            name: "JamesBond",
            created_at: "2014-03-06",
            updated_at: "2014-03-06",
        },
    },
    {
        id: 2,
        content: "Reply 2 on topic 1",
        user_id: 1,
        created_at: "2014-03-06",
        updated_at: "2014-03-06",
        author: null,
    }]
}]

Question

As you can see of the jsoncode, both the posts are created by the same user (with id 1), but only the first has the author object on it. Any pointers on how to figure out my problem would be perfect.

Disclaimer

This is a striped down version of my project, as I dont want to spam the question with information. If I lack serten elements to the question, I will be happy to supply it.

Solution

My model mapping was off.

public function author() {
    return $this->belongsTo('User', 'user_id', 'id');
}

makes sure that its the user_id its looking for in the posts table, up against the id column in the users table

SELECT * FROM users WHERE id = posts.user_id;
R. Gulbrandsen
  • 3,648
  • 1
  • 22
  • 35

2 Answers2

3

In your Topic model the relationship for the author should be

class Topic extends Eloquent {

    //...

    public function author() {
        return $this->belongsTo('User');
    }
}

Same goes to your Post model:

class Post extends Eloquent {

    // ...

    public function author() {
        return $this->belongsTo('User');
    }
}

It's because, in both tables topics and posts you have user_id and the user_id relates to the users table, so, think this way, each user_id in your topics and posts table belongs to user table where the corresponding field is id in the users table. In this case, both topics and posts tables are child of users table.

The Alpha
  • 143,660
  • 29
  • 287
  • 307
  • switching from "hasOne" to "belongsTo" returns the same result. Post with id 2 still has author:null and user_id:1 – R. Gulbrandsen Mar 06 '14 at 18:26
  • Make sure your both posts contains the corresponding `user_id` and try only `->with('posts.author')` once only for debugging. Also, try the reverse, `User::whereId(1)->with('posts')->get()` and check how many posts you get. – The Alpha Mar 06 '14 at 18:33
  • user_id are on both rows in the database :: with only 'posts.author' it returns the posts as shown, but with no author on the topic :: line returns user with posts: [..] with both the posts correct :: thanks for your time – R. Gulbrandsen Mar 06 '14 at 18:39
  • still no author on post(2) – R. Gulbrandsen Mar 06 '14 at 18:40
  • your questions started me on a line of thoughts. `Post::whereId(1)->with('author')->get();` returns author. `Post::whereId(2)->with('author')->get();` returns null, we're onto something – R. Gulbrandsen Mar 06 '14 at 18:42
  • Then there is no `user_id` in that post/2, at least I can think this logically. – The Alpha Mar 06 '14 at 18:44
  • Did you check the `posts` table in database ? Can you re-entry the `user_id` manually in `post` with `id` of `2` from database. Just make sure it's there. – The Alpha Mar 06 '14 at 18:47
  • yes, see my solution part in the question. was mapping issues :) thanks a lot! – R. Gulbrandsen Mar 06 '14 at 18:50
  • Oh! that was it, but you may omit both and it should work, but glad you made it :-) – The Alpha Mar 06 '14 at 18:52
2

I think you are mixing your relationships. Should it not be:

A Post belongs to a User

A Post belongs to a Topic

A User has many Post

A Topic has many Post

Table Fields

Users: id, name

Posts: id, user_id, topic_id, content

Topic: id, title, content

Models

class User extends Eloquent {
    protected $table = 'users';

    public function posts() {
        reutrn $this->hasMany('Post');
    }
}

class Topic extends Eloquent {
    protected $table = 'topics';

    public function posts() {
        return $this->hasMany('Post');
    }

}

class Post extends Eloquent {
    protected $table = 'posts';

    public function topic() {
        return $this->belongsTo('Topic');
    }

    public function author() {
        return $this->belongsTo('User', 'id');
    }
}

To get posts with author and topic:

return Post::where('topic_id', '>=', $topicId)
    ->with('topic', 'author')
    ->get();
Lucky Soni
  • 6,811
  • 3
  • 38
  • 57
  • You are right that the connection between posts and topics are missing, but I'll add it now – R. Gulbrandsen Mar 06 '14 at 17:36
  • I've added a UML diagram to make it more clear. Dont think Im mixing the relationships. A topic has title and content, and was written by someone, then it is commented on by someone, with content – R. Gulbrandsen Mar 06 '14 at 17:44