[OOP] CRUD method's
En het mooie is, met dit design is je datamapper een repository geworden. Hij interact niet meteen met de database, maar met de layer die met de database interact: http://code.tutsplus.com/tutorials/the-repository-design-pattern--net-35804
Oh God, het beestje heeft een naampje! Ik ga kijken!
Het mooie van een UserMapper is juist dat het ook meerdere objecten kan selecteren van hetzelfde type. Een methode als findAll zal dan een array terug geven van die onjecten.
Offtopic:
Iemand enig idee waarom ik continue op alle verschillende mediums opnieuw in moet loggen?
Toevoeging op 10/02/2014 18:18:41:
Hmm na enige discussies met mijzelf ben ik hierop gekomen. Ik zat vooral met of ik nu wel of niet een extra method moest maken voor bijvoorbeeld gebruiker ophalen met het ID. Gekozen voor wel.
Class: UserMapper
Code (php)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
<?php
public function getAll( $aColumns )
{
$sColumns = implode(', ', $aColumns);
$sql = "SELECT
".$sColumns."
FROM
".$this->table;
# DatabaseStorage aanroepen
$DatabaseStorage = new DatabaseStorage($db);
# Alle ophalen
$UserData = $DatabaseStorage->read( $sql );
# User objecten maken
foreach( $UserData as $User )
{
$User = new User( $User[$aColumns[0]], $User[$aColumns[1]], $User[$aColumns[2]], $User[$aColumns[3]], $User[$aColumns[4]], $User[$aColumns[5]] );
}
return 'Gelukt? Ja of Nee.';
}
?>
public function getAll( $aColumns )
{
$sColumns = implode(', ', $aColumns);
$sql = "SELECT
".$sColumns."
FROM
".$this->table;
# DatabaseStorage aanroepen
$DatabaseStorage = new DatabaseStorage($db);
# Alle ophalen
$UserData = $DatabaseStorage->read( $sql );
# User objecten maken
foreach( $UserData as $User )
{
$User = new User( $User[$aColumns[0]], $User[$aColumns[1]], $User[$aColumns[2]], $User[$aColumns[3]], $User[$aColumns[4]], $User[$aColumns[5]] );
}
return 'Gelukt? Ja of Nee.';
}
?>
Class: DatabaseStorage
Code (php)
Aanroepen van:
Code (php)
1
2
3
4
5
6
7
2
3
4
5
6
7
# UserMapper aanroepen
$UserMapper = new UserMapper($db);
$aColumns = array ( 'username', 'password', 'name', 'email', 'phone' );
# Alle gebruikers ophalen
$User = $UserMapper->getAll($aColumns);
$UserMapper = new UserMapper($db);
$aColumns = array ( 'username', 'password', 'name', 'email', 'phone' );
# Alle gebruikers ophalen
$User = $UserMapper->getAll($aColumns);
In theorie moet dit verhaal werken, ik heb het nog niet geprobeerd, ga ik nu doen! Maar ik zit sowieso met het feit dat niet direct zie welke waardes ik waar in het User object stop. Dat kan natuurlijk ongelooflijk de verkeerde kant op gaan?
Wat erg apart is, dat hij nu bij het testen blijft zeuren over dat de variable $db niet is gedefinieerd. Punt is, dat is hij wel...
Gewijzigd op 10/02/2014 18:39:37 door Milo S
$this->db wellicht?
Inmiddels werkt het, behalve het db gebeuren, maar daar kijken we morgen wel naar. Wat ik wel ook nog wil vragen is of dat dit wat ik morgen even erbij zet iets is wat jullie zouden doen?
En foutafhandeling / bevestiging van goedkeuring hoe kun je dat het beste aanpakken. Ik zou natuurlijk een aparte ExceptionHandler bouwen waarmee ik beide dmv numerieke waardes op een gewenste manier kan tonen? Klinkt dat als wenselijk voor jullie? Of denken jullie erheel anders over
Gewijzigd op 10/02/2014 23:09:36 door Milo S
Er is maar 1 klasse (1 plek eigenlijk) in je hele code die weet hoe de user database tabel en het User object aan elkaar gekoppeld zijn. Sterker nog, er is maar 1 klasse die überhaupt weet dat het User object in een database tabel wordt opgeslagen.
De rest van de objecten weet of alleen dat er een user database tabel is en welke waardes die bevat of dat er een User object is en hoe je die gebruikt (let op, alleen een factory weet hoe je een User object aanmaakt). De grote meerderheid zou niks van de database af weten, eigenlijk weet alleen de DatabaseStorage klasse daar vanaf.
In jouw UserMapper heb je een getAll method die kolommen accepteert. Die moet dus door een ander object worden aangeroepen met de database kolommen. Nu heb jij dus een willekeurig ander object die ineens de kolommen weet en je hebt een UserMapper die die kolommen niet weet. Dat is een beetje vaag, vind je ook niet?
Deze UserMapper maakt zelf zijn DatabaseStorage klasse aan. Hier zijn 2 grote problemen mee:
- Je bent alle flexibiliteit kwijt. Wanneer je van database naar file wil veranderen moet je je klassen niet hoeven aanpassen. In jouw geval moet je alle DataMapper klassen aanpassen.
- Per DataMapper wordt er weer een nieuwe DatabaseStorage aangemaakt, 1tje zou veel beter zijn, niet?
Wat je dus doet is de Storage klasse buiten de DataMapper aanmaken en die vervolgens meegeven aan de DataMapper's constructor (ipv $db).
Dan nog een naam dingetje, ->find of ->findAll is wat gebruikelijker dan ->get en ->getAll in DataMappers. Maar dit kan natuurlijk ook volkomen persoonlijke smaak zijn.
Om dat te voorkomen moet ik dus de SQL String gewoon aanmaken bij de pagina die wordt getoont. Op deze manier gaat er een query mee naar de DataMapper getAll method zodat die daarna alles op kan vragen aan de databaseStorage.
Op deze manier kan ik heel makkelijk zeggen ik wil geen databaseStorage meer maar bijvoorbeeld txtStorage. Ik hoef dan alleen maar een andere storage classe mee te geven bij het oproepen?
Correct? Duidelijk Verwoord?
Class UserMapper
Code (php)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
<?php
public function __construct( $Storage )
{
$this->storage = $Storage;
}
public function getAll( $sql )
{
# Data opvragen uit storage
$UserData = $this->storage->read( $sql );
# Result Opvangen en in User object plaatsen
for( $i = 0; $i <= ( count( $UserData ) - 1); $i++ )
{
$User[] = new User( $UserData[$i]['id'], $UserData[$i]['username'], $UserData[$i]['name'], $UserData[$i]['phone'], $UserData[$i]['email'] );
}
# Array retouneren
return $User;
}
?>
public function __construct( $Storage )
{
$this->storage = $Storage;
}
public function getAll( $sql )
{
# Data opvragen uit storage
$UserData = $this->storage->read( $sql );
# Result Opvangen en in User object plaatsen
for( $i = 0; $i <= ( count( $UserData ) - 1); $i++ )
{
$User[] = new User( $UserData[$i]['id'], $UserData[$i]['username'], $UserData[$i]['name'], $UserData[$i]['phone'], $UserData[$i]['email'] );
}
# Array retouneren
return $User;
}
?>
Class DatabaseStorage
Code (php)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
Gewijzigd op 11/02/2014 08:57:02 door Milo S
Ik kom er alleen wel achter dat ik steeds minder methods nodig heb.
Alles wat ik nu nog heb is een save, findById, FindAll method in mijn Mappers en create, read, update en delete in mijn Storage class. En zelf daar zou eigenlijk de update weg kunnen, hij is namelijk praktisch hetzelfde als create.
Wat denken jullie ervan?
Ik ga het even op een rij zetten voordat ik weer heel enthousiast ga programmeren... Ik baseer het verhaal even op het gebruikersgedeelte. Hiermee kan ik dan het principe onder de knie krijgen om dan vervolgens de rest aan te pakken.
UserMapper
- create( $_POST )
- getAll()
- getById( $iId )
- update( $_POST )
- delete()
- populate()
In de eerste 5 methods wordt een query gemaakt. De Query wordt doorgestuurd naar de DatabaseStorage. Mocht ik dan een FileStorage willen, dan maak ik een nieuwe UserMaper of pas ik deze aan zodat hij de juiste gegevens stuurt naar de FileStorage.
In mijn getAll & getById methods roep ik een populate / factory (hoe je het ook noemen wilt) method aan om het user object aan te maken zodat ik deze uiteindelijk kan retourneren naar de pagina waarop ik het weergeven wil.
DatabaseStorage
- save( $sSql )
- read( $sSql )
- delete( $sSql )
De DatabaseStorage ontvangt de SQL code van de Usermapper. Hij voert de code uit en retourneert het naar de UserMapper.
Ik ben het alleen niet zo eens met een gescheiden save method, dus ene create en update apart. Het doet werkelijk precies hetzelfde. Vandaar dat ik er voor kies om een save method te gebruiken voor beide.
Zeg me alstublieft dat ik het dan nu eindelijk door heb...
Gewijzigd op 12/02/2014 22:31:52 door Milo S
Ja, dat klopt :) Je code voorbeeld toonde: public function getAll( $sql ) in de usermapper. Dat was dus verkeerd, wat je hierboven schreef is correct!
God dank haha! Ik heb je niet een na laatste post maar die daarvoor geloof ik wel 20 keer gelezen en ik maar niet begrijpen wat je nu bedoelde. Ben superblij dat het nu eindelijk iets gaat worden haha.