I have a website written with procedural PHP and now I'm re-coding it in (at least partly) OOP style so that I can start learning it. It is a simple page displaying several learning courses (title, description, etc) from a database. The admin can add or delete anything so it has to be dynamic.
At first I ran a single line of code:
$courses=$pdo->run("SELECT id,title,description FROM courses WHERE status=1 ORDER BY id")->fetchAll(PDO::FETCH_CLASS, 'Course');
$cmax = count($courses);
and echoed e.g. $courses[3]->description but I felt like I'm doing nothing else but pretending OOP while just using a multidimensional array. Again, it would be ok for the purpose of the website but my question is, in order to get used to OOP logic, can I do it like this: I'm generating a dropdown menu with only the titles and IDs from the database, and after either is clicked, only then I'm creating the object (to get the description, date, teacher, whatever):
$obj = new Course($pdo,$userSelectedID);
echo $obj->getTitle($pdo);
$obj->showDetails($pdo); // etc
The class:
class Course {
protected $id;
protected $title;
protected $description;
public function __construct($pdo,$id) {
$this->id=$id;
}
public function getTitle($pdo) {
$this->title=$pdo->run("SELECT title FROM courses WHERE id=?",[$this->id])->fetchColumn();
return $this->title;
}
public function getDescription($pdo) {
$this->description=$pdo->run("SELECT description FROM courses WHERE id=?",[$this->id])->fetchColumn();
return $this->description;
}
public function showDetails($pdo) {
echo "<h3>".$this->getTitle($pdo)."</h3>".$this->getDescription($pdo);
}
}
Is this a wrong approach? Is it ok to run sql commands inside a class? Especially when I already had to use some DB data to generate the dropdown menu. I hope my question makes sense.
PS: I've heard passing the PDO object every time isn't the best practice but I'm not there yet to do it with the recommended instance(?)
A good approach is to create model classes for every table you have in your database.
A model contains private attributes corresponding yo your table columns, with associated getters and setters.
For your Course table:
class Course {
protected $id;
protected $title;
protected $description;
public function getId() {
return $this->id;
}
public function setId($id) {
$this->id = $id;
}
public function getTitle() {
return $this->title;
}
public function setTitle($title) {
$this->title = $title;
}
public function getDescription() {
return $this->description;
}
public function setDescription($description) {
$this->description = $description;
}
}
Then, you have the concept of Data Access Objects. You can create an abstract class that will be extended by your data access objects:
abstract class AbstractDAO {
protected $pdo;
public function __construct($pdo)
{
$this->pdo = $pdo;
}
abstract public function find($id);
abstract public function findAll();
abstract protected function buildModel($attributes);
}
For your course table:
class CourseDAO extends AbstractDAO {
public function find($id) {
$statement = $this->pdo->prepare("SELECT * FROM courses WHERE id = :id");
$statement->execute(array(':id' => $id));
$result = $statement->fetch(PDO::FETCH_ASSOC);
return $this->buildModel($result);
}
public function findAll() {
$statement = $this->pdo->prepare("SELECT * FROM courses");
$statement->execute();
$results = $statement->fetchAll(PDO::FETCH_ASSOC);
$courses = [];
foreach($results as $row)
$courses[] = $this->buildModel($row);
return $courses;
}
public function findByTitle($title)
{
...
}
public function create(Course $course)
{
...
}
protected function buildModel($attributes) {
$course = new Course();
$course->setId($attributes['id']);
$course->setTitle($attributes['title']);
$course->setDescription($attributes['description']);
return $course;
}
}
Modern frameworks do this automatically, but I think it is good to understand how it works before using powerful tools like Eloquent or Doctrine
Related
I have a controller that acquires data to pass to a view. Into this is injected (via a pimple container) a service which uses a number of domain models + business logic to create the data.
The service itself has a 'repository' class injected into it which has methods for creating data mappers and returning a domain model instance.
I'm aware that I might not have got my head around the repository concept as Martin Fowler puts it to "build another layer of abstraction over the mapping layer" & "A Repository mediates between the domain and data mapping layers, acting like an in-memory domain object collection." So I may be using this term erroneously.
service:
class InputService
{
private $repos;
public function __construct($repo) {
$this->repos = $repo;
}
public function getInitialData()
{
$product = $this->repo->getProduct();
$country = $this->repo->getCountry();
$spinalPoint = $this->repo->getPoint();
/*business logic with model instances to produce data array*/
return //array of data
}
}
repository:
class InputRepository
{
private $db;
public function __construct($db) {
$this->db = $db;
}
public function getCountry()
{
$mapper = new CountryMapper($this->db);
$country = $mapper->fetch();
return $country; //returns country object
}
// lots of other methods for returning different model objects
}
mapper:
class CountryMapper
{
private $db;
public function __construct($db) {
$this->db = $db;
}
public function fetch()
{
$data = //code to grab data from db;
$obj = new Country($data);
return $obj;
}
}
As you can see, the mappers are tightly coupled to the repository class, however I can't see a way around it.
I was wondering if there is a way to implement this repository that provides looser coupling to the data mapper classes?
In the grand scheme of things this application is fairly small and so having to update code across both wouldn't be disastrous, but you never now when thing will grow!
The db operations should be performed through adapters (MySqliAdapter, PdoAdapter, etc). So, the db connections are injected into adapters, not into the mappers. And certainly not in the repositories, because then the abstraction purpose of the repositories would be pointless.
A mapper receives adapter(s) as dependencies and can receive other mappers too.
The mappers are passed as dependencies to the repositories.
A repository name is semantically related to the domain layer names, not really to the ones of the service layer. E.g: "InputService": ok. "InputRepository": wrong. "CountryRepository": correct.
A service can receive more repositories. Or mappers, if you don't want to apply the extra layer of repositories.
In the code, the only tightly coupled structure is the Country object (entity or domain object) - dynamically created for each fetched table row. Even this could be avoided through the use of a domain objects factory, but I, personally, don't see it really necessary.
P.S: Sorry for not providing a more documented code.
Service
class InputService {
private $countryRepository;
private $productRepository;
public function __construct(CountryRepositoryInterface $countryRepository, ProductRepositoryInterface $productRepository) {
$this->countryRepository = $countryRepository;
$this->productRepository = $productRepository;
}
public function getInitialData() {
$products = $this->productRepository->findAll();
$country = $this->countryRepository->findByName('England');
//...
return // resulted data
}
}
Repository
class CountryRepository implements CountryRepositoryInterface {
private $countryMapper;
public function __construct(CountryMapperInterface $countryMapper) {
$this->countryMapper = $countryMapper;
}
public function findByPrefix($prefix) {
return $this->countryMapper->find(['prefix' => $prefix]);
}
public function findByName($name) {
return $this->countryMapper->find(['name' => $name]);
}
public function findAll() {
return $this->countryMapper->find();
}
public function store(CountryInterface $country) {
return $this->countryMapper->save($country);
}
public function remove(CountryInterface $country) {
return $this->countryMapper->delete($country);
}
}
Data mapper
class CountryMapper implements CountryMapperInterface {
private $adapter;
private $countryCollection;
public function __construct(AdapterInterface $adapter, CountryCollectionInterface $countryCollection) {
$this->adapter = $adapter;
$this->countryCollection = $countryCollection;
}
public function find(array $filter = [], $one = FALSE) {
// If $one is TRUE then add limit to sql statement, or so...
$rows = $this->adapter->find($sql, $bindings);
// If $one is TRUE return a domain object, else a domain objects list.
if ($one) {
return $this->createCountry($row[0]);
}
return $this->createCountryCollection($rows);
}
public function save(CountryInterface $country) {
if (NULL === $country->id) {
// Build the INSERT statement and the bindings array...
$this->adapter->insert($sql, $bindings);
$lastInsertId = $this->adapter->getLastInsertId();
return $this->find(['id' => $lastInsertId], true);
}
// Build the UPDATE statement and the bindings array...
$this->adapter->update($sql, $bindings);
return $this->find(['id' => $country->id], true);
}
public function delete(CountryInterface $country) {
$sql = 'DELETE FROM countries WHERE id=:id';
$bindings = [':id' => $country->id];
$rowCount = $this->adapter->delete($sql, $bindings);
return $rowCount > 0;
}
// Create a Country (domain object) from row.
public function createCountry(array $row = []) {
$country = new Country();
/*
* Iterate through the row items.
* Assign a property to Country object for each item's name/value.
*/
return $country;
}
// Create a Country[] list from rows list.
public function createCountryCollection(array $rows) {
/*
* Iterate through rows.
* Create a Country object for each row, with column names/values as properties.
* Push Country object object to collection.
* Return collection's content.
*/
return $this->countryCollection->all();
}
}
Db adapter
class PdoAdapter implements AdapterInterface {
private $connection;
public function __construct(PDO $connection) {
$this->connection = $connection;
}
public function find(string $sql, array $bindings = [], int $fetchMode = PDO::FETCH_ASSOC, $fetchArgument = NULL, array $fetchConstructorArguments = []) {
$statement = $this->connection->prepare($sql);
$statement->execute($bindings);
return $statement->fetchAll($fetchMode, $fetchArgument, $fetchConstructorArguments);
}
//...
}
Domain objects collection
class CountryCollection implements CountryCollectionInterface {
private $countries = [];
public function push(CountryInterface $country) {
$this->countries[] = $country;
return $this;
}
public function all() {
return $this->countries;
}
public function getIterator() {
return new ArrayIterator($this->countries);
}
//...
}
Domain object
class Country implements CountryInterface {
// Business logic: properties and methods...
}
You could inject the class names OR instances in the constructor:
class InputRepository
{
private $db;
protected $mappers = array();
public function __construct($db, array $mappers) {
$this->db = $db;
$this->mappers = $mappers;
}
public function getMapper($key) {
if (!isset($this->mappers[$key]) {
throw new Exception('Invalid mapper "'. $key .'"');
}
if (!$this->mappers[$key] instanceof MapperInterface) {
$this->mappers[$key] = new $this->mappers[$key]($this->db);
}
return $this->mappers[$key];
}
public function getCountry()
{
$mapper = $this->getMapper('country');
$country = $mapper->fetch();
return $country; //returns country object
}
// lots of other methods for returning different model objects
}
You would probably want to make the interface checking a bit more robust, obviously.
What I have is a product class, you can get a product via its id or its product nr. So I have created 2 constructors. The class is retrieving the product via the database and mapping the result to the class variables.
class Partnumber extends CI_Model
{
private $partNr;
private $description;
private $type;
public function __construct() {
}
public static function withId( $id ) {
$instance = new self();
$instance->loadByID( $id );
return $instance;
}
public static function withNr($partnumber) {
$instance = new self();
$instance->getIdFromPartnumber($partnumber);
return $instance;
}
protected function loadByID( $id ) {
$instance = new self();
$instance->getPartnumberFromId($id);
return $instance;
}
private function getIdFromPartnumber($partnumber){
$this->db->select("*");
$this->db->from('part_list');
$this->db->where('part_number', $partnumber);
$query = $this->db->get();
return $query->result_object();
}
//get the partnumber from an part id
private function getPartnumberFromId($partId){
$this->db->select("*");
$this->db->from('part_list');
$this->db->where('id', $partId);
$query = $this->db->get();
$this->mapToObject($query->result());
}
private function mapToObject($result){
$this->partNr = $result[0]->Part_number;
$this->description = $result[0]->Description;
$this->type = $result[0]->Type;
}
public function toJson(){
return json_encode($this->partNr);
}
}
The mapping works, (I know, I have to catch the errors). But all the values are null when I calling the toJson method.
I call it like this:
class TestController extends MX_Controller{
public function __construct(){
parent::__construct();
$this->load->model('Partnumber');
}
public function loadPage() {
$p = Partnumber::withId(1);
echo $p->toJson();
}
}
And yes, I know for sure that data is coming back, because I can print all the items in the mapping method. But why is the data gone when I acces it via toJson?
Your method withId calls loadByID which creates a new instance of your model. It does not load the data into the model that was created in withId which is returned
I'm building a small and simple PHP content management system and have chosen to adopt an MVC design pattern.
I'm struggling to grasp how my models should work in conjunction with the database.
I'd like to separate the database queries themselves, so that if we choose to change our database engine in the future, it is easy to do so.
As a basic concept, would the below proposed solution work, is there a better way of doing things what are the pitfalls with such an approach?
First, I'd have a database class to handle all MySQL specific pieces of code:
class Database
{
protected $table_name;
protected $primary_key;
private $db;
public function __construct()
{
$this->db = DatabaseFactory::getFactory()->getConnection();
}
public function query($sql)
{
$query = $this->db->prepare($sql);
$query->execute();
return $query->fetchAll();
}
public function loadSingle($id)
{
$sql = "SELECT * FROM $this->table_name WHERE $this->primary_key = $id";
return $this->query($sql);
}
public function loadAll()
{
$sql = "SELECT * FROM $this->table_name";
return $this->query($sql);
}
}
Second, I'd have a model, in this case to hold all my menu items:
class MenuItemModel
{
public $menu_name;
public $menu_url;
private $data;
public function __construct($data)
{
$this->data = $data;
$this->menu_name = $data['menu_name'];
$this->menu_url = $data['menu_url'];
}
}
Finally, I'd have a 'factory' to pull the two together:
class MenuItemModelFactory extends Database
{
public function __construct() {
$this->table_name = 'menus';
$this->primary_key = 'menu_id';
parent::__construct();
}
public function loadById($id)
{
$data = parent::loadSingle($this->table_name, $this->primary_key, $id);
return new MenuItemModel($data);
}
public function loadAll()
{
$list = array();
$data = parent::loadAll();
foreach ($data as $row) {
$list[] = new MenuItemModel($row);
}
return $list;
}
}
Your solution will work of course, but there are some flaws.
Class Database uses inside it's constructor class DatabaseFactory - it is not good. DatabaseFactory must create Database object by itself. However it okay here, because if we will look at class Database, we will see that is not a database, it is some kind of QueryObject pattern (see link for more details). So we can solve the problem here by just renaming class Database to a more suitable name.
Class MenuItemModelFactory is extending class Database - it is not good. Because we decided already, that Database is just a query object. So it must hold only methods for general querying database. And here you mixing knowledge of creating model with general database querying. Don't use inheritance. Just use instance of Database (query object) inside MenuItemModelFactory to query database. So now, you can change only instance of "Database", if you will decide to migrate to another database and will change SQL syntax. And class MenuItemModelFactory won't change because of migrating to a new relational database.
MenuItemModelFactory is not suitable naming, because factory purpose in DDD (domain-driven design) is to hide complexity of creating entities or aggregates, when they need many parameters or other objects. But here you are not hiding complexity of creating object. You don't even "creating" object, you are "loading" object from some collection.
So if we take into account all the shortcomings and correct them, we will come to this design:
class Query
{
protected $table_name;
protected $primary_key;
private $db;
public function __construct()
{
$this->db = DatabaseFactory::getFactory()->getConnection();
}
public function query($sql)
{
$query = $this->db->prepare($sql);
$query->execute();
return $query->fetchAll();
}
public function loadSingle($id)
{
$sql = "SELECT * FROM $this->table_name WHERE $this->primary_key = $id";
return $this->query($sql);
}
public function loadAll()
{
$sql = "SELECT * FROM $this->table_name";
return $this->query($sql);
}
}
class MenuItemModel
{
public $menu_name;
public $menu_url;
private $data;
public function __construct($data)
{
$this->data = $data;
$this->menu_name = $data['menu_name'];
$this->menu_url = $data['menu_url'];
}
}
class MenuItemModelDataMapper
{
public function __construct() {
$this->table_name = 'menus';
$this->primary_key = 'menu_id';
$this->query = new Query();
}
public function loadById($id)
{
$data = $this->query->loadSingle($this->table_name, $this->primary_key, $id);
return new MenuItemModel($data);
}
public function loadAll()
{
$list = array();
$data = $this->query->loadAll();
foreach ($data as $row) {
$list[] = new MenuItemModel($row);
}
return $list;
}
}
Also consider reading this:
DataMapper pattern
Repository pattern
DDD
I think code given below works fine (I am busy on learning OOP PHP and not tested these code yet) if I want to retrieve single record. What if I want to loop the record ? How to do that ? Can I use single class to retrieve single and loop record ? If yes how ?
include('class.database.php');
class News
{
protected $id;
protected $title;
protected $detail;
protected $updatedon;
protected $views;
protected $pic;
protected $cat;
protected $reporter;
function __construct ($id);
$newsdb = new Database;
$Query = "SELECT * FROM news WHERE nws_sn =".$id;
$db->query($Query);
$db->singleRecord();
$this->id = $newsdb->Record['nws_sn'];
$this->title = $newsdb->Record['nws_title'];
$this->detail = $newsdb->Record['nws_detail'];
$this->updatedon = $newsdb->Record['nws_time'];
$this->views = $newsdb->Record['nws_view'];
$this->pic = $newsdb->Record['nws_pic'];
$this->cat = $newsdb->Record['nws_cat_id'];
$this->reporter = $newsdb->Record['nws_rptr_id']
}
function getId () {
return $this->id;
}
function getTitle () {
return $this->title;
}
function getDetail () {
return $this->detail;
}
function getViews () {
return $this->views;
}
function getImage () {
return $this->pic;
}
function getTime () {
return $this->updatedon;
}
}
You want to use a constructor to initialize an internal state of your object. In your case you do too much in your constructor which also breaks "single responsibility principle". It seems that "News" is just an entity or data transfer object, so you have to initialize it from outside.
First, I would keep News just to store information received from database.
Second, I would create a static factory method inside News class so it create an actual News object and populate it with data passed to the method from outside. Alternatively, you could create a factory object to create your entity, but since the construction logic is simple enough, I thought it makes sense to keep it inside a single method.
Consider the code below:
class News
{
protected $id;
protected $title;
protected $detail;
protected $updatedon;
protected $views;
protected $pic;
protected $cat;
protected $reporter;
public static createFromRecord($record)
{
$obj = new self();
$obj->setId($record->Record['nws_sn']);
$obj->setTitle($record->Record['nws_title']);
$obj->setDetail($record->Record['nws_detail']);
$obj->setUpdateon($record->Record['nws_time']);
$obj->setViews($record->Record['nws_view']);
$obj->setPic($record->Record['nws_pic']);
$obj->setCat($record->Record['nws_cat_id']);
$obj->setReporter($record->Record['nws_rptr_id']);
return $obj;
}
function getId () {
return $this->id;
}
function getTitle () {
return $this->title;
}
function getDetail () {
return $this->detail;
}
function getViews () {
return $this->views;
}
function getImage () {
return $this->pic;
}
function getTime () {
return $this->updatedon;
}
// ... add public setters for the properties
}
...
$newsdb = new Database;
$Query = "SELECT * FROM news WHERE nws_sn =".$id;
$db->query($Query);
$record = $db->singleRecord();
$newsObject = News::createFromRecord($record);
I'm trying to use a session var and call the logged in users details through object on the page. The user has already logged in through my login object. Here are my objects:
class User {
public $userdata = array();
//instantiate The User Class
public function User(){ }
public function set($var, $value) {
$this->userdata[$var] = $value;
}
public function get($var) {
if(isset($this->userdata[$var]))
{
return $this->userdata[$var];
}
return NULL;
}
function __destruct() {
if($this->userdata){
$this->userdata;
}
}
}
class UserService {
private $db;
private $fields;
public $user;
private $session;
public function __construct() {
$this->db = new Database();
}
// //get current user by ID
public function getCurrentUser($session) {
$this->session = $session;
$query = sprintf("SELECT * FROM User WHERE idUser=%s",
$this->db->GetSQLValueString($this->session, "int"));
$result = $this->db->query($query);
if($result && $this->db->num_rows($result) > 0){
//create new user
$user = new User();
$row = $this->db->fetch_assoc($result);
//set as object
foreach($row as $key => $value) {
$user->set($key, $value);
break;
}
return $user;
//return $this->user;
}
return NULL;
}
}
On my page I've check my session var has a value which it does, so I call the object like so.
$um = new UserService();
$user = $um->getCurrentUser($_SESSION['MM_Username']);
echo $user->get('UserSurname');
however, I see no user surname on the page. I have checked with a none object query and I see a surname but as soon as its object is doesn't work.
I think the problem is here:
foreach($row as $key => $value) {
$user->set($key, $value);
break; // you should probably remove it
}
You should use unnecessary break and probably after setting for example id you stop setting another object properties (UserSurname, Name and so on).
In addition it's quite confusing that inside $_SESSION['MM_Username'] you store idUser and not UserName
Code review
Marcin Nabialek allready answered your question. That break in the foreach is. well. what is it doing there?
But, there are much more things broken in your code. So here is a code review:
Constrcutors
You obviously know what a constructor is. You use it in both classes. But, differently. why? You User class has a public function User() but your UserService has a public function __construct(). Pick one, and stick to it. And if you can choose, pick the correct one: __construct()
From the phpdoc:
As of PHP 5.3.3, methods with the same name as the last element of a namespaced class name will no longer be treated as constructor. This change doesn't affect non-namespaced classes.
So namespacing your User class will break your constructor. This may not be a problem now, but it smells. Simply use __construct(). It is the prefered and correct way to do it. We live today, and not in the past of php4- days :)
Code styling
Oh god, a lot of kittens died today!
Sometimes you have a bracket on a new line:
if (isset($this->userdata[$var]))
{
return $this->userdata[$var];
}
and sometimes you don't
if($this->userdata){
$this->userdata;
}
Again, pick something and stick to it. and if you want to save some kittens. stick to the standards: PSR-1 & PSR-2
Public atributes, jeuk
Your User class has a public var $attributes. So it is accessible from the outside world. But you also give us a get and set method. why?
A good rule is: public $var smells, protected $var should be used with caution and private $var is the good stuff.
What are your classes? and why don't you use __constructors?
If I look at the User class, I always look at the __constructor. The User class needs no variables. So I should be able to do something like this:
$me = new User();
$me->getName(); //who am I ?
This ofcourse doesn't work. A User without a name doesn't make sense. It always has one. So ask for it!
class User
{
public function __construct($name)
{
$this->name = $name;
}
}
$me = new User('jeroen');
$m->getName(); //I am jeroen :)
If you need something ask for it ;)
So:
public function __construct(Database $db)
Is the way to roll!
Don't make me read the database
Now, your get/set methods are tigthly coupled with your database. If you change the name of a column in the database. You can refractor your entire code to get('new_column_name'); . Sounds like fun!
Also, what does the method say me? Nothing, does it write easy? no
getName says what it does, it gets me the name.
get tels me i'm getting something. but what?
other questions rise: get('name') =?= get('Name')
It's ok for the User object to know what it has.
Summary
Ok, I outlined some things wrong in your code. Some concepts you should look into:
SOLID
PSR standards
Factory Pattern (this will help you with your UserService
Inversion Of Control
So, for the sake of the article, here is your code revamped. Note that I wrote it into this commentbox directly, so I could have missed some things and made some errors.
Changelist:
I cleaned up styling
I added some comments
removed _destruct() (it wasn't doing anything)
Used PDO instead of Databse class (no idea what you are using, but looks like a PDO wrapper)
changed some table names and the select query (never use * in a selct query. Onyl ask for that what you need)
used prepared statements
more flexibility
exceptions instead of returning null;
Your $DBH could be put into a singleton/factory to ease your $dbh creation: Database::getInstance(); or DatabaseFactory::getInstance()->createPDO(); or so. Long time since I wrote something like this
Usage:
$DBH = new PDO("mysql:host=$host;dbname=$dbname", $user, $pass);
$userRepository = new UserRepository($DBH);
$id = $_SESSION['MM_Username'];
try
{
$me = $userRepository->find($id);
}
catch( UserNotFoundException $e )
{
//user not found
}
print $me->getSurName();
User class:
class User
{
/**
* If the User persists in the DataBase
* $id holds it's db id
* #var int
*/
private $id;
/**
* #var String
*/
private $surName;
/**
* #var String
*/
private $firstName;
/**
* #param String $firstName
* #param String $surName
* #param int $dbId
*/
public function __construct($firstName, $surName, $dbId=null)
{
$this->id = $dbId;
$this->firstName = $surName;
$this->surName = $surName;
}
/**
* Does the user ecist in the DB?
* #return boolean
*/
public function hasId()
{
return $this->id !== null;
}
/**
* #return int
* #return null user doesn't persist in DB
*/
public function getId()
{
return $this->id;
}
/**
* Return the users full name
* The fullname consists of his FirstName and SurNAme
* #return String
*/
public function getName()
{
return $this->firstName . ' ' . $this->surName;
}
/**
* #return String
*/
public function getSurName()
{
return $this->surName;
}
/**
* #return String
*/
public function getFirstName()
{
return $this->firstName;
}
/**
* Setters: we return $this to allow chaning
*/
public function setId($id)
{
$this->id = $id;
return $this;
}
// ... other methods here. You can add extra swet stuff.
// for instance check or it is a valid firstName, or email or ...
//I removed your __destrouct, because wtf? it isn't doing anything at all
}
and your UserRepository:
/**
* The UserRepository queries the database and get's you your users
*/
class UserRepository
{
private $db;
public function __construct(PDO $db)
{
$this->db = $db;
}
public function find($id)
{
$statement = $this->db->prepare('SELECT id,first_name,sur_name FROM users WHERE id = :id');
$statement->execute(array(
'id' => $id
));
if ( null === ($user = $statement->fetch(PDO::FETCH_ASSOC)) )
{
throw new UserNotFoundException();
}
return new User(
$user['first_name'],
$user['sur_name'],
$user['id']
);
}
}
and the exception:
class UserNotFoundException extends Exception();