OOP in combinatie met database
ik heb hier even een klein begin gemaakt voor een blog systeem maar nu loop ik telkens tegen hezelfde probleem. Hoe kan ik mijn database hieraan toevoegen? Ik zou het graag met pdo doen omdat je daar het meeste met kan maar dan moet ik eerst de pdo class ergens vandaan halen. Ik heb al gekeken op php.net maar de start lukt me niet echt goed..
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
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
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
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
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
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
<?php
class Blog
{
protected $_db; // Ik gebruik alitjd _ voor de var als het niet een eigenschap van het object is
protected $id;
protected $title;
protected $content;
protected $reaction_ids;
// Met PDO voor $db zorgen we dat $db een instance moet zijn van PDO
public function __construct( PDO $db )
{
$this->_db = $db;
}
public function setID( $id )
{
$this->id = (int) $id;
$sQuery = "SELECT title, content, author_id FROM posts WHERE id = ".$this->id;
$stmt = $this->_db->prepare($sQuery);
$stmt->execute();
$result = current($stmt->fetchAll());
$this->title = $result['title'];
$this->content = $result['content'];
$this->author = new Author($result['author_id']); // Author is een eigen classe die user extends
}
public function getTitle()
{
return $this->title;
}
public function getContent()
{
return $this->content;
}
public function getAuthor()
{
return $this->author;
}
public function getReactionIDs()
{
if( empty($this->reaction_ids) )
{
$sQuery = "SELECT id FROM reactions WHERE post_id = ".$this->id;
$stmt = $this->_db->prepare($sQuery);
$stmt->execute;
$this->reaction_ids = Array();
while( $row = $stmt->fetch(PDO::FETCH_ASSOC) )
{
$this->reaction_ids[] = $row['id'];
}
}
return $this->reaction_ids;
}
}
?>
class Blog
{
protected $_db; // Ik gebruik alitjd _ voor de var als het niet een eigenschap van het object is
protected $id;
protected $title;
protected $content;
protected $reaction_ids;
// Met PDO voor $db zorgen we dat $db een instance moet zijn van PDO
public function __construct( PDO $db )
{
$this->_db = $db;
}
public function setID( $id )
{
$this->id = (int) $id;
$sQuery = "SELECT title, content, author_id FROM posts WHERE id = ".$this->id;
$stmt = $this->_db->prepare($sQuery);
$stmt->execute();
$result = current($stmt->fetchAll());
$this->title = $result['title'];
$this->content = $result['content'];
$this->author = new Author($result['author_id']); // Author is een eigen classe die user extends
}
public function getTitle()
{
return $this->title;
}
public function getContent()
{
return $this->content;
}
public function getAuthor()
{
return $this->author;
}
public function getReactionIDs()
{
if( empty($this->reaction_ids) )
{
$sQuery = "SELECT id FROM reactions WHERE post_id = ".$this->id;
$stmt = $this->_db->prepare($sQuery);
$stmt->execute;
$this->reaction_ids = Array();
while( $row = $stmt->fetch(PDO::FETCH_ASSOC) )
{
$this->reaction_ids[] = $row['id'];
}
}
return $this->reaction_ids;
}
}
?>
Zoiets denk ik, er kunnen fouten in zitten en ik ben nog niet heel lang bezig met OO dus er zitten misschien wat kromme denkwijzes in.
De genoemde classes zouden - in mijn ogen - alleen methods moeten hebben welke:
1. records kan registreren
2. contoles / validaties kan uitvoeren
3. eventuele output kan verifieren / beveiligen
4. eventuele specifieke berekeningen
2 en 3 zijn dan vaak instances van andere classes, anders heb je x keer de zelfde method functionaliteit in verschillende classes en dat is uiteraard niet de bedoeling
Objecten worden toch "by reference" doorgegeven; er is niet echt nood om dat object (of dus de handle, of de pointer (hoe heet zoiets in php?)) overal als property te kopiëren.
Kris Peeters op 02/01/2012 13:39:05:
In dit soort gevallen, wanneer je je db connectie via pdo doet, kan je ook eventueel een $db object als global zetten.
Objecten worden toch "by reference" doorgegeven; er is niet echt nood om dat object (of dus de handle, of de pointer (hoe heet zoiets in php?)) overal als property te kopiëren.
Objecten worden toch "by reference" doorgegeven; er is niet echt nood om dat object (of dus de handle, of de pointer (hoe heet zoiets in php?)) overal als property te kopiëren.
Dit zou ik niet doen. Ik zou er een singleton class omheen bouwen. Of misschien zelfs een registry om globale objecten te beheren.
Als we Blog even BlogPost noemen:
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
40
41
42
43
44
45
46
47
48
49
50
51
52
53
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
40
41
42
43
44
45
46
47
48
49
50
51
52
53
<?php
class BlogPostMapper
{
protected $db;
public function __construct(PDO $db)
{
$this->db = $db;
}
public function getById($id)
{
$sql = 'SELECT * FROM X WHERE id = ?';
$stmt = $this->db->prepare($sql);
$data = $stmt->execute(array($id))->fetch();
return $this->populate($data);
}
protected function populate(array $data)
{
$blogPost = new BlogPost();
$blogPost->setId($data['id']);
$blogPost->setContent($data['content']);
return $blogPost;
}
public function save(BlogPost $post)
{
$sql = 'UPDATE X SET content = :content WHERE id = :id';
$stmt = $db->prepare($sql);
$stmt->execute(array(
'content' => $post->getContent(),
'id' => $post->getId()
));
}
public function insert(BlogPost $post)
{
$sql = 'INSERT INTO X (content) VALUE (:content)';
$stmt = $db->prepare($sql);
$stmt->execute(array(
'content' => $post->getContent()
));
$post->setId((int) $this->db->lastInsertId);
return $post;
}
}
?>
class BlogPostMapper
{
protected $db;
public function __construct(PDO $db)
{
$this->db = $db;
}
public function getById($id)
{
$sql = 'SELECT * FROM X WHERE id = ?';
$stmt = $this->db->prepare($sql);
$data = $stmt->execute(array($id))->fetch();
return $this->populate($data);
}
protected function populate(array $data)
{
$blogPost = new BlogPost();
$blogPost->setId($data['id']);
$blogPost->setContent($data['content']);
return $blogPost;
}
public function save(BlogPost $post)
{
$sql = 'UPDATE X SET content = :content WHERE id = :id';
$stmt = $db->prepare($sql);
$stmt->execute(array(
'content' => $post->getContent(),
'id' => $post->getId()
));
}
public function insert(BlogPost $post)
{
$sql = 'INSERT INTO X (content) VALUE (:content)';
$stmt = $db->prepare($sql);
$stmt->execute(array(
'content' => $post->getContent()
));
$post->setId((int) $this->db->lastInsertId);
return $post;
}
}
?>
Iets als dit stelt je in staat mooi je opslag van je daadwerkelijke object te scheiden. Enkele delen van de mapper kan je hergebruiken voor andere modellen.
Niet is global, niet static.
Mooi toch? ;)
De mapper sla je dan op in een registry of service container.
Ook kan je het op aanvraag aanmaken met een opgeslagen PDO instance.
Toevoeging op 03/01/2012 18:25:06:
Gebruik:
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
<?php
$pdo = new PDO();
$mapper = new BlogPostMapper();
$blog = new Blog();
$blog->setContent('test');
$mapper->insert($blog);
$id = $blog->getId();
// Volgende request
$pdo = new PDO();
$mapper = new BlogPostMapper();
$blog = $mapper->getById($id);
$blog->setContent('blaaa');
$mapper->save($blog);
?>
$pdo = new PDO();
$mapper = new BlogPostMapper();
$blog = new Blog();
$blog->setContent('test');
$mapper->insert($blog);
$id = $blog->getId();
// Volgende request
$pdo = new PDO();
$mapper = new BlogPostMapper();
$blog = $mapper->getById($id);
$blog->setContent('blaaa');
$mapper->save($blog);
?>
Gewijzigd op 03/01/2012 18:16:22 door Pim -
@pim, mooi systeempje. :) Telkens denk ik dat ik de object geörienteerde gedachtegang onder de knie heb maar nee.. toch niet dus. Ik zal me er nog eens verder in verdiepen.
Snap je wel elk detail van wat ik geschreven heb?
Toevoeging op 03/01/2012 19:46:06:
Nu is het trouwens een leuke uitdaging om relaties tussen objecten mogelijk te maken. Succes :)
Moet er op regel 34, 35 en 45 niet : voor de key?
En is die populate method niet een beetje zinloos? Gebruik je zoiets nou in het echt of is het alleen om even de mooiheid van een datamapper te laten zien?
[Offtopic mode]
Kun je misschien eens al dit soort begrippen (zoals datamapper en factory) eens opschrijven. Want ik kom er heel veel tegen in jou berichten, maar telkens vergeet ik ze weer. En wil ze toch gaan leren.
Gewijzigd op 03/01/2012 20:20:50 door Wouter J
Die populatie method is best handig, omdat je zo korte get*() methodes kan maken.
Bijv:
Code (php)
Als ik dezelfde code twee keer gebruik, probeer ik een manier te verzinnen om de code te hergebruiken. Zo is het maken van aanpassingen veel makkelijker.
Ik het misschien wel zo doen:
Code (php)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<?php
public function getById($id)
{
$sql = 'SELECT * FROM X WHERE id = ?';
$data = $this->fetchBySql($sql, $id);
return $this->populate($data);
}
protected function fetchBySql($sql, $identifier)
{
$stmt = $this->db->prepare($sql);
$data = $stmt->execute(array($identifier))->fetch();
if($data === false)
throw new LogicException();
return $data;
}
?>
public function getById($id)
{
$sql = 'SELECT * FROM X WHERE id = ?';
$data = $this->fetchBySql($sql, $id);
return $this->populate($data);
}
protected function fetchBySql($sql, $identifier)
{
$stmt = $this->db->prepare($sql);
$data = $stmt->execute(array($identifier))->fetch();
if($data === false)
throw new LogicException();
return $data;
}
?>
Zo kan je in drie eenvoudige regels een selector maken.
Ja misschien is het leuk als tutorial zo'n begrippenlijst te maken, maar ik heb er net al eentje gepost en heb er nu even niet veel zin in.
Er zit een Doctrine2 smaakje aan je post Pim :p ... heerlijk!
Kees Schepers op 04/01/2012 08:42:25:
Er zit een Doctrine2 smaakje aan je post Pim :p ... heerlijk!
code fetishist! :P
<off topic>
Ik zie heel veel losse topics / vragen van mensen die willen beginnen met / bezig zijn met OOP en / of (onbewust) MVC. Telkens komt Pim dan om die hoek kijken en worden er hele mooie (en in mijn ogen vernieuwende) code voorbeeldjes en bruikbare tips gegeven. Ik denk dan altijd... hé da's handig, dat moet ik ook eens op die manier gaan doen! Aangezien ik over niet al te lange tijd ga beginnen met het programmeren van m'n cms zou ik een mooie tutorial door PIM wel heel gaaf vinden! Nee, dat hoeft natuurlijk geen complete cms te zijn, maar ik zou bijvoorbeeld graag een hele simpele tutorial zien over hoe je het beste vorm kunt geven aan een MVC model, bijvoorbeeld aan de hand van een heel simpel en klein voorbeeld: een autodealer verkoopt auto's. Er moet 1 pagina komen waarop alle auto's getoond worden en 1 beheerpagina waarop de dealer een auto kan aanmaken / invoeren. Hoe werkt dit principe. Hoe voeg je een database toe aan de class die het overzicht met auto's toont. Hoe kun je het beste de auto opslaan in de database op de invoer beheerpagina? Gewoon een heel simpel en klein voorbeeld, wat je (ik en de andere leden) als voorbeeld kunt gebruiken voor je eigen MVC / OOP implementatie. Ik denk dat heel veel mensen daar baat bij zullen hebben. Dus mijn vraag aan Pim... zou jij zo'n tutorial kunnen maken? Hoeft dus absoluut geen grote tutorial te zijn. Mag heel klein zelfs. Het gaat mij (en vele anderen) erom dat duidelijk wordt hoe je het beste bepaalde (veel voorkomende zaken) kunt aanpakken. Lijkt mij super tof als je dat zou willen doen! Mochten er meer leden zijn die dit lezen en die denken... hé ik zou ook graag willen dat Pim zo'n tutorial maakt, typ hieronder dan even een berichtje met de tekst "Go Pim!" zodat we kunnen zien of meer mensen hier behoefte aan hebben.
</off topic>
Gewijzigd op 04/01/2012 09:13:03 door Ozzie PHP
Bijvoorbeeld een stukje i.c.m kohana
Code (php)
1
2
3
4
5
6
7
2
3
4
5
6
7
<?php
class Model_Contact extends Model
{
}
$contact = ORM::factory('Contact',15); //nu hebben we het contact met id 15
?>
class Model_Contact extends Model
{
}
$contact = ORM::factory('Contact',15); //nu hebben we het contact met id 15
?>
@ Ozzie
Ja misschien moet ik dat maar eens doen, eventueel samen met anderen hier die ook wat meer ervaring hebben.
Misschien in drie delen:
Micro mvc framework
Datamapper
Voorbeeldapplicatie
@tvb
Tools gebruiken, maar niet weten hoe ze werken is nooit verstandig...
Toevoeging op 04/01/2012 14:47:25:
En leest allen mijn tutorial over Dependency Injection! :-)
Pim - op 04/01/2012 14:44:49:
@tvb
Tools gebruiken, maar niet weten hoe ze werken is nooit verstandig...
Tools gebruiken, maar niet weten hoe ze werken is nooit verstandig...
Eenmalig tijd steken in het begrijpen van een tool of telkens weer tijd steken in het zelf maken. Het ligt er maar aan of je je verveelt.
Pim - op 04/01/2012 14:44:49:
@ Ozzie
Ja misschien moet ik dat maar eens doen, eventueel samen met anderen hier die ook wat meer ervaring hebben.
Misschien in drie delen:
Micro mvc framework
Datamapper
Voorbeeldapplicatie
Ja misschien moet ik dat maar eens doen, eventueel samen met anderen hier die ook wat meer ervaring hebben.
Misschien in drie delen:
Micro mvc framework
Datamapper
Voorbeeldapplicatie
dat zou fijn zijn. ;)
Gewijzigd op 04/01/2012 14:52:37 door Jasper DS
Pim... dat zou gewéééééldig zijn!!!! Als dat zou kunnen dan heel erg graag! Wat mij betreft mag je het gewoon in je eentje maken, want je legt altijd alles heel duidelijk uit. Ik zou hier in ieder geval heel erg blij mee zijn :)
@Pim Als je het gaat doen en iemand nodig hebt voor feedback. Stuur maar een pm
Mij zou het persoonlijk ook erg helpen. Ik denk dat ik de OOP gedachtegang begin te begrijpen maar om echt een app te maken.. Een duwtje in de rug kan helpen. ;)
Pim, kunnen we deze tutorial verwachten? Heb je er tijd voor?
Weer een heel erg goede tutorial.
Maar wacht dus nog even rustig af. Eventueel kan ik wel helpen. Ben helaas nog niet goed in OOP, maar heb het in korte tijd goed kunnen uitbreiden. Maar misschien meer voor het controleren en eventueel teksten begrijpbaar te maken voor de OO beginners wil ik best wel aan de slag.