Zijn we weer terwijl ik werkelijk geen steek verder gekomen ben. Dat komt hoogstwaarschijnlijk omdat ik blijf denken over hoe ik nu alles het beste kan doen. Bedoel het werkt nu allemaal wel en dat is fijn, maar het is niet zoals ik wil.
Ik zou namelijk mijn data op willen slaan via bijvoorbeeld een UserMapper naar een DatabaseStorage de database in. Het klinkt allemaal romantischer dan het is, vooral het lezen. Voornamelijk omdat je zo ongelovelijk veel functies hebt. Neem bijvoorbeeld gewoon een MySql database, ik wil wel gebruik kunnen maken van een eventuele JOIN of DATE functie binnen SQL. Het schrijven en dergelijke lukt me nog wel om een array van te maken en uit te laten voeren. Ik heb alleen geen enkel idee voor de lees functie.
Wat ik nu gebruik
<?php
public function read($table, $columns, $id)
{
$columns = implode(', ', $columns);
# Query
$sql = "SELECT ".$columns." FROM ".$table;
# Als er een ID is
if( $id != NULL )
{
$sql .= " WHERE id = '".$id;
}
# Query Interpreteren en Controleren door Database
$stmt = $this->db->prepare($sql);
# Query Uitvoeren
$stmt->execute(array((int) $id));
# Result Opvangen en Retouneren d.m.v populate function
while ($result = $stmt->fetch(PDO::FETCH_ASSOC))
{
$data[] = $result;
}
return $data;
}
?>
Zoals je ziet kan ik dan alleen niet JOINEN. Moet ik het zoeken bij een multidimensionale array? Moet ik meerdere methods gaan maken welke dan bijvoorbeeld de MySql functies representeren? Waar zit jullie gedachte hierbij? Dat laatste haalt alleen ook weer functionaliteit weg lijkt mij?
Vind het lastige keuzes waar ik al tijden mee aan het stoeien ben.
Ja, dat is precies wat ik bedoel. Raad jij trouwens aan om dan ook een soort van container method te maken? Voor als je met een UserMapper zit je ook meerdere gebruikers kunt selecteren.
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.
Ik moet nu helaas op weg naar mijn andere hobby / werk dus kan niets proberen / schematisch neerknallen, maar ik ga vanavond wat proberen en de uitkomst laat ik zeker weten. Ben namelijk altijd opzoek naar verbeterpunten.
[offtopic]Iemand enig idee waarom ik continue op alle verschillende mediums opnieuw in moet loggen?[/offtopic]
[size=xsmall]Toevoeging op 10/02/2014 18:18:41:[/size]
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
<?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.';
}
?>
Class: DatabaseStorage
<?php
public function read( $sql )
{
# Query Interpreteren en Controleren door Database
$stmt = $this->db->prepare($sql);
# Query Uitvoeren
$stmt->execute();
# Result Opvangen en Retouneren
return $result = $stmt->fetch(PDO::FETCH_ASSOC);
}
?>
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...
Gek genoeg had ik dat dus in mijn code al opgemerkt en aangepast...
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
Naar mijn idee zijn er een paar dingen mis met je huidige DataMapper:
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.
Ik heb de DatabaseStorage nu buiten de DataMapper aan laten maken, maar vraag me af of ik begrijp wat je bedoeld met het aanpassen van alle DataMappers.
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
<?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;
}
?>
Class DatabaseStorage
<?php
public function read( $sql )
{
# Query Interpreteren en Controleren door Database
$stmt = $this->db->prepare($sql);
# Query Uitvoeren
$stmt->execute();
# Result Opvangen en Retouneren
while( $result = $stmt->fetch( PDO::FETCH_ASSOC ) )
{
$res[] = $result;
}
return $res;
}
?>
Inmiddels is het mij ook gelukt om data toe te voegen via de huidige gedachtegang en draait eigenlijk alles wel soepel.
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.
Nou, je begrijp er nog niet veel van (wat betreft het query verhaal). Nu moet een klasse buiten de DataMapper dus een query gaan maken. Dat betekend dat de klasse buiten de DataMapper moet weten in welke tabel het User object zich bevindt en wat voor kolommen deze tabel heeft. Dat is allemaal de taak van de DataMapper. Maak een query in de datamapper en geef die door aan de DatabaseStorage. Op die manier kun je makkelijk die DatabaseStorage veranderen in een FileStorage, door alleen de DataMapper aan te passen.