Hoi,

ik ben terug aan het programmeren geslagen en wou nog eens proberen een OOP member systeem maken. Ik heb daarvoor het dataMapper patern gebruikt dat WouterJ me eens had geleerd.

Kunnen jullie eens kijken of mijn structuur goed zit?



User_User

<?php

/* user class */

class User_User
{
	private $name;
	private $password;
	private $email;
	private $id;

	public function __construct($name, $password, $email)
	{
		$this->name = (string) $name;
		$this->password = (string) $password;
		$this->email = (string) $email;
	}

	public function setId($value)
	{
		$this->id = $value;
	}

	public function setName($value)
	{
		$this->name = $value;
	}

	public function setPassword($value)
	{
		$this->password = $value;
	}

	public function setEmail($value)
	{
		$this->email = $value;
	}

	public function getId()
	{
		return $this->id;
	}

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

	public function getPassword()
	{
		return $this->password;
	}

	public function getEmail()
	{
		return $this->email;
	}
}


?>


User_UserMapper

<?php

class User_UserMapper
{
	protected $db; // db abstractielaag

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


	/**
     * Uit de database komt een array, populate maakt van de array een User object
     */
    public function populate(array $data)
    {
        $user = new User_User($data['name'], $data['password'], $data['email']);
        $user->setId($data['id']);

        return $user;
    }

	public function getUserById($id)
	{
		$qry = $this->db->prepare("SELECT name, password, email FROM users WHERE id = ?");

        $qry->execute(array((int) $id));
        $result = $qry->fetch(PDO::FETCH_ASSOC);
        $result['id'] = (int) $id;

        return $this->populate($result);
	}

	public function getUserByPassAndEmail($email, $password)
	{
		$qry = $this->db->prepare("SELECT id, name FROM users WHERE email = ? AND password = ?");

        $qry->execute(array($email, $password));
        $result = $qry->fetch(PDO::FETCH_ASSOC);
        $result['email'] = $email;
        $result['password'] = $password;

        return $this->populate($result);
	}

    public function saveUser(User $user)
    {

    }

    public function deleteUserById($id)
    {
        
    }
}

?>


Session_Session
<?php

class Session_Session
{
public function __construct($id)
{
$_SESSION['user_id'] = $id;
}
}

?>

Public/index.php
<?php
include('../lib/autoLoader.php');

$db = new PDO('mysql:host=localhost;dbname=test', 'root', '');
$userMapper = new User_UserMapper($db);
$jasper = $userMapper->getUserByPassAndEmail('jasp.***@gmail.com', 'test123');
echo $jasper->getName(); // geeft jasper -> OK
new Session_Session($jasper->getId());
echo $_SESSION['user_id']; // geeft 1 -> OK
?>

Bedankt!
ik ben nu ook nog deze tutorial aan het volgen. Die doet ook ongeveer wat ik wil doen maar wel zonder ORM.

Als ik het goed begrijp kan ik het zo stellen:
model = domain object + datamapper
UserModel = User + UserMapper

Als ik dan in de UserMapper de storage ophaal en daar dan de functie op toepas dan kan ik vanuit de UserMapper de verschillende storage mogelijkheden ophalen toch?

<?php
class UserMapper
{
public function create(User $object)
{
$this->getStorage()->create($object);
}
}

?>

Wat ik dus wil doen is de UserMapper als laag tussen de domain objects en de Storage maken.

<?php

class PDODatabaseStorage()
{
create($object)
{

}
}

?>

Dus dan krijgt elke create function het object binnen dat moet opgeslagen worden. Het enige waar ik nog geen oplossing op weet is hoe ik het zo dynamisch mogelijk kan houden. Stel nu dat ik eerst alleen een property name in mijn User object hebt en ik wil dat nadien opsplitsen in name en lastName dan moet ik elke storage klasse aanpassen en dat is wat we niet willen doen hé?

Ben ik op deze manier al een stapje verder op de denkpiste of sta ik nog altijd op de zelfde plek en snap ik dus nog niet waarom er een ORM nodig is.

Wat is de taak van de mapper en wat is de taak van de ORM? Klopt mijn interpretatie of doen die twee zaken toch iets anders dan ik denk dat ze doen.
Hoi,

er is weer een heleboel veranderd. De UserMapper krijgt het object User binnen, die maakt er een array van en stuurt het door naar de storage die de UserMapper ook binnenkrijgt.

Mijn PDOStorage krijgt dus een array binnen bij oa de methode create(), ik heb dit in de praktijk zo uitgewerkt. Is dat efficiënt?

<?php
public function create($object, array $fields)
{
$fieldNames = implode(', ',array_keys($fields));
$prepare = '';
foreach ($fields as $key => $value)
{
$prepare .= ':'.$key .', ';

// make an array for the prepared statements
$prepared[':'.$key] = $value;
}

$prepare = substr($prepare, 0, -2);

try
{

$qry = $this->db->prepare("INSERT INTO ".$object." (" . $fieldNames . ") VALUES (".$prepare.") ");

//echo '<pre>' . print_r($fieldNames) . '</pre>';
//echo $object;

$qry->execute($prepared);
}
catch(PDOException $e)
{
echo $e->getMessage();
}

}
?>

Nu wil ik beginnen aan PDOStorage->update() Vinden jullie dat die ook alleen een array met de user gegevens moet binnen krijgen of ook een array criterium. Ik krijg het praktisch niet goed uitgewerkt.
Ik zou ook nog even $prepared = array(); neerzetten rond regel 5, maar voor de rest klopt het wel (behalve die comments dan, die kunnen nooit werken). En die exception vang je ook wel mooi op, maar je zou hem ook verder kunnen laten opborrelen.

Hoi Wouter,

bedankt voor je reactie. Wat bedoel je juist met het verder laten opborrelen van de exception?

Ik heb de functies (find - create - update) nu allemaal afzonderlijk getest en ze blijken te werken. Vind je dat het goed in een zit? Heb je nog extra tips? Het "ORM" mapje is nu niet meer nodig zeker?

Code staat op git https://github.com/JasperDS/login_system/tree/master/lib/Jds

Jasper
Hoi Wouter,

mijn createfunctie in de userMapper ziet er nu zo uit:
<?php
public function create(User $user)
{
$this->getStorage()->create('users', array('name' => $user->getName(), 'email' => $user->getEmail(), 'password' => $user->getPassword()));
}
?>

Zoals je ziet geef ik geen id mee omdat de db dit zelf doet met Auto Increment.
MAAR mijn sessionStorage die moet wel een id binnen krijgen. Moet ik het id dan toch doorgeven in mijn mapper en het er terug uitgooien in mijn PDOStorage of is er een andere optie?
Ik zou de Storage klassen iets leuks laten teruggeven, een Result klasse ofzo (of gewoon een simpel array'tje). Daar kun je dan wat data uit halen:
<?php
// ...
public function create(User $user)
{
$result = $this->getStorage()->create('users', array(
...,
));

$user->setId($result->getInsertedId());

return $user;
}
?>
Wouter,

In dat topic over de exceptions zie ik veel over de "Application-class" / controller. Ontbreekt deze niet in mijn "systeempje". Moet ik die controller zien zoals een controller bij het MVC pattern en heb ik nu slechts mijn model gemaakt?

Jij zou dus elke functie uit de Usermapper / Storage klassen een User / object laten returnen of zie ik dat verkeerd?

Wat is het voordeel dat de create functie de User terug geeft en is het wel zijn taak om dat te doen?

Bedankt voor het lezen!
Jasper

Reageren