Commit cb5a426c authored by Taylor Otwell's avatar Taylor Otwell

added database connectors and cleaned up configuration.

parent 5387312e
...@@ -49,7 +49,7 @@ return array( ...@@ -49,7 +49,7 @@ return array(
'laravel.database' => array('singleton' => true, 'resolver' => function($container) 'laravel.database' => array('singleton' => true, 'resolver' => function($container)
{ {
return new Database\Manager($container->resolve('laravel.config')->get('database')); return new Database\Manager($container->resolve('laravel.config'));
}), }),
......
...@@ -5,6 +5,13 @@ use PDOStatement; ...@@ -5,6 +5,13 @@ use PDOStatement;
class Connection { class Connection {
/**
* The connection configuration array.
*
* @var array
*/
protected $config;
/** /**
* The PDO connection. * The PDO connection.
* *
...@@ -23,11 +30,13 @@ class Connection { ...@@ -23,11 +30,13 @@ class Connection {
* Create a new database connection instance. * Create a new database connection instance.
* *
* @param PDO $pdo * @param PDO $pdo
* @param array $config
* @return void * @return void
*/ */
public function __construct(PDO $pdo) public function __construct(PDO $pdo, $config)
{ {
$this->pdo = $pdo; $this->pdo = $pdo;
$this->config = $config;
} }
/** /**
...@@ -114,18 +123,15 @@ class Connection { ...@@ -114,18 +123,15 @@ class Connection {
/** /**
* Create a new query grammar for the connection. * Create a new query grammar for the connection.
* *
* @return Queries\Grammars\Grammar * @return Grammars\Grammar
*/ */
protected function grammar() protected function grammar()
{ {
switch ($this->driver()) switch (isset($this->config['grammar']) ? $this->config['grammar'] : $this->driver())
{ {
case 'mysql': case 'mysql':
return new Grammars\MySQL; return new Grammars\MySQL;
case 'pgsql':
return new Grammars\Postgres;
default: default:
return new Grammars\Grammar; return new Grammars\Grammar;
} }
......
<?php namespace Laravel\Database\Connectors; use PDO;
abstract class Connector {
/**
* The PDO connection options.
*
* @var array
*/
protected $options = array(
PDO::ATTR_CASE => PDO::CASE_LOWER,
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
PDO::ATTR_ORACLE_NULLS => PDO::NULL_NATURAL,
PDO::ATTR_STRINGIFY_FETCHES => false,
PDO::ATTR_EMULATE_PREPARES => false,
);
/**
* Establish a PDO database connection for a given database configuration.
*
* @param array $config
* @return PDO
*/
abstract public function connect($config);
/**
* Get the PDO connection options for a given database configuration.
*
* Developer specified options will override the default connection options.
*
* @param array $config
* @return array
*/
protected function options($config)
{
$options = (isset($config['options'])) ? $config['options'] : array();
return array_merge($this->options, $options);
}
}
\ No newline at end of file
<?php namespace Laravel\Database\Connectors; use PDO;
class MySQL extends Connector {
/**
* Establish a PDO database connection for a given database configuration.
*
* @param array $config
* @return PDO
*/
public function connect($config)
{
$connection = new PDO($this->dsn($config), $config['username'], $config['password'], $this->options($config));
if (isset($config['charset']))
{
$connection->prepare("SET NAMES '{$config['charset']}'")->execute();
}
return $connection;
}
/**
* Format the DSN connection string for a MySQL connection.
*
* @param array $config
* @return string
*/
protected function dsn($config)
{
// Format the initial MySQL PDO connection string. These options are required
// for every MySQL connection that is established. The connection strings
// have the following convention: "mysql:host=hostname;dbname=database"
$dsn = sprintf('%s:host=%s;dbname=%s', $config['driver'], $config['host'], $config['database']);
// Check for any optional MySQL PDO options. These options are not required
// to establish a PDO connection; however, may be needed in certain server
// or hosting environments used by the developer.
foreach (array('port', 'unix_socket') as $key => $value)
{
if (isset($config[$key])) $dsn .= ";{$key}={$value}";
}
return $dsn;
}
}
\ No newline at end of file
<?php namespace Laravel\Database\Connectors; use PDO;
class Postgres extends Connector {
/**
* Establish a PDO database connection for a given database configuration.
*
* @param array $config
* @return PDO
*/
public function connect($config)
{
$connection = new PDO($this->dsn($config), $config['username'], $config['password'], $this->options($config));
if (isset($config['charset']))
{
$connection->prepare("SET NAMES '{$config['charset']}'")->execute();
}
return $connection;
}
/**
* Format the DSN connection string for a Postgres connection.
*
* @param array $config
* @return string
*/
protected function dsn($config)
{
// Format the initial Postgres PDO connection string. These options are required
// for every Postgres connection that is established. The connection strings
// have the following convention: "pgsql:host=hostname;dbname=database"
$dsn = sprintf('%s:host=%s;dbname=%s', $config['driver'], $config['host'], $config['database']);
// Check for any optional Postgres PDO options. These options are not required
// to establish a PDO connection; however, may be needed in certain server
// or hosting environments used by the developer.
foreach (array('port', 'unix_socket') as $key => $value)
{
if (isset($config[$key])) $dsn .= ";{$key}={$value}";
}
return $dsn;
}
}
\ No newline at end of file
<?php namespace Laravel\Database\Connectors; use PDO;
class SQLite extends Connector {
/**
* Establish a PDO database connection for a given database configuration.
*
* @param array $config
* @return PDO
*/
public function connect($config)
{
$options = $this->options($config);
if ($config['database'] == ':memory:')
{
return new PDO('sqlite::memory:', null, null, $options);
}
elseif (file_exists($path = DATABASE_PATH.$config['database'].'.sqlite'))
{
return new PDO('sqlite:'.$path, null, null, $options);
}
elseif (file_exists($config['database']))
{
return new PDO('sqlite:'.$config['database'], null, null, $options);
}
throw new \Exception("SQLite database [{$config['database']}] could not be found.");
}
}
\ No newline at end of file
<?php namespace Laravel\Database; <?php namespace Laravel\Database;
use Laravel\Config;
class Manager { class Manager {
/** /**
...@@ -9,13 +11,20 @@ class Manager { ...@@ -9,13 +11,20 @@ class Manager {
*/ */
protected $connections = array(); protected $connections = array();
/**
* The configuration manager instance.
*
* @var Config
*/
protected $config;
/** /**
* Create a new database manager instance. * Create a new database manager instance.
* *
* @param array $config * @param Connector $connector
* @return void * @return void
*/ */
public function __construct($config) public function __construct(Config $config)
{ {
$this->config = $config; $this->config = $config;
} }
...@@ -32,27 +41,54 @@ class Manager { ...@@ -32,27 +41,54 @@ class Manager {
*/ */
public function connection($connection = null) public function connection($connection = null)
{ {
if (is_null($connection)) $connection = $this->config['default']; if (is_null($connection)) $connection = $this->config->get('database.default');
if ( ! array_key_exists($connection, $this->connections)) if ( ! array_key_exists($connection, $this->connections))
{ {
if ( ! isset($this->config['connectors'][$connection])) $config = $this->config->get("database.connections.{$connection}");
if (is_null($config))
{ {
throw new \Exception("Database connection configuration is not defined for connection [$connection]."); throw new \Exception("Database connection configuration is not defined for connection [$connection].");
} }
// Database connections are established by developer configurable connector closures. $this->connections[$connection] = new Connection($this->connect($config), $config);
// This provides the developer the maximum amount of freedom in establishing their
// database connections, and allows the framework to remain agonstic to ugly database
// specific PDO connection details. Less code. Less bugs.
$pdo = call_user_func($this->config['connectors'][$connection], $this->config);
$this->connections[$connection] = new Connection($pdo, $this->config);
} }
return $this->connections[$connection]; return $this->connections[$connection];
} }
/**
* Get a PDO database connection for a given database configuration.
*
* @param array $config
* @return PDO
*/
protected function connect($config)
{
if (isset($config['connector'])) { return call_user_func($config['connector'], $config); }
switch ($config['driver'])
{
case 'sqlite':
$connector = new Connectors\SQLite;
break;
case 'mysql':
$connector = new Connectors\MySQL;
break;
case 'pgsql':
$connector = new Connectors\Postgres;
break;
default:
throw new \Exception("Database driver [{$config['driver']}] is not supported.");
}
return $connector->connect($config);
}
/** /**
* Begin a fluent query against a table. * Begin a fluent query against a table.
* *
......
...@@ -122,7 +122,7 @@ class Query { ...@@ -122,7 +122,7 @@ class Query {
*/ */
public function select($columns = array('*')) public function select($columns = array('*'))
{ {
$this->select = $columns; $this->select = (array) $columns;
return $this; return $this;
} }
...@@ -478,12 +478,25 @@ class Query { ...@@ -478,12 +478,25 @@ class Query {
/** /**
* Execute the query as a SELECT statement and return the first result. * Execute the query as a SELECT statement and return the first result.
* *
* If a single column is selected from the database, only the value of that column will be returned.
*
* @param array $columns * @param array $columns
* @return stdClass * @return mixed
*/ */
public function first($columns = array('*')) public function first($columns = array('*'))
{ {
return (count($results = $this->take(1)->get($columns)) > 0) ? $results[0] : null; $columns = (array) $columns;
$results = (count($results = $this->take(1)->get($columns)) > 0) ? $results[0] : null;
// If we have results and only a single column was selected from the database,
// we will simply return the value of that column for convenience.
if ( ! is_null($results) and count($columns) == 1 and $columns[0] !== '*')
{
return $results->{$columns[0]};
}
return $results;
} }
/** /**
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment