Changeset 2955

Show
Ignore:
Timestamp:
07/01/2008 05:53:31 PM (5 months ago)
Author:
Shadowhand
Message:

Changes to the object_db module:

  • Organized and optimized Database_Select
  • Updated Database_Where, starting syntax changes
  • Replace Database completely, starting from scratch
Location:
trunk/modules/object_db/libraries
Files:
3 modified

Legend:

Unmodified
Added
Removed
  • trunk/modules/object_db/libraries/Database.php

    r2932 r2955  
    1212class Database_Core { 
    1313 
    14         // Global benchmark 
    15         public static $benchmarks = array(); 
     14        // Database instances 
     15        protected static $instances; 
    1616 
    17         // Configuration 
    18         protected $config = array 
    19         ( 
    20                 'benchmark'     => TRUE, 
    21                 'persistent'    => FALSE, 
    22                 'connection'    => '', 
    23                 'character_set' => 'utf8', 
    24                 'table_prefix'  => '', 
    25                 'object'        => TRUE, 
    26                 'cache'         => FALSE, 
    27                 'escape'        => TRUE, 
    28         ); 
     17        // Driver instance 
     18        protected $driver; 
    2919 
    30         // Database driver object 
    31         protected $driver; 
    32         protected $link; 
     20        public static function instance($name = 'default', $config = NULL) 
     21        { 
     22                if (empty(Database::$instances[$name])) 
     23                { 
     24                        // Create a named Database instance 
     25                        Database::$instances[$name] = new Database($config); 
     26                } 
    3327 
    34         // Un-compiled parts of the SQL query 
    35         protected $select     = array(); 
    36         protected $set        = array(); 
    37         protected $from       = array(); 
    38         protected $join       = array(); 
    39         protected $where      = array(); 
    40         protected $orderby    = array(); 
    41         protected $order      = array(); 
    42         protected $groupby    = array(); 
    43         protected $having     = array(); 
    44         protected $distinct   = FALSE; 
    45         protected $limit      = FALSE; 
    46         protected $offset     = FALSE; 
    47         protected $last_query = ''; 
    48  
    49         /** 
    50          * Returns a singleton instance of Database. 
    51          * 
    52          * @param   mixed   configuration array or DSN 
    53          * @return  object 
    54          */ 
    55         public static function instance($config = array()) 
    56         { 
    57                 static $instance; 
    58  
    59                 // Create the instance if it does not exist 
    60                 ($instance === NULL) and $instance = new Database($config); 
    61  
    62                 return $instance; 
     28                return Database::$instances[$name]; 
    6329        } 
    6430 
    65         /** 
    66          * Sets up the database configuration, loads the Database_Driver. 
    67          * 
    68          * @throws  Kohana_Database_Exception 
    69          */ 
    70         public function __construct($config = array()) 
     31        public function __construct($config = NULL) 
    7132        { 
    7233                if (empty($config)) 
    7334                { 
    74                         // Load the default group 
     35                        // Load default configuration 
    7536                        $config = Config::item('database.default'); 
    7637                } 
    77                 elseif (is_string($config)) 
     38 
     39                if ( ! (is_array($config) AND isset($config['hostname']) AND isset($config['database']))) 
     40                        throw new Kohana_Exception('database.invalid_configuation'); 
     41        } 
     42 
     43        public function select($col = '*') 
     44        { 
     45                $args = func_get_args(); 
     46 
     47                if (empty($args)) 
    7848                { 
    79                         // The config is a DSN string 
    80                         if (strpos($config, '://') !== FALSE) 
    81                         { 
    82                                 $config = array('connection' => $config); 
    83                         } 
    84                         // The config is a group name 
    85                         else 
    86                         { 
    87                                 $name = $config; 
    88  
    89                                 // Test the config group name 
    90                                 if (($config = Config::item('database.'.$config)) === NULL) 
    91                                         throw new Kohana_Database_Exception('database.undefined_group', $name); 
    92                         } 
     49                        // Default to "SELECT *" 
     50                        $args = array('*'); 
    9351                } 
    9452 
    95                 // Merge the default config with the passed config 
    96                 $this->config = array_merge($this->config, $config); 
    97  
    98                 // Make sure the connection is valid 
    99                 if (strpos($this->config['connection'], '://') === FALSE) 
    100                         throw new Kohana_Database_Exception('database.invalid_dsn', $this->config['connection']); 
    101  
    102                 // Parse the DSN, creating an array to hold the connection parameters 
    103                 $db = array 
    104                 ( 
    105                         'type'     => FALSE, 
    106                         'user'     => FALSE, 
    107                         'pass'     => FALSE, 
    108                         'host'     => FALSE, 
    109                         'port'     => FALSE, 
    110                         'socket'   => FALSE, 
    111                         'database' => FALSE 
    112                 ); 
    113  
    114                 // Get the protocol and arguments 
    115                 list ($db['type'], $connection) = explode('://', $this->config['connection'], 2); 
    116  
    117                 if (strpos($connection, '@') !== FALSE) 
    118                 { 
    119                         // Get the username and password 
    120                         list ($db['pass'], $connection) = explode('@', $connection, 2); 
    121                         // Check if a password is supplied 
    122                         $logindata = explode(':', $db['pass'], 2); 
    123                         $db['pass'] = (count($logindata) > 1) ? $logindata[1] : ''; 
    124                         $db['user'] = $logindata[0]; 
    125  
    126                         // Prepare for finding the database 
    127                         $connection = explode('/', $connection); 
    128  
    129                         // Find the database name 
    130                         $db['database'] = array_pop($connection); 
    131  
    132                         // Reset connection string 
    133                         $connection = implode('/', $connection); 
    134  
    135                         // Find the socket 
    136                         if (preg_match('/^unix\([^)]++\)/', $connection)) 
    137                         { 
    138                                 // This one is a little hairy: we explode based on the end of 
    139                                 // the socket, removing the 'unix(' from the connection string 
    140                                 list ($db['socket'], $connection) = explode(')', substr($connection, 5), 2); 
    141                         } 
    142                         elseif (strpos($connection, ':') !== FALSE) 
    143                         { 
    144                                 // Fetch the host and port name 
    145                                 list ($db['host'], $db['port']) = explode(':', $connection, 2); 
    146                         } 
    147                         else 
    148                         { 
    149                                 $db['host'] = $connection; 
    150                         } 
    151                 } 
    152                 else 
    153                 { 
    154                         // File connection 
    155                         $connection = explode('/', $connection); 
    156  
    157                         // Find database file name 
    158                         $db['database'] = array_pop($connection); 
    159  
    160                         // Find database directory name 
    161                         $db['socket'] = implode('/', $connection).'/'; 
    162                 } 
    163  
    164                 // Reset the connection array to the database config 
    165                 $this->config['connection'] = $db; 
    166  
    167                 // Set driver name 
    168                 $driver = 'Database_'.ucfirst($this->config['connection']['type']).'_Driver'; 
    169  
    170                 // Load the driver 
    171                 if ( ! Kohana::auto_load($driver)) 
    172                         throw new Kohana_Database_Exception('database.driver_not_supported', $this->config['connection']['type']); 
    173  
    174                 // Initialize the driver 
    175                 $this->driver = new $driver($this->config); 
    176  
    177                 // Validate the driver 
    178                 if ( ! ($this->driver instanceof Database_Driver)) 
    179                         throw new Kohana_Database_Exception('database.driver_not_supported', 'Database drivers must use the Database_Driver interface.'); 
    180  
    181                 Log::add('debug', 'Database Library initialized'); 
     53                return new Database_Select($args, $this); 
    18254        } 
    18355 
    184         /** 
    185          * Simple connect method to get the database queries up and running. 
    186          * 
    187          * @return  void 
    188          */ 
    189         public function connect() 
     56        public function query($sql = NULL) 
    19057        { 
    191                 // A link can be a resource or an object 
    192                 if ( ! is_resource($this->link) AND ! is_object($this->link)) 
     58                if ( ! is_string($sql)) 
    19359                { 
    194                         $this->link = $this->driver->connect(); 
    195                         if ( ! is_resource($this->link) AND ! is_object($this->link)) 
    196                                 throw new Kohana_Database_Exception('database.connection', $this->driver->show_error()); 
    197  
    198                         // Clear password after successful connect 
    199                         $this->config['connection']['pass'] = NULL; 
     60                        echo 'not an SQL string'; 
    20061                } 
    20162        } 
    20263 
    203         /** 
    204          * Runs a query into the driver and returns the result. 
    205          * 
    206          * @param   string  SQL query to execute 
    207          * @return  object  Database_Result 
    208          */ 
    209         public function query($sql = '') 
    210         { 
    211                 if ($sql == '') return FALSE; 
    212  
    213                 // No link? Connect! 
    214                 $this->link or $this->connect(); 
    215  
    216                 // Start the benchmark 
    217                 $start = microtime(TRUE); 
    218  
    219                 if (func_num_args() > 1) //if we have more than one argument ($sql) 
    220                 { 
    221                         $argv = func_get_args(); 
    222                         $binds = (is_array(next($argv))) ? current($argv) : array_slice($argv, 1); 
    223                 } 
    224  
    225                 // Compile binds if needed 
    226                 if (isset($binds)) 
    227                 { 
    228                         $sql = $this->compile_binds($sql, $binds); 
    229                 } 
    230  
    231                 // Fetch the result 
    232                 $result = $this->driver->query($this->last_query = $sql); 
    233  
    234                 // Stop the benchmark 
    235                 $stop = microtime(TRUE); 
    236  
    237                 if ($this->config['benchmark'] == TRUE) 
    238                 { 
    239                         // Benchmark the query 
    240                         self::$benchmarks[] = array('query' => $sql, 'time' => $stop - $start, 'rows' => count($result)); 
    241                 } 
    242  
    243                 return $result; 
    244         } 
    245  
    246         /** 
    247          * Selects the column names for a database query. 
    248          * 
    249          * @param   string  string or array of column names to select 
    250          * @return  object  This Database object. 
    251          */ 
    252         public function select($sql = '*') 
    253         { 
    254                 if (func_num_args() > 1) 
    255                 { 
    256                         $sql = func_get_args(); 
    257                 } 
    258                 elseif (is_string($sql)) 
    259                 { 
    260                         $sql = explode(',', $sql); 
    261                 } 
    262                 else 
    263                 { 
    264                         $sql = (array) $sql; 
    265                 } 
    266  
    267                 foreach($sql as $val) 
    268                 { 
    269                         if (($val = trim($val)) === '') continue; 
    270  
    271                         if (strpos($val, '(') === FALSE AND $val !== '*') 
    272                         { 
    273                                 if (preg_match('/^DISTINCT\s++(.+)$/i', $val, $matches)) 
    274                                 { 
    275                                         $val            = $this->config['table_prefix'].$matches[1]; 
    276                                         $this->distinct = TRUE; 
    277                                 } 
    278                                 else 
    279                                 { 
    280                                         $val = (strpos($val, '.') !== FALSE) ? $this->config['table_prefix'].$val : $val; 
    281                                 } 
    282  
    283                                 $val = $this->driver->escape_column($val); 
    284                         } 
    285  
    286                         $this->select[] = $val; 
    287                 } 
    288  
    289                 return $this; 
    290         } 
    291  
    292         /** 
    293          * Selects the from table(s) for a database query. 
    294          * 
    295          * @param   string  string or array of tables to select 
    296          * @return  object  This Database object. 
    297          */ 
    298         public function from($sql) 
    299         { 
    300                 foreach((array) $sql as $val) 
    301                 { 
    302                         if (($val = trim($val)) === '') continue; 
    303  
    304                         $this->from[] = $this->config['table_prefix'].$val; 
    305                 } 
    306  
    307                 return $this; 
    308         } 
    309  
    310         /** 
    311          * Generates the JOIN portion of the query. 
    312          * 
    313          * @param   string        table name 
    314          * @param   string|array  where key or array of key => value pairs 
    315          * @param   string        where value 
    316          * @param   string        type of join 
    317          * @return  object        This Database object. 
    318          */ 
    319         public function join($table, $key, $value = NULL, $type = '') 
    320         { 
    321                 if ($type != '') 
    322                 { 
    323                         $type = strtoupper(trim($type)); 
    324  
    325                         if ( ! in_array($type, array('LEFT', 'RIGHT', 'OUTER', 'INNER', 'LEFT OUTER', 'RIGHT OUTER'), TRUE)) 
    326                         { 
    327                                 $type = ''; 
    328                         } 
    329                         else 
    330                         { 
    331                                 $type .= ' '; 
    332                         } 
    333                 } 
    334  
    335                 $cond = array(); 
    336                 $keys  = is_array($key) ? $key : array($key => $value); 
    337                 foreach ($keys as $key => $value) 
    338                 { 
    339                         $key    = (strpos($key, '.') !== FALSE) ? $this->config['table_prefix'].$key : $key; 
    340                         $cond[] = $this->driver->where($key, $this->driver->escape_column($this->config['table_prefix'].$value), 'AND ', count($cond), FALSE); 
    341                 } 
    342  
    343                 $this->join[] = $type.'JOIN '.$this->driver->escape_column($this->config['table_prefix'].$table).' ON '.implode(' ', $cond); 
    344  
    345                 return $this; 
    346         } 
    347  
    348         /** 
    349          * Selects the where(s) for a database query. 
    350          * 
    351          * @param   string|array  key name or array of key => value pairs 
    352          * @param   string        value to match with key 
    353          * @param   boolean       disable quoting of WHERE clause 
    354          * @return  object        This Database object. 
    355          */ 
    356         public function where($key, $value = NULL, $quote = TRUE) 
    357         { 
    358                 $quote = (func_num_args() < 2 AND ! is_array($key)) ? -1 : $quote; 
    359                 $keys  = is_array($key) ? $key : array($key => $value); 
    360  
    361                 foreach ($keys as $key => $value) 
    362                 { 
    363                         $key           = (strpos($key, '.') !== FALSE) ? $this->config['table_prefix'].$key : $key; 
    364                         $this->where[] = $this->driver->where($key, $value, 'AND ', count($this->where), $quote); 
    365                 } 
    366  
    367                 return $this; 
    368         } 
    369  
    370         /** 
    371          * Selects the or where(s) for a database query. 
    372          * 
    373          * @param   string|array  key name or array of key => value pairs 
    374          * @param   string        value to match with key 
    375          * @param   boolean       disable quoting of WHERE clause 
    376          * @return  object        This Database object. 
    377          */ 
    378         public function orwhere($key, $value = NULL, $quote = TRUE) 
    379         { 
    380                 $quote = (func_num_args() < 2 AND ! is_array($key)) ? -1 : $quote; 
    381                 $keys  = is_array($key) ? $key : array($key => $value); 
    382  
    383                 foreach ($keys as $key => $value) 
    384                 { 
    385                         $key           = (strpos($key, '.') !== FALSE) ? $this->config['table_prefix'].$key : $key; 
    386                         $this->where[] = $this->driver->where($key, $value, 'OR ', count($this->where), $quote); 
    387                 } 
    388  
    389                 return $this; 
    390         } 
    391  
    392         /** 
    393          * Selects the like(s) for a database query. 
    394          * 
    395          * @param   string|array  field name or array of field => match pairs 
    396          * @param   string        like value to match with field 
    397          * @param   boolean       automatically add starting and ending wildcards 
    398          * @return  object        This Database object. 
    399          */ 
    400         public function like($field, $match = '', $auto = TRUE) 
    401         { 
    402                 $fields = is_array($field) ? $field : array($field => $match); 
    403  
    404                 foreach ($fields as $field => $match) 
    405                 { 
    406                         $field         = (strpos($field, '.') !== FALSE) ? $this->config['table_prefix'].$field : $field; 
    407                         $this->where[] = $this->driver->like($field, $match, $auto, 'AND ', count($this->where)); 
    408                 } 
    409  
    410                 return $this; 
    411         } 
    412  
    413         /** 
    414          * Selects the or like(s) for a database query. 
    415          * 
    416          * @param   string|array  field name or array of field => match pairs 
    417          * @param   string        like value to match with field 
    418          * @param   boolean       automatically add starting and ending wildcards 
    419          * @return  object        This Database object. 
    420          */ 
    421         public function orlike($field, $match = '', $auto = TRUE) 
    422         { 
    423                 $fields = is_array($field) ? $field : array($field => $match); 
    424  
    425                 foreach ($fields as $field => $match) 
    426                 { 
    427                         $field         = (strpos($field, '.') !== FALSE) ? $this->config['table_prefix'].$field : $field; 
    428                         $this->where[] = $this->driver->like($field, $match, $auto, 'OR ', count($this->where)); 
    429                 } 
    430  
    431                 return $this; 
    432         } 
    433  
    434         /** 
    435          * Selects the not like(s) for a database query. 
    436          * 
    437          * @param   string|array  field name or array of field => match pairs 
    438          * @param   string        like value to match with field 
    439          * @param   boolean       automatically add starting and ending wildcards 
    440          * @return  object        This Database object. 
    441          */ 
    442         public function notlike($field, $match = '', $auto = TRUE) 
    443         { 
    444                 $fields = is_array($field) ? $field : array($field => $match); 
    445  
    446                 foreach ($fields as $field => $match) 
    447                 { 
    448                         $field         = (strpos($field, '.') !== FALSE) ? $this->config['table_prefix'].$field : $field; 
    449                         $this->where[] = $this->driver->notlike($field, $match, 'AND ', count($this->where)); 
    450                 } 
    451  
    452                 return $this; 
    453         } 
    454  
    455         /** 
    456          * Selects the or not like(s) for a database query. 
    457          * 
    458          * @param   string|array  field name or array of field => match pairs 
    459          * @param   string        like value to match with field 
    460          * @return  object        This Database object. 
    461          */ 
    462         public function ornotlike($field, $match = '') 
    463         { 
    464                 $fields = is_array($field) ? $field : array($field => $match); 
    465  
    466                 foreach ($fields as $field => $match) 
    467                 { 
    468                         $field         = (strpos($field, '.') !== FALSE) ? $this->config['table_prefix'].$field : $field; 
    469                         $this->where[] = $this->driver->notlike($field, $match, 'OR ', count($this->where)); 
    470                 } 
    471  
    472                 return $this; 
    473         } 
    474  
    475         /** 
    476          * Selects the like(s) for a database query. 
    477          * 
    478          * @param   string|array  field name or array of field => match pairs 
    479          * @param   string        like value to match with field 
    480          * @return  object        This Database object. 
    481          */ 
    482         public function regex($field, $match = '') 
    483         { 
    484                 $fields = is_array($field) ? $field : array($field => $match); 
    485  
    486                 foreach ($fields as $field => $match) 
    487                 { 
    488                         $field         = (strpos($field, '.') !== FALSE) ? $this->config['table_prefix'].$field : $field; 
    489                         $this->where[] = $this->driver->regex($field, $match, 'AND ', count($this->where)); 
    490                 } 
    491  
    492                 return $this; 
    493         } 
    494  
    495         /** 
    496          * Selects the or like(s) for a database query. 
    497          * 
    498          * @param   string|array  field name or array of field => match pairs 
    499          * @param   string        like value to match with field 
    500          * @return  object        This Database object. 
    501          */ 
    502         public function orregex($field, $match = '') 
    503         { 
    504                 $fields = is_array($field) ? $field : array($field => $match); 
    505  
    506                 foreach ($fields as $field => $match) 
    507                 { 
    508                         $field         = (strpos($field, '.') !== FALSE) ? $this->config['table_prefix'].$field : $field; 
    509                         $this->where[] = $this->driver->regex($field, $match, 'OR ', count($this->where)); 
    510                 } 
    511  
    512                 return $this; 
    513         } 
    514  
    515         /** 
    516          * Selects the not regex(s) for a database query. 
    517          * 
    518          * @param   string|array  field name or array of field => match pairs 
    519          * @param   string        regex value to match with field 
    520          * @return  object        This Database object. 
    521          */ 
    522         public function notregex($field, $match = '') 
    523         { 
    524                 $fields = is_array($field) ? $field : array($field => $match); 
    525  
    526                 foreach ($fields as $field => $match) 
    527                 { 
    528                         $field         = (strpos($field, '.') !== FALSE) ? $this->config['table_prefix'].$field : $field; 
    529                         $this->where[] = $this->driver->notregex($field, $match, 'AND ', count($this->where)); 
    530                 } 
    531  
    532                 return $this; 
    533         } 
    534  
    535         /** 
    536          * Selects the or not regex(s) for a database query. 
    537          * 
    538          * @param   string|array  field name or array of field => match pairs 
    539          * @param   string        regex value to match with field 
    540          * @return  object        This Database object. 
    541          */ 
    542         public function ornotregex($field, $match = '') 
    543         { 
    544                 $fields = is_array($field) ? $field : array($field => $match); 
    545  
    546                 foreach ($fields as $field => $match) 
    547                 { 
    548                         $field         = (strpos($field, '.') !== FALSE) ? $this->config['table_prefix'].$field : $field; 
    549                         $this->where[] = $this->driver->notregex($field, $match, 'OR ', count($this->where)); 
    550                 } 
    551  
    552                 return $this; 
    553         } 
    554  
    555         /** 
    556          * Chooses the column to group by in a select query. 
    557          * 
    558          * @param   string  column name to group by 
    559          * @return  object  This Database object. 
    560          */ 
    561         public function groupby($by) 
    562         { 
    563                 if ( ! is_array($by)) 
    564                 { 
    565                         $by = explode(',', (string) $by); 
    566                 } 
    567  
    568                 foreach ($by as $val) 
    569                 { 
    570                         $val = trim($val); 
    571  
    572                         if ($val != '') 
    573                         { 
    574                                 $this->groupby[] = $val; 
    575                         } 
    576                 } 
    577  
    578                 return $this; 
    579         } 
    580  
    581         /** 
    582          * Selects the having(s) for a database query. 
    583          * 
    584          * @param   string|array  key name or array of key => value pairs 
    585          * @param   string        value to match with key 
    586          * @param   boolean       disable quoting of WHERE clause 
    587          * @return  object        This Database object. 
    588          */ 
    589         public function having($key, $value = '', $quote = TRUE) 
    590         { 
    591                 $this->having[] = $this->driver->where($key, $value, 'AND', count($this->having), TRUE); 
    592                 return $this; 
    593         } 
    594  
    595         /** 
    596          * Selects the or having(s) for a database query. 
    597          * 
    598          * @param   string|array  key name or array of key => value pairs 
    599          * @param   string        value to match with key 
    600          * @param   boolean       disable quoting of WHERE clause 
    601          * @return  object        This Database object. 
    602          */ 
    603         public function orhaving($key, $value = '', $quote = TRUE) 
    604         { 
    605                 $this->having[] = $this->driver->where($key, $value, 'OR', count($this->having), TRUE); 
    606                 return $this; 
    607         } 
    608  
    609         /** 
    610          * Chooses which column(s) to order the select query by. 
    611          * 
    612          * @param   string|array  column(s) to order on, can be an array, single column, or comma seperated list of columns 
    613          * @param   string        direction of the order 
    614          * @return  object        This Database object. 
    615          */ 
    616         public function orderby($orderby, $direction = '') 
    617         { 
    618                 $direction = strtoupper(tri