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
|
<?php
// php/Model.php
class Model extends DB
{
protected $db; // instance de PDO
protected $table; // <= enfant
//static protected $tableStructure;
public function __construct()
{
//~ $this->db = parent::getInstance(); // connexion
//~ $this->table = strtolower(__CLASS__);
}
// getters
public function getTable(): string
{
return($this->table);
}
// setters
public function hydrate(array $data): bool // $data = tableau associatif en entrée: nom_du_champ => valeur
{
foreach($data as $key => $value)
{
// nom du setter
// nom_du_champ devient setNomDuChamp
// on sépare les mots par des espaces, ucwords met la première lettre de chaque mot en majuscule, puis on supprime les espaces
$setter_name = 'set' . str_replace(' ', '', ucwords(str_replace('_', ' ', $key))); // ucwords: première lettre de chaque mot en majuscule
if(method_exists($this, $setter_name))
{
$this->$setter_name($value);
}
else
{
echo "debug: la méthode $setter_name n'existe pas\n";
return false;
}
}
return true;
}
// exécuter le SQL
// les attributs correspondent aux ? dans les requêtes préparées
// ne pas surcharger la méthode PDO::query() qui n'est pas compatible
protected function execQuery(string $sql, array $attributes = null)
{
$this->db = parent::getInstance(); // connexion
if($attributes !== null) // requête préparée
{
var_dump($sql);
var_dump($attributes);
$query = $this->db->prepare($sql);
$query->execute($attributes);
return $query;
}
else // requête simple
{
return $this->db->query($sql);
}
}
// méthodes CRUD
// create INSERT
public function create() // = write
{
$fields = [];
$question_marks = []; // ?
$values = [];
//~ var_dump($this);
foreach($this as $field => $value)
{
var_dump($field); var_dump($value);
// champs non renseignées et variables de l'objet qui ne sont pas des champs
// note: avec le !== (au lieu de !=) une valeur 0 est différente de null
if($value !== null && $field != 'db' && $field != 'table')
{
$fields[] = $field; // push
$question_marks[] = '?';
$values[] = $value;
}
}
$field_list = implode(', ', $fields);
$question_mark_list = implode(', ', $question_marks);
// INSERT INTO annonces (titre, description, actif) VALUES (?, ?, ?)
return($this->execQuery('INSERT INTO ' . $this->table . ' (' . $field_list . ') VALUES (' . $question_mark_list . ')', $values));
}
// read SELECT
protected function readAll(): array // obtenir une table
{
return($this->execQuery('SELECT * FROM ' . $this->table)->fetchAll()); // fonctionne aussi sans le point virgule dans le SQL!!
}
public function findById(int $id) // obtenir une entrée avec son ID
{
return($this->execQuery('SELECT * FROM ' . $this->table . ' WHERE id = ' . $id)->fetch());
}
protected function find(array $criteria): array // obtenir une entrée avec un tableau associatif 'champ' => 'valeur'
{
$fields = [];
$values = [];
// change "'ID' => 2" en "'ID' = ?" et "2"
foreach($criteria as $field => $value)
{
$fields[] = "$field = ?"; // même chose que: $field . " = ?"
$values[] = $value;
}
$field_list = implode(' AND ', $fields); // créer une chaîne reliant les morceaux avec le morceau AND en paramètre: 'adresse = ? AND ID = ?'
// SELECT * FROM annonces WHERE actif = 1;
return($this->execQuery('SELECT * FROM ' . $this->table . ' WHERE ' . $field_list, $values)->fetchAll());
}
// update UPDATE
public function update(int $id)
{
$fields = [];
$values = [];
foreach($this as $field => $value)
{
if($value !== null && $field != 'db' && $field != 'table') // champs non renseignées et variables de l'objet qui ne sont pas des champs
{
$fields[] = $field . ' = ?';
$values[] = $value;
}
}
$values[] = $id;
$field_list = implode(', ', $fields);
// UPDATE annonces SET titre = ?, description = ?, actif = ? WHERE id= ?
return($this->execQuery('UPDATE ' . $this->table . ' SET ' . $field_list . ' WHERE id = ?', $values));
}
// delete DELETE
protected function delete(int $id)
{
return($this->execQuery("DELETE FROM {$this->table} WHERE id = ?", [$id])); // double quotes "" pour insertion de variable, paramètre [$id] parce qu'on veut un tableau
}
// fonction appelée une seule fois au lancement du programme
// le tableau nécessaire n'est pas copié en mémoire à l'instanciation (pas de fuite de mémoire), mais uniquement à l'appel de cette fonction statique, à la fin de la fonction la mémoire est libérée
// DBStructure::${self::$tableStructure} permet de nommer une variable statique de classe
static public function createTables()
{
foreach(StructTablesDB::$structureOfTables as $tableName => $oneTable)
{
//var_dump(StructTablesDB::${self::$tableStructure}); => propriété statique de classe dans une variable
$fields_and_types = [];
$query = 'CREATE TABLE IF NOT EXISTS ' . $tableName . ' (';
foreach($oneTable as $key => $value)
{
$fields_and_types[] = $key . ' ' . $value;
}
$query .= implode(', ', $fields_and_types); // implode() convertit un tableau en une chaîne avec un séparateur entre chaque élément
$query .= ', PRIMARY KEY(ID AUTOINCREMENT));';
//echo($query . "\n\n");
parent::getInstance()->exec($query); // merci singleton!
}
}
}
|