DataObjects
Ik ben lui, en ik denk dat er meer met mij zijn. Ik wil het liefst gewoon een object manipuleren en voor de rest niet omkijken naar inhoud escapen, datatypen controleren enz. enz.
Dus ik 'bedacht' dataobjecten. Deze abstracte klassen.
En om het leven nog wat makkelijker te maken, zijn zowel de DataObjecten als de DataSets zo gebakken dat zij voldoen aan de voorwaarden die de interface Iterator stelt. Hierdoor kan je ze probleemloos in een foreach-lus gebruiken!
Iedere klasse vertegenwoordigt een tabel in je database. Je zal in iedere klasse dus de structuur van de tabel moeten opgeven.
Heel belangrijk: Roep voor het gebruik van de objecten DataSet::buffer() aan, eventueel met het aantal objecten dat je van te voren wilt vullen als parameter. Dit zorgt ervoor dat hij al die objecten in 1 keer voltankt, en niet per object een query uitvoert.
Maar genoeg gepraat, een voorbeeld is vast begrijpbaarder:
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
class Film extends AbstractDataObject {
public static $genres = Array (
1 => 'actie',
2 => 'animatie',
4 => 'avontuur'
);
/* De tabelnaam in de database */
protected $tableName = 'films';
/*
* De primaire sleutel. Deze wordt gebruikt bij SELECT
* en UPDATE en moet dus, heel belangrijk, uniek zijn.
*/
protected $primaryKey = 'filmId';
/*
* De tabelstructuur:
* key: de alias, daarmee roep je hem later aan als $object->keynaam
* eerste array-entry: de veldnaam in de db
* de rest in de array: flags. Datatype (gebruikt door
* -- AbstractDataObject::convert) en READ_ONLY. Spreekt voor zich.
*/
protected $tableStructure = array(
'id' => array('filmId', AbstractDataObject::INT, AbstractDataObject::READ_ONLY),
'title' => array('filmTitle', AbstractDataObject::STRING),
'round' => array('filmRound', AbstractDataObject::INT),
'playtime' => array('filmPlaytime', AbstractDataObject::INT),
'IMDBRating'=> array('filmIMDBRating', AbstractDataObject::FLOAT),
'filmGenres'=> array('filmGenres')
);
/*
* LET OP! Er wordt sowieso een instanse gemaakt zonder paramters
* door de db-klasse, om de tabelstructuur te achterhalen. let er dus op
* dat je _niets doet_ zonder parameters. Zonder parameters is is het
* __een dummy__!
*/
public function __construct($filmName = null, $databaseInstance = null)
{
$this->databaseInstance = $databaseInstance;
if(is_string($filmName)) {
if(!$this->populate('filmTitle = :filmName', array('filmName' => $filmName))) {
throw new Exception('Film '.$filmName.' not found');
}
} elseif(is_int($filmName)) {
if(!$this->populate('filmId = :filmId', array('filmId' => $filmName))) {
throw new Exception('Film #'.$filmName.' not found');
}
}
/* zie je, ik onderneem geen actie waneer geen parameter is meegegeven */
}
/*
* Voorbeeld van callback-functie:
* Waneer je $ditObject->genres vult, wordt er teruggegaan naar
* deze functie. Deze functie is vervolgens verantwoordelijk voor
* het manipuleren van de $data-array die hij meekrijgt, dat is
* de array met alle bijna raw inhoud van de database. Voorzichtig dus!
*
* In dit geval wordt dus een array (die van Film::$genres) omgezet in
* een integer, aangezien ik moeilijk die hele array erin kan stoppen.
*/
public function setGenres(&$data, $filmGenres)
{
$data['filmGenres'] = array_sum($filmGenres);
return true;
}
/*
* En omdat ik niets heb aan een integer, maar een array met genres wil,
* levert deze callback-functie mij een array met alle genres die door de
* integer uit de db vertegenwoordigd worden.
*/
public function getGenres(&$data)
{
$keys = array();
foreach(array_keys(self::$genres) as $key) {
if($data['filmGenres'] & $key) {
$keys[] = self::$genres[$key];
}
}
return $keys;
}
/*
* En nog even een laatste voorbeeld: je callback-functie hoeft niet
* in de $this->tableStructure voor te komen. Maar $instance->link
* zal een gestripte $this->title geven.
*/
public function getLink($page) {
return str_replace(' ', '-', sprintf($page, $this->title));
}
}
//En nu het gebruik:
$db = new Database('localhost', 'root', '', 'films');
$resultSet = $db->fetch('Film', 'filmRound = :ronde', array('ronde' => 1));
$resultSet->buffer(); //laad alle regels vast in
foreach($resultSet as $film) {
echo 'Deze film heet ' . $film->title;
foreach($film as $sleutel => $waarde) {
echo '[' . $sleutel . '] => ' . var_dump($waarde, true) . '<br>';
}
}
// update voorbeeld
$resultSet->rewind(); // even overnieuw
$resultSet->next();
$film = $resultSet->current();
$film->title = str_repeat($film->title, 2);
$film->commit();
// en toen was de naam dubbelop!
?>
Inserten is ook vrij simpel: gewoon je decorator lief invullen
2
3
4
5
6
7
$film = new Film(null, $db);
$film->title = 'iets';
// enz.
$film->commit();
// en hij zit erin!
?>
Er zullen nog wel wat meer features inzitten, die ik zelf zelfs al vergeten ben. Ik gebruik hem gewoon, en het werkt. En zo hoort het :) Mocht je vragen of problemen hebben, maak een topic in het forum en post hier een link in de reacties naar het topic. Zo houden we de reacties schoon.
Gesponsorde koppelingen
PHP script bestanden
Om te reageren heb je een account nodig en je moet ingelogd zijn.