How to handle has-a relationship in data mappers?

14 Views Asked by At

I have 2 entities - blog and tag. A blog can have multiple tags.

Data mappers exist for both entities. I have a save method in the blog mapper, which takes a blog entity, validates its data, and creates a new record in the DB (or throws an exception if it can't). Part of this data validation process includes checking that the tag names associated with the blog entity actually exist, which is done like so:

foreach ($blog->getTags() as $tag_name) {
    if (!$this->tag_mapper->existsByName($tag_name)) {
        throw new BadTagNameException("No such tag with name {$tag_name}", $code = BadTagNameException::NONEXISTENT);
    }
}

The code to check if a tag exists by its name resides in the tag mapper class, so the blog mapper is currently dependent on the it to access that method and validate the blog entity's tag names. This approach seems awkward to me, as an entire other mapper needs to be constructed and passed in just for 1 method call. And since the existsByName method queries the tags table, I feel that it doesn't make sense for the blog mapper to be the one to make the SQL query.

What other approaches can I take to handle this relationship and what would their pros/cons be?

1

There are 1 best solutions below

0
Rob Conklin On

Each related entity should have its mapper passed in. This allows you to properly encapsulate SRP. You will likely be passing more in. Blogs have authors, readers, statuses, etc... If you are going to decompose and encapsulate, you will have a bunch of these mappers.

The good news is, they will be reusable if you have a consistent domain.

The alternative is, of course, to not encapsulate, and do everything in single mappers. That will work, but it will not scale to more complex mappings (are blogs the only things with tags?). If it's truly a 1-off, you can do it all in the blog mapper, but since you are explicit in saying that this is a has-a relationship, you should probably model it as such.