Question

I have read a lot in the past few days about domain objects, data mappers, and a bunch of other stuff I had no idea about. I have decided to try and implement this in a bit of code I am writing (partly for learning purposes, and partly because I want to create a REALLY simplified framework to build a few projects quickly...with code that I can easily understand and modify).

After reading this and this, I was planning on creating a SINGLE data mapper, with a connection to the DB inside of it, and then use a factory to pass the data mapper into every domain object (well, the ones that would need it). I include some sample code below

class data_mapper {
    private $dbh;

    function __construct() 
    {
        $this->dbh = new PDO(DB_STRING, DB_USER, DB_PASS);
    }
    public function createUser($data) ...
    public function updateUser($user_id, $data) ...
    public function createCategory($data) ...
}

class user {
    private $data_mapper;
    public $user_id;
    public $data;

    function __construct($dm) 
    {
        $this->data_mapper = $dm;
    }

    function someFunction() {
        /* some code */
        $this->data_mapper->updateUser($user_id, $data);
        /* some more code */
    }
}

class factory {    
    private $data_mapper = null;

    function __construct($dm) 
    {
        $this->data_mapper = $dm;
    }

    public function create($name)
    {
        return new $name($this->data_mapper);
    }
}
/* USAGE */
$dm = new data_mapper();
$factory = new factory($dm);
$user = $factory->create('user');

I am left with two questions:

  1. A lot of recent examples I've looked at create a different data_mapper for each model. Should I be doing this? And if I do, wouldn't that make the factory much more complex (i.e. I would need to create single PDO object and pass that into each data mapper, and then pass the right data mapper into each model)?

  2. If my above code exposes some flaw in the understanding of models, data mappers or anything else, please enlighten me (not really a question, i know)...

Was it helpful?

Solution

As far as I can tell, "data mapper" pattern implemented in modern frameworks in the form of prototype Model class, from which all application models are inherited.

In this prototype model you can implement CRUD methods and thus your models will possess it.

Speaking of passing pdo around, local scholars will tell you that you should pass PDO object as constructor parameter. But if you'll take a look at any modern framework - they are using some sort of singleton that contains a PDO instance

OTHER TIPS

So, you want a REALLY simplified PHP framework. Data mappers sound like over-engineering.

Over the years i made a few KISS frameworks in PHP, this is what i did:

  • Use templates (aka view) such as Smarty. Great for outsourcing your webdesign.
  • Make a folder named pages (aka controller). Pages are called by index.php only.
  • Make a folder named models. Only models talk with your DB.
  • Make a index.php (aka router). Has a ?page=dog parameter.

Strict MCV (aka MVC) terminology is not the holy grail, the above is a nice implementation for a simple website/app/CMS.

The parts

/pages/page_dog.inc.php A page loads the model(s) he needs, manipulates and shows it:

<?php if(!defined('YOURFRAMEWORK')){die('External access denied');}

// Page init
require './models/model_dog.inc.php';

$id = $_GET['id']; // todo fix injection attacks

$ModelDog = new ModelDog($DB);

// Page main
$ModelDog->Load($id);
echo $ModelDog->item['breed'];

For listings (a page where user selected the $id) you may not want seperate models representing each result. Make a lister class instead, much like the model but returning multiple items in one array. Its tempting to DRY and make the ListerDog class use the ModelDog but there is no readability gain just performance pain.

/index.php (aka router) calls a page (via require_once()) after auth and init ($DB):

<?php

define('YOURFRAMEWORK', 1); // disable "External access denied" error.

require_once('config.inc.php'); // todo have this hold the $config[] array.

$DB = @new mysqli( // or your derative, so you can log each query() call.
  $config['db']['host'],
  $config['db']['user'],
  $config['db']['pasw'],
  $config['db']['database']
);
if ($DB->connect_error) { die('db error: ' . mysqli_connect_errno()); }

// Load page requested by user. For now, its dog hardcoded.
require_once('./pages/page_dog.inc.php');

$DB->close;

/models/model_dog.inc.php (aka model) talks to the DB for you, processes and sanitizes data. I also use this put form processing functions.

<?php if(!defined('YOURFRAMEWORK')){die('External access denied');}

class ModelDog extends BaseModel {
  private $tablename = 'dogs';

  /**
   * Load last (or specific) item.
   * @param integer $id
   * @return boolean Returns false when failed.
   */
  public function Load($id=null) {
    $query = "SELECT * FROM `".$this->tablename."` WHERE `id`='".$this->DB->Sanitize($id)."';";
    // TODO ..  $this->item =
  }

  public function ItemDefaults() {
    return array(
      'id' => 0,
      'breed' => 'unknown',
      'height' => 0
    );
  }

  // TODO ..

}

/models/basemodel.inc.php extend every model class from something common like:

abstract class BaseModel
{
  protected $item = array(); // Here is all the data!
  protected $DB = null;

  public function __construct($aQDB) {
    parent::__construct();
    $this->DB = $aDB;
    $this->Reset();
  }

  public function Reset() {
    $this->item = ItemDefaults();
  }

  public function Item() { return $item; }

  // As seen in dog
  abstract public function Load($id);
  abstract public function ItemDefaults();

  // But descendants (models) must also implement:     
  abstract public function Save($id = NULL);
  abstract public function Delete($id);
  // You may want to add Validate() and other internal things here.
}

All of the above is a bare-minimum version of what i build myself when i need another tiny framework. You gain more in proper subclassing than making more classes doing more things. A website is a simple thing in essence, until one overcomplicates it..

The gist / TLDR;

If you really want a REALLY simplified PHP framework, dont read to much. Just write code and you'll discover what it needs to make you work better.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top