a tiny mvc framework for php using php-activerecord
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

dos -> unix line format

Kien La c4407ceb 75c9d852

+861 -861
+456 -456
lib/php-activerecord/lib/Connection.php
··· 1 - <?php 2 - /** 3 - * @package ActiveRecord 4 - */ 5 - namespace ActiveRecord; 6 - 7 - require 'Column.php'; 8 - 9 - use PDO; 10 - use PDOException; 11 - use Closure; 12 - 13 - /** 14 - * The base class for database connection adapters. 15 - * 16 - * @package ActiveRecord 17 - */ 18 - abstract class Connection 19 - { 20 - /** 21 - * The PDO connection object. 22 - * @var mixed 23 - */ 24 - public $connection; 25 - 26 - /** 27 - * The last query run. 28 - * @var string 29 - */ 30 - public $last_query; 31 - 32 - /** 33 - * Switch for logging. 34 - * 35 - * @var bool 36 - */ 37 - private $logging = false; 38 - 39 - /** 40 - * Contains a Logger object that must impelement a log() method. 41 - * 42 - * @var object 43 - */ 44 - private $logger; 45 - 46 - /** 47 - * Default PDO options to set for each connection. 48 - * @var array 49 - */ 50 - static $PDO_OPTIONS = array( 51 - PDO::ATTR_CASE => PDO::CASE_LOWER, 52 - PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION, 53 - PDO::ATTR_ORACLE_NULLS => PDO::NULL_NATURAL, 54 - PDO::ATTR_STRINGIFY_FETCHES => false); 55 - 56 - /** 57 - * The quote character for stuff like column and field names. 58 - * @var string 59 - */ 60 - static $QUOTE_CHARACTER = '`'; 61 - 62 - /** 63 - * Default port. 64 - * @var int 65 - */ 66 - static $DEFAULT_PORT = 0; 67 - 68 - /** 69 - * Retrieve a database connection. 70 - * 71 - * @param string $connection_string_or_connection_name A database connection string (ex. mysql://user:pass@host[:port]/dbname) 72 - * Everything after the protocol:// part is specific to the connection adapter. 73 - * OR 74 - * A connection name that is set in ActiveRecord\Config 75 - * If null it will use the default connection specified by ActiveRecord\Config->set_default_connection 76 - * @return Connection 77 - * @see parse_connection_url 78 - */ 79 - public static function instance($connection_string_or_connection_name=null) 80 - { 81 - $config = Config::instance(); 82 - 83 - if (strpos($connection_string_or_connection_name,'://') === false) 84 - { 85 - $connection_string = $connection_string_or_connection_name ? 86 - $config->get_connection($connection_string_or_connection_name) : 87 - $config->get_default_connection_string(); 88 - } 89 - else 90 - $connection_string = $connection_string_or_connection_name; 91 - 92 - if (!$connection_string) 93 - throw new DatabaseException("Empty connection string"); 94 - 95 - $info = static::parse_connection_url($connection_string); 96 - $fqclass = static::load_adapter_class($info->protocol); 97 - 98 - try { 99 - $connection = new $fqclass($info); 100 - $connection->protocol = $info->protocol; 101 - $connection->logging = $config->get_logging(); 102 - $connection->logger = $connection->logging ? $config->get_logger() : null; 103 - } catch (PDOException $e) { 104 - throw new DatabaseException($e); 105 - } 106 - return $connection; 107 - } 108 - 109 - /** 110 - * Loads the specified class for an adapter. 111 - * 112 - * @param string $adapter Name of the adapter. 113 - * @return string The full name of the class including namespace. 114 - */ 115 - private static function load_adapter_class($adapter) 116 - { 117 - $class = ucwords($adapter) . 'Adapter'; 118 - $fqclass = 'ActiveRecord\\' . $class; 119 - $source = dirname(__FILE__) . "/adapters/$class.php"; 120 - 121 - if (!file_exists($source)) 122 - throw new DatabaseException("$fqclass not found!"); 123 - 124 - require_once($source); 125 - return $fqclass; 126 - } 127 - 128 - /** 129 - * Use this for any adapters that can take connection info in the form below 130 - * to set the adapters connection info. 131 - * 132 - * <code> 133 - * protocol://username:password@host[:port]/dbname 134 - * protocol://urlencoded%20username:urlencoded%20password@host[:port]/dbname?decode=true 135 - * protocol://username:password@unix(/some/file/path)/dbname 136 - * </code> 137 - * 138 - * @param string $connection_url A connection URL 139 - * @return object the parsed URL as an object. 140 - */ 141 - public static function parse_connection_url($connection_url) 142 - { 143 - $url = @parse_url($connection_url); 144 - 145 - if (!isset($url['host'])) 146 - throw new DatabaseException('Database host must be specified in the connection string.'); 147 - 148 - $info = new \stdClass(); 149 - $info->protocol = $url['scheme']; 150 - $info->host = $url['host']; 151 - $info->db = isset($url['path']) ? substr($url['path'],1) : null; 152 - $info->user = isset($url['user']) ? $url['user'] : null; 153 - $info->pass = isset($url['pass']) ? $url['pass'] : null; 154 - 155 - if ($info->host == 'unix(') 156 - { 157 - $socket_database = $info->host . '/' . $info->db; 158 - 159 - if (preg_match_all('/^unix\((.+)\)\/(.+)$/', $socket_database, $matches) > 0) 160 - { 161 - $info->host = $matches[1][0]; 162 - $info->db = $matches[2][0]; 163 - } 164 - } 165 - 166 - if (isset($url['port'])) 167 - $info->port = $url['port']; 168 - 169 - if (strpos($connection_url,'decode=true') !== false) 170 - { 171 - if ($info->user) 172 - $info->user = urldecode($info->user); 173 - 174 - if ($info->pass) 175 - $info->pass = urldecode($info->pass); 176 - } 177 - 178 - return $info; 179 - } 180 - 181 - /** 182 - * Class Connection is a singleton. Access it via instance(). 183 - * 184 - * @param array $info Array containing URL parts 185 - * @return Connection 186 - */ 187 - protected function __construct($info) 188 - { 189 - try 190 - { 191 - // unix sockets start with a / 192 - if ($info->host[0] != '/') 193 - { 194 - $host = "host=$info->host"; 195 - 196 - if (isset($info->port)) 197 - $host .= ";port=$info->port"; 198 - } 199 - else 200 - $host = "unix_socket=$info->host"; 201 - 202 - $this->connection = new PDO("$info->protocol:$host;dbname=$info->db",$info->user,$info->pass,static::$PDO_OPTIONS); 203 - } catch (PDOException $e) { 204 - throw new DatabaseException($e); 205 - } 206 - } 207 - 208 - /** 209 - * Retrieves column meta data for the specified table. 210 - * 211 - * @param string $table Name of a table 212 - * @return array An array of {@link Column} objects. 213 - */ 214 - public function columns($table) 215 - { 216 - $columns = array(); 217 - $sth = $this->query_column_info($table); 218 - 219 - while (($row = $sth->fetch())) 220 - { 221 - $c = $this->create_column($row); 222 - $columns[$c->name] = $c; 223 - } 224 - return $columns; 225 - } 226 - 227 - /** 228 - * Escapes quotes in a string. 229 - * 230 - * @param string $string The string to be quoted. 231 - * @return string The string with any quotes in it properly escaped. 232 - */ 233 - public function escape($string) 234 - { 235 - return $this->connection->quote($string); 236 - } 237 - 238 - /** 239 - * Retrieve the insert id of the last model saved. 240 - * 241 - * @param string $sequence Optional name of a sequence to use 242 - * @return int 243 - */ 244 - public function insert_id($sequence=null) 245 - { 246 - return $this->connection->lastInsertId($sequence); 247 - } 248 - 249 - /** 250 - * Execute a raw SQL query on the database. 251 - * 252 - * @param string $sql Raw SQL string to execute. 253 - * @param array &$values Optional array of bind values 254 - * @return mixed A result set object 255 - */ 256 - public function query($sql, &$values=array()) 257 - { 258 - if ($this->logging) 259 - $this->logger->log($sql); 260 - 261 - $this->last_query = $sql; 262 - 263 - try { 264 - if (!($sth = $this->connection->prepare($sql))) 265 - throw new DatabaseException($this); 266 - } catch (PDOException $e) { 267 - throw new DatabaseException($this); 268 - } 269 - 270 - $sth->setFetchMode(PDO::FETCH_ASSOC); 271 - 272 - try { 273 - if (!$sth->execute($values)) 274 - throw new DatabaseException($this); 275 - } catch (PDOException $e) { 276 - throw new DatabaseException($sth); 277 - } 278 - return $sth; 279 - } 280 - 281 - /** 282 - * Execute a query that returns maximum of one row with one field and return it. 283 - * 284 - * @param string $sql Raw SQL string to execute. 285 - * @param array &$values Optional array of values to bind to the query. 286 - * @return string 287 - */ 288 - public function query_and_fetch_one($sql, &$values=array()) 289 - { 290 - $sth = $this->query($sql,$values); 291 - $row = $sth->fetch(PDO::FETCH_NUM); 292 - return $row[0]; 293 - } 294 - 295 - /** 296 - * Execute a raw SQL query and fetch the results. 297 - * 298 - * @param string $sql Raw SQL string to execute. 299 - * @param Closure $handler Closure that will be passed the fetched results. 300 - */ 301 - public function query_and_fetch($sql, Closure $handler) 302 - { 303 - $sth = $this->query($sql); 304 - 305 - while (($row = $sth->fetch(PDO::FETCH_ASSOC))) 306 - $handler($row); 307 - } 308 - 309 - /** 310 - * Returns all tables for the current database. 311 - * 312 - * @return array Array containing table names. 313 - */ 314 - public function tables() 315 - { 316 - $tables = array(); 317 - $sth = $this->query_for_tables(); 318 - 319 - while (($row = $sth->fetch(PDO::FETCH_NUM))) 320 - $tables[] = $row[0]; 321 - 322 - return $tables; 323 - } 324 - 325 - /** 326 - * Starts a transaction. 327 - */ 328 - public function transaction() 329 - { 330 - if (!$this->connection->beginTransaction()) 331 - throw new DatabaseException($this); 332 - } 333 - 334 - /** 335 - * Commits the current transaction. 336 - */ 337 - public function commit() 338 - { 339 - if (!$this->connection->commit()) 340 - throw new DatabaseException($this); 341 - } 342 - 343 - /** 344 - * Rollback a transaction. 345 - */ 346 - public function rollback() 347 - { 348 - if (!$this->connection->rollback()) 349 - throw new DatabaseException($this); 350 - } 351 - 352 - /** 353 - * Tells you if this adapter supports sequences or not. 354 - * 355 - * @return boolean 356 - */ 357 - function supports_sequences() { return false; } 358 - 359 - /** 360 - * Return a default sequence name for the specified table. 361 - * 362 - * @param string $table Name of a table 363 - * @param string $column_name Name of column sequence is for 364 - * @return string sequence name or null if not supported. 365 - */ 366 - public function get_sequence_name($table, $column_name) 367 - { 368 - return "{$table}_seq"; 369 - } 370 - 371 - /** 372 - * Return SQL for getting the next value in a sequence. 373 - * 374 - * @param string $sequence_name Name of the sequence 375 - * @return string 376 - */ 377 - public function next_sequence_value($sequence_name) { return null; } 378 - 379 - /** 380 - * Quote a name like table names and field names. 381 - * 382 - * @param string $string String to quote. 383 - * @return string 384 - */ 385 - public function quote_name($string) 386 - { 387 - return $string[0] === static::$QUOTE_CHARACTER || $string[strlen($string)-1] === static::$QUOTE_CHARACTER ? 388 - $string : static::$QUOTE_CHARACTER . $string . static::$QUOTE_CHARACTER; 389 - } 390 - 391 - /** 392 - * Return a date time formatted into the database's date format. 393 - * 394 - * @param DateTime $datetime The DateTime object 395 - * @return string 396 - */ 397 - public function date_to_string($datetime) 398 - { 399 - return $datetime->format('Y-m-d'); 400 - } 401 - 402 - /** 403 - * Return a date time formatted into the database's datetime format. 404 - * 405 - * @param DateTime $datetime The DateTime object 406 - * @return string 407 - */ 408 - public function datetime_to_string($datetime) 409 - { 410 - return $datetime->format('Y-m-d H:i:s T'); 411 - } 412 - 413 - /** 414 - * Converts a string representation of a datetime into a DateTime object. 415 - * 416 - * @param string $string A datetime in the form accepted by date_create() 417 - * @return DateTime 418 - */ 419 - public function string_to_datetime($string) 420 - { 421 - $date = date_create($string); 422 - $errors = \DateTime::getLastErrors(); 423 - 424 - if ($errors['warning_count'] > 0 || $errors['error_count'] > 0) 425 - return null; 426 - 427 - return new DateTime($date->format('Y-m-d H:i:s T')); 428 - } 429 - 430 - /** 431 - * Adds a limit clause to the SQL query. 432 - * 433 - * @param string $sql The SQL statement. 434 - * @param int $offset Row offset to start at. 435 - * @param int $limit Maximum number of rows to return. 436 - * @return string The SQL query that will limit results to specified parameters 437 - */ 438 - abstract function limit($sql, $offset, $limit); 439 - 440 - /** 441 - * Query for column meta info and return statement handle. 442 - * 443 - * @param string $table Name of a table 444 - * @return PDOStatement 445 - */ 446 - abstract public function query_column_info($table); 447 - 448 - /** 449 - * Query for all tables in the current database. The result must only 450 - * contain one column which has the name of the table. 451 - * 452 - * @return PDOStatement 453 - */ 454 - abstract function query_for_tables(); 455 - }; 456 - ?> 1 + <?php 2 + /** 3 + * @package ActiveRecord 4 + */ 5 + namespace ActiveRecord; 6 + 7 + require 'Column.php'; 8 + 9 + use PDO; 10 + use PDOException; 11 + use Closure; 12 + 13 + /** 14 + * The base class for database connection adapters. 15 + * 16 + * @package ActiveRecord 17 + */ 18 + abstract class Connection 19 + { 20 + /** 21 + * The PDO connection object. 22 + * @var mixed 23 + */ 24 + public $connection; 25 + 26 + /** 27 + * The last query run. 28 + * @var string 29 + */ 30 + public $last_query; 31 + 32 + /** 33 + * Switch for logging. 34 + * 35 + * @var bool 36 + */ 37 + private $logging = false; 38 + 39 + /** 40 + * Contains a Logger object that must impelement a log() method. 41 + * 42 + * @var object 43 + */ 44 + private $logger; 45 + 46 + /** 47 + * Default PDO options to set for each connection. 48 + * @var array 49 + */ 50 + static $PDO_OPTIONS = array( 51 + PDO::ATTR_CASE => PDO::CASE_LOWER, 52 + PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION, 53 + PDO::ATTR_ORACLE_NULLS => PDO::NULL_NATURAL, 54 + PDO::ATTR_STRINGIFY_FETCHES => false); 55 + 56 + /** 57 + * The quote character for stuff like column and field names. 58 + * @var string 59 + */ 60 + static $QUOTE_CHARACTER = '`'; 61 + 62 + /** 63 + * Default port. 64 + * @var int 65 + */ 66 + static $DEFAULT_PORT = 0; 67 + 68 + /** 69 + * Retrieve a database connection. 70 + * 71 + * @param string $connection_string_or_connection_name A database connection string (ex. mysql://user:pass@host[:port]/dbname) 72 + * Everything after the protocol:// part is specific to the connection adapter. 73 + * OR 74 + * A connection name that is set in ActiveRecord\Config 75 + * If null it will use the default connection specified by ActiveRecord\Config->set_default_connection 76 + * @return Connection 77 + * @see parse_connection_url 78 + */ 79 + public static function instance($connection_string_or_connection_name=null) 80 + { 81 + $config = Config::instance(); 82 + 83 + if (strpos($connection_string_or_connection_name,'://') === false) 84 + { 85 + $connection_string = $connection_string_or_connection_name ? 86 + $config->get_connection($connection_string_or_connection_name) : 87 + $config->get_default_connection_string(); 88 + } 89 + else 90 + $connection_string = $connection_string_or_connection_name; 91 + 92 + if (!$connection_string) 93 + throw new DatabaseException("Empty connection string"); 94 + 95 + $info = static::parse_connection_url($connection_string); 96 + $fqclass = static::load_adapter_class($info->protocol); 97 + 98 + try { 99 + $connection = new $fqclass($info); 100 + $connection->protocol = $info->protocol; 101 + $connection->logging = $config->get_logging(); 102 + $connection->logger = $connection->logging ? $config->get_logger() : null; 103 + } catch (PDOException $e) { 104 + throw new DatabaseException($e); 105 + } 106 + return $connection; 107 + } 108 + 109 + /** 110 + * Loads the specified class for an adapter. 111 + * 112 + * @param string $adapter Name of the adapter. 113 + * @return string The full name of the class including namespace. 114 + */ 115 + private static function load_adapter_class($adapter) 116 + { 117 + $class = ucwords($adapter) . 'Adapter'; 118 + $fqclass = 'ActiveRecord\\' . $class; 119 + $source = dirname(__FILE__) . "/adapters/$class.php"; 120 + 121 + if (!file_exists($source)) 122 + throw new DatabaseException("$fqclass not found!"); 123 + 124 + require_once($source); 125 + return $fqclass; 126 + } 127 + 128 + /** 129 + * Use this for any adapters that can take connection info in the form below 130 + * to set the adapters connection info. 131 + * 132 + * <code> 133 + * protocol://username:password@host[:port]/dbname 134 + * protocol://urlencoded%20username:urlencoded%20password@host[:port]/dbname?decode=true 135 + * protocol://username:password@unix(/some/file/path)/dbname 136 + * </code> 137 + * 138 + * @param string $connection_url A connection URL 139 + * @return object the parsed URL as an object. 140 + */ 141 + public static function parse_connection_url($connection_url) 142 + { 143 + $url = @parse_url($connection_url); 144 + 145 + if (!isset($url['host'])) 146 + throw new DatabaseException('Database host must be specified in the connection string.'); 147 + 148 + $info = new \stdClass(); 149 + $info->protocol = $url['scheme']; 150 + $info->host = $url['host']; 151 + $info->db = isset($url['path']) ? substr($url['path'],1) : null; 152 + $info->user = isset($url['user']) ? $url['user'] : null; 153 + $info->pass = isset($url['pass']) ? $url['pass'] : null; 154 + 155 + if ($info->host == 'unix(') 156 + { 157 + $socket_database = $info->host . '/' . $info->db; 158 + 159 + if (preg_match_all('/^unix\((.+)\)\/(.+)$/', $socket_database, $matches) > 0) 160 + { 161 + $info->host = $matches[1][0]; 162 + $info->db = $matches[2][0]; 163 + } 164 + } 165 + 166 + if (isset($url['port'])) 167 + $info->port = $url['port']; 168 + 169 + if (strpos($connection_url,'decode=true') !== false) 170 + { 171 + if ($info->user) 172 + $info->user = urldecode($info->user); 173 + 174 + if ($info->pass) 175 + $info->pass = urldecode($info->pass); 176 + } 177 + 178 + return $info; 179 + } 180 + 181 + /** 182 + * Class Connection is a singleton. Access it via instance(). 183 + * 184 + * @param array $info Array containing URL parts 185 + * @return Connection 186 + */ 187 + protected function __construct($info) 188 + { 189 + try 190 + { 191 + // unix sockets start with a / 192 + if ($info->host[0] != '/') 193 + { 194 + $host = "host=$info->host"; 195 + 196 + if (isset($info->port)) 197 + $host .= ";port=$info->port"; 198 + } 199 + else 200 + $host = "unix_socket=$info->host"; 201 + 202 + $this->connection = new PDO("$info->protocol:$host;dbname=$info->db",$info->user,$info->pass,static::$PDO_OPTIONS); 203 + } catch (PDOException $e) { 204 + throw new DatabaseException($e); 205 + } 206 + } 207 + 208 + /** 209 + * Retrieves column meta data for the specified table. 210 + * 211 + * @param string $table Name of a table 212 + * @return array An array of {@link Column} objects. 213 + */ 214 + public function columns($table) 215 + { 216 + $columns = array(); 217 + $sth = $this->query_column_info($table); 218 + 219 + while (($row = $sth->fetch())) 220 + { 221 + $c = $this->create_column($row); 222 + $columns[$c->name] = $c; 223 + } 224 + return $columns; 225 + } 226 + 227 + /** 228 + * Escapes quotes in a string. 229 + * 230 + * @param string $string The string to be quoted. 231 + * @return string The string with any quotes in it properly escaped. 232 + */ 233 + public function escape($string) 234 + { 235 + return $this->connection->quote($string); 236 + } 237 + 238 + /** 239 + * Retrieve the insert id of the last model saved. 240 + * 241 + * @param string $sequence Optional name of a sequence to use 242 + * @return int 243 + */ 244 + public function insert_id($sequence=null) 245 + { 246 + return $this->connection->lastInsertId($sequence); 247 + } 248 + 249 + /** 250 + * Execute a raw SQL query on the database. 251 + * 252 + * @param string $sql Raw SQL string to execute. 253 + * @param array &$values Optional array of bind values 254 + * @return mixed A result set object 255 + */ 256 + public function query($sql, &$values=array()) 257 + { 258 + if ($this->logging) 259 + $this->logger->log($sql); 260 + 261 + $this->last_query = $sql; 262 + 263 + try { 264 + if (!($sth = $this->connection->prepare($sql))) 265 + throw new DatabaseException($this); 266 + } catch (PDOException $e) { 267 + throw new DatabaseException($this); 268 + } 269 + 270 + $sth->setFetchMode(PDO::FETCH_ASSOC); 271 + 272 + try { 273 + if (!$sth->execute($values)) 274 + throw new DatabaseException($this); 275 + } catch (PDOException $e) { 276 + throw new DatabaseException($sth); 277 + } 278 + return $sth; 279 + } 280 + 281 + /** 282 + * Execute a query that returns maximum of one row with one field and return it. 283 + * 284 + * @param string $sql Raw SQL string to execute. 285 + * @param array &$values Optional array of values to bind to the query. 286 + * @return string 287 + */ 288 + public function query_and_fetch_one($sql, &$values=array()) 289 + { 290 + $sth = $this->query($sql,$values); 291 + $row = $sth->fetch(PDO::FETCH_NUM); 292 + return $row[0]; 293 + } 294 + 295 + /** 296 + * Execute a raw SQL query and fetch the results. 297 + * 298 + * @param string $sql Raw SQL string to execute. 299 + * @param Closure $handler Closure that will be passed the fetched results. 300 + */ 301 + public function query_and_fetch($sql, Closure $handler) 302 + { 303 + $sth = $this->query($sql); 304 + 305 + while (($row = $sth->fetch(PDO::FETCH_ASSOC))) 306 + $handler($row); 307 + } 308 + 309 + /** 310 + * Returns all tables for the current database. 311 + * 312 + * @return array Array containing table names. 313 + */ 314 + public function tables() 315 + { 316 + $tables = array(); 317 + $sth = $this->query_for_tables(); 318 + 319 + while (($row = $sth->fetch(PDO::FETCH_NUM))) 320 + $tables[] = $row[0]; 321 + 322 + return $tables; 323 + } 324 + 325 + /** 326 + * Starts a transaction. 327 + */ 328 + public function transaction() 329 + { 330 + if (!$this->connection->beginTransaction()) 331 + throw new DatabaseException($this); 332 + } 333 + 334 + /** 335 + * Commits the current transaction. 336 + */ 337 + public function commit() 338 + { 339 + if (!$this->connection->commit()) 340 + throw new DatabaseException($this); 341 + } 342 + 343 + /** 344 + * Rollback a transaction. 345 + */ 346 + public function rollback() 347 + { 348 + if (!$this->connection->rollback()) 349 + throw new DatabaseException($this); 350 + } 351 + 352 + /** 353 + * Tells you if this adapter supports sequences or not. 354 + * 355 + * @return boolean 356 + */ 357 + function supports_sequences() { return false; } 358 + 359 + /** 360 + * Return a default sequence name for the specified table. 361 + * 362 + * @param string $table Name of a table 363 + * @param string $column_name Name of column sequence is for 364 + * @return string sequence name or null if not supported. 365 + */ 366 + public function get_sequence_name($table, $column_name) 367 + { 368 + return "{$table}_seq"; 369 + } 370 + 371 + /** 372 + * Return SQL for getting the next value in a sequence. 373 + * 374 + * @param string $sequence_name Name of the sequence 375 + * @return string 376 + */ 377 + public function next_sequence_value($sequence_name) { return null; } 378 + 379 + /** 380 + * Quote a name like table names and field names. 381 + * 382 + * @param string $string String to quote. 383 + * @return string 384 + */ 385 + public function quote_name($string) 386 + { 387 + return $string[0] === static::$QUOTE_CHARACTER || $string[strlen($string)-1] === static::$QUOTE_CHARACTER ? 388 + $string : static::$QUOTE_CHARACTER . $string . static::$QUOTE_CHARACTER; 389 + } 390 + 391 + /** 392 + * Return a date time formatted into the database's date format. 393 + * 394 + * @param DateTime $datetime The DateTime object 395 + * @return string 396 + */ 397 + public function date_to_string($datetime) 398 + { 399 + return $datetime->format('Y-m-d'); 400 + } 401 + 402 + /** 403 + * Return a date time formatted into the database's datetime format. 404 + * 405 + * @param DateTime $datetime The DateTime object 406 + * @return string 407 + */ 408 + public function datetime_to_string($datetime) 409 + { 410 + return $datetime->format('Y-m-d H:i:s T'); 411 + } 412 + 413 + /** 414 + * Converts a string representation of a datetime into a DateTime object. 415 + * 416 + * @param string $string A datetime in the form accepted by date_create() 417 + * @return DateTime 418 + */ 419 + public function string_to_datetime($string) 420 + { 421 + $date = date_create($string); 422 + $errors = \DateTime::getLastErrors(); 423 + 424 + if ($errors['warning_count'] > 0 || $errors['error_count'] > 0) 425 + return null; 426 + 427 + return new DateTime($date->format('Y-m-d H:i:s T')); 428 + } 429 + 430 + /** 431 + * Adds a limit clause to the SQL query. 432 + * 433 + * @param string $sql The SQL statement. 434 + * @param int $offset Row offset to start at. 435 + * @param int $limit Maximum number of rows to return. 436 + * @return string The SQL query that will limit results to specified parameters 437 + */ 438 + abstract function limit($sql, $offset, $limit); 439 + 440 + /** 441 + * Query for column meta info and return statement handle. 442 + * 443 + * @param string $table Name of a table 444 + * @return PDOStatement 445 + */ 446 + abstract public function query_column_info($table); 447 + 448 + /** 449 + * Query for all tables in the current database. The result must only 450 + * contain one column which has the name of the table. 451 + * 452 + * @return PDOStatement 453 + */ 454 + abstract function query_for_tables(); 455 + }; 456 + ?>
+405 -405
lib/php-activerecord/test/helpers/AdapterTest.php
··· 1 - <?php 2 - use ActiveRecord\Column; 3 - 4 - class AdapterTest extends DatabaseTest 5 - { 6 - const InvalidDb = '__1337__invalid_db__'; 7 - 8 - public function set_up($connection_name=null) 9 - { 10 - if (($connection_name && !in_array($connection_name, PDO::getAvailableDrivers())) || 11 - ActiveRecord\Config::instance()->get_connection($connection_name) == 'skip') 12 - $this->mark_test_skipped($connection_name . ' drivers are not present'); 13 - 14 - parent::set_up($connection_name); 15 - } 16 - 17 - public function test_i_has_a_default_port_unless_im_sqlite() 18 - { 19 - if ($this->conn instanceof ActiveRecord\SqliteAdapter) 20 - return; 21 - 22 - $c = $this->conn; 23 - $this->assert_true($c::$DEFAULT_PORT > 0); 24 - } 25 - 26 - public function test_should_set_adapter_variables() 27 - { 28 - $this->assert_not_null($this->conn->protocol); 29 - } 30 - 31 - public function test_null_connection_string_uses_default_connection() 32 - { 33 - $this->assert_not_null(ActiveRecord\Connection::instance(null)); 34 - $this->assert_not_null(ActiveRecord\Connection::instance('')); 35 - $this->assert_not_null(ActiveRecord\Connection::instance()); 36 - } 37 - 38 - /** 39 - * @expectedException ActiveRecord\DatabaseException 40 - */ 41 - public function test_invalid_connection_protocol() 42 - { 43 - ActiveRecord\Connection::instance('terribledb://user:pass@host/db'); 44 - } 45 - 46 - /** 47 - * @expectedException ActiveRecord\DatabaseException 48 - */ 49 - public function test_no_host_connection() 50 - { 51 - if (!$GLOBALS['slow_tests']) 52 - throw new ActiveRecord\DatabaseException(""); 53 - 54 - ActiveRecord\Connection::instance("{$this->conn->protocol}://user:pass"); 55 - } 56 - 57 - /** 58 - * @expectedException ActiveRecord\DatabaseException 59 - */ 60 - public function test_connection_failed_invalid_host() 61 - { 62 - if (!$GLOBALS['slow_tests']) 63 - throw new ActiveRecord\DatabaseException(""); 64 - 65 - ActiveRecord\Connection::instance("{$this->conn->protocol}://user:pass/1.1.1.1/db"); 66 - } 67 - 68 - /** 69 - * @expectedException ActiveRecord\DatabaseException 70 - */ 71 - public function test_connection_failed() 72 - { 73 - ActiveRecord\Connection::instance("{$this->conn->protocol}://baduser:badpass@127.0.0.1/db"); 74 - } 75 - 76 - /** 77 - * @expectedException ActiveRecord\DatabaseException 78 - */ 79 - public function test_connect_failed() 80 - { 81 - ActiveRecord\Connection::instance("{$this->conn->protocol}://zzz:zzz@127.0.0.1/test"); 82 - } 83 - 84 - public function test_connect_with_port() 85 - { 86 - $config = ActiveRecord\Config::instance(); 87 - $name = $config->get_default_connection(); 88 - $url = parse_url($config->get_connection($name)); 89 - $conn = $this->conn; 90 - $port = $conn::$DEFAULT_PORT; 91 - 92 - if ($this->conn->protocol != 'sqlite') 93 - ActiveRecord\Connection::instance("{$url['scheme']}://{$url['user']}:{$url['pass']}@{$url['host']}:$port{$url['path']}"); 94 - } 95 - 96 - /** 97 - * @expectedException ActiveRecord\DatabaseException 98 - */ 99 - public function test_connect_to_invalid_database() 100 - { 101 - ActiveRecord\Connection::instance("{$this->conn->protocol}://test:test@127.0.0.1/" . self::InvalidDb); 102 - } 103 - 104 - public function test_date_time_type() 105 - { 106 - $columns = $this->conn->columns('authors'); 107 - $this->assert_equals('datetime',$columns['created_at']->raw_type); 108 - $this->assert_equals(Column::DATETIME,$columns['created_at']->type); 109 - $this->assert_true($columns['created_at']->length > 0); 110 - } 111 - 112 - public function test_date() 113 - { 114 - $columns = $this->conn->columns('authors'); 115 - $this->assert_equals('date',$columns['some_date']->raw_type); 116 - $this->assert_equals(Column::DATE,$columns['some_date']->type); 117 - $this->assert_true($columns['some_date']->length >= 7); 118 - } 119 - 120 - public function test_columns_no_inflection_on_hash_key() 121 - { 122 - $author_columns = $this->conn->columns('authors'); 123 - $this->assert_true(array_key_exists('author_id',$author_columns)); 124 - } 125 - 126 - public function test_columns_nullable() 127 - { 128 - $author_columns = $this->conn->columns('authors'); 129 - $this->assert_false($author_columns['author_id']->nullable); 130 - $this->assert_true($author_columns['parent_author_id']->nullable); 131 - } 132 - 133 - public function test_columns_pk() 134 - { 135 - $author_columns = $this->conn->columns('authors'); 136 - $this->assert_true($author_columns['author_id']->pk); 137 - $this->assert_false($author_columns['parent_author_id']->pk); 138 - } 139 - 140 - public function test_columns_sequence() 141 - { 142 - if ($this->conn->supports_sequences()) 143 - { 144 - $author_columns = $this->conn->columns('authors'); 145 - $this->assert_equals('authors_author_id_seq',$author_columns['author_id']->sequence); 146 - } 147 - } 148 - 149 - public function test_columns_default() 150 - { 151 - $author_columns = $this->conn->columns('authors'); 152 - $this->assert_equals('default_name',$author_columns['name']->default); 153 - } 154 - 155 - public function test_columns_type() 156 - { 157 - $author_columns = $this->conn->columns('authors'); 158 - $this->assert_equals('varchar',substr($author_columns['name']->raw_type,0,7)); 159 - $this->assert_equals(Column::STRING,$author_columns['name']->type); 160 - $this->assert_equals(25,$author_columns['name']->length); 161 - } 162 - 163 - public function test_columns_text() 164 - { 165 - $author_columns = $this->conn->columns('authors'); 166 - $this->assert_equals('text',$author_columns['some_text']->raw_type); 167 - $this->assert_equals(null,$author_columns['some_text']->length); 168 - } 169 - 170 - public function test_columns_time() 171 - { 172 - $author_columns = $this->conn->columns('authors'); 173 - $this->assert_equals('time',$author_columns['some_time']->raw_type); 174 - $this->assert_equals(Column::TIME,$author_columns['some_time']->type); 175 - } 176 - 177 - public function test_query() 178 - { 179 - $sth = $this->conn->query('SELECT * FROM authors'); 180 - 181 - while (($row = $sth->fetch())) 182 - $this->assert_not_null($row); 183 - 184 - $sth = $this->conn->query('SELECT * FROM authors WHERE author_id=1'); 185 - $row = $sth->fetch(); 186 - $this->assert_equals('Tito',$row['name']); 187 - } 188 - 189 - /** 190 - * @expectedException ActiveRecord\DatabaseException 191 - */ 192 - public function test_invalid_query() 193 - { 194 - $this->conn->query('alsdkjfsdf'); 195 - } 196 - 197 - public function test_fetch() 198 - { 199 - $sth = $this->conn->query('SELECT * FROM authors WHERE author_id IN(1,2,3)'); 200 - $i = 0; 201 - $ids = array(); 202 - 203 - while (($row = $sth->fetch())) 204 - { 205 - ++$i; 206 - $ids[] = $row['author_id']; 207 - } 208 - 209 - $this->assert_equals(3,$i); 210 - $this->assert_equals(array(1,2,3),$ids); 211 - } 212 - 213 - public function test_query_with_params() 214 - { 215 - $x=array('Bill Clinton','Tito'); 216 - $sth = $this->conn->query('SELECT * FROM authors WHERE name IN(?,?) ORDER BY name DESC',$x); 217 - $row = $sth->fetch(); 218 - $this->assert_equals('Tito',$row['name']); 219 - 220 - $row = $sth->fetch(); 221 - $this->assert_equals('Bill Clinton',$row['name']); 222 - 223 - $row = $sth->fetch(); 224 - $this->assert_equals(null,$row); 225 - } 226 - 227 - public function test_insert_id_should_return_explicitly_inserted_id() 228 - { 229 - $this->conn->query('INSERT INTO authors(author_id,name) VALUES(99,\'name\')'); 230 - $this->assert_true($this->conn->insert_id() > 0); 231 - } 232 - 233 - public function test_insert_id() 234 - { 235 - $this->conn->query("INSERT INTO authors(name) VALUES('name')"); 236 - $this->assert_true($this->conn->insert_id() > 0); 237 - } 238 - 239 - public function test_insert_id_with_params() 240 - { 241 - $x = array('name'); 242 - $this->conn->query('INSERT INTO authors(name) VALUES(?)',$x); 243 - $this->assert_true($this->conn->insert_id() > 0); 244 - } 245 - 246 - public function test_inflection() 247 - { 248 - $columns = $this->conn->columns('authors'); 249 - $this->assert_equals('parent_author_id',$columns['parent_author_id']->inflected_name); 250 - } 251 - 252 - public function test_escape() 253 - { 254 - $s = "Bob's"; 255 - $this->assert_not_equals($s,$this->conn->escape($s)); 256 - } 257 - 258 - public function test_columnsx() 259 - { 260 - $columns = $this->conn->columns('authors'); 261 - $names = array('author_id','parent_author_id','name','updated_at','created_at','some_date','some_time','some_text','encrypted_password','mixedCaseField'); 262 - 263 - if ($this->conn instanceof ActiveRecord\OciAdapter) 264 - $names = array_filter(array_map('strtolower',$names),function($s) { $s !== 'some_time'; }); 265 - 266 - foreach ($names as $field) 267 - $this->assert_true(array_key_exists($field,$columns)); 268 - 269 - $this->assert_equals(true,$columns['author_id']->pk); 270 - $this->assert_equals('int',$columns['author_id']->raw_type); 271 - $this->assert_equals(Column::INTEGER,$columns['author_id']->type); 272 - $this->assert_true($columns['author_id']->length > 1); 273 - $this->assert_false($columns['author_id']->nullable); 274 - 275 - $this->assert_equals(false,$columns['parent_author_id']->pk); 276 - $this->assert_true($columns['parent_author_id']->nullable); 277 - 278 - $this->assert_equals('varchar',substr($columns['name']->raw_type,0,7)); 279 - $this->assert_equals(Column::STRING,$columns['name']->type); 280 - $this->assert_equals(25,$columns['name']->length); 281 - } 282 - 283 - public function test_columns_decimal() 284 - { 285 - $columns = $this->conn->columns('books'); 286 - $this->assert_equals(Column::DECIMAL,$columns['special']->type); 287 - $this->assert_true($columns['special']->length >= 10); 288 - } 289 - 290 - private function limit($offset, $limit) 291 - { 292 - $ret = array(); 293 - $sql = 'SELECT * FROM authors ORDER BY name ASC'; 294 - $this->conn->query_and_fetch($this->conn->limit($sql,$offset,$limit),function($row) use (&$ret) { $ret[] = $row; }); 295 - return ActiveRecord\collect($ret,'author_id'); 296 - } 297 - 298 - public function test_limit() 299 - { 300 - $this->assert_equals(array(2,1),$this->limit(1,2)); 301 - } 302 - 303 - public function test_limit_to_first_record() 304 - { 305 - $this->assert_equals(array(3),$this->limit(0,1)); 306 - } 307 - 308 - public function test_limit_to_last_record() 309 - { 310 - $this->assert_equals(array(1),$this->limit(2,1)); 311 - } 312 - 313 - public function test_limit_with_null_offset() 314 - { 315 - $this->assert_equals(array(3),$this->limit(null,1)); 316 - } 317 - 318 - public function test_limit_with_nulls() 319 - { 320 - $this->assert_equals(array(),$this->limit(null,null)); 321 - } 322 - 323 - public function test_fetch_no_results() 324 - { 325 - $sth = $this->conn->query('SELECT * FROM authors WHERE author_id=65534'); 326 - $this->assert_equals(null,$sth->fetch()); 327 - } 328 - 329 - public function test_tables() 330 - { 331 - $this->assert_true(count($this->conn->tables()) > 0); 332 - } 333 - 334 - public function test_query_column_info() 335 - { 336 - $this->assert_greater_than(0,count($this->conn->query_column_info("authors"))); 337 - } 338 - 339 - public function test_query_table_info() 340 - { 341 - $this->assert_greater_than(0,count($this->conn->query_for_tables())); 342 - } 343 - 344 - public function test_query_table_info_must_return_one_field() 345 - { 346 - $sth = $this->conn->query_for_tables(); 347 - $this->assert_equals(1,count($sth->fetch())); 348 - } 349 - 350 - public function test_transaction_commit() 351 - { 352 - $original = $this->conn->query_and_fetch_one("select count(*) from authors"); 353 - 354 - $this->conn->transaction(); 355 - $this->conn->query("insert into authors(author_id,name) values(9999,'blahhhhhhhh')"); 356 - $this->conn->commit(); 357 - 358 - $this->assert_equals($original+1,$this->conn->query_and_fetch_one("select count(*) from authors")); 359 - } 360 - 361 - public function test_transaction_rollback() 362 - { 363 - $original = $this->conn->query_and_fetch_one("select count(*) from authors"); 364 - 365 - $this->conn->transaction(); 366 - $this->conn->query("insert into authors(author_id,name) values(9999,'blahhhhhhhh')"); 367 - $this->conn->rollback(); 368 - 369 - $this->assert_equals($original,$this->conn->query_and_fetch_one("select count(*) from authors")); 370 - } 371 - 372 - public function test_show_me_a_useful_pdo_exception_message() 373 - { 374 - try { 375 - $this->conn->query('select * from an_invalid_column'); 376 - $this->fail(); 377 - } catch (Exception $e) { 378 - $this->assert_equals(1,preg_match('/(an_invalid_column)|(exist)/',$e->getMessage())); 379 - } 380 - } 381 - 382 - public function test_quote_name_does_not_over_quote() 383 - { 384 - $c = $this->conn; 385 - $q = $c::$QUOTE_CHARACTER; 386 - $qn = function($s) use ($c) { return $c->quote_name($s); }; 387 - 388 - $this->assert_equals("{$q}string", $qn("{$q}string")); 389 - $this->assert_equals("string{$q}", $qn("string{$q}")); 390 - $this->assert_equals("{$q}string{$q}", $qn("{$q}string{$q}")); 391 - } 392 - 393 - public function test_datetime_to_string() 394 - { 395 - $datetime = '2009-01-01 01:01:01 EST'; 396 - $this->assert_equals($datetime,$this->conn->datetime_to_string(date_create($datetime))); 397 - } 398 - 399 - public function test_date_to_string() 400 - { 401 - $datetime = '2009-01-01'; 402 - $this->assert_equals($datetime,$this->conn->date_to_string(date_create($datetime))); 403 - } 404 - } 405 - ?> 1 + <?php 2 + use ActiveRecord\Column; 3 + 4 + class AdapterTest extends DatabaseTest 5 + { 6 + const InvalidDb = '__1337__invalid_db__'; 7 + 8 + public function set_up($connection_name=null) 9 + { 10 + if (($connection_name && !in_array($connection_name, PDO::getAvailableDrivers())) || 11 + ActiveRecord\Config::instance()->get_connection($connection_name) == 'skip') 12 + $this->mark_test_skipped($connection_name . ' drivers are not present'); 13 + 14 + parent::set_up($connection_name); 15 + } 16 + 17 + public function test_i_has_a_default_port_unless_im_sqlite() 18 + { 19 + if ($this->conn instanceof ActiveRecord\SqliteAdapter) 20 + return; 21 + 22 + $c = $this->conn; 23 + $this->assert_true($c::$DEFAULT_PORT > 0); 24 + } 25 + 26 + public function test_should_set_adapter_variables() 27 + { 28 + $this->assert_not_null($this->conn->protocol); 29 + } 30 + 31 + public function test_null_connection_string_uses_default_connection() 32 + { 33 + $this->assert_not_null(ActiveRecord\Connection::instance(null)); 34 + $this->assert_not_null(ActiveRecord\Connection::instance('')); 35 + $this->assert_not_null(ActiveRecord\Connection::instance()); 36 + } 37 + 38 + /** 39 + * @expectedException ActiveRecord\DatabaseException 40 + */ 41 + public function test_invalid_connection_protocol() 42 + { 43 + ActiveRecord\Connection::instance('terribledb://user:pass@host/db'); 44 + } 45 + 46 + /** 47 + * @expectedException ActiveRecord\DatabaseException 48 + */ 49 + public function test_no_host_connection() 50 + { 51 + if (!$GLOBALS['slow_tests']) 52 + throw new ActiveRecord\DatabaseException(""); 53 + 54 + ActiveRecord\Connection::instance("{$this->conn->protocol}://user:pass"); 55 + } 56 + 57 + /** 58 + * @expectedException ActiveRecord\DatabaseException 59 + */ 60 + public function test_connection_failed_invalid_host() 61 + { 62 + if (!$GLOBALS['slow_tests']) 63 + throw new ActiveRecord\DatabaseException(""); 64 + 65 + ActiveRecord\Connection::instance("{$this->conn->protocol}://user:pass/1.1.1.1/db"); 66 + } 67 + 68 + /** 69 + * @expectedException ActiveRecord\DatabaseException 70 + */ 71 + public function test_connection_failed() 72 + { 73 + ActiveRecord\Connection::instance("{$this->conn->protocol}://baduser:badpass@127.0.0.1/db"); 74 + } 75 + 76 + /** 77 + * @expectedException ActiveRecord\DatabaseException 78 + */ 79 + public function test_connect_failed() 80 + { 81 + ActiveRecord\Connection::instance("{$this->conn->protocol}://zzz:zzz@127.0.0.1/test"); 82 + } 83 + 84 + public function test_connect_with_port() 85 + { 86 + $config = ActiveRecord\Config::instance(); 87 + $name = $config->get_default_connection(); 88 + $url = parse_url($config->get_connection($name)); 89 + $conn = $this->conn; 90 + $port = $conn::$DEFAULT_PORT; 91 + 92 + if ($this->conn->protocol != 'sqlite') 93 + ActiveRecord\Connection::instance("{$url['scheme']}://{$url['user']}:{$url['pass']}@{$url['host']}:$port{$url['path']}"); 94 + } 95 + 96 + /** 97 + * @expectedException ActiveRecord\DatabaseException 98 + */ 99 + public function test_connect_to_invalid_database() 100 + { 101 + ActiveRecord\Connection::instance("{$this->conn->protocol}://test:test@127.0.0.1/" . self::InvalidDb); 102 + } 103 + 104 + public function test_date_time_type() 105 + { 106 + $columns = $this->conn->columns('authors'); 107 + $this->assert_equals('datetime',$columns['created_at']->raw_type); 108 + $this->assert_equals(Column::DATETIME,$columns['created_at']->type); 109 + $this->assert_true($columns['created_at']->length > 0); 110 + } 111 + 112 + public function test_date() 113 + { 114 + $columns = $this->conn->columns('authors'); 115 + $this->assert_equals('date',$columns['some_date']->raw_type); 116 + $this->assert_equals(Column::DATE,$columns['some_date']->type); 117 + $this->assert_true($columns['some_date']->length >= 7); 118 + } 119 + 120 + public function test_columns_no_inflection_on_hash_key() 121 + { 122 + $author_columns = $this->conn->columns('authors'); 123 + $this->assert_true(array_key_exists('author_id',$author_columns)); 124 + } 125 + 126 + public function test_columns_nullable() 127 + { 128 + $author_columns = $this->conn->columns('authors'); 129 + $this->assert_false($author_columns['author_id']->nullable); 130 + $this->assert_true($author_columns['parent_author_id']->nullable); 131 + } 132 + 133 + public function test_columns_pk() 134 + { 135 + $author_columns = $this->conn->columns('authors'); 136 + $this->assert_true($author_columns['author_id']->pk); 137 + $this->assert_false($author_columns['parent_author_id']->pk); 138 + } 139 + 140 + public function test_columns_sequence() 141 + { 142 + if ($this->conn->supports_sequences()) 143 + { 144 + $author_columns = $this->conn->columns('authors'); 145 + $this->assert_equals('authors_author_id_seq',$author_columns['author_id']->sequence); 146 + } 147 + } 148 + 149 + public function test_columns_default() 150 + { 151 + $author_columns = $this->conn->columns('authors'); 152 + $this->assert_equals('default_name',$author_columns['name']->default); 153 + } 154 + 155 + public function test_columns_type() 156 + { 157 + $author_columns = $this->conn->columns('authors'); 158 + $this->assert_equals('varchar',substr($author_columns['name']->raw_type,0,7)); 159 + $this->assert_equals(Column::STRING,$author_columns['name']->type); 160 + $this->assert_equals(25,$author_columns['name']->length); 161 + } 162 + 163 + public function test_columns_text() 164 + { 165 + $author_columns = $this->conn->columns('authors'); 166 + $this->assert_equals('text',$author_columns['some_text']->raw_type); 167 + $this->assert_equals(null,$author_columns['some_text']->length); 168 + } 169 + 170 + public function test_columns_time() 171 + { 172 + $author_columns = $this->conn->columns('authors'); 173 + $this->assert_equals('time',$author_columns['some_time']->raw_type); 174 + $this->assert_equals(Column::TIME,$author_columns['some_time']->type); 175 + } 176 + 177 + public function test_query() 178 + { 179 + $sth = $this->conn->query('SELECT * FROM authors'); 180 + 181 + while (($row = $sth->fetch())) 182 + $this->assert_not_null($row); 183 + 184 + $sth = $this->conn->query('SELECT * FROM authors WHERE author_id=1'); 185 + $row = $sth->fetch(); 186 + $this->assert_equals('Tito',$row['name']); 187 + } 188 + 189 + /** 190 + * @expectedException ActiveRecord\DatabaseException 191 + */ 192 + public function test_invalid_query() 193 + { 194 + $this->conn->query('alsdkjfsdf'); 195 + } 196 + 197 + public function test_fetch() 198 + { 199 + $sth = $this->conn->query('SELECT * FROM authors WHERE author_id IN(1,2,3)'); 200 + $i = 0; 201 + $ids = array(); 202 + 203 + while (($row = $sth->fetch())) 204 + { 205 + ++$i; 206 + $ids[] = $row['author_id']; 207 + } 208 + 209 + $this->assert_equals(3,$i); 210 + $this->assert_equals(array(1,2,3),$ids); 211 + } 212 + 213 + public function test_query_with_params() 214 + { 215 + $x=array('Bill Clinton','Tito'); 216 + $sth = $this->conn->query('SELECT * FROM authors WHERE name IN(?,?) ORDER BY name DESC',$x); 217 + $row = $sth->fetch(); 218 + $this->assert_equals('Tito',$row['name']); 219 + 220 + $row = $sth->fetch(); 221 + $this->assert_equals('Bill Clinton',$row['name']); 222 + 223 + $row = $sth->fetch(); 224 + $this->assert_equals(null,$row); 225 + } 226 + 227 + public function test_insert_id_should_return_explicitly_inserted_id() 228 + { 229 + $this->conn->query('INSERT INTO authors(author_id,name) VALUES(99,\'name\')'); 230 + $this->assert_true($this->conn->insert_id() > 0); 231 + } 232 + 233 + public function test_insert_id() 234 + { 235 + $this->conn->query("INSERT INTO authors(name) VALUES('name')"); 236 + $this->assert_true($this->conn->insert_id() > 0); 237 + } 238 + 239 + public function test_insert_id_with_params() 240 + { 241 + $x = array('name'); 242 + $this->conn->query('INSERT INTO authors(name) VALUES(?)',$x); 243 + $this->assert_true($this->conn->insert_id() > 0); 244 + } 245 + 246 + public function test_inflection() 247 + { 248 + $columns = $this->conn->columns('authors'); 249 + $this->assert_equals('parent_author_id',$columns['parent_author_id']->inflected_name); 250 + } 251 + 252 + public function test_escape() 253 + { 254 + $s = "Bob's"; 255 + $this->assert_not_equals($s,$this->conn->escape($s)); 256 + } 257 + 258 + public function test_columnsx() 259 + { 260 + $columns = $this->conn->columns('authors'); 261 + $names = array('author_id','parent_author_id','name','updated_at','created_at','some_date','some_time','some_text','encrypted_password','mixedCaseField'); 262 + 263 + if ($this->conn instanceof ActiveRecord\OciAdapter) 264 + $names = array_filter(array_map('strtolower',$names),function($s) { $s !== 'some_time'; }); 265 + 266 + foreach ($names as $field) 267 + $this->assert_true(array_key_exists($field,$columns)); 268 + 269 + $this->assert_equals(true,$columns['author_id']->pk); 270 + $this->assert_equals('int',$columns['author_id']->raw_type); 271 + $this->assert_equals(Column::INTEGER,$columns['author_id']->type); 272 + $this->assert_true($columns['author_id']->length > 1); 273 + $this->assert_false($columns['author_id']->nullable); 274 + 275 + $this->assert_equals(false,$columns['parent_author_id']->pk); 276 + $this->assert_true($columns['parent_author_id']->nullable); 277 + 278 + $this->assert_equals('varchar',substr($columns['name']->raw_type,0,7)); 279 + $this->assert_equals(Column::STRING,$columns['name']->type); 280 + $this->assert_equals(25,$columns['name']->length); 281 + } 282 + 283 + public function test_columns_decimal() 284 + { 285 + $columns = $this->conn->columns('books'); 286 + $this->assert_equals(Column::DECIMAL,$columns['special']->type); 287 + $this->assert_true($columns['special']->length >= 10); 288 + } 289 + 290 + private function limit($offset, $limit) 291 + { 292 + $ret = array(); 293 + $sql = 'SELECT * FROM authors ORDER BY name ASC'; 294 + $this->conn->query_and_fetch($this->conn->limit($sql,$offset,$limit),function($row) use (&$ret) { $ret[] = $row; }); 295 + return ActiveRecord\collect($ret,'author_id'); 296 + } 297 + 298 + public function test_limit() 299 + { 300 + $this->assert_equals(array(2,1),$this->limit(1,2)); 301 + } 302 + 303 + public function test_limit_to_first_record() 304 + { 305 + $this->assert_equals(array(3),$this->limit(0,1)); 306 + } 307 + 308 + public function test_limit_to_last_record() 309 + { 310 + $this->assert_equals(array(1),$this->limit(2,1)); 311 + } 312 + 313 + public function test_limit_with_null_offset() 314 + { 315 + $this->assert_equals(array(3),$this->limit(null,1)); 316 + } 317 + 318 + public function test_limit_with_nulls() 319 + { 320 + $this->assert_equals(array(),$this->limit(null,null)); 321 + } 322 + 323 + public function test_fetch_no_results() 324 + { 325 + $sth = $this->conn->query('SELECT * FROM authors WHERE author_id=65534'); 326 + $this->assert_equals(null,$sth->fetch()); 327 + } 328 + 329 + public function test_tables() 330 + { 331 + $this->assert_true(count($this->conn->tables()) > 0); 332 + } 333 + 334 + public function test_query_column_info() 335 + { 336 + $this->assert_greater_than(0,count($this->conn->query_column_info("authors"))); 337 + } 338 + 339 + public function test_query_table_info() 340 + { 341 + $this->assert_greater_than(0,count($this->conn->query_for_tables())); 342 + } 343 + 344 + public function test_query_table_info_must_return_one_field() 345 + { 346 + $sth = $this->conn->query_for_tables(); 347 + $this->assert_equals(1,count($sth->fetch())); 348 + } 349 + 350 + public function test_transaction_commit() 351 + { 352 + $original = $this->conn->query_and_fetch_one("select count(*) from authors"); 353 + 354 + $this->conn->transaction(); 355 + $this->conn->query("insert into authors(author_id,name) values(9999,'blahhhhhhhh')"); 356 + $this->conn->commit(); 357 + 358 + $this->assert_equals($original+1,$this->conn->query_and_fetch_one("select count(*) from authors")); 359 + } 360 + 361 + public function test_transaction_rollback() 362 + { 363 + $original = $this->conn->query_and_fetch_one("select count(*) from authors"); 364 + 365 + $this->conn->transaction(); 366 + $this->conn->query("insert into authors(author_id,name) values(9999,'blahhhhhhhh')"); 367 + $this->conn->rollback(); 368 + 369 + $this->assert_equals($original,$this->conn->query_and_fetch_one("select count(*) from authors")); 370 + } 371 + 372 + public function test_show_me_a_useful_pdo_exception_message() 373 + { 374 + try { 375 + $this->conn->query('select * from an_invalid_column'); 376 + $this->fail(); 377 + } catch (Exception $e) { 378 + $this->assert_equals(1,preg_match('/(an_invalid_column)|(exist)/',$e->getMessage())); 379 + } 380 + } 381 + 382 + public function test_quote_name_does_not_over_quote() 383 + { 384 + $c = $this->conn; 385 + $q = $c::$QUOTE_CHARACTER; 386 + $qn = function($s) use ($c) { return $c->quote_name($s); }; 387 + 388 + $this->assert_equals("{$q}string", $qn("{$q}string")); 389 + $this->assert_equals("string{$q}", $qn("string{$q}")); 390 + $this->assert_equals("{$q}string{$q}", $qn("{$q}string{$q}")); 391 + } 392 + 393 + public function test_datetime_to_string() 394 + { 395 + $datetime = '2009-01-01 01:01:01 EST'; 396 + $this->assert_equals($datetime,$this->conn->datetime_to_string(date_create($datetime))); 397 + } 398 + 399 + public function test_date_to_string() 400 + { 401 + $datetime = '2009-01-01'; 402 + $this->assert_equals($datetime,$this->conn->date_to_string(date_create($datetime))); 403 + } 404 + } 405 + ?>