Subversion Repositories PHPX

Rev

Rev 34 | Rev 44 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed

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