OOP Database
Oh zo, hehe.
Valt volgens mij wel mee hoor, het enige wat steeds herschreven moet worden is de SQL, en dat moet eigenlijk sowieso gebeuren, zoals ik net zei. Alle andere code om met je PDO te communiceren kan je in de abstract zetten. Volgens mij kan je prima zoiets doen:
Verder is het ook zo goed als onmogelijk om met gedeeltelijke objecten te werken met een ORM. Doctrine kan het wel, maar ja, doe het maar eens na...
Valt volgens mij wel mee hoor, het enige wat steeds herschreven moet worden is de SQL, en dat moet eigenlijk sowieso gebeuren, zoals ik net zei. Alle andere code om met je PDO te communiceren kan je in de abstract zetten. Volgens mij kan je prima zoiets doen:
Code (php)
Verder is het ook zo goed als onmogelijk om met gedeeltelijke objecten te werken met een ORM. Doctrine kan het wel, maar ja, doe het maar eens na...
Gewijzigd op 02/06/2010 15:43:45 door Pim -
Datamappers maken is saai omdat al die insert- en update queries exact hetzelfde zijn. INSERT al je kolommen INTO tabel, bind al je waarden uit een array aan al die kolommen, execute, foutafhandeling. BOOORING. De select queries zijn als enige nog een beetje een uitdaging, omdat je dan nog te maken krijgt met joins e.d. Maar voor de insert- en update queries genereer ik liever de code. Kan mooi met een abstracte datamapper waar de anderen uit afgeleid zijn.
Idd, die SELECT query laten genereren als je met gelinkte objecten/tabellen/classes zit was wel behoorlijk tricky, maar het is zeker niet onmogelijk, gewoon je koppie er goed bij houden.
Straks moet ik nog de INSERT en UPDATE generators maken, maar dat zal wel vlot lopen denk ik zo..
Straks moet ik nog de INSERT en UPDATE generators maken, maar dat zal wel vlot lopen denk ik zo..
Hoezo
Is het niet handiger om je user queries ook in user te dowen?
Code (php)
1
2
3
4
5
6
7
8
9
10
11
2
3
4
5
6
7
8
9
10
11
<?php
$mapper = new Datamapper_User;
$user = $mapper->findById($id);
$mapper->save($user);
// IPV
$user = User::findById($id);
$user->save();
?>
$mapper = new Datamapper_User;
$user = $mapper->findById($id);
$mapper->save($user);
// IPV
$user = User::findById($id);
$user->save();
?>
Is het niet handiger om je user queries ook in user te dowen?
Moozzie Moozzie op 02/06/2010 16:08:50:
Is het niet handiger om je user queries ook in user te dowen?
Stel je wil apc gebruiken om je database wat minder te belasten, en resultaten van queries tijdelijk opslaan in het geheugen. Maar je site werkt op 2 hosts, en op een daarvan heb je geen APC.
Wanneer je al je data-ophalen-code in User stopt, heb je maar één mogelijkheid: de code in User volgooien met if-statements om te kijken of apc wordt ondersteund. Als je User en de data-ophaal-code scheidt, bijvoorbeeld door deze in een Datamapper achtige class te gooien, kan je gewoon een tweede datamapper maken. Host a? Gebruik dan datamapper a. Host b, gebruik dan de trage datamapper implementatie.
... dit is ook meteen een argument waarom je je datamapper niet allemaal static methods moet gaan geven.
Jelmer rrrr op 02/06/2010 16:19:03:
Stel je wil apc gebruiken om je database wat minder te belasten, en resultaten van queries tijdelijk opslaan in het geheugen. Maar je site werkt op 2 hosts, en op een daarvan heb je geen APC.
Wanneer je al je data-ophalen-code in User stopt, heb je maar één mogelijkheid: de code in User volgooien met if-statements om te kijken of apc wordt ondersteund. Als je User en de data-ophaal-code scheidt, bijvoorbeeld door deze in een Datamapper achtige class te gooien, kan je gewoon een tweede datamapper maken. Host a? Gebruik dan datamapper a. Host b, gebruik dan de trage datamapper implementatie.
... dit is ook meteen een argument waarom je je datamapper niet allemaal static methods moet gaan geven.
Moozzie Moozzie op 02/06/2010 16:08:50:
Is het niet handiger om je user queries ook in user te dowen?
Stel je wil apc gebruiken om je database wat minder te belasten, en resultaten van queries tijdelijk opslaan in het geheugen. Maar je site werkt op 2 hosts, en op een daarvan heb je geen APC.
Wanneer je al je data-ophalen-code in User stopt, heb je maar één mogelijkheid: de code in User volgooien met if-statements om te kijken of apc wordt ondersteund. Als je User en de data-ophaal-code scheidt, bijvoorbeeld door deze in een Datamapper achtige class te gooien, kan je gewoon een tweede datamapper maken. Host a? Gebruik dan datamapper a. Host b, gebruik dan de trage datamapper implementatie.
... dit is ook meteen een argument waarom je je datamapper niet allemaal static methods moet gaan geven.
Slim om te weten. Bedankt :)
Leerzame reactie's komen hierzo. Ik kreeg van iemand de tip om te werken met TDD. Ik ben nu bezig met het uitdenken van een forum. Dit is het gene wat ik al bedacht heb. Ben ik zo goed op weg?
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
26
27
28
29
30
31
32
33
34
35
36
37
38
39
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
Functionaliteiten forum
Een forum is een plaats op een website waar ingelogde gebruikers een vraag kunnen stellen die door andere ingelogde gebruiker beantwoord kunnen worden. Er zijn een aantal functie���s in het forum
- Het aanmaken van een topic
- Het aanmaken van een reactie
- Het bekijken van een topic overzicht
- Het bekijken van de reactie���s op een topic
Classes:
- forum
- users
- topic_list
- reaction
Tabellen:
Users
- user_id
- user_name
- user_password
- user_email
- user_regcode
- user_active
Topics
- topic_id
- topic_user_id
- topic_name
- topic_description
Reactions
- reaction_id
- reaction_user_id
- reaction_value
Objecten:
- forum
o topic overzicht weergeven
- reactie
o reactie weergeven
- user
o registreren
o activeren
o inloggen
o topic openen
o reactie plaatsen
Een forum is een plaats op een website waar ingelogde gebruikers een vraag kunnen stellen die door andere ingelogde gebruiker beantwoord kunnen worden. Er zijn een aantal functie���s in het forum
- Het aanmaken van een topic
- Het aanmaken van een reactie
- Het bekijken van een topic overzicht
- Het bekijken van de reactie���s op een topic
Classes:
- forum
- users
- topic_list
- reaction
Tabellen:
Users
- user_id
- user_name
- user_password
- user_email
- user_regcode
- user_active
Topics
- topic_id
- topic_user_id
- topic_name
- topic_description
Reactions
- reaction_id
- reaction_user_id
- reaction_value
Objecten:
- forum
o topic overzicht weergeven
- reactie
o reactie weergeven
- user
o registreren
o activeren
o inloggen
o topic openen
o reactie plaatsen
Gewijzigd op 02/06/2010 16:56:07 door Niels K
ik zou dit doen ongeveer:
Een klasse topiclist is mijn insziens overbodig.
Code (php)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
class forum {
array $topics;
..
}
class topic {
array $reacties;
user $user;
..
}
class reactie {
user $user;
..
}
class user {
..
}
array $topics;
..
}
class topic {
array $reacties;
user $user;
..
}
class reactie {
user $user;
..
}
class user {
..
}
Een klasse topiclist is mijn insziens overbodig.
Ok. En waar regel ik de registratie ? Het hoort bij het object user. Of misschien toch niet. Het zorgt er voor dat er een user object komt. Apparte klasse dus?
Volgens mij heb je 2 mogelijkheden wanneer je gebruik maakt van een datamapper:
1. Je vult een record, bijv. User, met de data uit je formulier, en geeft vervolgens dat object aan de mapper om het op te slaan.
2. Je geeft je mapper een nieuwe method, createUser (registerUser, whatever) welke alle informatie die nodig is om een gebruiker aan te maken als argumenten neemt. Die method voegt vervolgens de gebruiker in de database in, en geeft je een volledig gevulde instantie van User terug.
Methode 1 heeft als voordeel dat je je User object ook kan gebruiken om tijdelijk informatie in op te slaan. Als je bijvoorbeeld een form hebt, kan je bijna exact dezelfde code gebruiken voor het nieuw maken als bewerken van een User. (Nu is dat voor User niet heel erg handig, omdat aanmelden vaak iets ingewikkelder is waardoor je toch aparte code nodig hebt, maar voor bijvoorbeeld een forumpost is het wel handig)
Methode 2 heeft als voordeel dat het naar mijn mening netter is. Als je een User object hebt, dan kan je het ook overal gebruiken omdat het daadwerkelijk een bestaande user is, omdat hij alleen uit de UserMapper kan komen. Waar je bij methode 1 nog bijvoorbeeld een foutieve user kan hebben (velden leeg, of geen id) en daar dus extra voorzichtig mee moet zijn, heb je dat bij methode 2 niet. Methode 2 heeft dan weer als nadeel dat nieuw aanmaken en bewerken wat minder hetzelfde is.
1. Je vult een record, bijv. User, met de data uit je formulier, en geeft vervolgens dat object aan de mapper om het op te slaan.
2. Je geeft je mapper een nieuwe method, createUser (registerUser, whatever) welke alle informatie die nodig is om een gebruiker aan te maken als argumenten neemt. Die method voegt vervolgens de gebruiker in de database in, en geeft je een volledig gevulde instantie van User terug.
Methode 1 heeft als voordeel dat je je User object ook kan gebruiken om tijdelijk informatie in op te slaan. Als je bijvoorbeeld een form hebt, kan je bijna exact dezelfde code gebruiken voor het nieuw maken als bewerken van een User. (Nu is dat voor User niet heel erg handig, omdat aanmelden vaak iets ingewikkelder is waardoor je toch aparte code nodig hebt, maar voor bijvoorbeeld een forumpost is het wel handig)
Methode 2 heeft als voordeel dat het naar mijn mening netter is. Als je een User object hebt, dan kan je het ook overal gebruiken omdat het daadwerkelijk een bestaande user is, omdat hij alleen uit de UserMapper kan komen. Waar je bij methode 1 nog bijvoorbeeld een foutieve user kan hebben (velden leeg, of geen id) en daar dus extra voorzichtig mee moet zijn, heb je dat bij methode 2 niet. Methode 2 heeft dan weer als nadeel dat nieuw aanmaken en bewerken wat minder hetzelfde is.
Ok. Maar ik kan toch veel beter gebruik maken van het MVC? Of begrijp ik datamapper nu niet?
Hipska BE op 02/06/2010 15:26:04:
Ik toon vanavond wel eens hoe een newsarticle class er bij mij uit ziet..
Bij deze: http://phphulp.pastebin.com/kK8a7XkC
Waarbij ik na aanroep van User::findByID($db, 1); dit resultaat krijg:
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
26
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
object(News\Article)#10 (6) {
["na_id"]=>
int(1)
["title"]=>
string(13) "Nieuwsbericht"
["content"]=>
string(1001) "Fusce eu congue risus. Curabitur nisl quam, pharetra quis blandit id, viverra pulvinar justo. Aenean vehicula facilisis orci non condimentum. Cras tincidunt euismod dui, et placerat nisl ultrices volutpat. Pellentesque non turpis nec augue feugiat ornare non at turpis. Aenean vel ipsum enim, sed euismod diam. Sed mauris metus, posuere vitae egestas sit amet, vestibulum et est. Donec rutrum condimentum odio iaculis feugiat. Pellentesque erat purus, pretium eget ultrices sed, facilisis eget sapien. Vivamus vestibulum egestas bibendum. Suspendisse tempor faucibus lacus eu bibendum. Aenean quis risus tempor magna mattis aliquam id eu mauris. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Cras eget magna eget sem ornare malesuada et molestie libero. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Suspendisse potenti. Morbi lacinia feugiat tortor, sit amet ornare augue mattis eu. Praesent vitae ultrices erat."
["pubDate"]=>
object(DateTime)#11 (3) {
["date"]=>
string(19) "2010-03-13 12:56:04"
["timezone_type"]=>
int(3)
["timezone"]=>
string(15) "Europe/Brussels"
}
["URL"]=>
string(21) "2010/05/Nieuwsbericht"
["category"]=>
object(News\Category)#12 (2) {
["nc_id"]=>
int(1)
["name"]=>
string(8) "Algemeen"
}
}
["na_id"]=>
int(1)
["title"]=>
string(13) "Nieuwsbericht"
["content"]=>
string(1001) "Fusce eu congue risus. Curabitur nisl quam, pharetra quis blandit id, viverra pulvinar justo. Aenean vehicula facilisis orci non condimentum. Cras tincidunt euismod dui, et placerat nisl ultrices volutpat. Pellentesque non turpis nec augue feugiat ornare non at turpis. Aenean vel ipsum enim, sed euismod diam. Sed mauris metus, posuere vitae egestas sit amet, vestibulum et est. Donec rutrum condimentum odio iaculis feugiat. Pellentesque erat purus, pretium eget ultrices sed, facilisis eget sapien. Vivamus vestibulum egestas bibendum. Suspendisse tempor faucibus lacus eu bibendum. Aenean quis risus tempor magna mattis aliquam id eu mauris. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Cras eget magna eget sem ornare malesuada et molestie libero. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Suspendisse potenti. Morbi lacinia feugiat tortor, sit amet ornare augue mattis eu. Praesent vitae ultrices erat."
["pubDate"]=>
object(DateTime)#11 (3) {
["date"]=>
string(19) "2010-03-13 12:56:04"
["timezone_type"]=>
int(3)
["timezone"]=>
string(15) "Europe/Brussels"
}
["URL"]=>
string(21) "2010/05/Nieuwsbericht"
["category"]=>
object(News\Category)#12 (2) {
["nc_id"]=>
int(1)
["name"]=>
string(8) "Algemeen"
}
}
Edit:
F***, dat lettertype in die code blokken is niet echt handig..
En de manier om de tabellen en de velden in te stellen is gebaseerd op die van Drupal. Zie http://api.drupal.org/api/group/schemaapi/7
En de manier om de tabellen en de velden in te stellen is gebaseerd op die van Drupal. Zie http://api.drupal.org/api/group/schemaapi/7
Gewijzigd op 02/06/2010 18:35:10 door Hipska BE
Niels Kieviet op 02/06/2010 18:23:46:
Ok. Maar ik kan toch veel beter gebruik maken van het MVC? Of begrijp ik datamapper nu niet?
MVC en Datamapper sluiten elkaar niet uit, en zijn zelfs nogal aan elkaar gekoppeld. MVC bepaalt op een veel hoger niveau hoe je gehele applicatie is ingedeeld. MVC komt meer uit de desktop-applicatie wereld, en het idee is simpel gezegd gewoon dat je het model als aparte code kan zien, dat de view de applicatie is zoals de gebruiker die ervaart, en dat de controller de lijm ertussen is. Het idee is dat je het model kan hergebruiken in een windows applicatie, een mac applicatie, een webapplicatie, etc. Maar in kleine applicaties, websites, is het voornamelijk dat je de onderdelen gewoon zoveel mogelijk scheidt zodat je je beter kan focussen op één onderdeel, en zodat eigenlijk één stuk code voor die functie verantwoordelijk is. Bijvoorbeeld het vinden van een forum-avatar. Het is de functie van het model om het juiste pad/url naar dat bestand te leveren. In veel scripts die niet vanuit het MVC oogpunt zijn opgezet zie je dat als je de avatars verplaatst, je in 6, 7 bestandjes aanpassingen zit te maken. Overal waar die avatar wordt weergegeven. (zeg maar gerust gewoon beginnersscripts, want als je een beetje ervaren bent ga je onbewust al richting MVC)
Datamapper gaat over hoe je je model indeelt, dus alleen dat deel van MVC.
Ok. Duidelijke uitleg. Dus als ik echt een goed forum wil bouwen moet ik gebruik maken van MVC.. Kan je een klein voorbeeldje geven hoe jij deze applicatie zou bouwen?
Dit is een hele goede MVC tut:
http://www.phpro.org/tutorials/Model-View-Controller-MVC.html
EDIT:
Mag ik trouwens aan Hispka vragen hoe hij de lazy loading van zijn objecten regelt?
En die overschreven methode prepare is nou ook niet echt het schoolvoorbeeld van code hergebruik toch?
En is het niet mooier als je categoryName en categoryId niet expliciet hoeft te vermelden? Dus alleen:
http://www.phpro.org/tutorials/Model-View-Controller-MVC.html
EDIT:
Mag ik trouwens aan Hispka vragen hoe hij de lazy loading van zijn objecten regelt?
En die overschreven methode prepare is nou ook niet echt het schoolvoorbeeld van code hergebruik toch?
En is het niet mooier als je categoryName en categoryId niet expliciet hoeft te vermelden? Dus alleen:
Code (php)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
Gewijzigd op 03/06/2010 09:58:38 door Pim -
Even reageren op Pim,
Die prepare hoeft normaal niet herschreven te worden, maar in dit geval wel, omdat ik (of de klant) het mogelijk wou maken om een artikel voor de toekomst te schrijven en die mag dus voordien nog niet uit de DB rollen..
Hoe mijn objecten gemaakt worden zal je kunnen zien wanneer ik mijn code release, wanneer het echt af is dus, maar ik kan je al de methode bespreken:
het komt er op neer dat ik in een __set magic method telkens ga controlleren welk veld men wil setten, en dan aan de hand van die $fields definitie ga kijken of het wel een correcte waarde is.
En dan het uit de DB halen gebeurt zo:
waarbij postProcess enkel instaat voor het aanmaken van een array bij relaties waar er meerdere van in kunnen zitten..
(denk aan een array van News/Tag objecten of een User met meerder OpenID login's of mailadressen)
Die prepare hoeft normaal niet herschreven te worden, maar in dit geval wel, omdat ik (of de klant) het mogelijk wou maken om een artikel voor de toekomst te schrijven en die mag dus voordien nog niet uit de DB rollen..
Hoe mijn objecten gemaakt worden zal je kunnen zien wanneer ik mijn code release, wanneer het echt af is dus, maar ik kan je al de methode bespreken:
het komt er op neer dat ik in een __set magic method telkens ga controlleren welk veld men wil setten, en dan aan de hand van die $fields definitie ga kijken of het wel een correcte waarde is.
Code (php)
1
2
3
4
5
2
3
4
5
switch($field['type']){
case 'TINYINT': // more checks to come.. (if value < 128 e.g.)
case 'INT':
case 'BIGINT':
parent::__set($name,(int) $value);
case 'TINYINT': // more checks to come.. (if value < 128 e.g.)
case 'INT':
case 'BIGINT':
parent::__set($name,(int) $value);
En dan het uit de DB halen gebeurt zo:
Code (php)
1
2
3
4
5
6
7
8
9
10
2
3
4
5
6
7
8
9
10
// execute the query
$stmt->execute();
$results = $stmt->fetchAll(PDO::FETCH_CLASS, get_called_class() );
// do postprocessing if needed
if($needsPostProcess) $results = static::postProcess($results,$limit);
// return the result(s)
if($multi) return $results;
else return current($results);
$stmt->execute();
$results = $stmt->fetchAll(PDO::FETCH_CLASS, get_called_class() );
// do postprocessing if needed
if($needsPostProcess) $results = static::postProcess($results,$limit);
// return the result(s)
if($multi) return $results;
else return current($results);
waarbij postProcess enkel instaat voor het aanmaken van een array bij relaties waar er meerdere van in kunnen zitten..
(denk aan een array van News/Tag objecten of een User met meerder OpenID login's of mailadressen)
Ik weet niet of je van plan bent om volledig je eigen MVC framework te gaan programmeren, maar kohana is goed MVC framework om mee van start te gaan als beginner, zeker als je nog nooit in contact bent gekomen met MVC.
@Thomas R:
Gedaan, maar ik heb nu zelf een MVC gemaakt aan de hand van die TUT van PHPpro
Gedaan, maar ik heb nu zelf een MVC gemaakt aan de hand van die TUT van PHPpro




