Skip to content

Commit

Permalink
Refactoring some code in Connection and Statement, to make it easier to
Browse files Browse the repository at this point in the history
use statements on their own and to cleanly share code between both
classes
  • Loading branch information
lorenzo committed Oct 14, 2012
1 parent d08e300 commit a6423e7
Show file tree
Hide file tree
Showing 3 changed files with 87 additions and 65 deletions.
72 changes: 20 additions & 52 deletions lib/Cake/Model/Datasource/Database/Connection.php
Expand Up @@ -70,13 +70,27 @@ public function __construct($config) {
if (!class_exists($config['datasource'])) {
throw new MissingDriverException(array('driver' => $config['datasource']));
}
$this->_driver = new $config['datasource'];

$this->setDriver($config['datasource']);
if (!$this->_driver->enabled()) {
throw new MissingExtensionException(array('driver' => get_class($this->_driver)));
}
}

/**
* Sets the driver instance. If an string is passed it will be treated
* as a class name and will be instantiated
*
* @param string|Driver $driver
* @return void
**/
public function setDriver($driver) {
if (is_string($driver)) {
$driver = new $driver;
}
$this->_driver = $driver;
}

/**
* Connects to the configured database
*
Expand Down Expand Up @@ -137,7 +151,7 @@ public function execute($query, array $params = array(), array $types = array())
$this->connect();
if ($params) {
$statement = $this->prepare($query);
$this->_bindValues($statement, $params, $types);
$statement->bind($params, $types);
$result = $statement->execute();
} else {
$statement = $this->query($query);
Expand Down Expand Up @@ -175,7 +189,7 @@ public function insert($table, array $data, array $types = array()) {
implode(',', $keys),
implode(',', array_fill(0, count($data), '?'))
);
$types = $this->_mapTypes($keys, $types);
$types = $this->matchTypes($keys, $types);
return $this->execute($sql, array_values($data), $types);
}

Expand All @@ -201,8 +215,8 @@ public function update($table, array $data, array $conditions = array(), $types
$conditions
);
if (!empty($types)) {
$types = $this->_mapTypes($keys, $types);
$types = array_merge($types, $this->_mapTypes($conditionsKeys, $types));
$types = $this->matchTypes($keys, $types);
$types = array_merge($types, $this->matchTypes($conditionsKeys, $types));
}
return $this->execute($sql, array_merge(array_values($data), $params), $types);
}
Expand All @@ -226,7 +240,7 @@ public function delete($table, $conditions = array(), $types = array()) {
$conditions
);
if (!empty($types)) {
$types = $this->_mapTypes($conditionsKeys, $types);
$types = $this->matchTypes($conditionsKeys, $types);
}
return $this->execute($sql, $params, $types);
}
Expand Down Expand Up @@ -397,52 +411,6 @@ public function charset($collation) {

}

/**
* Binds values to statement object with corresponding type
*
* @param \Cake\Model\Datasource\Database\Statement The statement objet to bind values to
* @param array $params list of values to be bound
* @param array $types list of types to be used, keys should match those in $params
* @return void
**/
protected function _bindValues($statement, $params, $types) {
if (empty($params)) {
return;
}

$annonymousParams = is_int(key($params)) ? true : false;
$offset = 1;
foreach ($params as $index => $value) {
$type = null;
if (isset($types[$index])) {
$type = $types[$index];
}
if ($annonymousParams) {
$index += $offset;
}
$statement->bindValue($index, $value, $type);
}
}

/**
* Auxiliary method to map columns to corresponding types
*
* Both $columns and $types should either be numeric based or string key based at
* the same time.
*
* @param array $columns list or associative array of columns and parameters to be bound with types
* @param array $types list or associative array of types
* @return array
**/
protected function _mapTypes($columns, $types) {
if (!is_int(key($types))) {
$positons = array_intersect_key(array_flip($columns), $types);
$types = array_intersect_key($types, $positons);
$types = array_combine($positons, $types);
}
return $types;
}

/**
* Simple conditions parser joined by AND
*
Expand Down
35 changes: 22 additions & 13 deletions lib/Cake/Model/Datasource/Database/Statement.php
Expand Up @@ -13,6 +13,8 @@
**/
class Statement implements \IteratorAggregate, \Countable {

use TypeConverter;

/**
* Statement instance implementation, such as PDOStatement
* or any other custom implementation
Expand Down Expand Up @@ -86,7 +88,7 @@ public function __get($property) {
**/
public function bindValue($column, $value, $type = null) {
if ($type !== null && !ctype_digit($type)) {
list($value, $type) = $this->_cast($value, $type);
list($value, $type) = $this->cast($value, $type);
}
$this->_statement->bindValue($column, $value, $type);
}
Expand Down Expand Up @@ -248,22 +250,29 @@ public function count() {
}

/**
* Auxiliary function to convert values to database type
* and return relevant internal statement type
* Binds a set of values to statement object with corresponding type
*
* @param mixed value
* @param string $type
* @return array list containing converted value and internal type
* @param array $params list of values to be bound
* @param array $types list of types to be used, keys should match those in $params
* @return void
**/
protected function _cast($value, $type) {
if (is_string($type)) {
$type = Type::build($type);
public function bind($params, $types) {
if (empty($params)) {
return;
}
if ($type instanceof Type) {
$value = $type->toDatabase($value, $this->_driver);
$type = $type->toStatement($value, $this->_driver);

$annonymousParams = is_int(key($params)) ? true : false;
$offset = 1;
foreach ($params as $index => $value) {
$type = null;
if (isset($types[$index])) {
$type = $types[$index];
}
if ($annonymousParams) {
$index += $offset;
}
$this->bindValue($index, $value, $type);
}
return [$value, $type];
}

}
45 changes: 45 additions & 0 deletions lib/Cake/Model/Datasource/Database/TypeConverter.php
@@ -0,0 +1,45 @@
<?php

namespace Cake\Model\Datasource\Database;

trait TypeConverter {

/**
* Converts a give value to a suitable database value based on type
* and return relevant internal statement type
*
* @param mixed value
* @param string $type
* @return array list containing converted value and internal type
**/
public function cast($value, $type) {
if (is_string($type)) {
$type = Type::build($type);
}
if ($type instanceof Type) {
$value = $type->toDatabase($value, $this->_driver);
$type = $type->toStatement($value, $this->_driver);
}
return [$value, $type];
}

/**
* Matches columns to corresponding types
*
* Both $columns and $types should either be numeric based or string key based at
* the same time.
*
* @param array $columns list or associative array of columns and parameters to be bound with types
* @param array $types list or associative array of types
* @return array
**/
public function matchTypes($columns, $types) {
if (!is_int(key($types))) {
$positons = array_intersect_key(array_flip($columns), $types);
$types = array_intersect_key($types, $positons);
$types = array_combine($positons, $types);
}
return $types;
}

}

0 comments on commit a6423e7

Please sign in to comment.