Datamapper pattern - confused

Hi,
I’m implementing my own interpretation of the datamapper pattern and have some questions about the pattern in general.

Everywhere I read about the datamapper pattern I see something like this:


<?php
$user_mapper = new UserMapper;
$user = $user_mapper->find(1)
$user->username = 'UserName';
$user_mapper->save($user);
?>

First; I cannot see any reason for not making the UserMapper a static class when you send it the $user object to save? This would accomplish the same thing in fewer lines with the same functionality and probably more efficient since we don’t have to instantiate a UserMapper object… What I mean is something like this:


<?php
$user = UserMapper::find(1)
$user->username = 'UserName';
UserMapper::save($user);
?>

Or what if I let the datamapper know about the current domainobject… Wouldn’t it be more convenient to just use $user_mapper->save(); and have the $user object already in the mapper? Since we already have to instantiate the UserMapper anyway…?


<?php
$user_mapper = new UserMapper;
$user = $user_mapper->find(1)
$user->username = 'UserName';
$user_mapper->save();
?>

I also see a lot of mappers with ‘static’ variables like relationships/properties (and their validation rules) used as regular variables with $this->_relations, when it is clearly that ALL mappers/models of that type will have the exact same relations/validations rules/properties and therefor should be static variables… or am I missing something? I feel that many PHP developers who use OOP, tries to make everything into objects just for the sake of it… I also see alot of singleton classes that clearly is singletons just because it makes them “object oriented”…

What I’m asking is basically if I’m implementing a datamapper pattern wrong if I use static variables for variables that doesn’t change between instances of the same class/mapper, and if I’m missing something if I leave out the $mapper->save($user) part (do $mapper->save() instead) and just makes the datamapper know about the $user object I’m currently editing by setting a variable $this->_domain_object within the datamapper so I don’t have to pass the $user domainobject back to the datamapper when saving…

Static or instance is orthogonal to the data mapper pattern. You can implement it either way.

First - Performance is a red herring. The time taken to instantiate an object is minuscule. Querying the database even once takes thousands times more resources. So please erase that thought from your head.

The difference between static and instance is a bit of a red herring as well. What you’re really comparing here is the difference in scope. A local variable (The first example) vs. a global variable (the second). In this case, you have achieved a global variable by the use of a static class. An alternative, but semantically equivalent variant is a singleton. Compare:


<?php
$user = UserMapper::find(1);
$user->username = 'UserName';
UserMapper::save($user);
?>

With this:


<?php
$user = UserMapper::getInstance()->find(1);
$user->username = 'UserName';
UserMapper::getInstance()->save($user);
?>

Or this variant:


<?php
$user = $GLOBALS['UserMapper']->find(1);
$user->username = 'UserName';
$GLOBALS['UserMapper']->save($user);
?>

Or even this:


<?php
$user = UserMapper()->find(1);
$user->username = 'UserName';
UserMapper()->save($user);
?>

The problem with a global variable - in whatever shape in comes - is that its scope is very wide. This makes it hard to reason about, and causes hidden dependencies and bad encapsulation. These are rather abstract problems, so they are hard to explain very concretely. They are real nonetheless.

That sounds like a very bad idea. What happens if you have to deal with more than one user object?

Thanks for a quick and thorough reply!

I know I’d have to instantiate a datamapper for each domainobject if I go for the last alternative, but even if it would produce more lines of code, it would seem more logical, well atleast I think so.

What you are basically saying is that I’m not wrong when thinking of the datamapper as a static class, since you propose 3 alternatives that are equal/very similar to using a static class?

I think the singleton pattern may be the most correct OOP solution I’m looking for, but I think I’ll have to try out different implementations and see which one gives me the most flexibility without sacrificing the right ‘feel’…

Question, why don’t you have the Mapper functionality in the actual User object?


<?php
$user = new User(1);
$user->username = 'UserName';
$user->save();
?>

What’s bad with that approach?

I tend to use what I call a Session (probably badly named) object, which contains mapping between classes, and their mappers, and deals the mapper instantiation and so on at runtime.

Something along the lines of…


class Session
{
  protected $mappers;

   protected function getMapper($object)
   {
     $className = get_class($object);
     while ($className && !isset($this->mappers[$className]))
       $className = get_parent_class($className);
     return $className ? $this->mappers[$className] : null;
   }

    function save($object)
    {
        $mapper = $this->getMapper($object);
        return $mapper->save($object);
    }
}

This frees up any need for any specific named mappers being elsewhere. Just call


$session->save($object);

Simplifies alot of mapping, I believe, particularly when objects span multiple tables (for instance when dealing with inheritance)

Check out a post by kyberfabrikken that made sense to me.

I tried not to pass any judgment. If you ask me, I strongly prefer local scope over global scope. So I would use neither of those three patterns. The point I was trying to make is that a static class is essentially a global variable - And each of those patterns basically do the same.

By which standard do you measure correctness? OOP is not about following a set of prescribed rules. It’s not an old testament religion. That aside, I would never use a singleton because 1) it’s a global variable (And I try to avoid those) and 2) there are better ways to create global variables in php (re. the patterns I showed above). But if it makes sense to you, then by all means go ahead.

I’m not using objective criteria when I measure correctness… I just base it on feel, and I just don’t get the feel that it is “correct” to instantiate a mapper and treat it like a static class when you have to pass the domainobject around…

If the mapper was aware of the domainobject, it would make sense to use the mapper like it is used in every other implementation (so I could use $mapper->save()). It just feels wrong to instantiate the mapper and use the methods within the mapper as just a set of functions ($mapper->find(1), $mapper->findByName(‘Ole’) etc… which all just returns a domainobject without knowing about it).

I’m not saying your wrong and I’m right, I’m just trying to make you understand how I think about it so you can convince me that I’m totally wrong with my perception of how the mapper should work… :slight_smile:

I’ve tried using a static class as the mapper, but since I’m currently limited to php 5.2, I’m starting to dislike the static class implementation… (I’m setting up relationships by instantiating the required domainobject on demand, and the mapper to use has to be dynamically called. $mapper::find(1) would have been so nice instead of the call_user_func solution I have to use… I’m thinking about letting it go and just do it the regular “wrong” way just to be able to use $mapper->find(1) :p). And addition to that limitation (which can be overcome) I’ve stumbled upon the problem with self:: binding to my parent mapper… which I don’t like at all, it may actually seem like I would be better of by spending some time to get php 5.3 going on freebsd or just use a regular class… or… use a singleton…

I don’t think I fully understand the global variable problem by using static classes/singletons… Can’t you access a mapper globally even if it is just a regular object? You can just instantiate it wherever you need it anyway? Or are you talking about that specific “instance” which you will be able to access globally when using static classes/singletons, but will not by using regular objects?

Either way, the mapper doesn’t do anything fancy, it is basically just some functions that return something based on what you give them… And it doesn’t matter if you have instance x or instance y of the mapper since they are all exactly the same. Can it be that I’m thinking like this because my mapper currently doesn’t do anything fancy, and the other mappers around actually do something useful that requires them to be regular objects ?

I must admit that the prettiest solution (IMO) is actually using regular objects, but it seems wrong in my head…

Thanks for your all your answers! :slight_smile:

This was something I struggled to grasp at first too. The biggest problem is that really, you’d need to do:


$user = new User($db, 1);

Which means the user object is tied to the database I/O. With $mapper->save(); you can leave the model unchanged but substitute the mapper… For example, you may want to create an audit trail when the user’s password or username is updated… but if they’re just updating profile information not write to the log. With DataMapper you can have two variants, one which creates the audit trail and one which doesn’t.
The only way to do this with ActiveRecord ($user->save()) is to add parameters to the save function on a model by model basis… which gets very messy very quickly.

edit: My current WIP implementation works like this:


$user = $this->mapper->user[123];
$user->firstName = 'Tom';
$this->mapper->save($user);

By implementing ArrayAccess and Countable I treat the mapper as if it were an array with complete access to the table.

It caches the fetched results so you can do something like:


$this->mapper->user[123]->firstName = 'Tom';
$this->mapper->user[123]->website = 'http://r.je';
$this->mapper->user->save($this->mapper->user[123]); // OR $this->mapper->user->save(123);

Though it was PoC more than anything, not sure how much of a good idea it is really. I also implemented an autosave feature, which runs in a register_shutdown_function() and saves any fetched and modified users (or whatever table(s) you’re dealing with) but imho, it was a nice idea but create’s too many unknowns in what the code is doing.

Heh, I shouldn’t post after 2AM, as realised that left out the key point of having the session in the first place.

It gets passed as an argument to the various mappers, so any related objects can get persisted with $session->save($relatedObject); too. Allowing cascaded updates/deletes.

I like that a lot, but can you load data through your “Session” object too?

Yeah. Though tend to be hand written methods for specific job, as I have a dislike for dynamically generated SQL.

Also has to deal with transactions, so end up with as want to remain ignorant of what the actually mapper does, it could perform several dml queries, just persisting one object (for instance spans multiple tables) or cascading related objects.


$session->beginTransaction();
try
{
   $session->save($object);
   $session->commit();
}
catch (Exception $e)
{
   $session->abort();
   throw $e;
}

I see, I thought that was a problem also, but after making a ton of websites, from 3 page sites to sites dealing with billions of records, I noticed that you will ALWAYS work with just one database object.

At first, I used to have my DB objects like you, but when optimization came, and had to move objects from one database to another, there was a TON of code to update.

Even if you have a master/slave setup, or get data from 15 different servers depending on what object your loading, you will never need more than one DB object.

So I made it static (singleton functionality, but with less typing / harder to unit test).


# Var loaded from a configuration file
$dbLink = array (
    'user' => '',
    'password' => '',
    'host' => '',
    'link' => 'default',
    'methods' => array('insert', 'update', 'delete'),  # This is a master server
  );
DB::connect($dbLink);

class User extends abstractDTO {
  private $conf = array (
      'dbLink' => 'default',   # What DB link to use.
      'cacheLink' => 'default',   # What cache link to use.
      'fields' => ...
      ...
    );
}

Each object (ex: User) is linked to the DB link, so when it interacts with the database, it can chose the correct connection.

The reason I ended up moving the object functionality into the actual object (witch used to be a DTO, but now it’s the data mapper & DTO in one) was because maintenance was easier with the two in one.

I worked in Java more than a year on a big project (alongside 11 big-shot developers), and we started with a very similar setup like yours here. It worked great for a few months, until the boss had a few ideas, and we had to re-factor some code. Once we started to re-factor the DTOs, we had to re-factor the mappers, to keep them clear (UserMapper deals with the User object, and so on), and that turned into a nightmare.

Eventually, programmers stopped re-factoring the mappers, and we ended up with ListMapper that returns a list of User objects, UserMapper that could return list of UserProperties and so on. Eventually, we created a mapper wrapper, so we can call any object through it (it would find the object type and call it’s mapper, returning the results), but that didn’t quite work either because there are always exceptions.

Basically, it was very hard to find out where is what, a problem that it’s hard to have if your object’s functionality is in that object.

I’ve never found separate data sources an issue either… and I didn’t mention that as a reason that DataMapper is better although it is a reason, like you it’s rarely an issue.

You may want to rean an XML file from an external source…

DataMapper makes this easy:


//I'll use "User" to be consistent with previous examples:
$user = $this->mapper->userXml->findById(123);

//The beauty of this, is that $user can now be saved to your DB with the standard mapper..

$this->mapper->user->save($user);

//Or the other way around to write the $user object to XML with whatever specific implementation details you like.

Though for me that’s a very small advantage.

What I said above is more relevant to me, being able to specifically switch mappers for certain parts of the system.

A good example is permissions.

For non-admins you may wish to always use “AND deleted= 0”, but admins might need to see all records. By doing this in the mapper, it allows a much cleaner approach:


$mapper = $this->mapper->getMapper('blogs'); 
//$this->mapper is a factory, which has knowledge of the currently logged in user. Either it creates "BlogMapper" and sets a flag, or it creates "AdminBlogMapper" or "BlogMapper".
$blogs = $mapper->findByDate(new DateTime('2010-02-22));

This gives a consistent approach and removes the need for extra logic at the controller level.

Of course most of the time this kind of thing is better done by filtering out the unwanted records in the view… but there are times when you do need to deal with stricter result sets throughout the application. (e.g. when you’re aggregating the data. You don’t want to have to loop through everything to do a simple count($results); )