Jump to content
Sign in to follow this  
NotionCommotion

Should mappers digest objects?

Recommended Posts

Until recently, my mapper methods would receive data and update the DB as applicable.

public function addSomething(array $params) {
    //update DB using $params as applicable
}
public function addParentToChild(int $parentId, int $childId) {
    //update DB using $parentId and $childId as applicable
}
public function deleteSomething(int $id) {
    //update DB using $id as applicable
}

Then I started passing an object to the mapper to add something.

public function addSomething(Something $something) {
    //update DB using $something as applicable
}

While at first it was a pain, I've since found it to be less error prone, and am doing so for other functionality.  Is this considered good practice?

public function addParentToChild(ParentObject $parentObject, ChildObject $childObject) {
    //update DB using parentObject->id and $childObject->id as applicable
}
public function deleteSomething(Something $something) {
    //update DB using $something->id as applicable
}

On a side note, what is the difference between the "mapper" and the "model".  I started using PHP with Joomla where they used a MVC architecture and included all the database update methods in the model class, and it has always seemed like the same thing.

Share this post


Link to post
Share on other sites

For a Data Mapper this is mixed. Since your mapper maps from and to the database. You would need to be able to use several types of input to get what you need.

<?php

interface UserMapper {
  function findOneById(int $id): ?User;
  function findAllById(array $id): ?UserCollection;

  function findOneByUsernameAndEmail(string $username, string $email): ?User;

  function findAllRegisteredBetween(DateTimeInterface $start, DateTimeInterface $end): ?UserCollection;
  function findAllRecentlyRegistered(DateTimeInterface $currentDate): ?UserCollection;

  function create(User $user): void;
  function createAll(UserCollection $users): void;
  
  function update(User $user): void;
  function updateAll(UserCollection $users): void;
  
  function delete(User $user): void;
  function deleteAll(UserCollection $users): void;

  function deleteOneById(int $id): void;
}

 

Share this post


Link to post
Share on other sites
2 hours ago, ignace said:

For a Data Mapper this is mixed. Since your mapper maps from and to the database. You would need to be able to use several types of input to get what you need.


<?php

interface UserMapper {
  function delete(User $user): void;
  function deleteOneById(int $id): void;
}

 

Thank you for your response ignace,

Why even have deleteOneByID() as an option?  By requiring a User object, we are assuring that the ID belongs to a user.

The old "me" would have used deleteOneByID() since it can be more efficient, but the new me isn't going to worry about that kind of thing.

Share this post


Link to post
Share on other sites
9 hours ago, NotionCommotion said:

Why even have deleteOneByID() as an option?  By requiring a User object, we are assuring that the ID belongs to a user.

Once the data is deleted the object will no longer be usable, right? Having deleteOneById saves you from spending extra resources having to pull up the User (if you didn't already have it) just so that you can delete it. But there's more.

You should have an object store set up - I don't remember the proper term, but it's a registry-esque thing that tracks all database objects in memory and prevents multiple objects from being created from the same data. Having a single object for some piece of data (eg, a User) means you can't accidentally have multiple copies and create concurrency problems, such as having $object->foo = 123 in one place and ->foo = 456 in another. That is, findOneById($int) === findOneById($int).

Given such a store, delete() and deleteOneById() would have slightly different behaviors.
- delete: If the object is still usable, mark it as unusable and perform the actual deletion. Having the concept of "usability" means a deleted User cannot later be re-saved or otherwise acted upon.
- deleteOneById: If the object store has a User for this ID then delete() it, thus existing objects being used elsewhere will be automatically unusable. If the store doesn't have this object then it can perform the deletion directly.

Share this post


Link to post
Share on other sites

What requinix said, and to reduce unnecessary: querying, hydrating, etc.. for what is essentially throwing something into the bin. 

And it still allows your mapper to fire off any associated events, if there would be any.

Another option would be to use a ghost copy, and drop the deleteOneById. But that depends on how you architect your software.

Since a DELETE is the opposite of a SELECT. You can create any "query" methods for it:

deleteAllByCompanyName(string $companyName);

Internally they do the same thing as with the deleteOneById.  They query and store any ID's scheduled for deletion. So that any future find's would return NULL even before the database is synchronised.

Avoid any createFromArray or updateFromArray methods though, use the find methods instead.

Edited by ignace

Share this post


Link to post
Share on other sites

I have a bit to learn.  Store (I think you like the word "esque".  Had to look it up a few posts ago), mappers that fire off (who would have know they would do such?), ghost copy (sounds scary), and the like.  That being said, most of it is starting to make sense just by doing (except for those damn ghosts!).  Would it be wrong to think that why it seems so foreign to me is that I am not using a proper ORM like Doctrine?  Just grasping for excuses...

One question.  Why should I avoid any createFromArray or updateFromArray methods?

Share this post


Link to post
Share on other sites

Events are a good way to extend your code without adding unnecessary dependencies.

A ghost copy is a class with only it's ID filled in.

Personally I avoid writing things that have been written before and rather build upon them. In the long run of an application you get burned by the "not invented here" syndrome. I have seen it over and over, and over again.

Share this post


Link to post
Share on other sites
28 minutes ago, ignace said:

Personally I avoid writing things that have been written before and rather build upon them. In the long run of an application you get burned by the "not invented here" syndrome. I have seen it over and over, and over again.

Maybe so, but sometimes you need to do it the hard way to appreciate what you have.  I still remember wood shop when we had to sand our first project by hand before being able to use power sanders.

Share this post


Link to post
Share on other sites

And after you started using the power sander, how often have you done it by hand since?

And if given the chance to do it by hand, would you still do it?

Regardless of the fact that these are apples and oranges. If done by hand or machine delivers about the same end-product. Regardless with which you started or ended. You can start by hand, go to the machine, and finish by hand. Also the work still has to be done, to get the final product.

This is not the case in software development. You would basically pick up an already sanded object of any length and any given size in an infinite supply. 

Share this post


Link to post
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Restore formatting

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

Sign in to follow this  

×
×
  • Create New...

Important Information

We have placed cookies on your device to help make this website better. You can adjust your cookie settings, otherwise we'll assume you're okay to continue.