Design Patterns - Gateway

design-patterns

http://net.tutsplus.com/tutorials/php/evolving-toward-a-persistence-layer/ - done reading

// Design Patterns - Gateway:

The Gateway stands between your Controller and your database. If your controller 
contains SQL statements, that is wrong.

This is also known as the "Table Data Gateway", is a simple pattern that offers 
the connection between the business logic and the database itself. Its main 
responsibility is to do the queries on the database and provide the retrieved 
data in a data structure typical for the programming language (like an array in 
PHP). This data is then usually filtered and modified in the PHP code so that 
we can obtain the information and variables needed to crate our objects. This 
information must then be passed to the Factories.

Here is a demonstration of the Gateway pattern and the Active Record pattern. 
The initial controller:

class BlogPostController {
  function save($data) {
    $dbhandle = new SQLite3(__DIR__ . '/Data/MyBlog');
    $query = sprintf('INSERT INTO BlogPosts VALUES ("%s","%s","%s")', 
      $data['title'], $data['content'], time());
    $dbhandle->exec($query);
  }
}

In the above code, the SQL statement is located inside the controller, which is 
wrong. The controller should contain just minimal logic that glue the view and 
the model (the data) together. Having various database code inside the controller 
make it bloated, and harder to maintain. This SQL code should be move to a 
separate file (a gateway). The Gateway can interact with various back-end 
databases.

class BlogPostController {
    private $gateway;
    function __construct(Gateway $gateway = null) {
        $this->gateway = $gateway ? : new SqlitePost();
    }
    function save($data) {
        $this->gateway->persist(new BlogPost($data['title'], 
            $data['content'], $data['timestamp']));
    }
}

In the above code, we've refactored our BlogPostController to use a gateway. 
The gateway is implemented:

require_once 'Gateway.php';

class SqlitePost implements Gateway {
    private $dbhandle;

    function __construct($dbhandle = null) {
        $this->dbhandle = $dbhandle ? : new SQLite3(__DIR__ . '/Data/MyBlog');
    }

    public function persist(BlogPost $blogPost) {
        $query = sprintf('INSERT INTO BlogPosts VALUES ("%s","%s","%s")', 
            $blogPost->title, $blogPost->content, $blogPost->timestamp);
        $this->dbhandle->exec($query);
    }

    public function findByTitle($title) {
        $SqliteResult = $this->dbhandle->query(sprintf(
            'SELECT * FROM BlogPosts WHERE title = "%s"', $title)
        );
        $blogPostAsString = $SqliteResult->fetchArray(SQLITE3_ASSOC);
        return new BlogPost($blogPostAsString['title'], 
            $blogPostAsString['content'], $blogPostAsString['timestamp']);
    }
}

With the Gateway pattern, the controller use the gateway object to save the data. 
It does not matter what the model class look like, or how the model class is 
implemented. The gateway object is not related to the model class. The gateway 
object just either save the attributes of the object to the database, or create 
the objects from the database. The model class is not aware of the gateway object. 
For each model class, we have to create a gateway class.

Going for Active Record:

class BlogPost {
    private $title;
    private $content;
    private $timestamp;

    private function __construct($title = null, $content = null, 
    $timestamp = null) {
        $this->title = $title;
        $this->content = $content;
        $this->timestamp = $timestamp;
    }

    function __get($name) {
        return $this->$name;
    }

    static function load($title = null, $content = null, $timestamp = null, 
    $gateway = null) {
        $gateway = $gateway ? : new SqlitePost();

        if(!$content) {
            $postArray = $gateway->findByTitle($title);
            if ($postArray) return new self($postArray['title'], 
                $postArray['content'], $postArray['timestamp']);
        }

        return new self($title, $content, $timestamp);
    }
}

class BlogPostController {
    function save($data) {
        $blogPost = BlogPost::load($data['title'], $data['content'], 
            $data['timestamp']);
        $blogPost->persist();
    }
    function findByTitle($title) {
        return BlogPost::load($title);
    }
}

With the Active Record pattern, the logic for loading data from the database is 
shift from the gateway class into the model class itself, and the controller 
invokes appropriate methods from the model class instead of using the gateway 
object/class directly.
Unless otherwise stated, the content of this page is licensed under Creative Commons Attribution-ShareAlike 3.0 License