[OOP] Forum, categorieën class
Beste,
Ik begin net in OOP, maar heb wel al aardig wat PHP ervaring. Nu wil ik alleen OOP gaan schrijven. Ik ben begonnen met een class genaamd categorie, nu vroeg ik me af of dit wel oke is.
Ik hoor graag, tips, opmerkingen en andere vormen van opbouwende kritiek...
Ik begin net in OOP, maar heb wel al aardig wat PHP ervaring. Nu wil ik alleen OOP gaan schrijven. Ik ben begonnen met een class genaamd categorie, nu vroeg ik me af of dit wel oke is.
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
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
<?php
class forumCategorie {
public $id;
public $parent_id;
function __construct( $host, $user, $pass, $datb ) {
/*
MySQL verbinding maken
*/
}
# Categorie ophalen
function getCategorie() {
}
# Sub-categorie ophalen
function getSubcategorie() {
}
# Laatste topic ophalen
function getLastTopic() {
}
# Aantal topic ophalen
function countTopic() {
}
# Posts ophalen
function counPost() {
}
}
?>
class forumCategorie {
public $id;
public $parent_id;
function __construct( $host, $user, $pass, $datb ) {
/*
MySQL verbinding maken
*/
}
# Categorie ophalen
function getCategorie() {
}
# Sub-categorie ophalen
function getSubcategorie() {
}
# Laatste topic ophalen
function getLastTopic() {
}
# Aantal topic ophalen
function countTopic() {
}
# Posts ophalen
function counPost() {
}
}
?>
Ik hoor graag, tips, opmerkingen en andere vormen van opbouwende kritiek...
Gewijzigd op 26/04/2011 15:17:00 door Milo S
Gesponsorde koppelingen:
Het lijkt mij niet handig om je verbinding naar de database op te zetten in de class "forumcategorie". Je kan hier beter een aparte class voor gebruiken (bijvoorbeeld PDO) en deze resource meegeven aan je constructor van de betreffende class.
Dus bijvoorbeeld (simplistisch):
Ik weet niet hoe je de categorieën in de database hebt opgezet, maar is het niet handiger om alle categorieën in één keer op te halen? Dus bijvoorbeeld werken met parent_id in de database en hiervoor alleen een functie "getCategorie" gebruiken? Hiermee kan je ook direct het laatste bericht ophalen (bijvoorbeeld via een subquery). Overigens haal je nu Engelse en Nederlandse benamingen door elkaar. Is niet erg, maar misschien op termijn niet handig.
En wat wil je met "public $id" en "public $parent_id" precies bereiken?
Dus bijvoorbeeld (simplistisch):
Ik weet niet hoe je de categorieën in de database hebt opgezet, maar is het niet handiger om alle categorieën in één keer op te halen? Dus bijvoorbeeld werken met parent_id in de database en hiervoor alleen een functie "getCategorie" gebruiken? Hiermee kan je ook direct het laatste bericht ophalen (bijvoorbeeld via een subquery). Overigens haal je nu Engelse en Nederlandse benamingen door elkaar. Is niet erg, maar misschien op termijn niet handig.
En wat wil je met "public $id" en "public $parent_id" precies bereiken?
Gewijzigd op 26/04/2011 15:42:11 door Arjan -
Beste Arjan,
Bedankt voor de snelle reactie. Ik heb eens gekeken, en rond gezocht op internet, en bedacht me dat ik niet eens een speciale class zou aanmaken voor me database. Ik heb er tenslotte maar 1, en maak 1 keer connectie en hou het voor gezien.
Ik heb zoals jij daar aangeeft me categorieen. Dus met een parent_id. Nu dacht ik dat het zo meteen de bedoeling was met OOP dat je dat allemaal spreid, het leek mij namelijk een op zich staand iets.
Ik ben tot nu toe hier:
Ik dacht dat je in je class de variabelen mee moest geven die je weer in je functies moet gebruiken, dit blijkt dus niet.
Bedankt voor de snelle reactie. Ik heb eens gekeken, en rond gezocht op internet, en bedacht me dat ik niet eens een speciale class zou aanmaken voor me database. Ik heb er tenslotte maar 1, en maak 1 keer connectie en hou het voor gezien.
Ik heb zoals jij daar aangeeft me categorieen. Dus met een parent_id. Nu dacht ik dat het zo meteen de bedoeling was met OOP dat je dat allemaal spreid, het leek mij namelijk een op zich staand iets.
Ik ben tot nu toe hier:
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
<?php
class forumCategorie
{
protected $db;
# Constructor, word dus automatisch uitgevoerd.
function __construct( $db )
{
$db = new PDO( 'mysql:host='.$db['host'].'; dbname='.$db['dbname'], $db['user'], $db['pass'] );
}
# Categorie ophalen
function getCategorie( $id )
{
}
# Laatste topic ophalen
function getLastTopic( $id )
{
}
# Aantal topic ophalen
function countTopic( $id )
{
}
# Posts ophalen
function countPost( $id, $top_id )
{
}
}
?>
class forumCategorie
{
protected $db;
# Constructor, word dus automatisch uitgevoerd.
function __construct( $db )
{
$db = new PDO( 'mysql:host='.$db['host'].'; dbname='.$db['dbname'], $db['user'], $db['pass'] );
}
# Categorie ophalen
function getCategorie( $id )
{
}
# Laatste topic ophalen
function getLastTopic( $id )
{
}
# Aantal topic ophalen
function countTopic( $id )
{
}
# Posts ophalen
function countPost( $id, $top_id )
{
}
}
?>
Ik dacht dat je in je class de variabelen mee moest geven die je weer in je functies moet gebruiken, dit blijkt dus niet.
Quote:
Bedankt voor de snelle reactie. Ik heb eens gekeken, en rond gezocht op internet, en bedacht me dat ik niet eens een speciale class zou aanmaken voor me database. Ik heb er tenslotte maar 1, en maak 1 keer connectie en hou het voor gezien.
PDO is al een class die je kan gebruiken in je overige classes. PDO heeft super veel voordelen (prepared statements, etc.), dus ik raad je aan om dit te gebruiken.
Quote:
Ik dacht dat je in je class de variabelen mee moest geven die je weer in je functies moet gebruiken...
Dit is ook de juiste manier, maar ik doelde meer op de functie van die twee variabelen (maar die gebruik je dus voor het opvragen van de subcategorieën?).
Maar wanneer jij alle categorieën wilt ophalen, dan kan je net zo goed gelijk de subcategorieën ophalen. Hierdoor hoef je niet voor elke categorie een aparte query te maken voor je subcategorieën. Dit scheelt veel meer tijd en resources dan dat je alles wilt scheiden omdat het overzichtelijker is.
En in jouw revisie maak je nog steeds een database connectie aan in je constructor.
Je kan het beter zo doen:
Code (php)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
<?php
class ForumCategorie {
protected $_db;
public function __construct(PDO $db) {
$this->_db = $db;
}
}
$db = // pdo connectie / Dit kan je in een apart sql bestand zetten die je op elke pagina include
$ForumCategorie = new ForumCategorie($db);
$AndereClass = new AndereClass($db); // Niet gedefinieerd maar dienend als voorbeeld
?>
class ForumCategorie {
protected $_db;
public function __construct(PDO $db) {
$this->_db = $db;
}
}
$db = // pdo connectie / Dit kan je in een apart sql bestand zetten die je op elke pagina include
$ForumCategorie = new ForumCategorie($db);
$AndereClass = new AndereClass($db); // Niet gedefinieerd maar dienend als voorbeeld
?>
Een andere mogelijkheid is het gebruik maken van het Singleton patroon (http://nl.wikipedia.org/wiki/Singleton_(informatica)).
Gewijzigd op 26/04/2011 16:34:09 door Arjan -
Aaah nu snap ik wat je bedoel met die PDO verbinding. Ik maak dan een config bestandje aan met bijvoorbeeld:
en mijn forum_cat.class.php heeft dit:
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
$db = array (
'host' => '',
'datb' => '',
'user' => '',
'pass' => ''
);
try
{
$db = new PDO('mysql:host='.$db['host'].';dbname='.$db['datb'], $db['user'], $db['pass']);
$db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
}
catch(PDOException $e)
{
echo 'Er is een fout opgetreden bij het maken van connectie met de database.';
}
?>
$db = array (
'host' => '',
'datb' => '',
'user' => '',
'pass' => ''
);
try
{
$db = new PDO('mysql:host='.$db['host'].';dbname='.$db['datb'], $db['user'], $db['pass']);
$db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
}
catch(PDOException $e)
{
echo 'Er is een fout opgetreden bij het maken van connectie met de database.';
}
?>
en mijn forum_cat.class.php heeft dit:
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
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
<?php
class ForumCategorie
{
public $cat_id;
public $top_id;
protected $_db;
# Constructor, word dus automatisch uitgevoerd.
public function __construct(PDO $db)
{
$this->_db = $db;
}
# Categorie ophalen
function getCategorie( )
{
}
# Laatste topic ophalen
function getLastTopic( $cat_id )
{
}
# Aantal topic ophalen
function countTopic( $cat_id )
{
}
# Posts ophalen
function countPost( $cat_id, $top_id )
{
}
}
?>
class ForumCategorie
{
public $cat_id;
public $top_id;
protected $_db;
# Constructor, word dus automatisch uitgevoerd.
public function __construct(PDO $db)
{
$this->_db = $db;
}
# Categorie ophalen
function getCategorie( )
{
}
# Laatste topic ophalen
function getLastTopic( $cat_id )
{
}
# Aantal topic ophalen
function countTopic( $cat_id )
{
}
# Posts ophalen
function countPost( $cat_id, $top_id )
{
}
}
?>
Gewijzigd op 26/04/2011 17:10:06 door Milo S
Wat betreft de database connectie is dat inderdaad de manier die ik bedoel (er zijn vele manieren dus een bepaalde manier is niet per definitie de beste manier).
En dan kan je dus in alle functies binnen je class een query opzetten middels bijvoorbeeld: $sql = $this->_db->prepare("");
En dan kan je dus in alle functies binnen je class een query opzetten middels bijvoorbeeld: $sql = $this->_db->prepare("");
Gewijzigd op 26/04/2011 17:10:29 door Arjan -
Dan ga ik vanuit dit opzetje verder werken, en een index pagina van een forum bouwen. Mag je nu eigenlijk wel gewoon queries uitvoeren enzo in je functies, uiteraard PDO...
Van mij wel :) (anders heb je ook niets aan de database resource binnen je class). Alle database data opvragen buiten je class lijkt mij wat lastig. Sommigen beweren dat de schaalbaarheid wordt verkleind door binnen je class queries uit te voeren, maar wanneer je de database benamingen universeel en database schaalbaar houdt dan is er mijn inziens niets aan de hand.
Extra data / velden ophalen vanuit de database (zoals de subcategorieën binnen de hoofdcategorieën) die je later niet nodig hebt is geen wereldramp, aangezien je hierdoor veel minder (onnodige) functies hoeft te gebruiken en wellicht ook (afhankelijk van het systeem) minder afzonderlijke queries nodig hebt.
Trouwens, de countpost functie kan je ook wel integreren in de getCategorie functie. Stel je hebt 20 categorieën, dan zal je dus afzonderlijk 20 keer de functie countpost en bijbehorende query moeten uitvoeren om het aantal posts te verkrijgen.
Voor de categorieën lijkt mij het mooist om een multidimensionale array te retourneren, waarin de categorieën, subcategorieën en de bijbehorende gegevens (aantal posts) zijn opgenomen. Zodoende kan je eenvoudig loopen door de gegevens.
Extra data / velden ophalen vanuit de database (zoals de subcategorieën binnen de hoofdcategorieën) die je later niet nodig hebt is geen wereldramp, aangezien je hierdoor veel minder (onnodige) functies hoeft te gebruiken en wellicht ook (afhankelijk van het systeem) minder afzonderlijke queries nodig hebt.
Trouwens, de countpost functie kan je ook wel integreren in de getCategorie functie. Stel je hebt 20 categorieën, dan zal je dus afzonderlijk 20 keer de functie countpost en bijbehorende query moeten uitvoeren om het aantal posts te verkrijgen.
Voor de categorieën lijkt mij het mooist om een multidimensionale array te retourneren, waarin de categorieën, subcategorieën en de bijbehorende gegevens (aantal posts) zijn opgenomen. Zodoende kan je eenvoudig loopen door de gegevens.
Gewijzigd op 26/04/2011 17:25:59 door Arjan -
Topic's en categorieën.. Moeten dat geen aparte klasses zijn? :)
Gewijzigd op 26/04/2011 17:41:07 door Niels Kieviet
Ja.
Gewijzigd op 26/04/2011 21:20:10 door Arjan -
@ Niels;
Zoals je ziet haal ik niet een heel topic op, maar alleen de laatste. Topic's zelf worden inderdaad een andere klasse... Niet goed?
Zoals je ziet haal ik niet een heel topic op, maar alleen de laatste. Topic's zelf worden inderdaad een andere klasse... Niet goed?
Offtopic: Ik dacht dat jij (Milo) vroeg of een topic in een aparte class moet :). Jullie avatars lijken op het eerste oog zo op elkaar.
Ontopic: De laatste topic opvragen behoort tot de categorieën, dus dat kan best in de ForumCategorie class.
Ontopic: De laatste topic opvragen behoort tot de categorieën, dus dat kan best in de ForumCategorie class.
Gewijzigd op 26/04/2011 20:18:50 door Arjan -
Arjan - op 26/04/2011 18:03:59:
Ja, eventueel kan je de topic class extenden naar de categorie class (class ForumTopic extends ForumCategorie), aangezien een topic altijd in een categorie valt.
Nee, niet extenden.. welke eigenschappen heeft een topic die een categorie ook heeft?
wanneer wel?
Class User;
Class Supplier Extends User;
class Manager Extends User;
// etc
De categorie? Maar je hebt wel gelijk hoor, harr.
Gewijzigd op 26/04/2011 21:23:17 door Merijn Venema
Ik heb dan nu alle queries gemaakt, en zal morgen kijken hoe dat met PDO allemaal werkt. Bedankt voor de hulp, ik zal deze dagen nog wel meer om hulp vragen. Het tis nu nog redelijk hocus spocus.
Uiteraard nog mysql_real_escape_string, maar weet niet hoe dat bij PDO zit, zijn daar andere functies voor enzovoorts...
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
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
<?php
class ForumCategorie
{
public $id;
public $top_id;
protected $_db;
# Constructor, word dus automatisch uitgevoerd.
public function __construct( PDO $db )
{
$this->_db = $db;
}
# Categorie ophalen
function getCategorie( )
{
$sql =
"
SELECT
cat.title AS cat,
subCat.id AS subCatID,
subCat.title AS subCat,
subCat.description
FROM
forum AS cat
INNER JOIN
forum AS subCat
ON
cat.id = subCat.parent_id
GROUP BY
subCat.id
ORDER BY
cat.id,
subCat.title
";
}
# Laatste topic ophalen
function getLastTopic( $id )
{
# Query
$sql =
"
SELECT
MAX( fu.username ) AS lastUser,
COUNT(fp.id) AS posts,
DATE_FORMAT( MAX( fp.dateTime ), '%d %M %Y, %H:%i' ) AS lastPostDate
FROM
forum_post AS fp
LEFT JOIN
user AS fu
ON
fp.user_id = fu.id
WHERE
fp.cat_id = '".$id."'
";
}
# Posts ophalen
function countPost( $id, $top_id )
{
$sql =
"
SELECT
ft.id,
COUNT(ft.id) AS topics
FROM
forum_topic AS ft
WHERE
ft.cat_id = '".$id."'
";
}
}
?>
class ForumCategorie
{
public $id;
public $top_id;
protected $_db;
# Constructor, word dus automatisch uitgevoerd.
public function __construct( PDO $db )
{
$this->_db = $db;
}
# Categorie ophalen
function getCategorie( )
{
$sql =
"
SELECT
cat.title AS cat,
subCat.id AS subCatID,
subCat.title AS subCat,
subCat.description
FROM
forum AS cat
INNER JOIN
forum AS subCat
ON
cat.id = subCat.parent_id
GROUP BY
subCat.id
ORDER BY
cat.id,
subCat.title
";
}
# Laatste topic ophalen
function getLastTopic( $id )
{
# Query
$sql =
"
SELECT
MAX( fu.username ) AS lastUser,
COUNT(fp.id) AS posts,
DATE_FORMAT( MAX( fp.dateTime ), '%d %M %Y, %H:%i' ) AS lastPostDate
FROM
forum_post AS fp
LEFT JOIN
user AS fu
ON
fp.user_id = fu.id
WHERE
fp.cat_id = '".$id."'
";
}
# Posts ophalen
function countPost( $id, $top_id )
{
$sql =
"
SELECT
ft.id,
COUNT(ft.id) AS topics
FROM
forum_topic AS ft
WHERE
ft.cat_id = '".$id."'
";
}
}
?>
Uiteraard nog mysql_real_escape_string, maar weet niet hoe dat bij PDO zit, zijn daar andere functies voor enzovoorts...
Met PDO gebruik je doorgaans prepared statements, kortweg komt het er op neer dat je het volgende doet:
Dus je bind een variabele aan een constante (beginnend met een dubbele punt) in je query. Hierdoor hoef je mysql_real_escape_string niet meer te gebruiken, aangezien de prepared statements (bindParam en bindValue) dit al voor je doen. Zo stop je altijd veilig de data in je database!
Hiermee kan je ook dit soort constructies gebruiken (simplistisch weergegeven):
Hierboven zal dus 0 t/m 9 in verschillende records worden toegevoegd in de database.
De bindParam zorgt ervoor dat een referentie wordt aangemaakt, waarbij de waarde veranderbaar is voor, in dit geval, de variabele $veldwaarde. Dus je kan de waarde van $veldwaarde elke keer veranderen, waarna je execute() uitvoert. Dit kan handig zijn als je bepaalde verschillende bewerkingen op alle records moet uitvoeren. Of, zoals in dit geval, meerdere records wil toevoegen met verschillende waarden.
Dit is de beste (Nederlandse) tutorial over PDO: http://www.phptuts.nl/view/27/
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
<?php
$veldwaarde = 'een waarde';
$sql = $db->prepare("
SELECT id FROM tabel WHERE veld = :veldwaarde
");
$sql->bindParam(':veldwaarde', $veldwaarde);
if($sql->execute()) {
$data = $sql->fetchAll(PDO::FETCH_ASSOC);
}
?>
$veldwaarde = 'een waarde';
$sql = $db->prepare("
SELECT id FROM tabel WHERE veld = :veldwaarde
");
$sql->bindParam(':veldwaarde', $veldwaarde);
if($sql->execute()) {
$data = $sql->fetchAll(PDO::FETCH_ASSOC);
}
?>
Dus je bind een variabele aan een constante (beginnend met een dubbele punt) in je query. Hierdoor hoef je mysql_real_escape_string niet meer te gebruiken, aangezien de prepared statements (bindParam en bindValue) dit al voor je doen. Zo stop je altijd veilig de data in je database!
Hiermee kan je ook dit soort constructies gebruiken (simplistisch weergegeven):
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
<?php
$sql = $db->prepare("
INSERT INTO tabel (veldnaam) VALUES (:veldwaarde)
");
$sql->bindParam(':veldwaarde', $veldwaarde, PDO::PARAM_INT);
for($i = 0; $i<10; $++) {
$veldwaarde = $i;
$sql->execute();
}
?>
$sql = $db->prepare("
INSERT INTO tabel (veldnaam) VALUES (:veldwaarde)
");
$sql->bindParam(':veldwaarde', $veldwaarde, PDO::PARAM_INT);
for($i = 0; $i<10; $++) {
$veldwaarde = $i;
$sql->execute();
}
?>
Hierboven zal dus 0 t/m 9 in verschillende records worden toegevoegd in de database.
De bindParam zorgt ervoor dat een referentie wordt aangemaakt, waarbij de waarde veranderbaar is voor, in dit geval, de variabele $veldwaarde. Dus je kan de waarde van $veldwaarde elke keer veranderen, waarna je execute() uitvoert. Dit kan handig zijn als je bepaalde verschillende bewerkingen op alle records moet uitvoeren. Of, zoals in dit geval, meerdere records wil toevoegen met verschillende waarden.
Dit is de beste (Nederlandse) tutorial over PDO: http://www.phptuts.nl/view/27/
Gewijzigd op 26/04/2011 22:27:04 door Arjan -
Daarnaast public variabeles zomin mogelijk gebruiken.. (Alternatief: Protected, private). Daarnaast hebben zijn functies nu altijd public... Benoemd ze dus even apart altijd ;) Dat is voor een andere programmeur ook makkelijker lezen..
Je zou ook eens kunnen kijken naar een ORM. Overigens SQL injection is eventueel mogelijk nu.. Maar ik weet dat je daar (normaliter) rekening mee houdt..
Heb je al nagedacht over user login / registratie ? Waar ga je de gebruiker(s) in opslaan? Ook database of iets anders? (Ldap bijvoorbeeld ;p)
Succes
Je zou ook eens kunnen kijken naar een ORM. Overigens SQL injection is eventueel mogelijk nu.. Maar ik weet dat je daar (normaliter) rekening mee houdt..
Heb je al nagedacht over user login / registratie ? Waar ga je de gebruiker(s) in opslaan? Ook database of iets anders? (Ldap bijvoorbeeld ;p)
Succes



