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 veronderstel dat de PDO "commando's" nu in de DatabaseStorage moeten en dat we die classe dan aanspreken in de Mappers zodat als we overschakelen op Mysqli dan we alleen de DatabaseStorage moeten aanpassen klopt?

Kijk daar komt de OO denkende jasper voorbij gelopen! Dit heb je helemaal gelijk met als enige punt dat ik niet de DatabaseStorage zal aanpassen, maar gewoon een nieuwe klasse zou schrijven bijv. MySQLiDatabaseStorage. Je kan die PDODatabaseStorage altijd nog een keer gebruiken.

Merk overigens op dat de DatabaseStorage nog iets moet doen: verbinding maken met de db.

Hoe zit dat nu bij de SessionStorage? Deze Class vervangt mijn class Session niet? Hoe zit dat nu concreet hoe moet ik de methode create bezien? Kan ik een volledig User Object in een Sessie steken? Nee dit moet zeker een int / string ofzo worden waarmee ik de User terug kan ophalen?

Lekker veel vragen:
2) Ja, dat klopt
3) Je kan hem zien zoals ik in het voorbeeld liet zien
4) Dit is de optie die ik liet zien
5) Dit kan je ook doen, is denk ik wat beter.

ik snap je manier van werken maar ik denk dat de methode van wouter abstracter is en dus dichter tegen het doel van OOP programmeren aanleunt dat jouw methode of zie ik dat verkeerd?

Er zijn meerdere wegen naar Rome. Vooral voor het opslaan van gegevens kent OOP vele manieren, tom en ik leggen de manier uit die wij het best vinden, maar er zijn er nog veel meer (zoals ActiveRecord, ORMs, ect.).
Hmm oke, ik ben half mee... Ik snap dat de Mapper geen PDO commando's mag hebben omdat we dan niet makkelijk op een andere engine kunnen overstappen maar wat moet er dan in de Mapper?

Kan je als voorbeeld de methode create van de UserMapper geven? Ik veronderstel dat die een Object User binnen krijgt maar ik weet niet goed wat die moet returnen..
Op de eerste alinea: Ja

Kan je als voorbeeld de methode create van de UserMapper geven? Ik veronderstel dat die een Object User binnen krijgt maar ik weet niet goed wat die moet returnen..

<?php
class User
{
private $id = 0;
private $name;
// ...

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

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

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

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

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

class UserMapper implements DataMapperInterface
{
private $storage;

public function __construct(StorageInterface $storage)
{
$this->setStorage($storage);
}

protected function setStorage(StorageInterface $storage)
{
$this->storage = $storage;
}

protected function getStorage()
{
return $this->storage;
}

public function create(User $user)
{
$this->getStorage()->create('user', array(
'name' => $user->getName(),
));

$user->setId($this->getStorage()->getLastId());

return $user;
}
}
?>
Oke mooi ik ben mee denk ik!

Als ik een nieuwe User wil maken is de code zo dus:
<?php

// User Object aanmaken
$user = new User('Jasper');
$user->setEmail('[email protected]');
$user->setPassword();

// Steek in de database
$pdo = new PDO(...);
$pdoStorage = new PDODatabaseStorage($pdo);
$userMapper = new UserMapper($pdoStorage);
$userMapper->create($user);

?>

Dan even concreet op de PDODatabaseStorage()
Die krijgt twee parameters binnen 'user' een een array. Ik veronderstel dat user naar de tabel in de database verwijst en de array naar de velden en de values verwijst?

Als ik tot nu toe nog correct aan het denken ben dan zit ik nu met een praktische vraag.
De parameter 'user' op de juiste plek te zetten zal nog wel lukken maar ik zit daar met een array die de velden als key hebben en de value als value. Hoe krijg ik die in mijn query? Heeft PDO daar een functie voor of moet ik de array uitlezen met een foreach?
Je bent nog goed aan het denken. Straks ga je ook nog andere methods maken als save, dan heb je iets als:
<?php
$user = new User('Jasper');
$user->setEmail('[email protected]');

$userMapper = ...;
$userMapper->create($user);

$user->setEmail('[email protected]');
$userMapper->save($user);
?>

Je ga merken dat het een beetje onpraktisch wordt om een UserMapper aan te maken:
<?php
$pdo = new PDO(...);
$pdoStorage = new PDODatabaseStorag($pdo);
$userMapper = new UserMapper($pdoStorage);
?>

Daarom ga je straks werken met een Service container:
<?php
$container = new Container();

$container->set('storage.database.adapter', 'PDODatabaseStorage');
$container->set('storage.database.connection', function($c) {
return new PDO(...);
});
$container->set('storage.database', function($c) {
return new $c->get('storage.database.adapter')($c->get('storage.database.connection'));
});

$container->set('mapper.storage', 'storage.database');
$container->set('mapper.user', function($c) {
return new UserMapper($c->get('mapper.storage'));
});

// in gebruik
$userMapper = $container->get('mapper.user');
$userMapper->create($user);
?>

Maar daar zullen we straks naar kijken, eerst even de storage klassen:

Hoe krijg ik die in mijn query? Heeft PDO daar een functie voor of moet ik de array uitlezen met een foreach?

Ik zou het zoiets doen:
<?php
class PDODatabaseStorage extends DatabaseStorage
{
// ...

public function create($table, array $fields)
{
$fieldNames = array_keys($fields);
$query = sprintf(
'INSERT INTO %s(%s) VALUES (',
$table,
implode(', ', $fieldNames)
);

foreach ($fields as $field) {
$query .= $field.',';
}
$query = substr($query, 0, -1).');';

// $query is nu een correcte query
}
}
?>
Oke, en waarom geven we de tabel niet mee met de PDODatabaseStorage?
<?php
$pdoStorage = new PDODatabaseStorage($pdo, 'user');
?>

<?php
public function __construct(PDO $db, string $table)
{
$this->db = $db;
$this->table = $table;
}
?>

<?php
public function create(array $fields)
{
$fieldNames = implode(', ',array_keys($fields));
foreach ($fields as $field)
{
$prepare .= '? ,';
}

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

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

$i = 1;

foreach ($fields as $field)
{
$qry->bindParam($i, $field);
$i++;
}

$qry->execute();
}
?>
Omdat de PDODatabaseStorage, alle Storage klassen eigenlijk, niet 1 tabel voorstellen, maar gewoon een algemene klasse. Je kan hem dus vaker gebruiken voor verschillende velden.

Merk ook op dat we het nu als tabel gebruiken, maar dat hij met een sessie bijv. de array key kan voorstellen.
maar dat kan met mijn manier toch ook? Misschien moet ik $table dan wel vervangen door $key ofzo.

[size=xsmall]Toevoeging op 09/11/2012 09:56:21:[/size]

Mijn User class implements de StorableInterface en toch krijg ik deze error?

Fatal error: Declaration of Jds\User\UserMapper::create() must be compatible with Jds\Store\Storage\StorageInterface::create(Jds\Store\Storable\StorableInterface $object) in C:\wamp\www\login_system\lib\Jds\User\UserMapper.php on line 7


[size=xsmall]Toevoeging op 09/11/2012 10:09:12:[/size]

Hier is mijn code: https://github.com/JasperDS/login_system
Jasper, je DataMapper is geen StorageInterface. Je kijkt het nu weer verkeerd: De storage klassen en datamappers zijn 2 andere dingen. De UserMapper moet de DataMapperInterface implementeren en niet een StorageInterface.
Oke correct, maar dan zit ik toch nog altijd met het probleem dat de create() uit PDODatabaseStorage een array als parameter heeft en niet een StorableInterface?

[size=xsmall]Toevoeging op 09/11/2012 10:40:20:[/size]

<?php

namespace Jds\Store\Storage;
use \PDO;
use \Jds\Store\Storage\StorageInterface;

class PDODatabaseStorage implements StorageInterface
{
protected $db;
protected $table;

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

public function getTable()
{
return $this->table();
}


public function create(array $fields)
{
$fieldNames = implode(', ',array_keys($fields));
foreach ($fields as $field)
{
$prepare .= '? ,';
}

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

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

$i = 1;

foreach ($fields as $field)
{
$qry->bindParam($i, $field);
$i++;
}

$qry->execute();
}
}

?>

PDODatabaseStorage->create($array) kan niet want $array is geen StorableInterface $object wat de StorageInterface wel afdwingt.

Reageren