3

I got the models Post and Category. A Post is assigned to a Category. A Category has many Posts. They should be stored in a database. I implemented the following classes for it:

Models/Post.php:

class Post {
    /**
     * Title of the post.
     *
     * @var string
     */
    public $title;

    /**
     * The category that is assigned to the post.
     *
     * @var Category
     */
    public $category;

    public function __construct($title, Category $category) {
        $this->title = $title;
        $this->category = $category;
    }
}

Models/Category.php:

class Category {
    /**
     * Name of the category.
     *
     * @var string
     */
    public $name;

    /**
     * Posts that are assigned to this category.
     *
     * @var Post[]
     */
    public $posts;

    public function __construct($name, array $posts) {
        $this->name = $name;
        $this->posts = $posts;
    }
}

When I want to display a post, I will fetch it via an ID from a database. But what about the category? When I want to get the name of the category (to display it in the meta informations below the post) I have to fetch all posts that belongs to this category.

So my questions is: Is it better to store the IDs of the posts in Category::$posts instead the entire objects?

  • Cyclical relationships like this are generally a code smell (hint: it smells like sweaty socks). Either sever that relationship entirely, or provide a different way to retrieve posts belonging to a category outside of that class. – user22815 Jul 13 '15 at 12:47
  • @Snowman: To resolve the cycle I have to remove Category::$posts. Would it be a good idea to write a class Mapper\Category that has a method like getPostsOf($id) where $id is the ID of the category in the database? In this method I would run through the posts and fetch that ones that category_id matches the $id. – ihmels Jul 13 '15 at 13:24
1

If I have understood your question correctly I cannot see the problem. With posts and categories are stored separately in the database the relationship between them should be stored inside a junction table. Then when you fetch a post by its ID you can lookup the corresponding category inside the junction table. An example:

Categories table columns:

  • id
  • name
  • description

Posts table columns:

  • id
  • title
  • contents

Junction table columns

  • category_id
  • post_id

Both columns inside the junction table are foreign keys of their respective table columns. So lets say you fetch post with an ID of 123. You then lookup the database row in the junction table where the column post_id equals 123. You now have the specific category ID and can now fetch only its specific details.

I hope this can help you, happy coding!

  • Yes, I also would do it like this, but e.g. I only want the name of the category. So I have to instantiate a Category object and because that object holds posts I also have to instantiate many Post objects. – ihmels Jul 13 '15 at 13:02
  • Ah okay. Then I would create a new class called something like MetaCategory. This should only store minimum information. You could then extend your current category from this to avoid code duplication. Or you could just pass en empty array of posts. – AnotherGuy Jul 13 '15 at 14:13
  • Will a Post have more than one Category assigned to it? – JeffO Jul 13 '15 at 20:56
  • With a junction table you can have a 1:many and many:many relationship. The deciding factor is whether the same post ID appears with different category IDs. – AnotherGuy Jul 13 '15 at 21:49
1

From what I see, you have designed your models in such a way that you can't have a category without posts.

You have multiple ways of solving this, I will cover a couple.

1. Utilize Inheritance and have 2 category objects.

Have 2 category classes. BaseCategory and CategoryWithPosts inheriting from BaseCategory. Unless you need all posts in your category object, instantiate BaseCategory. In the constructor for CategoryWithPosts load your posts.

2. Have the posts lazy loaded.

Supply an instance of PostService to your category class upon instantiation and expose a method named GetPost(). This way you can operate on your category class as you need and when you need the posts, just call the method.

I am pretty certain you don't need posts in most of the instances of your category class.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.