Subversion Repositories PHPX

Rev

Rev 34 | Rev 44 | Go to most recent revision | Show entire file | Ignore whitespace | Details | Blame | Last modification | View Log | RSS feed

Rev 34 Rev 41
Line 4... Line 4...
4
require_once __DIR__ . '/../AbstractModel.php';
4
require_once __DIR__ . '/../AbstractModel.php';
5
5
6
/**
6
/**
7
 * Generic database model class using PDO (PHP Data Objects)
7
 * Generic database model class using PDO (PHP Data Objects)
8
 *
8
 *
-
 
9
 * @property-read PDO $connection
-
 
10
 *   Database connection.  Established on read access to this
-
 
11
 *   property if not yet established.
9
 * @property-read array $lastError
12
 * @property-read array $lastError
10
 *   Last error information of the database operation.
13
 *   Last error information of the database operation.
11
 *   See {@link PDOStatement::errorInfo()}.
14
 *   See {@link PDOStatement::errorInfo()}.
12
 * @property-read string $lastInsertId
15
 * @property-read string $lastInsertId
13
 *   ID of the last inserted row, or the last value from a sequence object,
16
 *   ID of the last inserted row, or the last value from a sequence object,
Line 19... Line 22...
19
 * @author Thomas Lahn
22
 * @author Thomas Lahn
20
 */
23
 */
21
class Database extends AbstractModel
24
class Database extends AbstractModel
22
{
25
{
23
  /* Access properties */
26
  /* Access properties */
24
 
27
25
  /**
28
  /**
26
   * DSN of the database
29
   * DSN of the database
27
   * @var string
30
   * @var string
28
   */
31
   */
29
  protected $_dsn = '';
32
  protected $_dsn = '';
30
 
33
31
  /**
34
  /**
32
   * Username to access the database
35
   * Username to access the database
33
   * @var string
36
   * @var string
34
   */
37
   */
35
  protected $_username;
38
  protected $_username;
36
 
39
37
  /**
40
  /**
38
   * Password to access the database
41
   * Password to access the database
39
   * @var string
42
   * @var string
40
   */
43
   */
41
  protected $_password;
44
  protected $_password;
42
 
45
43
  /**
46
  /**
44
   * PDO driver-specific options
47
   * PDO driver-specific options
45
   * @var array
48
   * @var array
46
   */
49
   */
47
  protected $_options = array();
50
  protected $_options = array();
Line 51... Line 54...
51
   * left-hand side (for security reasons and to prevent a name
54
   * left-hand side (for security reasons and to prevent a name
52
   * from being parsed as a keyword).
55
   * from being parsed as a keyword).
53
   * @var string
56
   * @var string
54
   */
57
   */
55
  protected $_leftQuote = '';
58
  protected $_leftQuote = '';
56
 
59
57
  /**
60
  /**
58
   * Database-specific string to use for quoting a name or value
61
   * Database-specific string to use for quoting a name or value
59
   * left-hand side (for security reasons and to prevent a name
62
   * left-hand side (for security reasons and to prevent a name
60
   * from being parsed as a keyword).
63
   * from being parsed as a keyword).
61
   * @var string
64
   * @var string
62
   */
65
   */
63
  protected $_rightQuote = '';
66
  protected $_rightQuote = '';
64
 
67
65
  /* Status properties */
68
  /* Status properties */
66
 
69
67
  /**
70
  /**
68
   * Database connection
71
   * Database connection
69
   * @var PDO
72
   * @var PDO
70
   */
73
   */
71
  protected $_connection;
74
  protected $_connection;
72
 
75
73
  /**
76
  /**
74
   * Last success value of the database operation
77
   * Last success value of the database operation
75
   * @var boolean
78
   * @var boolean
76
   */
79
   */
77
  protected $_lastSuccess;
80
  protected $_lastSuccess;
Line 79... Line 82...
79
  /**
82
  /**
80
   * Last error information of the database operation
83
   * Last error information of the database operation
81
   * @var array
84
   * @var array
82
   */
85
   */
83
  protected $_lastError;
86
  protected $_lastError;
84
 
87
85
  /**
88
  /**
86
   * Last result of the database operation
89
   * Last result of the database operation
87
   * @var array
90
   * @var array
88
   */
91
   */
89
  protected $_lastResult;
92
  protected $_lastResult;
Line 92... Line 95...
92
  * ID of the last inserted row, or the last value from a sequence object,
95
  * ID of the last inserted row, or the last value from a sequence object,
93
  * depending on the underlying driver. May not be supported by all databases.
96
  * depending on the underlying driver. May not be supported by all databases.
94
  * @var string
97
  * @var string
95
  */
98
  */
96
  protected $_lastInsertId = '';
99
  protected $_lastInsertId = '';
97
 
100
98
  /**
101
  /**
99
   * Creates a new <code>Database</code> instance.
102
   * Creates a new <code>Database</code> instance.
100
   *
103
   *
101
   * Each of the parameters is optional and can also be given
104
   * Each of the parameters is optional and can also be given
102
   * by a protected property where the parameter name is preceded
105
   * by a protected property where the parameter name is preceded
Line 115... Line 118...
115
  {
118
  {
116
    if ($dsn !== '')
119
    if ($dsn !== '')
117
    {
120
    {
118
      $this->_dsn = $dsn;
121
      $this->_dsn = $dsn;
119
    }
122
    }
120
   
123
121
    if ($username !== null)
124
    if ($username !== null)
122
    {
125
    {
123
      $this->_username = $username;
126
      $this->_username = $username;
124
    }
127
    }
125
   
128
126
    if ($password !== null)
129
    if ($password !== null)
127
    {
130
    {
128
      $this->_password = $password;
131
      $this->_password = $password;
129
    }
132
    }
130
   
133
131
    if ($options)
134
    if ($options)
132
    {
135
    {
133
      $this->_options = $options;
136
      $this->_options = $options;
134
    }
137
    }
135
   
-
 
136
    $this->_connection =
-
 
137
      new PDO($this->_dsn, $this->_username, $this->_password, $this->_options);
-
 
138
  }
138
  }
139
 
139
-
 
140
  /**
-
 
141
   * @return PDO
-
 
142
   */
-
 
143
  public function getConnection ()
-
 
144
  {
-
 
145
    if ($this->_connection === null)
-
 
146
    {
-
 
147
      $this->_connection =
-
 
148
        new PDO($this->_dsn, $this->_username, $this->_password, $this->_options);
-
 
149
    }
-
 
150
-
 
151
    return $this->_connection;
-
 
152
  }
-
 
153
140
  /**
154
  /**
141
   * Initiates a transaction
155
   * Initiates a transaction
142
   *
156
   *
143
   * @return bool
157
   * @return bool
144
   * @see PDO::beginTransaction()
158
   * @see PDO::beginTransaction()
145
   */
159
   */
146
  public function beginTransaction()
160
  public function beginTransaction()
147
  {
161
  {
148
    return $this->_connection->beginTransaction();
162
    return $this->connection->beginTransaction();
149
  }
163
  }
150
 
164
151
  /**
165
  /**
152
   * Rolls back a transaction
166
   * Rolls back a transaction
153
   *
167
   *
154
   * @return bool
168
   * @return bool
155
   * @see PDO::rollBack()
169
   * @see PDO::rollBack()
156
   */
170
   */
157
  public function rollBack()
171
  public function rollBack()
158
  {
172
  {
159
    return $this->_connection->rollBack();
173
    return $this->connection->rollBack();
160
  }
174
  }
161
 
175
162
  /**
176
  /**
163
   * Commits a transaction
177
   * Commits a transaction
164
   *
178
   *
165
   * @return bool
179
   * @return bool
166
   * @see PDO::commit()
180
   * @see PDO::commit()
167
   */
181
   */
168
  public function commit()
182
  public function commit()
169
  {
183
  {
170
    return $this->_connection->commit();
184
    return $this->connection->commit();
171
  }
185
  }
172
 
186
173
  /**
187
  /**
174
   * Prepares a statement for execution with the database
188
   * Prepares a statement for execution with the database
175
   * @param string $query
189
   * @param string $query
176
   */
190
   */
177
  public function prepare($query, array $driver_options = array())
191
  public function prepare($query, array $driver_options = array())
178
  {
192
  {
179
    return $this->_connection->prepare($query, $driver_options);
193
    return $this->connection->prepare($query, $driver_options);
180
  }
194
  }
181
 
195
182
  /**
196
  /**
183
   * Returns the ID of the last inserted row, or the last value from
197
   * Returns the ID of the last inserted row, or the last value from
184
   * a sequence object, depending on the underlying driver.
198
   * a sequence object, depending on the underlying driver.
185
   *
199
   *
186
   * @return int
200
   * @return int
187
   */
201
   */
188
  public function getLastInsertId()
202
  public function getLastInsertId()
189
  {
203
  {
190
    return $this->_lastInsertId;
204
    return $this->_lastInsertId;
191
  }
205
  }
192
 
206
193
  /**
207
  /**
194
   * Escapes a database name so that it can be used in a query.
208
   * Escapes a database name so that it can be used in a query.
195
   *
209
   *
196
   * @param string $name
210
   * @param string $name
197
   *   The name to be escaped
211
   *   The name to be escaped
Line 200... Line 214...
200
   */
214
   */
201
  public function escapeName($name)
215
  public function escapeName($name)
202
  {
216
  {
203
    return $this->_leftQuote . $name . $this->_rightQuote;
217
    return $this->_leftQuote . $name . $this->_rightQuote;
204
  }
218
  }
205
 
219
206
  /**
220
  /**
207
   * Determines if an array is associative (has not all integer keys).
221
   * Determines if an array is associative (has not all integer keys).
208
   *
222
   *
209
   * @author
223
   * @author
210
   *   Algorithm courtesy of squirrel, <http://stackoverflow.com/a/5969617/855543>.
224
   *   Algorithm courtesy of squirrel, <http://stackoverflow.com/a/5969617/855543>.
Line 216... Line 230...
216
  protected function _isAssociativeArray(array $a)
230
  protected function _isAssociativeArray(array $a)
217
  {
231
  {
218
    for (reset($a); is_int(key($a)); next($a));
232
    for (reset($a); is_int(key($a)); next($a));
219
    return !is_null(key($a));
233
    return !is_null(key($a));
220
  }
234
  }
221
 
235
222
  /**
236
  /**
223
   * Escapes an associative array so that its string representation can be used
237
   * Escapes an associative array so that its string representation can be used
224
   * as list with table or column aliases in a query.
238
   * as list with table or column aliases in a query.
225
   *
239
   *
226
   * This method does not actually escape anything; it only inserts the
240
   * This method does not actually escape anything; it only inserts the
Line 242... Line 256...
242
      if (strpos($column, $this->_leftQuote) === false
256
      if (strpos($column, $this->_leftQuote) === false
243
         && strpos($column, $this->_rightQuote) === false)
257
         && strpos($column, $this->_rightQuote) === false)
244
      {
258
      {
245
        $quotedColumn = $this->_leftQuote . $column . $this->_rightQuote;
259
        $quotedColumn = $this->_leftQuote . $column . $this->_rightQuote;
246
      }
260
      }
247
     
261
248
      $value = $value . ' AS ' . $quotedColumn;
262
      $value = $value . ' AS ' . $quotedColumn;
249
    }
263
    }
250
 
264
251
    return $array;
265
    return $array;
252
  }
266
  }
253
267
254
  /**
268
  /**
255
   * @param array $a
269
   * @param array $a
256
   * @param string $prefix
270
   * @param string $prefix
257
   */
271
   */
258
  private static function _expand(array $a, $prefix)
272
  private static function _expand(array $a, $prefix)
259
  {
273
  {
260
    $a2 = array();
274
    $a2 = array();
261
   
275
262
    foreach ($a as $key => $value)
276
    foreach ($a as $key => $value)
263
    {
277
    {
264
      $a2[] = ':' . $prefix . ($key + 1);
278
      $a2[] = ':' . $prefix . ($key + 1);
265
    }
279
    }
266
   
280
267
    return $a2;
281
    return $a2;
268
  }
282
  }
269
 
283
270
  /**
284
  /**
271
   * Escapes an associative array so that its string representation can be used
285
   * Escapes an associative array so that its string representation can be used
272
   * as value list in a query.
286
   * as value list in a query.
273
   *
287
   *
274
   * This method should be overridden by inheriting classes to escape
288
   * This method should be overridden by inheriting classes to escape
Line 291... Line 305...
291
   *   The escaped array
305
   *   The escaped array
292
   */
306
   */
293
  protected function _escapeValueArray(array &$array, $suffix = '')
307
  protected function _escapeValueArray(array &$array, $suffix = '')
294
  {
308
  {
295
    $result = array();
309
    $result = array();
296
       
310
297
    foreach ($array as $column => $value)
311
    foreach ($array as $column => $value)
298
    {
312
    {
299
      $op = '=';
313
      $op = '=';
300
      $placeholder = ":{$column}";
314
      $placeholder = ":{$column}";
301
     
315
302
      if (is_array($value) && $this->_isAssociativeArray($value))
316
      if (is_array($value) && $this->_isAssociativeArray($value))
303
      {
317
      {
304
        reset($value);
318
        reset($value);
305
        $op = ' ' . key($value) . ' ';
319
        $op = ' ' . key($value) . ' ';
306
       
320
307
        $value = $value[key($value)];
321
        $value = $value[key($value)];
308
      }
322
      }
309
     
323
310
      if (is_array($value))
324
      if (is_array($value))
311
      {
325
      {
312
        $placeholder = '(' . implode(', ', self::_expand($value, $column)) . ')';
326
        $placeholder = '(' . implode(', ', self::_expand($value, $column)) . ')';
313
      }
327
      }
314
     
328
315
      $result[] = $this->_leftQuote . $column . $this->_rightQuote . "{$op}{$placeholder}{$suffix}";
329
      $result[] = $this->_leftQuote . $column . $this->_rightQuote . "{$op}{$placeholder}{$suffix}";
316
    }
330
    }
317
 
331
318
    return $result;
332
    return $result;
319
  }
333
  }
320
   
334
321
  /**
335
  /**
322
   * Constructs the WHERE part of a query
336
   * Constructs the WHERE part of a query
323
   *
337
   *
324
   * @param string|array $where
338
   * @param string|array $where
325
   *   Condition
339
   *   Condition
Line 338... Line 352...
338
      {
352
      {
339
        if (count($where) < 1)
353
        if (count($where) < 1)
340
        {
354
        {
341
          return '';
355
          return '';
342
        }
356
        }
343
 
357
344
        if ($this->_isAssociativeArray($where))
358
        if ($this->_isAssociativeArray($where))
345
        {
359
        {
346
          $where = $this->_escapeValueArray($where, $suffix);
360
          $where = $this->_escapeValueArray($where, $suffix);
347
        }
361
        }
348
 
362
349
        $where = '(' . implode(') AND (', $where) . ')';
363
        $where = '(' . implode(') AND (', $where) . ')';
350
      }
364
      }
351
 
365
352
      return ' WHERE ' . $where;
366
      return ' WHERE ' . $where;
353
    }
367
    }
354
 
368
355
    return '';
369
    return '';
356
  }
370
  }
357
371
358
  /**
372
  /**
359
   * Selects data from one or more tables; the resulting records are stored
373
   * Selects data from one or more tables; the resulting records are stored
Line 378... Line 392...
378
  {
392
  {
379
    if (is_null($columns))
393
    if (is_null($columns))
380
    {
394
    {
381
      $columns = array('*');
395
      $columns = array('*');
382
    }
396
    }
383
   
397
384
    if (is_array($columns))
398
    if (is_array($columns))
385
    {
399
    {
386
      if ($this->_isAssociativeArray($columns))
400
      if ($this->_isAssociativeArray($columns))
387
      {
401
      {
388
        $columns = $this->_escapeAliasArray($columns);
402
        $columns = $this->_escapeAliasArray($columns);
Line 407... Line 421...
407
    {
421
    {
408
      if (is_array($order))
422
      if (is_array($order))
409
      {
423
      {
410
        $order = 'ORDER BY ' . implode(', ', $order);
424
        $order = 'ORDER BY ' . implode(', ', $order);
411
      }
425
      }
412
     
426
413
      $query .= " $order";
427
      $query .= " $order";
414
    }
428
    }
415
429
416
    if (!is_null($limit))
430
    if (!is_null($limit))
417
    {
431
    {
418
      $query .= " LIMIT $limit";
432
      $query .= " LIMIT $limit";
419
    }
433
    }
420
   
434
421
    $stmt = $this->prepare($query);
435
    $stmt = $this->prepare($query);
422
436
423
    $params = array();
437
    $params = array();
424
   
438
425
    if (is_array($where) && $this->_isAssociativeArray($where))
439
    if (is_array($where) && $this->_isAssociativeArray($where))
426
    {
440
    {
427
      /* FIXME: Export and reuse this */
441
      /* FIXME: Export and reuse this */
428
      foreach ($where as $column => $condition)
442
      foreach ($where as $column => $condition)
429
      {
443
      {
430
        /* TODO: Also handle function calls as keys */
444
        /* TODO: Also handle function calls as keys */
431
        if (is_array($condition) && $this->_isAssociativeArray($condition))
445
        if (is_array($condition) && $this->_isAssociativeArray($condition))
432
        {
446
        {
433
          reset($condition);
447
          reset($condition);
434
          $condition = $condition[key($condition)];
448
          $condition = $condition[key($condition)];
435
         
449
436
          if (is_array($condition))
450
          if (is_array($condition))
437
          {
451
          {
438
            foreach (self::_expand($condition, $column) as $param_index => $param_name)
452
            foreach (self::_expand($condition, $column) as $param_index => $param_name)
439
            {
453
            {
440
              $params[$param_name] = $condition[$param_index];
454
              $params[$param_name] = $condition[$param_index];
Line 454... Line 468...
454
      debug(array(
468
      debug(array(
455
        'query'  => $query,
469
        'query'  => $query,
456
        'params' => $params
470
        'params' => $params
457
      ));
471
      ));
458
    }
472
    }
459
   
473
460
    $success =& $this->_lastSuccess;
474
    $success =& $this->_lastSuccess;
461
    $success =  $stmt->execute($params);
475
    $success =  $stmt->execute($params);
462
   
476
463
    $errorInfo =& $this->_lastError;
477
    $errorInfo =& $this->_lastError;
464
    $errorInfo =  $stmt->errorInfo();
478
    $errorInfo =  $stmt->errorInfo();
465
   
479
466
    $result =& $this->_lastResult;
480
    $result =& $this->_lastResult;
467
    $result =  $stmt->fetchAll($fetch_style);
481
    $result =  $stmt->fetchAll($fetch_style);
468
   
482
469
    if (defined('DEBUG') && DEBUG > 1)
483
    if (defined('DEBUG') && DEBUG > 1)
470
    {
484
    {
471
      debug(array(
485
      debug(array(
472
        '_lastSuccess' => $success,
486
        '_lastSuccess' => $success,
473
        '_lastError'   => $errorInfo,
487
        '_lastError'   => $errorInfo,
474
        '_lastResult'  => $result
488
        '_lastResult'  => $result
475
      ));
489
      ));
476
    }
490
    }
477
   
491
478
    return $result;
492
    return $result;
479
  }
493
  }
480
494
481
  /**
495
  /**
482
   * Sets and returns the ID of the last inserted row, or the last value from
496
   * Sets and returns the ID of the last inserted row, or the last value from
Line 486... Line 500...
486
   *   Name of the sequence object from which the ID should be returned.
500
   *   Name of the sequence object from which the ID should be returned.
487
   * @return string
501
   * @return string
488
   */
502
   */
489
  protected function _setLastInsertId($name = null)
503
  protected function _setLastInsertId($name = null)
490
  {
504
  {
491
    return ($this->_lastInsertId = $this->_connection->lastInsertId($name));
505
    return ($this->_lastInsertId = $this->connection->lastInsertId($name));
492
  }
506
  }
493
507
494
  /**
508
  /**
495
   * Resets the the ID of the last inserted row, or the last value from
509
   * Resets the the ID of the last inserted row, or the last value from
496
   * a sequence object, depending on the underlying driver.
510
   * a sequence object, depending on the underlying driver.
Line 500... Line 514...
500
   */
514
   */
501
  protected function _resetLastInsertId()
515
  protected function _resetLastInsertId()
502
  {
516
  {
503
    return ($this->_lastInsertId = '');
517
    return ($this->_lastInsertId = '');
504
  }
518
  }
505
 
519
506
  /**
520
  /**
507
   * Updates one or more records
521
   * Updates one or more records
508
   *
522
   *
509
   * @param string|array $tables
523
   * @param string|array $tables
510
   *   Table name
524
   *   Table name
Line 518... Line 532...
518
  {
532
  {
519
    if (!$tables)
533
    if (!$tables)
520
    {
534
    {
521
      throw new InvalidArgumentException('No table specified');
535
      throw new InvalidArgumentException('No table specified');
522
    }
536
    }
523
     
537
524
    if (is_array($tables))
538
    if (is_array($tables))
525
    {
539
    {
526
      $tables = implode(', ', $tables);
540
      $tables = implode(', ', $tables);
527
    }
541
    }
528
     
542
529
    if (!$updates)
543
    if (!$updates)
530
    {
544
    {
531
      throw new InvalidArgumentException('No values specified');
545
      throw new InvalidArgumentException('No values specified');
532
    }
546
    }
533
547
534
    $params = array();
548
    $params = array();
535
   
549
536
    if ($this->_isAssociativeArray($updates))
550
    if ($this->_isAssociativeArray($updates))
537
    {
551
    {
538
      foreach ($updates as $key => $condition)
552
      foreach ($updates as $key => $condition)
539
      {
553
      {
540
        $params[":{$key}"] = $condition;
554
        $params[":{$key}"] = $condition;
541
      }
555
      }
542
    }
556
    }
543
   
557
544
    $updates = implode(', ', $this->_escapeValueArray($updates));
558
    $updates = implode(', ', $this->_escapeValueArray($updates));
545
         
559
546
    /* TODO: Should escape table names with escapeName(), but what about aliases? */
560
    /* TODO: Should escape table names with escapeName(), but what about aliases? */
547
    $query = "UPDATE {$tables} SET {$updates}" . $this->_where($where, '2');
561
    $query = "UPDATE {$tables} SET {$updates}" . $this->_where($where, '2');
548
   
562
549
    $stmt = $this->prepare($query);
563
    $stmt = $this->prepare($query);
550
   
564
551
    if (is_array($where) && $this->_isAssociativeArray($where))
565
    if (is_array($where) && $this->_isAssociativeArray($where))
552
    {
566
    {
553
      foreach ($where as $column => $condition)
567
      foreach ($where as $column => $condition)
554
      {
568
      {
555
        if (is_array($condition) && $this->_isAssociativeArray($condition))
569
        if (is_array($condition) && $this->_isAssociativeArray($condition))
556
        {
570
        {
557
          reset($condition);
571
          reset($condition);
558
          $condition = $condition[key($condition)];
572
          $condition = $condition[key($condition)];
559
         
573
560
          if (is_array($condition))
574
          if (is_array($condition))
561
          {
575
          {
562
            foreach (self::_expand($condition, $column) as $param_index => $param_name)
576
            foreach (self::_expand($condition, $column) as $param_index => $param_name)
563
            {
577
            {
564
              $params[$param_name] = $condition[$param_index];
578
              $params[$param_name] = $condition[$param_index];
Line 578... Line 592...
578
      debug(array(
592
      debug(array(
579
        'query'  => $query,
593
        'query'  => $query,
580
        'params' => $params
594
        'params' => $params
581
      ));
595
      ));
582
    }
596
    }
583
   
597
584
    $success =& $this->_lastSuccess;
598
    $success =& $this->_lastSuccess;
585
    $success =  $stmt->execute($params);
599
    $success =  $stmt->execute($params);
586
   
600
587
    $errorInfo =& $this->_lastError;
601
    $errorInfo =& $this->_lastError;
588
    $errorInfo =  $stmt->errorInfo();
602
    $errorInfo =  $stmt->errorInfo();
589
   
603
590
    $this->_resetLastInsertId();
604
    $this->_resetLastInsertId();
591
   
605
592
    $result =& $this->_lastResult;
606
    $result =& $this->_lastResult;
593
    $result =  $stmt->fetchAll();
607
    $result =  $stmt->fetchAll();
594
   
608
595
    if (defined('DEBUG') && DEBUG > 1)
609
    if (defined('DEBUG') && DEBUG > 1)
596
    {
610
    {
597
      debug(array(
611
      debug(array(
598
        '_lastSuccess' => $success,
612
        '_lastSuccess' => $success,
599
        '_lastError'    => $errorInfo,
613
        '_lastError'    => $errorInfo,
600
        '_lastResult'  => $result
614
        '_lastResult'  => $result
601
      ));
615
      ));
602
    }
616
    }
603
   
617
604
    return $success;
618
    return $success;
605
  }
619
  }
606
 
620
607
  /**
621
  /**
608
   * Inserts a record into a table.<p>The AUTO_INCREMENT value of the inserted
622
   * Inserts a record into a table.<p>The AUTO_INCREMENT value of the inserted
609
   * row, if any (> 0), is stored in the {@link $lastInsertId} property of
623
   * row, if any (> 0), is stored in the {@link $lastInsertId} property of
610
   * the <code>Database</code> instance.</p>
624
   * the <code>Database</code> instance.</p>
611
   *
625
   *
Line 636... Line 650...
636
    }
650
    }
637
    else
651
    else
638
    {
652
    {
639
      $cols = '';
653
      $cols = '';
640
    }
654
    }
641
 
655
642
    /* DEBUG */
656
    /* DEBUG */
643
    if (defined('DEBUG') && DEBUG > 2)
657
    if (defined('DEBUG') && DEBUG > 2)
644
    {
658
    {
645
      debug(array('values' => $values));
659
      debug(array('values' => $values));
646
    }
660
    }
647
 
661
648
    $params = array();
662
    $params = array();
649
   
663
650
    if (is_array($values))
664
    if (is_array($values))
651
    {
665
    {
652
      if ($this->_isAssociativeArray($values))
666
      if ($this->_isAssociativeArray($values))
653
      {
667
      {
654
        foreach ($values as $key => $condition)
668
        foreach ($values as $key => $condition)
655
        {
669
        {
656
          $params[":{$key}"] = $condition;
670
          $params[":{$key}"] = $condition;
657
        }
671
        }
658
       
672
659
        $values = $this->_escapeValueArray($values);
673
        $values = $this->_escapeValueArray($values);
660
       
674
661
        $cols = '';
675
        $cols = '';
662
        $values = 'SET ' . implode(', ', $values);
676
        $values = 'SET ' . implode(', ', $values);
663
      }
677
      }
664
      else
678
      else
665
      {
679
      {
Line 668... Line 682...
668
          if (is_string($value))
682
          if (is_string($value))
669
          {
683
          {
670
            $value = "'" . $value . "'";
684
            $value = "'" . $value . "'";
671
          }
685
          }
672
        }
686
        }
673
         
687
674
        $values = ' VALUES (' . implode(', ', $values) . ')';
688
        $values = ' VALUES (' . implode(', ', $values) . ')';
675
      }
689
      }
676
    }
690
    }
677
 
691
678
    /* TODO: Should escape table names with escapeName(), but what about aliases? */
692
    /* TODO: Should escape table names with escapeName(), but what about aliases? */
679
    $query = "INSERT INTO {$table} {$cols} {$values}";
693
    $query = "INSERT INTO {$table} {$cols} {$values}";
680
 
694
681
    $stmt = $this->prepare($query);
695
    $stmt = $this->prepare($query);
682
 
696
683
      /* DEBUG */
697
      /* DEBUG */
684
    if (defined('DEBUG') && DEBUG > 1)
698
    if (defined('DEBUG') && DEBUG > 1)
685
    {
699
    {
686
       debug(array(
700
       debug(array(
687
         'query'  => $query,
701
         'query'  => $query,
688
         'params' => $params
702
         'params' => $params
689
       ));
703
       ));
690
    }
704
    }
691
   
705
692
    $success =& $this->_lastSuccess;
706
    $success =& $this->_lastSuccess;
693
    $success = $stmt->execute($params);
707
    $success = $stmt->execute($params);
694
   
708
695
    $errorInfo =& $this->_lastError;
709
    $errorInfo =& $this->_lastError;
696
    $errorInfo =  $stmt->errorInfo();
710
    $errorInfo =  $stmt->errorInfo();
697
   
711
698
    $this->_setLastInsertId();
712
    $this->_setLastInsertId();
699
   
713
700
    $result =& $this->_lastResult;
714
    $result =& $this->_lastResult;
701
    $result =  $stmt->fetchAll();
715
    $result =  $stmt->fetchAll();
702
716
703
    if (defined('DEBUG') && DEBUG > 1)
717
    if (defined('DEBUG') && DEBUG > 1)
704
    {
718
    {
Line 707... Line 721...
707
        '_lastError'    => $errorInfo,
721
        '_lastError'    => $errorInfo,
708
        '_lastInsertId' => $this->_lastInsertId,
722
        '_lastInsertId' => $this->_lastInsertId,
709
        '_lastResult'   => $result
723
        '_lastResult'   => $result
710
      ));
724
      ));
711
    }
725
    }
712
   
726
713
    return $success;
727
    return $success;
714
  }
728
  }
715
   
729
716
  /**
730
  /**
717
   * Retrieves all rows from a table
731
   * Retrieves all rows from a table
718
   *
732
   *
719
   * @param int[optional] $fetch_style
733
   * @param int[optional] $fetch_style
720
   * @param int[optional] $column_index
734
   * @param int[optional] $column_index
Line 725... Line 739...
725
  public function fetchAll($table, $fetch_style = null, $column_index = null, array $ctor_args = null)
739
  public function fetchAll($table, $fetch_style = null, $column_index = null, array $ctor_args = null)
726
  {
740
  {
727
    /* NOTE: Cannot use table name as statement parameter */
741
    /* NOTE: Cannot use table name as statement parameter */
728
    $stmt = $this->prepare("SELECT * FROM $table");
742
    $stmt = $this->prepare("SELECT * FROM $table");
729
    $this->_lastSuccess = $stmt->execute();
743
    $this->_lastSuccess = $stmt->execute();
730
 
744
731
    $this->_lastError = $stmt->errorInfo();
745
    $this->_lastError = $stmt->errorInfo();
732
   
746
733
    $result =& $this->_lastResult;
747
    $result =& $this->_lastResult;
734
   
748
735
    if (is_null($fetch_style))
749
    if (is_null($fetch_style))
736
    {
750
    {
737
      $fetch_style = PDO::FETCH_ASSOC;
751
      $fetch_style = PDO::FETCH_ASSOC;
738
    }
752
    }
739
   
753
740
    if (!is_null($ctor_args))
754
    if (!is_null($ctor_args))
741
    {
755
    {
742
      $result = $stmt->fetchAll($fetch_style, $column_index, $ctor_args);
756
      $result = $stmt->fetchAll($fetch_style, $column_index, $ctor_args);
743
    }
757
    }
744
    else if (!is_null($column_index))
758
    else if (!is_null($column_index))
Line 751... Line 765...
751
    }
765
    }
752
    else
766
    else
753
    {
767
    {
754
      $result = $stmt->fetchAll();
768
      $result = $stmt->fetchAll();
755
    }
769
    }
756
 
770
757
    return $result;
771
    return $result;
758
  }
772
  }
759
773
760
  /**
774
  /**
761
   * Deletes one or more records
775
   * Deletes one or more records
Line 771... Line 785...
771
  {
785
  {
772
    if (!$tables)
786
    if (!$tables)
773
    {
787
    {
774
      throw new InvalidArgumentException('No table specified');
788
      throw new InvalidArgumentException('No table specified');
775
    }
789
    }
776
         
790
777
    if (is_array($tables))
791
    if (is_array($tables))
778
    {
792
    {
779
      $tables = implode(', ', $tables);
793
      $tables = implode(', ', $tables);
780
    }
794
    }
781
     
795
782
    $params = array();
796
    $params = array();
783
   
797
784
    $query = "DELETE FROM {$tables}" . $this->_where($where);
798
    $query = "DELETE FROM {$tables}" . $this->_where($where);
785
   
799
786
    $stmt = $this->prepare($query);
800
    $stmt = $this->prepare($query);
787
   
801
788
    if ($this->_isAssociativeArray($where))
802
    if ($this->_isAssociativeArray($where))
789
    {
803
    {
790
      foreach ($where as $column => $condition)
804
      foreach ($where as $column => $condition)
791
      {
805
      {
792
        if (is_array($condition) && $this->_isAssociativeArray($condition))
806
        if (is_array($condition) && $this->_isAssociativeArray($condition))
793
        {
807
        {
794
          reset($condition);
808
          reset($condition);
795
          $condition = $condition[key($condition)];
809
          $condition = $condition[key($condition)];
796
         
810
797
          if (is_array($condition))
811
          if (is_array($condition))
798
          {
812
          {
799
            foreach (self::_expand($condition, $column) as $param_index => $param_name)
813
            foreach (self::_expand($condition, $column) as $param_index => $param_name)
800
            {
814
            {
801
              $params[$param_name] = $condition[$param_index];
815
              $params[$param_name] = $condition[$param_index];
Line 815... Line 829...
815
      debug(array(
829
      debug(array(
816
        'query'  => $query,
830
        'query'  => $query,
817
        'params' => $params
831
        'params' => $params
818
      ));
832
      ));
819
    }
833
    }
820
   
834
821
    $success =& $this->_lastSuccess;
835
    $success =& $this->_lastSuccess;
822
    $success =  $stmt->execute($params);
836
    $success =  $stmt->execute($params);
823
   
837
824
    $result =& $this->_lastResult;
838
    $result =& $this->_lastResult;
825
    $result =  $stmt->fetchAll();
839
    $result =  $stmt->fetchAll();
826
   
840
827
    $errorInfo =& $this->_lastError;
841
    $errorInfo =& $this->_lastError;
828
    $errorInfo =  $stmt->errorInfo();
842
    $errorInfo =  $stmt->errorInfo();
829
   
843
830
    if (defined('DEBUG') && DEBUG > 1)
844
    if (defined('DEBUG') && DEBUG > 1)
831
    {
845
    {
832
      debug(array(
846
      debug(array(
833
        '_lastSuccess' => $success,
847
        '_lastSuccess' => $success,
834
        '_lastError'   => $errorInfo,
848
        '_lastError'   => $errorInfo,
835
        '_lastResult'  => $result
849
        '_lastResult'  => $result
836
      ));
850
      ));
837
    }
851
    }
838
   
852
839
    return $success;
853
    return $success;
840
  }
854
  }
841
}
855
}
842
856