[OOP] Forum, categorieën class
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
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 -
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 -
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
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...
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 -
Gewijzigd op 26/04/2011 17:41:07 door Niels K
Gewijzigd op 26/04/2011 21:20:10 door Arjan -
Zoals je ziet haal ik niet een heel topic op, maar alleen de laatste. Topic's zelf worden inderdaad een andere klasse... Niet goed?
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
Gewijzigd op 26/04/2011 21:23:17 door Pieter Jansen
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...
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 -
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