Skip to content

Commit d5f1895

Browse files
authored
Merge pull request #494 from koenpunt/array-connection-info
separate connection string parsing from connection
2 parents 05b3277 + d447040 commit d5f1895

15 files changed

+374
-240
lines changed

ActiveRecord.php

+1
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
require __DIR__.'/lib/Table.php';
1717
require __DIR__.'/lib/ConnectionManager.php';
1818
require __DIR__.'/lib/Connection.php';
19+
require __DIR__.'/lib/ConnectionInfo.php';
1920
require __DIR__.'/lib/Serialization.php';
2021
require __DIR__.'/lib/Expressions.php';
2122
require __DIR__.'/lib/SQLBuilder.php';

lib/Config.php

+25-4
Original file line numberDiff line numberDiff line change
@@ -125,13 +125,25 @@ public static function initialize(Closure $initializer)
125125
}
126126

127127
/**
128-
* Sets the list of database connection strings.
128+
* Sets the list of database connections. Can be an array of connection strings or an array of arrays.
129129
*
130130
* <code>
131131
* $config->set_connections(array(
132132
* 'development' => 'mysql://username:[email protected]/database_name'));
133133
* </code>
134134
*
135+
* <code>
136+
* $config->set_connections(array(
137+
* 'development' => array(
138+
* 'adapter' => 'mysql',
139+
* 'host' => '127.0.0.1',
140+
* 'database' => 'database_name',
141+
* 'username' => 'username',
142+
* 'password' => 'password'
143+
* )
144+
* ));
145+
* </code>
146+
*
135147
* @param array $connections Array of connections
136148
* @param string $default_connection Optionally specify the default_connection
137149
* @return void
@@ -145,7 +157,16 @@ public function set_connections($connections, $default_connection=null)
145157
if ($default_connection)
146158
$this->set_default_connection($default_connection);
147159

148-
$this->connections = $connections;
160+
$this->connections = array_map(function($connection){
161+
if(is_string($connection))
162+
{
163+
return ConnectionInfo::from_connection_url($connection);
164+
}
165+
else
166+
{
167+
return new ConnectionInfo($connection);
168+
}
169+
}, $connections);
149170
}
150171

151172
/**
@@ -164,7 +185,7 @@ public function get_connections()
164185
* @param string $name Name of connection to retrieve
165186
* @return string connection info for specified connection name
166187
*/
167-
public function get_connection($name)
188+
public function get_connection_info($name)
168189
{
169190
if (array_key_exists($name, $this->connections))
170191
return $this->connections[$name];
@@ -177,7 +198,7 @@ public function get_connection($name)
177198
*
178199
* @return string
179200
*/
180-
public function get_default_connection_string()
201+
public function get_default_connection_info()
181202
{
182203
return array_key_exists($this->default_connection,$this->connections) ?
183204
$this->connections[$this->default_connection] : null;

lib/Connection.php

+30-108
Original file line numberDiff line numberDiff line change
@@ -54,10 +54,10 @@ abstract class Connection
5454
*/
5555
private $logger;
5656
/**
57-
* The name of the protocol that is used.
57+
* The name of the adapter that is used.
5858
* @var string
5959
*/
60-
public $protocol;
60+
public $adapter;
6161
/**
6262
* Database's date format
6363
* @var string
@@ -91,41 +91,49 @@ abstract class Connection
9191
/**
9292
* Retrieve a database connection.
9393
*
94-
* @param string $connection_string_or_connection_name A database connection string (ex. mysql://user:pass@host[:port]/dbname)
95-
* Everything after the protocol:// part is specific to the connection adapter.
94+
* @param string $connection_info_or_name A database connection string (ex. mysql://user:pass@host[:port]/dbname)
95+
* Everything after the adapter:// part is specific to the connection adapter.
9696
* OR
9797
* A connection name that is set in ActiveRecord\Config
9898
* If null it will use the default connection specified by ActiveRecord\Config->set_default_connection
9999
* @return Connection
100-
* @see parse_connection_url
100+
* @see ConnectionInfo::from_connection_url
101101
*/
102-
public static function instance($connection_string_or_connection_name=null)
102+
public static function instance($connection_info=null)
103103
{
104104
$config = Config::instance();
105105

106-
if (strpos($connection_string_or_connection_name, '://') === false)
106+
if (!($connection_info instanceof ConnectionInfo))
107107
{
108-
$connection_string = $connection_string_or_connection_name ?
109-
$config->get_connection($connection_string_or_connection_name) :
110-
$config->get_default_connection_string();
108+
// Connection instantiation using a connection array
109+
if (is_array($connection_info))
110+
{
111+
$connection_info = new ConnectionInfo($connection_info);
112+
}
113+
// Connection instantiation using a connection url
114+
else if (is_string($connection_info) && strpos($connection_info, '://') !== false)
115+
{
116+
$connection_info = ConnectionInfo::from_connection_url($connection_info);
117+
}
118+
// Connection instantiation using a connection name
119+
else
120+
{
121+
$connection_info = $connection_info ?
122+
$config->get_connection_info($connection_info) :
123+
$config->get_default_connection_info();
124+
}
111125
}
112-
else
113-
$connection_string = $connection_string_or_connection_name;
114-
115-
if (!$connection_string)
116-
throw new DatabaseException("Empty connection string");
117126

118-
$info = static::parse_connection_url($connection_string);
119-
$fqclass = static::load_adapter_class($info->protocol);
127+
$fqclass = static::load_adapter_class($connection_info->adapter);
120128

121129
try {
122-
$connection = new $fqclass($info);
123-
$connection->protocol = $info->protocol;
130+
$connection = new $fqclass($connection_info);
131+
$connection->adapter = $connection_info->adapter;
124132
$connection->logging = $config->get_logging();
125133
$connection->logger = $connection->logging ? $config->get_logger() : null;
126134

127-
if (isset($info->charset))
128-
$connection->set_encoding($info->charset);
135+
if (isset($connection_info->charset))
136+
$connection->set_encoding($connection_info->charset);
129137
} catch (PDOException $e) {
130138
throw new DatabaseException($e);
131139
}
@@ -151,92 +159,6 @@ private static function load_adapter_class($adapter)
151159
return $fqclass;
152160
}
153161

154-
/**
155-
* Use this for any adapters that can take connection info in the form below
156-
* to set the adapters connection info.
157-
*
158-
* <code>
159-
* protocol://username:password@host[:port]/dbname
160-
* protocol://urlencoded%20username:urlencoded%20password@host[:port]/dbname?decode=true
161-
* protocol://username:password@unix(/some/file/path)/dbname
162-
* </code>
163-
*
164-
* Sqlite has a special syntax, as it does not need a database name or user authentication:
165-
*
166-
* <code>
167-
* sqlite://file.db
168-
* sqlite://../relative/path/to/file.db
169-
* sqlite://unix(/absolute/path/to/file.db)
170-
* sqlite://windows(c%2A/absolute/path/to/file.db)
171-
* </code>
172-
*
173-
* @param string $connection_url A connection URL
174-
* @return object the parsed URL as an object.
175-
*/
176-
public static function parse_connection_url($connection_url)
177-
{
178-
$url = @parse_url($connection_url);
179-
180-
if (!isset($url['host']))
181-
throw new DatabaseException('Database host must be specified in the connection string. If you want to specify an absolute filename, use e.g. sqlite://unix(/path/to/file)');
182-
183-
$info = new \stdClass();
184-
$info->protocol = $url['scheme'];
185-
$info->host = $url['host'];
186-
$info->db = isset($url['path']) ? substr($url['path'], 1) : null;
187-
$info->user = isset($url['user']) ? $url['user'] : null;
188-
$info->pass = isset($url['pass']) ? $url['pass'] : null;
189-
190-
$allow_blank_db = ($info->protocol == 'sqlite');
191-
192-
if ($info->host == 'unix(')
193-
{
194-
$socket_database = $info->host . '/' . $info->db;
195-
196-
if ($allow_blank_db)
197-
$unix_regex = '/^unix\((.+)\)\/?().*$/';
198-
else
199-
$unix_regex = '/^unix\((.+)\)\/(.+)$/';
200-
201-
if (preg_match_all($unix_regex, $socket_database, $matches) > 0)
202-
{
203-
$info->host = $matches[1][0];
204-
$info->db = $matches[2][0];
205-
}
206-
} elseif (substr($info->host, 0, 8) == 'windows(')
207-
{
208-
$info->host = urldecode(substr($info->host, 8) . '/' . substr($info->db, 0, -1));
209-
$info->db = null;
210-
}
211-
212-
if ($allow_blank_db && $info->db)
213-
$info->host .= '/' . $info->db;
214-
215-
if (isset($url['port']))
216-
$info->port = $url['port'];
217-
218-
if (strpos($connection_url, 'decode=true') !== false)
219-
{
220-
if ($info->user)
221-
$info->user = urldecode($info->user);
222-
223-
if ($info->pass)
224-
$info->pass = urldecode($info->pass);
225-
}
226-
227-
if (isset($url['query']))
228-
{
229-
foreach (explode('/&/', $url['query']) as $pair) {
230-
list($name, $value) = explode('=', $pair);
231-
232-
if ($name == 'charset')
233-
$info->charset = $value;
234-
}
235-
}
236-
237-
return $info;
238-
}
239-
240162
/**
241163
* Class Connection is a singleton. Access it via instance().
242164
*
@@ -257,7 +179,7 @@ protected function __construct($info)
257179
else
258180
$host = "unix_socket=$info->host";
259181

260-
$this->connection = new PDO("$info->protocol:$host;dbname=$info->db", $info->user, $info->pass, static::$PDO_OPTIONS);
182+
$this->connection = new PDO("$info->adapter:$host;dbname=$info->database", $info->username, $info->password, static::$PDO_OPTIONS);
261183
} catch (PDOException $e) {
262184
throw new DatabaseException($e);
263185
}

0 commit comments

Comments
 (0)