OOP database
Ik ben nog steeds bezig met het leren van OOP, maar er is nog steeds iets dat ik niet snap.
Neem bijvoorbeeld deze code:
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
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
<?php
class Person
{
private $_prefix;
private $_givenName;
private $_familyName;
private $_suffix;
public function setPrefix($prefix)
{
$this->_prefix = $prefix;
}
public function getPrefix()
{
return $this->_prefix;
}
public function setGivenName($gn)
{
$this->_givenName = $gn;
}
public function getGivenName()
{
return $this->_givenName;
}
public function setFamilyName($fn)
{
$this->_familyName = $fn;
}
public function getFamilyName()
{
return $this->_familyName;
}
public function setSuffix($suffix)
{
$this->_suffix = $suffix;
}
public function getSuffix()
{
return $_suffix;
}
}
$person = new Person();
$person->setPrefix('Mr.');
$person->setGivenName('John');
echo $person->getPrefix() . ' ' . $person->getGivenName();
?>
class Person
{
private $_prefix;
private $_givenName;
private $_familyName;
private $_suffix;
public function setPrefix($prefix)
{
$this->_prefix = $prefix;
}
public function getPrefix()
{
return $this->_prefix;
}
public function setGivenName($gn)
{
$this->_givenName = $gn;
}
public function getGivenName()
{
return $this->_givenName;
}
public function setFamilyName($fn)
{
$this->_familyName = $fn;
}
public function getFamilyName()
{
return $this->_familyName;
}
public function setSuffix($suffix)
{
$this->_suffix = $suffix;
}
public function getSuffix()
{
return $_suffix;
}
}
$person = new Person();
$person->setPrefix('Mr.');
$person->setGivenName('John');
echo $person->getPrefix() . ' ' . $person->getGivenName();
?>
Hiermee kun je dus een 'persoon' aanmaken en aanpassen, die gegevens worden dan dus in de variabelen van de class opgeslagen.
Maar dan kun je ze alleen aanroepen op de pagina waar je dus die personen hebt aangemaakt.
Om ze overal aan te kunnen roepen kun je ze dus bijvoorbeeld opslaan in een database, maar hoe moet je dit nou precies in die class verwerken?
Moet je de variabelen die bovenaan in de class zijn weghalen en alle getters en setters een select / update query laten uitvoeren om gegevens op te halen en aan te passen?
En hoe haal je dan gegevens op van een persoon dat al bestaat?
Ik hoop dat iemand me hier antwoord op kan geven.
Alvast bedankt!
Sowieso moet je OO altijd alle verantwoordelijkheden delen, een method heeft maar 1 verantwoordelijkheid en een klasse ook. Je kunt dus niet de klasse en de gegeven vast laten houden en interactie laten hebben met de Database.
De meest gebruikte manier is om een DataMapper te gebruiken. Het eind resultaat ziet er dan zo uit:
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
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
<?php
$dbal = new PDO(...);
$personMapper = new PersonMapper($dbal);
// create
$person = new Person();
$person->setName('Kees');
$person->setAge(32);
$personMapper->create($person); // bijv. `INSERT persons (name, age) VALUES ('kees', 32)`
// read
$person = $personMapper->findById(4); // bijv. `SELECT ... FROM persons WHERE id = 4`
// update
$person->setAge(54);
$personMapper->save($person); // bijv. `UPDATE persons SET age = 54 WHERE id = ...`
// delete
$personMapper->remove($person); // bijv. `DELETE FROM persons WHERE id = ...`
?>
$dbal = new PDO(...);
$personMapper = new PersonMapper($dbal);
// create
$person = new Person();
$person->setName('Kees');
$person->setAge(32);
$personMapper->create($person); // bijv. `INSERT persons (name, age) VALUES ('kees', 32)`
// read
$person = $personMapper->findById(4); // bijv. `SELECT ... FROM persons WHERE id = 4`
// update
$person->setAge(54);
$personMapper->save($person); // bijv. `UPDATE persons SET age = 54 WHERE id = ...`
// delete
$personMapper->remove($person); // bijv. `DELETE FROM persons WHERE id = ...`
?>
Om te zien hoe dit in een klasse eruit ziet kun je eens naar 1 van deze uitleggen en code voorbeelden kijken: http://www.phphulp.nl/php/forum/topic/datamappers/85007/last/ , http://www.phphulp.nl/php/forum/topic/oop-in-combinatie-met-database/81754/#580025 en http://www.phphulp.nl/php/forum/topic/oop-gedachtengang/85017/1/#606620
Je kan ook bijv. active record gebruiken: http://www.phphulp.nl/php/forum/topic/applicatie-naamgeving/81370/3/#578116 en http://www.phphulp.nl/php/forum/topic/activerecord-en-method-chaining/83025/#590652
Edit:
Ik heb nu het volgende gemaakt:
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
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
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
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
<?php
//> Database
// Database Configuration
$SQL = new mysqli('', '', '', '');
// Database Connection
if ($SQL->connect_errno)
{
trigger_error('Fout bij verbinding: ' . $SQL->error);
}
// Database Charset
$SQL->set_charset('utf8');
//>
//> Classes
//> User
// User Interface
interface UserInterface
{
public function setID($ID);
public function setActivated($activated);
public function setUsername($username);
public function setPassword($password);
public function setEmail($email);
public function setBirthday($birthday);
public function setGender($gender);
public function setDateTime($dateTime);
public function setIP($IP);
public function getID();
public function getActivated();
public function getUsername();
public function getPassword();
public function getEmail();
public function getBirthday();
public function getGender();
public function getDateTime();
public function getIP();
}
// User Class
class User implements UserInterface
{
// Variables
private $ID;
private $activated;
private $username;
private $password;
private $email;
private $birthday;
private $gender;
private $dateTime;
private $IP;
// Constructor
public function __construct($activated, $username, $password, $email, $birthday, $gender, $dateTime, $IP)
{
$this->activated = $activated;
$this->username = $username;
$this->password = $password;
$this->email = $email;
$this->birthday = $birthday;
$this->gender = $gender;
$this->dateTime = $dateTime;
$this->IP = $IP;
}
// Set ID
public function setID($ID)
{
$this->ID = $ID;
}
// Set Activated
public function setActivated($activated)
{
$this->activated = $activated;
}
// Set Username
public function setUsername($username)
{
$this->username = $username;
}
// Set Password
public function setPassword($password)
{
$this->password = $password;
}
// Set Email
public function setEmail($email)
{
$this->email = $email;
}
// Set Birthday
public function setBirthday($birthday)
{
$this->birthday = $birthday;
}
// Set Gender
public function setGender($gender)
{
$this->gender = $gender;
}
// Set DateTime
public function setDateTime($dateTime)
{
$this->dateTime = $dateTime;
}
// Set IP
public function setIP($IP)
{
$this->IP = $IP;
}
// Get ID
public function getID()
{
return $this->ID;
}
// Get Activated
public function getActivated()
{
return $this->activated;
}
// Get Username
public function getUsername()
{
return $this->username;
}
// Get Password
public function getPassword()
{
return $this->password;
}
// Get Email
public function getEmail()
{
return $this->email;
}
// Get Birthday
public function getBirthday()
{
return $this->birthday;
}
// Get Gender
public function getGender()
{
return $this->gender;
}
// Get DateTime
public function getDateTime()
{
return $this->dateTime;
}
// Get IP
public function getIP()
{
return $this->IP;
}
}
// User Mapper
class UserMapper
{
// Variables
private $SQL;
// Constructor
public function __construct(MySQLi $SQL)
{
$this->SQL = $SQL;
}
// Get By ID
public function getByID($ID)
{
$query = '
SELECT
*
FROM
users
WHERE
ID = ' . $this->SQL->real_escape_string($ID);
$result = $this->SQL->query($query);
$rUser = $result->fetch_assoc();
return $this->populate($rUser);
}
// Populate
public function populate(array $data)
{
$user = new User($data['activated'], $data['username'], $data['password'], $data['email'], $data['birthday'], $data['gender'], $data['dateTime'], $data['IP']);
$user->setID($data['ID']);
return $user;
}
// Save
public function save(User $user)
{
$query = '
UPDATE
users
SET
activated = ' . $this->SQL->real_escape_string($user->getActivated()) . ',
username = "' . $this->SQL->real_escape_string($user->getUsername()) . '",
password = "' . $this->SQL->real_escape_string($user->getPassword()) . '",
email = "' . $this->SQL->real_escape_string($user->getEmail()) . '",
birthday = "' . $this->SQL->real_escape_string($user->getBirthday()) . '",
gender = "' . $this->SQL->real_escape_string($user->getGender()) . '",
dateTime = "' . $this->SQL->real_escape_string($user->getDateTime()) . '",
IP = "' . $this->SQL->real_escape_string($user->getIP()) . '"
WHERE
ID = ' . $this->SQL->real_escape_string($user->getID());
$this->SQL->query($query);
}
}
//>
//>
// Create UserMapper
$userMapper = new UserMapper($SQL);
// Get User
$user = $userMapper->getById(1);
// Display Username
echo $user->getUsername();
?>
//> Database
// Database Configuration
$SQL = new mysqli('', '', '', '');
// Database Connection
if ($SQL->connect_errno)
{
trigger_error('Fout bij verbinding: ' . $SQL->error);
}
// Database Charset
$SQL->set_charset('utf8');
//>
//> Classes
//> User
// User Interface
interface UserInterface
{
public function setID($ID);
public function setActivated($activated);
public function setUsername($username);
public function setPassword($password);
public function setEmail($email);
public function setBirthday($birthday);
public function setGender($gender);
public function setDateTime($dateTime);
public function setIP($IP);
public function getID();
public function getActivated();
public function getUsername();
public function getPassword();
public function getEmail();
public function getBirthday();
public function getGender();
public function getDateTime();
public function getIP();
}
// User Class
class User implements UserInterface
{
// Variables
private $ID;
private $activated;
private $username;
private $password;
private $email;
private $birthday;
private $gender;
private $dateTime;
private $IP;
// Constructor
public function __construct($activated, $username, $password, $email, $birthday, $gender, $dateTime, $IP)
{
$this->activated = $activated;
$this->username = $username;
$this->password = $password;
$this->email = $email;
$this->birthday = $birthday;
$this->gender = $gender;
$this->dateTime = $dateTime;
$this->IP = $IP;
}
// Set ID
public function setID($ID)
{
$this->ID = $ID;
}
// Set Activated
public function setActivated($activated)
{
$this->activated = $activated;
}
// Set Username
public function setUsername($username)
{
$this->username = $username;
}
// Set Password
public function setPassword($password)
{
$this->password = $password;
}
// Set Email
public function setEmail($email)
{
$this->email = $email;
}
// Set Birthday
public function setBirthday($birthday)
{
$this->birthday = $birthday;
}
// Set Gender
public function setGender($gender)
{
$this->gender = $gender;
}
// Set DateTime
public function setDateTime($dateTime)
{
$this->dateTime = $dateTime;
}
// Set IP
public function setIP($IP)
{
$this->IP = $IP;
}
// Get ID
public function getID()
{
return $this->ID;
}
// Get Activated
public function getActivated()
{
return $this->activated;
}
// Get Username
public function getUsername()
{
return $this->username;
}
// Get Password
public function getPassword()
{
return $this->password;
}
// Get Email
public function getEmail()
{
return $this->email;
}
// Get Birthday
public function getBirthday()
{
return $this->birthday;
}
// Get Gender
public function getGender()
{
return $this->gender;
}
// Get DateTime
public function getDateTime()
{
return $this->dateTime;
}
// Get IP
public function getIP()
{
return $this->IP;
}
}
// User Mapper
class UserMapper
{
// Variables
private $SQL;
// Constructor
public function __construct(MySQLi $SQL)
{
$this->SQL = $SQL;
}
// Get By ID
public function getByID($ID)
{
$query = '
SELECT
*
FROM
users
WHERE
ID = ' . $this->SQL->real_escape_string($ID);
$result = $this->SQL->query($query);
$rUser = $result->fetch_assoc();
return $this->populate($rUser);
}
// Populate
public function populate(array $data)
{
$user = new User($data['activated'], $data['username'], $data['password'], $data['email'], $data['birthday'], $data['gender'], $data['dateTime'], $data['IP']);
$user->setID($data['ID']);
return $user;
}
// Save
public function save(User $user)
{
$query = '
UPDATE
users
SET
activated = ' . $this->SQL->real_escape_string($user->getActivated()) . ',
username = "' . $this->SQL->real_escape_string($user->getUsername()) . '",
password = "' . $this->SQL->real_escape_string($user->getPassword()) . '",
email = "' . $this->SQL->real_escape_string($user->getEmail()) . '",
birthday = "' . $this->SQL->real_escape_string($user->getBirthday()) . '",
gender = "' . $this->SQL->real_escape_string($user->getGender()) . '",
dateTime = "' . $this->SQL->real_escape_string($user->getDateTime()) . '",
IP = "' . $this->SQL->real_escape_string($user->getIP()) . '"
WHERE
ID = ' . $this->SQL->real_escape_string($user->getID());
$this->SQL->query($query);
}
}
//>
//>
// Create UserMapper
$userMapper = new UserMapper($SQL);
// Get User
$user = $userMapper->getById(1);
// Display Username
echo $user->getUsername();
?>
Het werkt, maar is dit zo goed?
En dan heb ik nog een vraagje:
Bij 'save' word ALLES opnieuw opgeslagen, hoe zorg ik ervoor dat alleen het aangepaste wordt opgeslagen? Want stel dat je een pagina bezoekt, dan worden al jouw gegevens in dat User object gezet. als er in tussentijd iets veranderd in de user tabel en jij voert op die pagina een save uit, dan wordt dat overschreven..
Gewijzigd op 06/01/2013 13:20:52 door Lord Gaga
Gewijzigd op 07/01/2013 19:41:10 door Lord Gaga
http://laravel.com/docs/database/eloquent Ik vind dat zelf een zeer fijne manier van werken met models en de database
Edit: dat alle data van je user gesaved wordt is toch juist goed? Je roept alleen maar een save aan als je ook daadwerkelijk de user van dat moment wil opslaan. Ik kan me geen scenario indenken waarin je dit niet zou willen
Kijk ook eens hier naar: Edit: dat alle data van je user gesaved wordt is toch juist goed? Je roept alleen maar een save aan als je ook daadwerkelijk de user van dat moment wil opslaan. Ik kan me geen scenario indenken waarin je dit niet zou willen
Gewijzigd op 07/01/2013 19:43:42 door Moose -
Sla niet elk property van user op in een apart private property, maar in een array. Op die manier ben je erg flexibel, want een nieuw property kan je eenvoudig toevoegen. Voor een update kan je dan ook snel zien wat wel en niet is aangepast, mist je alleen die gegevens in de array zet die zijn aangepast. Alles wat in de array zit moet je dan udpaten in de database niets meer.
De save functie is goed zo, dat kun je niet veranderen. Wat je je eerder moet af vragen is hoe er plotseling iets kan veranderen in de DB, dit zal altijd via de User en UserMapper moeten.
Wouter J op 07/01/2013 19:45:06:
Wat Not Moose laat zien is Active Record, niet dat het slecht is maar ik hou er niet van (en het is typisch Laravel style: lekker static).
De save functie is goed zo, dat kun je niet veranderen. Wat je je eerder moet af vragen is hoe er plotseling iets kan veranderen in de DB, dit zal altijd via de User en UserMapper moeten.
De save functie is goed zo, dat kun je niet veranderen. Wat je je eerder moet af vragen is hoe er plotseling iets kan veranderen in de DB, dit zal altijd via de User en UserMapper moeten.
Nou, in dit geval is dat nog niet echt mogelijk, maar stel dat ik een veld heb waarin het aantal 'coins' van de gebruiker worden opgeslagen.
Als die gebruiker bijvoorbeeld zijn email wil veranderen, dan gaat hij naar zijn settings, op dat moment wordt, neem ik aan, een user object gemaakt met daarin al zijn data.
Als er ondertussen bijvoorbeeld een moderator is die hem een x aantal coins geeft, worden die weer overschreven op het moment dat de gebruiker zijn email aanpast.
Of zie ik dit nu verkeerd?
Een User object wordt als het goed is direct bij het controleren van de user gemaakt, dus als een van de eerste dingen in je request flow.
Wouter J op 07/01/2013 19:50:34:
Een User object wordt als het goed is direct bij het controleren van de user gemaakt, dus als een van de eerste dingen in je request flow.
Maar wordt die gemaakt op het moment als ik de pagina aanroep of op het moment dat ik ook daadwerkelijk gegevens op wil slaan?
Als je op een settings pagina komt moet je eerst kijken of die user wel op de settings pagina mag komen, dan maak je dus al een USer object aan.
Stel nou dat jij ergens je email wilt veranderen, dus je gaat naar die pagina en er wordt meteen een userobject aangemaakt:
naam: Wouter J
email: [email protected]
munten: 100
Terwijl jij op die pagina zit is er ergens iemand die jou 10 munten geeft.
In de database staat dus nu dat jij 110 munten hebt, terwijl in jouw user object nog staat dat jij er 100 hebt.
Dan sla jij je nieuwe email op, maar omdat alle gegevens worden opgeslagen, worden die 100 munten dus ook opnieuw in de database gezet, waardoor jij nu opeens maar weer 100 munten hebt..
Gewijzigd op 07/01/2013 19:58:23 door Lord Gaga
Daar zou je dan een koppel tabel voor kunnen maken
Not Moose op 07/01/2013 20:01:23:
Daar zou je dan een koppel tabel voor kunnen maken
Maar dan zou ik toch voor alle velden, waarvan ook maar de mogelijkheid is dat ze door een andere dan jijzelf worden veranderd, een koppeltabel moeten maken? :/
Ook lijkt het me handig om inderdaad elk veld wat eventueel door iemand anders aangepast kan worden, op te slaan in een aparte tabel. Anders blijf je met dit soort dingen zitten. Een andere oplossing zou zijn om alleen maar de velden mee te geven die je wilt aanpassen, maar dan kan je net zo goed de query zelf gaan schrijven
Edit: ik zou voor dit specifieke geval zelfs drie tabellen aanmaken
user, transactie, huidige_munten
transactie heeft een id, een gever, een ontvanger en een amount (plus of min)
user is je model
huidige_munten is een aparte tabel met een userid en een veld met het aantal munten. De enige aanpassingen die je doet op deze tabel is + munten of - munten. Je maakt eerst een transactie aan, en na het aanmaken van de transactie update je ook meteen je huidige_munten tabel. Je mag alleen maar deze tabel aanpassen net nadat er een transactie is aangemaakt. Zo kan het nooit voorkomen dat dit verkeerd wordt aangepast
Gewijzigd op 07/01/2013 20:28:58 door Moose -
En is het uiteindelijk niet veel makkelijker dat save() alleen de dingen opslaat die zijn aangepast? Volgens mij voorkomt dit een heel hoop gedoe met allerlei omweggetjes via koppeltabellen..
Koppel tabel is geen omweg, het is de oplossing
Ik snap niet echt hoe je dit nou precies met een koppeltabel doet, kun je een voorbeeld geven van hoe ik dit zou moeten doen?
Die heb ik toch gegeven daarboven? Als je het aantal munten gewoon als kolom bij je user tabel neerzet krijg je toch nog steeds problemen dat hij dubbel overschreven kan worden?
Maar toch, ik kan me voorstellen dat je alleen wilt updaten wat je gewijzigd hebt. dan zou je een mechanisme moeten bedenken die dus bijhoud welke variabelen je gewijzigd hebt...
@No one:
Inderdaad, als je een update query maakt, pas je toch ook alleen aan wat je wilt aanpassen?
Gewijzigd op 08/01/2013 12:14:00 door Lord Gaga