Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Implementing a S.O.L.I.D Domain Object Model in the following project

I have the following example in which I tend to use a couple of classes, to create a simple web app.

The file hierarchy seems like this.

> cupid 
    - libs 
        - request
        - router 
        - database
        - view 
    - bootstrap.php 
  - index.php 

The index.php just calls the bootstrap.php which in turn contains something like this:

// bootstrap.php
namespace cupid
use request, router, database, view; 

spl_autoload_register(function($class){ /* autoload */ });

$request  = new view; 
$response = new response; 
$router   = new router; 
$database = new database; 

$router->get('/blog/{id}', function($id) use ($database, $view) {

    $article = $database->select("SELECT blog, content FROM foo WHERE id = ?",[$id]); 

    $view->layout('blogPage', ['article'=>$article]);
}); 

As you can probably tell, my problem is this line:

$article = $database->select("SELECT blog, content FROM foo WHERE id = ?", [$id]); 

Which I don't want to use, and instead try a " Domain Object Model " approach.

Now, given that I will add another folder called domain, with blog.php

> cupid 
    - domain
       - Blog.php
    - libs 
        ...

And fill blog.php with properties mapping table rows, and getter and setters ..

namespace App\Domain; 

class Blog {

    private $id, $title, $content, $author; 

    public function getTitle(){
        return $this->title; 
    }           

    public function setTitle($title){
        $this->title = $title; 
    }

    ...
}

My question is: Assuming my understanding of DOM is so far correct, and that I have a CRUD/ORM class, or a PDO wrapper to query the database;

"How can I tie together, i.e. the blog model with the PDO wrapper to fetch a blog inside my bootstrap file?"..

like image 860
samayo Avatar asked Jul 17 '15 17:07

samayo


1 Answers

As far as a Domain Object you basically already have written one, your blog object. To qualify as a domain model all a class must to is to provide a representation along with any of the functionality of a concept within your problem space.

The more interesting problem here and the one you appear to be struggling with is how to persist a domain model. Keeping with the tenet of the single responsibility principle your Blog class should deal with being a blog post and doing the things that a blog post can do, not storing one. For that you would introduce the concept of a repository of blog posts that would deal with storing and retrieving objects of this type. Below is a simple implementation of how this can be done.

class BlogRepository  {
    public function __construct(\cupid\database $db){
        $this->db = $db;
    }

    public function findById($id){
        $blogData = $this->db->select("select * from blog where id = ?", [$id]);
        if ($blogData){
            return $this->createBlogFromArray($blogData);
        }
        return null;
    }
    public function findAllByTag($tag){...}
    public function save(Blog $blog) {...}
    private function createBlogFromArray(array $array){
        $blog = new Blog();
        $blog->setId($blogData["id"]);
        $blog->setTitle($blogData["title"]);
        $blog->setContent($blogData["content"]);
        $blog->setAuthor($blogData["author"]);
        return $blog;
    }
}

Then your controller should look something like this.

$router->get('/blog/{id}', function($id) use ($blogRepository, $view) {
    $article = $blogRepository->findById($id);
    if ($article) {
        $view->layout('blogPage', ['article'=>$article]);
    } else {
        $view->setError("404");
    }
}); 

To truly be SOLID the above class should be a database specific implementation of a BlogRepository interface to adhere to IoC. A factory should also probably be supplied to BlogRepository to actually create the blog objects from data retrieved from the store.

In my opinion one of the great benefits of doing this is you have a single place where you can implement and maintain all of your blog related interactions with the database.

Other Advantages to this method

  • Implementing caching for your domain objects would be trivial
  • Switching to a different data source (from flat files, blogger api, Document Database Server,PostgresSQL etc.) could be done easily.

You can alternatively use a type aware ORM for a more general solution to this same problem. Basically this Repository class is nothing more than a ORM for a single class.

The important thing here is that you are not talking directly to the database and leaving sql scattered throughout your code. This creates a maintenance nightmare and couples your code to the schema of your database.

like image 143
Orangepill Avatar answered Oct 01 '22 06:10

Orangepill