« Back to Index

S.O.L.I.D - (S)ingle Responsibility Principle

View original Gist on GitHub

1. Bad Example.php

<?php
namespace Model;

interface UserInterface
{
    public function setId($id);
    public function getId();

    public function setName($name);
    public function getName();

    public function setEmail($email);
    public function getEmail();
    public function getGravatar();

    public function findById($id);
    public function insert();
    public function update();
    public function delete();
}

////////////////////////////////////////////////////////////////////////////////////

<?php
namespace Model;

use Library\Database\DatabaseAdapterInterface;

class User implements UserInterface
{
    private $id;
    private $name;
    private $email;
    private $db;
    private $table = "users";

    public function __construct(DatabaseAdapterInterface $db) {
        $this->db = $db;
    }

    public function setId($id) {
        if ($this->id !== null) {
            throw new \BadMethodCallException("The user ID has been set already.");
        }
        
        if (!is_int($id) || $id < 1) {
            throw new \InvalidArgumentException("The user ID is invalid.");
        }
        
        $this->id = $id;
        
        return $this;
    }
    
    public function getId() {
        return $this->id;
    }
    
    public function setName($name) {
        if (strlen($name) < 2 || strlen($name) > 30) {
            throw new \InvalidArgumentException("The user name is invalid.");
        }
        
        $this->name = $name;
        
        return $this;
    }
    
    public function getName() {
        if ($this->name === null) {
            throw new \UnexpectedValueException("The user name has not been set.");
        }
        
        return $this->name;
    }

    public function setEmail($email) {
        if (!filter_var($email, FILTER_VALIDATE_EMAIL)) {
            throw new \InvalidArgumentException("The user email is invalid.");
        }
        
        $this->email = $email;
        
        return $this;
    }
    
    public function getEmail() {
        if ($this->email === null) {
            throw new \UnexpectedValueException("The user email has not been set.");
        }
        return $this->email;
    }
    
    public function getGravatar($size = 70, $default = "monsterid") {
        return "http://www.gravatar.com/avatar/" .
            md5(strtolower($this->getEmail())) .
            "?s=" . (integer) $size .
            "&d=" . urlencode($default) .
            "&r=G";
    }
    
    public function findById($id) {
        $this->db->select($this->table, ["id" => $id]);
        
        if (!$row = $this->db->fetch()) {
            return null;
        }
        
        $user = new User($this->db);
        $user->setId($row["id"])
             ->setName($row["name"])
             ->setEmail($row["email"]);
        
        return $user;
    }
    
    public function insert() {
        $this->db->insert($this->table, [
            "name"  => $this->getName(), 
            "email" => $this->getEmail()
        ]);
    }
    
    public function update() {
        $this->db->update($this->table, [
                "name"  => $this->getName(), 
                "email" => $this->getEmail()], 
            "id = {$this->id}");
    }

    public function delete() {
        $this->db->delete($this->table, "id = {$this->id}");
    }
}

2. Better Example.php

<?php
namespace Mapper;
use Model\UserInterface;

interface UserMapperInterface
{
    public function findById($id);
    public function insert(UserInterface $user);
    public function update(UserInterface $user);
    public function delete($id);
}

////////////////////////////////////////////////////////////////////////////////////

<?php
namespace Mapper;
use Library\Database\DatabaseAdapterInterface,
    Model\UserInterface,
    Model\User;

class UserMapper implements UserMapperInterface
{
    private $db;
    private $table = "users";
    
    public function __construct(DatabaseAdapterInterface $db) {
        $this->db = $db;
    }
    
    public function findById($id) {
        $this->db->select($this->table, ["id" => $id]);
        
        if (!$row = $this->db->fetch()) {
            return null;
        }
        
        return $this->loadUser($row);
    }
    
    public function insert(UserInterface $user) {
        return $this->db->insert($this->table, [
            "name"  => $user->getName(), 
            "email" => $user->getEmail()
        ]);
    }
    
    public function update(UserInterface $user) {
        return $this->db->update($this->table, [
            "name"  => $user->getName(), 
            "email" => $user->getEmail()
        ], 
        "id = {$user->getId()}");
    }
    
    public function delete($id) {
        if ($id instanceof UserInterface) {
            $id = $id->getId();
        }
        
        return $this->db->delete($this->table, "id = $id");
    }
    
    private function loadUser(array $row) {
        $user = new User($row["name"], $row["email"]);
        $user->setId($row["id"]);
        return $user;
    }
}

////////////////////////////////////////////////////////////////////////////////////

<?php
namespace Model;

interface UserInterface
{
    public function setId($id);
    public function getId();

    public function setName($name);
    public function getName();

    public function setEmail($email);
    public function getEmail();
    public function getGravatar();
}

////////////////////////////////////////////////////////////////////////////////////

<?php
namespace Model;

class User implements UserInterface
{
    private $id;
    private $name;
    private $email;

    public function __construct($name, $email) {
        $this->setName($name);
        $this->setEmail($email);
    }
    
    public function setId($id) {
        if ($this->id !== null) {
            throw new \BadMethodCallException("The user ID has been set already.");
        }
        
        if (!is_int($id) || $id < 1) {
            throw new \InvalidArgumentException("The user ID is invalid.");
        }
        
        $this->id = $id;
        
        return $this;
    }
    
    public function getId() {
        return $this->id;
    }
    
    public function setName($name) {
        if (strlen($name) < 2 || strlen($name) > 30) {
            throw new \InvalidArgumentException("The user name is invalid.");
        }
        
        $this->name = $name;
        
        return $this;
    }
    
    public function getName() {
        return $this->name;
    }

    public function setEmail($email) {
        if (!filter_var($email, FILTER_VALIDATE_EMAIL)) {
            throw new \InvalidArgumentException("The user email is invalid.");
        }
        
        $this->email = $email;
        
        return $this;
    }
    
    public function getEmail() {
        return $this->email;
    }
     
    public function getGravatar($size = 70, $default = "monsterid") {
        return "http://www.gravatar.com/avatar/" .
            md5(strtolower($this->email)) .
            "?s=" . (integer) $size .
            "&d=" . urlencode($default) .
            "&r=G";
    }
}

////////////////////////////////////////////////////////////////////////////////////

<?php
$db = new PdoAdapter("mysql:dbname=test", "myusername",
    "mypassword");
$userMapper = new UserMapper($db);

// Display user data
$user = $userMapper->findById(1);
echo $user->getName() . ' ' . $user->getEmail() .
    '<img src="' . $user->getGravatar() . '">';

// Insert a new user
$user = new User("John Doe", "john@example.com");
$userMapper->insert($user);

// Update a user
$user = $userMapper->findById(2);
$user->setName("Jack");
$userMapper->update($user);

// Delete a user    
$userMapper->delete(3);