[V1.1.3] MySQL Database class

Gepost door Tom Janssen op 01-03-2009 12:58.

Met deze class kun je gemakkelijk controle kunt houden over een (MySQL) database. Tevens is dit de aller eerste class die ik ooit heb geschreven.

Ik denk dat deze class beter is dan degene die er al in staan omdat je hier alle query's kan nalezen en het result ervan opnieuw opvragen. Je kunt meerdere query's in een commando uitvoeren. Als je een enkele query uitvoert, hoef je geen result mee te geven aan fetch en numRows, hier wordt automatisch het laatste result gebruikt.

De class kent 3 error niveau's: (zijn te veranderen in de class constants)
100: Een fout in een normale functie.
200: Een fout in een config functie.
250: Een kritieke fout, script kan niet verder werken.

Changelog:
01-02-2009 - Release version 1.1.3
* Bugfixes

01-02-2009 - Release version 1.1.2
* Functie insertId toegevoegd.
* Errors codes in constats geduwd.
* Mogelijkheid om port op te geven en sockets gebruiken bij ev. andere subclasses.

28-02-2009 - Release version 1.1.1
* setConnection verandert in getConnection.

27-02-2009 - Release version 1.1.0
* Mogelijkheid zelf een child class te maken.
* MySQL class toegevoegd.

26-02-2009 - Release version 1.0

Bestanden van dit script

index.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
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
Uitleg
------
<?php
//Voorbeeld om zelf een child class te maken:
class mysqliDatabase extends databaseCore {
    //Declare alle abstracte functies (ev. meer)
}
//Je kan type veranderen (bij getConnection) in mysqli en het script zoekt het verder uit.

############################################################################

//class opzetten (port & socket worden in de MySQL variant niet gebruikt.
$db = databaseCore::getConnection(array(
                                            'type'         => 'mysql', //Hier de prefix van de child class. 
                                            'host'         => '', 
                                            'port'        => '', //Wordt niet gebruikt bij mysql, voeg toe bij host.
                                            'socket'     => '', //Wordt niet gebruikt bij mysql, gebruik host.
                                            'user'         => '', 
                                            'password'     => '', 
                                            'dbname'     => ''
                                        ), [$debug=false[, $connect=true]]);

//Query uitvoeren (retourneert het result)
$db->query($sqlCode);

//Meerdere query's uitvoeren (kunnen zoveel query's in als je wilt)
$db->multiQuery($sqlCode[, $...  ]);

//Rijen ophalen (zonder een argument wordt de laatste query gebruikt)
$db->fetch([$result]);

//Aantal rijen tellen (zonder een argument wordt de laatste query gebruikt)
$db->numRows([$result]);

//Geeft het aantal results van de laatste UPDATE, INSERT etc. query terug.
$db->affectedRows();

//Escaped zodat het veilig is in te voegen (zoals mysql_real_escape_string)
$db->escape($str);

//Geeft laatste insert id terug (zoals mysql_insert_id)
$db->insertId();

//Retourneert de SQL code of het RESULT van een query die is uitgevoerd
$db->getQuery($id); //id begint altijd met een q of een r, q staat voor de sql code, r staat voor het result. Daarna wordt een integer verwacht (het echte id)

//Aantal query's dat is uitgevoerd.
$db->getQueryTime();

//Retourneert de waarde van $this->debug
$db->getDebug();

//Veranderd het debug variabel
$db->setDebug($str); //Str kan zij: true, false of switch
?>

Voorbeeld.php
-------------
<?php
require_once('databasecore.class.php');
require_once('mysqldatabase.class.php');

try {
       $db = databaseCore::getConnection(array(
                                                'type'         => 'mysql', 
                                                'host'         => 'HOST', 
                                                'user'         => 'USER', 
                                                'password'     => 'PASSWORD', 
                                                'dbname'     => 'DATABASE_NAME'
                                            ), true, false);
    $db->query("SELECT * FROM test");
    while($row = $db->fetch()) {
        echo $row['name'].' zegt: '.$row['message'].'<br />';
    }
    echo 'Total messages: '.$db->numRows().'<br />';
} catch(Exception $e) {
    echo $e->getMessage().'<br />Code: '.$e->getCode().'<br />Line: '.$e->getLine().'<br />File: '.$e->getFile();
    if($e->getCode() > 100) {
        exit;
    }
}

try {
    $db->multiQuery(    "UPDATE status SET sitestatus = 'offline' WHERE id = 1",
                        "INSERT INTO users(name, pass, email) VALUES ('Pietje', '".md5('Dit_is_een_slecht_wachtwoord')."', '".$db->escape('pietje.s@domain.com')."')",
                        "UPDATE users SET ip = '".$_SERVER['REMOTE_ADDR']."' WHERE name = 'Pietje'",
                        "SELECT * FROM test"
                    );
    while($row = $db->fetch()) {
        echo $row['name'].' zegt: '.$row['message'].'<br />';
    }
} catch(Exception $e) {
    echo $e->getMessage().'<br />Code: '.$e->getCode().'<br />Line: '.$e->getLine().'<br />File: '.$e->getFile();
    if($e->getCode() > 100) {
        exit;
    }
}
?>

databasecore.class.php
-----------------------
<?php
/**
 * databaseCore
 * @package databaseConnector
 * @author Tom Janssen
 * @copyright Copyright (c) 2009, Tom Janssen
 * @license Free to use under GNU {@link http://www.gnu.org/licenses/gpl.html}
 * @version 1.1.3
 */
abstract class databaseCore {
    /**
     * General error level, generated by among other querys
     */
    const GEN_ERROR = 100;
    /**
     * General error level, generated by among other connection failure
     */
    const CON_ERROR = 200;
    /**
     * General error level, generated by among other setup failure
     */
    const FAT_ERROR = 250;
    /**
     * Holds the link identifier
     * @access protected
     * @var mixed
     */
    protected $_dblink;
   
    /**
     * Holds all the host settings before connecting
     * @static
     * @access protected
     * @var array
     */
    static protected $_data = array     (
                                'type'        => '',
                                'host'        => '',
                                'port'        => '',
                                'socket'    => '',
                                'user'        => '',
                                'password'    => '',
                                'dbname'    => ''
                            );
    
     /**
     * Holds all the host settings that the user has given.
     * @access protected
     * @var array
     */
    protected $_userdata = array ();
   
    /**
     * Debug true or false. Default false.
     * @access protected
     * @var bool
     */
    protected $debug = false;
   
    /**
     * Holds all query's in order of executing
     * @access protected
     * @var array
     */
    protected $queryCache = array();
    /**
     * Holds the 'id' of the last query.
     * @access protected
     * @var int
     */
    protected $queryTime = 0; //Dit is het aantal querys dat is uitgevoerd.

    /**
     * Constructor, sets the connecting vars and connects. Also set debug to true.
     * @access public
     * @param bool $debug holds the debug choise
     */
    public function __construct($debug=false) {
        if($debug === true) {
            $this->debug = true;
        }
    }
    
    /**#@+
     * @abstract
     */
    /**
     * connect, called by functions who connect to MySQL.
     * @access protected
     */
    abstract public function connect();
    
    /**
     * checkConnection, checks if there is a connection.
     * @access protected
     * @return bool
     */
    abstract protected function checkConnection();
    
    /**
     * escape, alias of mysql_real_escape_string
     * @access public
     * @param string $toEcape string to escape with mysql_real_escape_string.
     * @return string
     */
    abstract public function escape($toEscape);
    
    /**
     * query, tries to execute a query.
     * @access public
     * @param string $sql SQL code to execute.
     * @return string
     */
    abstract public function query($sql);
    
    /**
     * multiQuery, excecutes so many query's if you want. Just add more SQL codes.
     * @access public
     * @param string $sql,.. you can add this parameter many times as you want.
     */
    abstract public function multiQuery();
    
    /**
     * fetch, if no parameter is given, use last query.
     * @access public
     * @param [string $query] contains a query resource or an query ID starting with a 'r'. Not required to be given.
     * @return array
     */
    abstract public function fetch();
    
    /**
     * numRows, if no parameter is given, use last query.
     * @access public
     * @param [string $query] contains a query resource or an query ID starting with a 'r'
     * @return int
     */
    abstract public function numRows();
    
    /**
     * affectedRows, gives affected rows from last UPDATE, INSERT etc. query.
     * @access public
     * @return int
     */
    abstract public function affectedRows();
    
    /**
     * insertId, gives last insert id.
     * @access public
     * @return int
     */
    abstract public function insertId();
    
    /**#@-*/ 
    
    /**
     * setDebug, change debug setting
     * @access public
     * @param bool $newValue sets debug on true or false.
     * @return bool
     */
    public function setDebug($newValue) {
        if($newValue === true || $newValue === false) {
            $this->debug = $newValue;
            return true;
        } elseif($newValue === 'switch') {
            if($this->debug === true) {
                $this->debug = false;
                return true;
            } elseif($this->debug === false) {
                $this->debug = true;
                return true;
            }
        }
       
        return false;
    }
   
    /**
     * getDebug, get the debug setting
     * @access public
     * @return bool
     */
    public function getDebug() {
        return $this->debug;
    }
   
    /**
     * getQueryTime, returns the $queryTime variable.
     * @access public
     * @return int
     */
    public function getQueryTime() {
        return $this->queryTime;
    }
   
    /**
     * getDebug, get the debug setting
     * @access public
     * @param string $id hold the ID starting with a 'q' or a 'r'.
     * @return array
     */
    public function getQuery($id) {
        $type = substr($id, 0, 1);
        if(ctype_digit(substr($id, 1)) && $id >= 0 && $type === 'q' || $type === 'r') {
            if($id <= $this->queryTime) {
                return $this->queryCache[$type][$id];
            }
        }
       
        //Return false in alle andere gevallen.
        return false;
    }

    /**
    * Hiermee selecteer je een database type.
    * @static
    * @since version 1.1
    * @param array $data contains all data wich are importent to connect.
    */
    static public function getConnection(array $data = null, $debug=false, $connect=true) {
        if(!!!($keys = array_diff_key($data, self::$_data))) {
            $data = array_merge(self::$_data, $data);
        } else {
            $_s = (count($keys) > 1) ? 's' : '';
            throw new Exception('Geen valid parameter '.$_s.': '.implode(', ', $keys), self::FAT_ERROR);   
        } 
                $class = $data['type'].'Database';
                if(class_exists($class, false) === true) {
                    return new $class($data, $debug, $connect);
                }
            throw new Exception('Het type dat is opgegeven klopt niet. Gebruik een ander type aan of definieer deze class.', self::FAT_ERROR);
    }
}
?>

mysqldatabase.class.php
-----------------------
<?php
/**
 * mysqlDatabase
 * @package databaseConnector
 * @author Tom Janssen
 * @copyright Copyright (c) 2009, Tom Janssen
 * @license Free to use under GNU {@link http://www.gnu.org/licenses/gpl.html}
 * @version 1.1.3
 */
class mysqlDatabase extends databaseCore {
    /**
     * Constructor
     * @access public
     * @param array $data contains all needed data to set up a connection
     */
    public function __construct(array $data, $debug=false, $connect=true) {
        parent::__construct($debug);
        
        if(isset($data['host'], $data['user'], $data['password'], $data['dbname'])) {
            $this->_userdata = $data;
            
            if($connect === true) {
                try {
                    $this->connect();
                } catch(Exception $e) {
                    //Errors doorsturen.
                    throw $e;
                }
            }
        } else {
            throw new Exception('Niet genoeg gegevens meegestuurd.', self::FAT_ERROR);
        }
    }
    
    /**
     * Connector, hiermee zet het script een connectie op met de eerder ingevoerde gegevens.
     * @access public
     */
    public function connect() {
        $this->_dblink = mysql_connect($this->_userdata['host'], $this->_userdata['user'], $this->_userdata['password']);
        
        if($this->_dblink === false) {
            $errorMessage = "Kon geen verbinding maken met de database maken.";
            if($this->debug === true) {
                $errorMessage .= "<br />".mysql_errno().": ".mysql_error();
            }
        } else {
            //Probeer nu de database te selecteren
            $dbbase = mysql_select_db($this->_userdata['dbname'], $this->_dblink);
            
            //Database select error handler
            if($dbbase === false) {
                $errorMessage = "Kon geen database selecteren.";
                if($this->debug === true) {
                    $errorMessage .= "<br />".mysql_errno().": ".mysql_error();
                }
            }
        }
        
        if(isset($errorMessage)) {
            throw new Exception($errorMessage, self::FAT_ERROR);
        }
    }
    
    /**
     * checkConnection, checks if there is a connection, alias from mysql_ping.
     * @access protected
     * @return bool
     */
    protected function checkConnection() {
        //Doe dit omdat als er nog geen connectie is er een lelijke error komt.
        if($this->_dblink !== NULL) {
            return mysql_ping($this->_dblink);
        }
        
        return false;
    }
    
    /**
     * escape, alias of mysql_real_escape_string
     * @access public
     * @param string $toEcape string to escape with mysql_real_escape_string.
     * @return string
     */
    public function escape($toEscape) {
        //Doe dit omdat als er nog geen connectie is er een lelijke error komt.
        if($this->_dblink !== NULL) {
            return mysql_real_escape_string($toEscape, $this->_dblink);
        }
        
        return mysql_real_escape_string($toEscape);
    }
   
    /**
     * query, tries to execute a query.
     * @access public
     * @param string $sql SQL code to execute.
     * @return string
     */
    public function query($sql) {
        if($this->checkConnection() === true) {
            $this->queryTime++;
            $this->queryCache['q'][$this->queryTime] = $sql;
           
            $query = mysql_query($sql, $this->_dblink);
            if($query !== false) {
                $this->queryCache['r'][$this->queryTime] = $query;
                return $query;
            }
            $errorMessage = "Kon geen query verzenden.";
            $eC = self::GEN_ERROR;
            $this->queryCache['r'][$this->queryTime] = mysql_error($this->_dblink);
        } else {
            $errorMessage = "Kon geen verbinding vinden.";
            $eC = self::CON_ERROR;
        }
       
        if($this->debug === true && $eC != self::CON_ERROR) {
            $errorMessage .= "<br />".mysql_errno($this->_dblink).": ".mysql_error($this->_dblink);
        }
        throw new Exception($errorMessage, $eC);
    }
   
    /**
     * multiQuery, excecutes so many query's if you want. Just add more SQL codes.
     * @access public
     * @param string $sql,.. you can add this parameter many times as you want.
     */
    public function multiQuery() {
        if($this->checkConnection() === true) {
            $numArgs = func_num_args();
            if($numArgs === 1) {
                return $this->query(func_get_arg(0));
            }
                for($i = 0; $i < $numArgs; $i++) {
                    $this->queryTime++;
                    $this->queryCache['q'][$this->queryTime] = func_get_arg($i);
                   
                        $query = mysql_query($this->queryCache['q'][$this->queryTime], $this->_dblink);
                        if($query !== false) {
                            $this->queryCache['r'][$this->queryTime] = $query;
                        } else {
                            $errorMessage = "Kon de query met id #".$this->queryTime." niet verzenden!";
                            $this->queryCache['r'][$this->queryTime] = mysql_error($this->_dblink);
                           
                            if($this->debug === true) {
                                $errorMessage .= "<br />".mysql_errno($this->_dblink).": ".mysql_error($this->_dblink);
                            }
                            throw new Exception($errorMessage, self::GEN_ERROR);
                        }
                   
                    $query = NULL;
                }
        } else {
            //Errors onmogelijk omdat er geen verbinding is.
            $errorMessage = "Kon geen verbinding vinden.";
            throw new Exception($errorMessage, self::CON_ERROR);
        }
    }
   
    /**
     * fetch, if no parameter is given, use last query.
     * @access public
     * @param string $query contains a query resource or an query ID starting with a 'r'. Not required to be given.
     * @return array
     */
    public function fetch() {
            if(func_num_args() == 0) {
                $query = 'r'.$this->queryTime;
            } else {
                $query = func_get_arg(0);
            }
        if(preg_match('/r[0-9]/i', $query)) {
            $rQuery = $this->queryCache[substr($query, 0, 1)][substr($query, 1)];
        } else {
            $rQuery = $query;
        }
       
        $fQuery = mysql_fetch_assoc($rQuery);
        if($fQuery === false && trim(mysql_error($this->_dblink)) != '') {
            $errorMessage = "Kon de query niet fetchen.";
            if($this->debug === true) {
                $errorMessage .= "<br />".mysql_errno($this->_dblink).": ".mysql_error($this->_dblink);
            }
           
            throw new Exception($errorMessage, self::GEN_ERROR); //Function stops here.
        }
        return $fQuery; //Else return the fetched rows.
    }
   
    /**
     * numRows, if no parameter is given, use last query.
     * @access public
     * @param string $query contains a query resource or an query ID starting with a 'r'
     * @return int
     */
    public function numRows() {
            if(func_num_args() == 0) {
                $query = 'r'.$this->queryTime;
            } else {
                $query = func_get_arg(0);
            }
        if(preg_match('/r[0-9]/i', $query)) {
            $rQuery = $this->queryCache['r'][substr($query, 1)];
        } else {
            $rQuery = $query;
        }
       
        return mysql_num_rows($rQuery);
    }
    
    /**
     * affectedRows, alias of mysql_affected_rows
     * @access public
     * @return int
     */
    public function affectedRows() {
        $affectedRows =  mysql_affected_rows($this->_dblink);
        
        //Als de laatste query heeft gefaald returnt hij -1. Gewenste waarde is dan 0.
        if($affectedRows === -1) {
            return 0;
        }
        return $affectedRows;
    }
    
    /**
     * insertId, alias of mysql_insert_id
     * @access public
     * @param mixed $tabel this will give the last auto_increment, if you specefy a tabel, this will be send with. Default: false.
     * @return int
     * @since version 1.1.2
     */
    public function insertId($tabel=false) {
        if($this->checkConnection()) {
                $idQuery = "SELECT LAST_INSERT_ID() AS last_id";
                if($tabel !== false) {
                    $idQuery .= " FROM ".$tabel;
                }
            try {
                $this->query($idQuery);
                $row = $this->fetch();
                return $row['last_id'];
            } catch(Exception $e) {
                throw $e;
            }
        } else {
            throw new Exception('Er is geen verbinding gevonden.', self::CON_ERROR);
        }
    }
}
?>

Commentaar

26-02-2009 19:22

Ziet er op zich goed uit. Mooi uitgebreid script. Het zou pas echt een mooi script zijn als de class met meerdere databases overweg kan. Je zou bijv. voor elke database de klas opnieuw kunnen maken (zelfde functie namen) zodat je alleen 1 regeltje code hoeft te weizigen en toch zorgen dat alles het nog doet.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<?php
require_once('db/mysql.php');
//require_once('db/postgresql.php');

$db = new DB_Mysql(....);

// Rest van je script
?>

Word dan:

<?php
//require_once('db/mysql.php');
require_once('db/postgresql.php');

$db = new DB_Postgresql(....);

// Rest van je script
?>
26-02-2009 19:37

@Leon: Ik heb erover zitten twijfelen om dit te toen, maar aangezien ik er zelf niet zoveel aan heb (omdat ik alleen MySQL gebruik) heb ik het toch maar achterwegen gelaten. Inderdaad misschien iets voor de toekomst maar dan iets in de richting van polymorphism en niet wat jij zegt.

1
2
3
Post hier de source-code van je script. Alle informatie tussen <? ... ?> en <?php ... ?> zal automatisch worden getoond in color-coding. 

Let op! Het is niet de bedoeling om hier een link naar je website te plaatsen. Post hier gewoon de code, veel simpeler, sneller en meer kans dat het blijft staan.
26-02-2009 21:47

Ik snap zelf ook niet waarom iedereen opeens meerdere databases moet kunnen gebruiken, MySQL is en blijft voor heel veel toepassingen dé database om te gebruiken. Aangezien het stabiel en snel is.

Opzich is het een leuke toevoeging hoor, maar in mijn opinie onnodig als je toch niet van plan bent om te het te gebruiken.

Ps. Misschien is het handig om nog meer statistieken bij te houden, hoe lang een query duurt, hoeveel results er zijn, hoeveel er gelezen worden (altijd gemakkelijk met het verbeteren van je website in totaal).

1
<? $save="databaseruimte"; ?>
26-02-2009 21:51

@Voor naam: Hoe bedoel je, statistieken. Misschien leuk en aardig maar kost allemaal net een beetje meer tijd en ik zou het persoonlijk niet gebruiken omdat het me niet interesseert of een query er 50 of 200 milliseconden over doet.

1
2
3
Post hier de source-code van je script. Alle informatie tussen <? ... ?> en <?php ... ?> zal automatisch worden getoond in color-coding. 

Let op! Het is niet de bedoeling om hier een link naar je website te plaatsen. Post hier gewoon de code, veel simpeler, sneller en meer kans dat het blijft staan.
27-02-2009 01:07

Ik snap eigenlijk nog steeds niet waarom iedereen zo klakkeloos denk dat MySQL dé database is. MySQL is niet de veiligste, niet de snelste, niet de uitgebreidste database, etc. Ik ben blij dat ik dit sinds kort heb ingezien. Het enige waarom MySQL zo populair is omdat iedereen het gebruikt.

Bijv. PostgreSQL is een goed alternatief. Hij is ook opensource, (dus gratis), werkt op linux, windows, etc. Maar het belangrijkste, hij is veiliger. Hij laat geen rare fouten toe, etc. En wat ik tot nu heb gemerkt is dat hij vaak nog sneller is ook.

1
2
3
Post hier de source-code van je script. Alle informatie tussen <? ... ?> en <?php ... ?> zal automatisch worden getoond in color-coding. 

Let op! Het is niet de bedoeling om hier een link naar je website te plaatsen. Post hier gewoon de code, veel simpeler, sneller en meer kans dat het blijft staan.
27-02-2009 12:03

@Lode: Ok, ik zal nog eens mijn script reviseren. Ik kende de functie mysql(i)_ping niet. Er zit ook een foutje in je code Lode:

1
2
3
4
5
6
7
8
9
10
11
12
13
<?php
            else{
                $_s = (count($keys) > 1) ? 's' : '';
                throw Lode_Sql_Exception('Unvalid parameter'.$_s.': '.implode(', ', $keys));   
            } 

//moet worden

            else{
                $_s = (count($keys) > 1) ? 's' : '';
                throw new Lode_Sql_Exception('Unvalid parameter'.$_s.': '.implode(', ', $keys));   //Hier ben je de new vergeten ;)
            } 
?>
27-02-2009 12:30

Watvoor database je neemt is natuurlijk geen script library discussie. Meer een persoonlijke keuze.

ik heb wel een aantal punten van kritiek!

ik zou nog geen verbinding maken in de __construct.
Maar pas als je 'm nodig hebt.

isConnected kan je veel makelijker doen met
http://nl.php.net/mysql_ping

de === operator gebruik je eigenlijk alleen bij null, true, false. Dus niet voor string vergelijkingen.

Een hoop mysql_* functies gebruiken optioneel de verbindings resource zoals mysql_error(), mysql_errno(), mysql_real_escape_string().
Niet voor niets! Ik mis de implementatie hiervoor veelal.

dan het result. mysql heeft allerlei functionaliteiten voor de result resource. maar hier gebeurd ook niks mee.
Hier kan je vrij eensvoudig een leuke result iterator omheen bakken. Die het resultaat weer veel eenvoudiger maakt.
zo mysql class bestaat eigenlijk ui 2 delen gebaseerd op de connection resource en de result resource.

Persoonlijk gebruik ik eigenlijk alleen nog mysqli als ik met mysql moet werken.

En ik kan je verklappen dat mijn opzet heel anders is.
Zie stukje code...
met een array is het wat universeler. een __construct voor andere databases ziet er qua abstractie dan hetzelfde uit.

abstract public function __construct(array $settings = null);

ik mis ook socket ondersteuning wat standaard is op de Mac zo ongeveer.

Verder qua escapen. in mysql wil je altijd '' om de variabelen hebben en alles door mysql(i)_real_escape_string halen.

ik heb danook optionele parameters voor de query() functie die er gelijk in gequote worden.

Ook mis ik ondersteuning voor prepared statements en transactions.

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
<?php
class Lode_Sql_Adapter_Mysqli extends Lode_Sql_Adapter{
    
    protected $_settings = array(
        'host'     => null,
        'user'     => null,
        'password' => null,
        'database' => null,
        'port'     => null,
        'socket'   => null    
    );
    protected $_source = null;
    protected $_resource = null;
    protected $_transaction = false;
    
    /**
     * Store connection settings into scope.
     * And check for host and username xor socket params.
     * 
     * @access public
     * @param array $settings
     */
    public function __construct(array $settings = null){
        if(!extension_loaded('mysqli')){
            throw new Lode_Sql_Exception('Mysqli extension is not loaded');
        }
        if(null !== $settings){
            if(!!!($keys = array_diff_key($settings, $this->_settings))){
                $settings = array_merge($this->_settings, $settings);
            }
            else{
                $_s = (count($keys) > 1) ? 's' : '';
                throw new Lode_Sql_Exception('Unvalid parameter'.$_s.': '.implode(', ', $keys));    
            }
            if(isset($settings['host'])){
                if(!isset($settings['user'])){
                    throw new Lode_Sql_Exception('Database connection requires a username');
                }
                $this->_source = $settings;
            }
            elseif(isset($settings['socket'])){
                $this->_source = $settings;
            }
            else{
                throw new Lode_Sql_Exception('Database connection requires a host');
            }
        }
        else{
            throw new Lode_Sql_Exception('Database connection has no settings');
        }
    }
}
?>
27-02-2009 13:40

Wat ik me afvrag. Ik ben gene held met Exceptions enzo? Maar is het gewoon neit handiger om de try en catch blokken IN die functies te zetten?

Dan hoef je in je code om de methods geen try-catch meer te gebruiken.

of lijkt dit onzin?

1
2
3
Post hier de source-code van je script. Alle informatie tussen <? ... ?> en <?php ... ?> zal automatisch worden getoond in color-coding. 

Let op! Het is niet de bedoeling om hier een link naar je website te plaatsen. Post hier gewoon de code, veel simpeler, sneller en meer kans dat het blijft staan.
27-02-2009 13:57

@Arien: Ik snap je opmerking niet echt. Ik ben nu bezig met wat aanpassingen en als je iets nuttigs hebt dan kan ik dat nu meenemen.

1
2
3
Post hier de source-code van je script. Alle informatie tussen <? ... ?> en <?php ... ?> zal automatisch worden getoond in color-coding. 

Let op! Het is niet de bedoeling om hier een link naar je website te plaatsen. Post hier gewoon de code, veel simpeler, sneller en meer kans dat het blijft staan.
27-02-2009 14:21

Ah, laatmaar...
ik keek scheel.
Er worden als exceptions aangeroepen in de functies, en dacht even verkeerd.
KOFFIETIJD :)

1
2
3
Post hier de source-code van je script. Alle informatie tussen <? ... ?> en <?php ... ?> zal automatisch worden getoond in color-coding. 

Let op! Het is niet de bedoeling om hier een link naar je website te plaatsen. Post hier gewoon de code, veel simpeler, sneller en meer kans dat het blijft staan.
28-02-2009 16:28

denk je ook aan:

* insert-id bij insert-queries?
* de problemen met stored procedures in de mysql lib?
* mensen die een andere port dan 3306 gebruiken?

Jouw codes 100, 200 en 250 lijken me perfect voor class constants

1
2
3
4
5
6
7
8
<?php
class myClass
{
  const GENERAL_ERROR = 100;
  const CONFIG_ERROR  = 200;
  const FATAL_ERROR   = 250;
}
?>
28-02-2009 17:31

@Boyd: Aan class constants had ik niet gedacht. Maar je kan toch als je een andere poort hebt dit opgeven bij $data['host']? Of dat zegt de phpmanual op php.net, en wat bedoel je precies met "de problemen met stored procedures in de mysql lib?"

1
2
3
Post hier de source-code van je script. Alle informatie tussen <? ... ?> en <?php ... ?> zal automatisch worden getoond in color-coding. 

Let op! Het is niet de bedoeling om hier een link naar je website te plaatsen. Post hier gewoon de code, veel simpeler, sneller en meer kans dat het blijft staan.
01-03-2009 11:11

>Maar je kan toch als je een andere poort hebt dit opgeven bij $data['host']? Of dat zegt de phpmanual op php.net

Je hebt gelijk, ik gebruik nog wel een mysqli en daarbij is de port een aparte parameter. Jouw class voorziet niet in een aparte port, mocht je deze nodig hebben.

>en wat bedoel je precies met "de problemen met stored procedures in de mysql lib?"

Zie: http://nl.php.net/manual/en/function.mysql-query.php#82429
Komt er op neer dat je dan beter mysqli kan gebruiken, aangezien deze een functie mysqli_multi_query heeft.
Dat gaat trouwens een issue worden met de naamgeving van jouw method multiQuery();

1
2
3
Post hier de source-code van je script. Alle informatie tussen <? ... ?> en <?php ... ?> zal automatisch worden getoond in color-coding. 

Let op! Het is niet de bedoeling om hier een link naar je website te plaatsen. Post hier gewoon de code, veel simpeler, sneller en meer kans dat het blijft staan.
01-03-2009 18:28

Vermeld hier alle zaken betreffende valkuilen, handige informatie, (installatie-)instructies e.d.

1
2
3
4
5
- Waarom is getConnection static? Kun je connecties hebben zonder de class te instantieren? Ik werk regelmatig met meerdere databaseverbindingen tegelijkertij in hetzelfde script.

- Waarom geef je een resultset identifier terug aan de aanroeper van de "query" method? Zo moet het script bij gaan houden welke parameters jouw class nodig heeft om dingen te doen, en als het script dat vergeet dan krijg het zomaar wat gegevens doorgespeeld van een query die ooit eens gedraaid is.

Wat ik steevast aanraadt is om twee aparte classes te maken, een voor het uitvoeren van queries en een om de resultaten te behandelen. De uitvoer class geeft altijd een resultaatobject terug in dat resultaat object bevat *alle* data die uit die query terugkwam, geen resultidentifier maar gewoon een array met records. Waarom: Zo kun je met 1 verbindingobject meerdere queries draaien zonder ooit in de knoop te raken, en je wilt altijd alle resultaten van een query ophalen dus kun je dat netzogoed direct doen en zo weer wat belasting van de server sparen.
01-03-2009 19:48

Eventjes in het algemeen wat opmerkingen. 'Jullie' werken 'altijd' anders dan waar scripts voor bedoeld zijn. Dit is niet voor scripts gemaakt waarmee ik 4 verschillende databases wil benaderen. Inderdaad, daar is dit script niet geschikt voor. Maar iedereen die dit wíl is in de meeste gevallen (redelijk) gevorderd en die schrijven hun eigen classes. Daar is deze class dus niet voor bedoeld. Het is bedoeld voor de mensen die makkelijk met mysql willen werken en als ze dan overstappen naar mysqli alleen een extra child hoeven schrijven en het script werkt in hun systeem. Zo hoeven ze niet een heel systeem te herschrijven. Maar ik vraag me dan altijd af, als jullie eigen script zoveel 'beter' is, waarom posten jullie het dan niet gewoon? Dan kunnen anderen ook van dat 'goede' script genieten!

1
n.v.t.
02-03-2009 10:03

Waarom heb je een script nodig?
PDO of MySQLi geeft je al alles wat je nodig hebt.
Als je daar namelijk goed naar kijkt, kan je dan nog 1 goede reden noemen waarom je een eigen implementatie moet schrijven, terwijl anderen al zoveel tijd geïnvesteerd hebben?

Zie PDO, MySQLi, PEAR, ADODB etc etc..

werkt prima, zo niet beter dan je eigen klasse.

1
2
3
Post hier de source-code van je script. Alle informatie tussen <? ... ?> en <?php ... ?> zal automatisch worden getoond in color-coding. 

Let op! Het is niet de bedoeling om hier een link naar je website te plaatsen. Post hier gewoon de code, veel simpeler, sneller en meer kans dat het blijft staan.
02-03-2009 15:34

@Boyd: Ik ben het niet met je eens. Je kan veel beter zélf een class schrijven (of extend) zodat je voor de meeste functies een mooie eigen aanpak hebt, en een query in kan gooien en een fetch eruit komt of zoals hier, dat het je query opslaat zodat je gewoon fetch(); gebruikt, en geen resource meegeeft oid.

1
2
3
Post hier de source-code van je script. Alle informatie tussen <? ... ?> en <?php ... ?> zal automatisch worden getoond in color-coding. 

Let op! Het is niet de bedoeling om hier een link naar je website te plaatsen. Post hier gewoon de code, veel simpeler, sneller en meer kans dat het blijft staan.
03-03-2009 09:50

Vermeld hier alle zaken betreffende valkuilen, handige informatie, (installatie-)instructies e.d.

1
2
3
4
5
6
7
8
9
"Je kan veel beter zélf een class schrijven"

Nou, 'veel' is een groot woord, maar het is wel zo dat de class van iemand anders zelden doet wat jij wilt/nodig hebt.

Dat brengt me op je andere reply, wat je daar zegt "Jullie doen aparte dingen", dat is nu juist het probleem, het is helemaal niet apart. Dat jij het nog niet gedaan hebt is meestal gewoon puur toeval.

Verder wordt je class niet simpeler door beperkingen in te bouwen, de toepassing wordt alleen maar ingewikkelder.

PS: en waarom post ik mijn class niet: goed idee, houd deze maar in de gaten: http://www.yapf.net/index.php/Database_access_class
03-03-2009 22:04

@Vincent: Interessante class. Heb hem eens bekeken maar ik mis de interface en de basisclass.

1
2
3
Post hier de source-code van je script. Alle informatie tussen <? ... ?> en <?php ... ?> zal automatisch worden getoond in color-coding. 

Let op! Het is niet de bedoeling om hier een link naar je website te plaatsen. Post hier gewoon de code, veel simpeler, sneller en meer kans dat het blijft staan.
Inloggen wachtwoord vergeten? Aanmelden