From 6a48f68955a55eebd80d5a86a5cf05e005dfa6c8 Mon Sep 17 00:00:00 2001 From: Carsten Brandt Date: Thu, 26 Jun 2014 00:00:37 +0200 Subject: [PATCH] split typecast method into two one method for fetching data and one for sending to db. fixes #2287 --- extensions/sphinx/ActiveRecord.php | 2 +- extensions/sphinx/CHANGELOG.md | 1 + extensions/sphinx/ColumnSchema.php | 22 +++++++++++++++++++--- extensions/sphinx/QueryBuilder.php | 4 ++-- framework/CHANGELOG.md | 1 + framework/db/ActiveRecord.php | 4 ++-- framework/db/ColumnSchema.php | 20 +++++++++++++++++--- framework/db/QueryBuilder.php | 6 +++--- framework/db/cubrid/Schema.php | 2 +- framework/db/mssql/Schema.php | 2 +- framework/db/mysql/Schema.php | 2 +- framework/db/oci/Schema.php | 2 +- framework/db/pgsql/Schema.php | 4 ++-- framework/db/sqlite/QueryBuilder.php | 2 +- framework/db/sqlite/Schema.php | 2 +- 15 files changed, 54 insertions(+), 22 deletions(-) diff --git a/extensions/sphinx/ActiveRecord.php b/extensions/sphinx/ActiveRecord.php index 9a0593b5b7..ee37faebf0 100644 --- a/extensions/sphinx/ActiveRecord.php +++ b/extensions/sphinx/ActiveRecord.php @@ -623,7 +623,7 @@ abstract class ActiveRecord extends BaseActiveRecord $mvaValue = explode(',', $value); $row[$name] = array_map(array($columns[$name], 'typecast'), $mvaValue); } else { - $row[$name] = $columns[$name]->typecast($value); + $row[$name] = $columns[$name]->typecastToPhp($value); } } } diff --git a/extensions/sphinx/CHANGELOG.md b/extensions/sphinx/CHANGELOG.md index df9dd354b6..b9b3d6a973 100644 --- a/extensions/sphinx/CHANGELOG.md +++ b/extensions/sphinx/CHANGELOG.md @@ -8,6 +8,7 @@ Yii Framework 2 sphinx extension Change Log - Bug #4018: AR relation eager loading does not work with db models (klimov-paul) - Enh: Added support for using sub-queries when building a DB query with `IN` condition (qiangxue) - Enh #3520: Added `unlinkAll()`-method to active record to remove all records of a model relation (NmDimas, samdark, cebe) +- Chg #2287: Split `yii\sphinx\ColumnSchema::typecast()` into two methods `typecastToPhp()` and `typecastToDatabase()` to allow specifying PDO type explicitly (cebe) 2.0.0-beta April 13, 2014 diff --git a/extensions/sphinx/ColumnSchema.php b/extensions/sphinx/ColumnSchema.php index a30c19864a..ad9fa277d3 100644 --- a/extensions/sphinx/ColumnSchema.php +++ b/extensions/sphinx/ColumnSchema.php @@ -55,12 +55,12 @@ class ColumnSchema extends Object public $isMva; /** - * Converts the input value according to [[phpType]]. + * Converts the input value according to [[phpType]] after retrieval from the database. * If the value is null or an [[Expression]], it will not be converted. * @param mixed $value input value * @return mixed converted value */ - public function typecast($value) + public function typecastToPhp($value) { if ($value === null || gettype($value) === $this->phpType || $value instanceof Expression) { return $value; @@ -70,13 +70,29 @@ class ColumnSchema extends Object } switch ($this->phpType) { case 'string': - return (string) $value; + return is_resource($value) ? $value : (string) $value; case 'integer': return (integer) $value; case 'boolean': return (boolean) $value; + case 'double': + return (double) $value; } return $value; } + + /** + * Converts the input value according to [[type]] and [[dbType]] for use in a db query. + * If the value is null or an [[Expression]], it will not be converted. + * @param mixed $value input value + * @return mixed converted value. This may also be an array containing the value as the first element + * and the PDO type as the second element. + */ + public function typecastToDatabase($value) + { + // the default implementation does the same as casting for PHP but it should be possible + // to override this with annotation of explicit PDO type. + return $this->typecastToPhp($value); + } } diff --git a/extensions/sphinx/QueryBuilder.php b/extensions/sphinx/QueryBuilder.php index bdf5399330..46bd05a979 100644 --- a/extensions/sphinx/QueryBuilder.php +++ b/extensions/sphinx/QueryBuilder.php @@ -973,14 +973,14 @@ class QueryBuilder extends Object } else { $phName = self::PARAM_PREFIX . count($params); $lineParts[] = $phName; - $params[$phName] = (isset($columnSchema)) ? $columnSchema->typecast($subValue) : $subValue; + $params[$phName] = (isset($columnSchema)) ? $columnSchema->typecastToDatabase($subValue) : $subValue; } } return '(' . implode(',', $lineParts) . ')'; } else { $phName = self::PARAM_PREFIX . count($params); - $params[$phName] = (isset($columnSchema)) ? $columnSchema->typecast($value) : $value; + $params[$phName] = (isset($columnSchema)) ? $columnSchema->typecastToDatabase($value) : $value; return $phName; } diff --git a/framework/CHANGELOG.md b/framework/CHANGELOG.md index 4d1ce83b58..0b3fd525ed 100644 --- a/framework/CHANGELOG.md +++ b/framework/CHANGELOG.md @@ -124,6 +124,7 @@ Yii Framework 2 Change Log - Enh: Improved `yii\helpers\Inflector::slug` to support more cases for Russian, Hebrew and special characters (samdark) - Enh #3926: `yii\widgets\Breadcrumbs::$links`. Allows individual link to have its own `template` (creocoder, umneeq) - Enh #4028: Added ability to `yii\widgets\Menu` to encode each item's label separately (creocoder, umneeq) +- Chg #2287: Split `yii\db\ColumnSchema::typecast()` into two methods `typecastToPhp()` and `typecastToDatabase()` to allow specifying PDO type explicitly (cebe) - Chg #2898: `yii\console\controllers\AssetController` is now using hashes instead of timestamps (samdark) - Chg #2913: RBAC `DbManager` is now initialized via migration (samdark) - Chg #3036: Upgraded Twitter Bootstrap to 3.1.x (qiangxue) diff --git a/framework/db/ActiveRecord.php b/framework/db/ActiveRecord.php index 965a947dd5..0e13bb4b7d 100644 --- a/framework/db/ActiveRecord.php +++ b/framework/db/ActiveRecord.php @@ -369,7 +369,7 @@ class ActiveRecord extends BaseActiveRecord $columns = static::getTableSchema()->columns; foreach ($row as $name => $value) { if (isset($columns[$name])) { - $row[$name] = $columns[$name]->typecast($value); + $row[$name] = $columns[$name]->typecastToPhp($value); } } parent::populateRecord($record, $row); @@ -466,7 +466,7 @@ class ActiveRecord extends BaseActiveRecord if ($table->sequenceName !== null) { foreach ($table->primaryKey as $name) { if ($this->getAttribute($name) === null) { - $id = $table->columns[$name]->typecast($db->getLastInsertID($table->sequenceName)); + $id = $table->columns[$name]->typecastToPhp($db->getLastInsertID($table->sequenceName)); $this->setAttribute($name, $id); $values[$name] = $id; break; diff --git a/framework/db/ColumnSchema.php b/framework/db/ColumnSchema.php index a9efcbfbdb..9eb9af2133 100644 --- a/framework/db/ColumnSchema.php +++ b/framework/db/ColumnSchema.php @@ -33,7 +33,7 @@ class ColumnSchema extends Object public $type; /** * @var string the PHP type of this column. Possible PHP types include: - * string, boolean, integer, double. + * `string`, `boolean`, `integer`, `double`. */ public $phpType; /** @@ -79,12 +79,12 @@ class ColumnSchema extends Object public $comment; /** - * Converts the input value according to [[phpType]]. + * Converts the input value according to [[phpType]] after retrieval from the database. * If the value is null or an [[Expression]], it will not be converted. * @param mixed $value input value * @return mixed converted value */ - public function typecast($value) + public function typecastToPhp($value) { if ($value === '' && $this->type !== Schema::TYPE_TEXT && $this->type !== Schema::TYPE_STRING && $this->type !== Schema::TYPE_BINARY) { return null; @@ -105,4 +105,18 @@ class ColumnSchema extends Object return $value; } + + /** + * Converts the input value according to [[type]] and [[dbType]] for use in a db query. + * If the value is null or an [[Expression]], it will not be converted. + * @param mixed $value input value + * @return mixed converted value. This may also be an array containing the value as the first element + * and the PDO type as the second element. + */ + public function typecastToDatabase($value) + { + // the default implementation does the same as casting for PHP but it should be possible + // to override this with annotation of explicit PDO type. + return $this->typecastToPhp($value); + } } diff --git a/framework/db/QueryBuilder.php b/framework/db/QueryBuilder.php index da1c2707b9..81c5b096c3 100644 --- a/framework/db/QueryBuilder.php +++ b/framework/db/QueryBuilder.php @@ -147,7 +147,7 @@ class QueryBuilder extends \yii\base\Object } else { $phName = self::PARAM_PREFIX . count($params); $placeholders[] = $phName; - $params[$phName] = !is_array($value) && isset($columnSchemas[$name]) ? $columnSchemas[$name]->typecast($value) : $value; + $params[$phName] = !is_array($value) && isset($columnSchemas[$name]) ? $columnSchemas[$name]->typecastToDatabase($value) : $value; } } @@ -188,7 +188,7 @@ class QueryBuilder extends \yii\base\Object $vs = []; foreach ($row as $i => $value) { if (!is_array($value) && isset($columnSchemas[$columns[$i]])) { - $value = $columnSchemas[$columns[$i]]->typecast($value); + $value = $columnSchemas[$columns[$i]]->typecastToDatabase($value); } if (is_string($value)) { $value = $this->db->quoteValue($value); @@ -247,7 +247,7 @@ class QueryBuilder extends \yii\base\Object } else { $phName = self::PARAM_PREFIX . count($params); $lines[] = $this->db->quoteColumnName($name) . '=' . $phName; - $params[$phName] = !is_array($value) && isset($columnSchemas[$name]) ? $columnSchemas[$name]->typecast($value) : $value; + $params[$phName] = !is_array($value) && isset($columnSchemas[$name]) ? $columnSchemas[$name]->typecastToDatabase($value) : $value; } } diff --git a/framework/db/cubrid/Schema.php b/framework/db/cubrid/Schema.php index 235fb6f4e1..bac2af334c 100644 --- a/framework/db/cubrid/Schema.php +++ b/framework/db/cubrid/Schema.php @@ -251,7 +251,7 @@ class Schema extends \yii\db\Schema } elseif (isset($type) && $type === 'bit') { $column->defaultValue = hexdec(trim($info['Default'],'X\'')); } else { - $column->defaultValue = $column->typecast($info['Default']); + $column->defaultValue = $column->typecastToPhp($info['Default']); } return $column; diff --git a/framework/db/mssql/Schema.php b/framework/db/mssql/Schema.php index adc1308f2c..6c263a9a70 100644 --- a/framework/db/mssql/Schema.php +++ b/framework/db/mssql/Schema.php @@ -222,7 +222,7 @@ class Schema extends \yii\db\Schema $info['column_default'] = null; } if (!$column->isPrimaryKey && ($column->type !== 'timestamp' || $info['column_default'] !== 'CURRENT_TIMESTAMP')) { - $column->defaultValue = $column->typecast($info['column_default']); + $column->defaultValue = $column->typecastToPhp($info['column_default']); } return $column; diff --git a/framework/db/mysql/Schema.php b/framework/db/mysql/Schema.php index 9becb4de26..44b273d445 100644 --- a/framework/db/mysql/Schema.php +++ b/framework/db/mysql/Schema.php @@ -177,7 +177,7 @@ class Schema extends \yii\db\Schema } elseif (isset($type) && $type === 'bit') { $column->defaultValue = bindec(trim($info['Default'],'b\'')); } else { - $column->defaultValue = $column->typecast($info['Default']); + $column->defaultValue = $column->typecastToPhp($info['Default']); } } diff --git a/framework/db/oci/Schema.php b/framework/db/oci/Schema.php index fafe2b8698..57b1d1d9b2 100644 --- a/framework/db/oci/Schema.php +++ b/framework/db/oci/Schema.php @@ -174,7 +174,7 @@ EOD; if (stripos($column['DATA_DEFAULT'], 'timestamp') !== false) { $c->defaultValue = null; } else { - $c->defaultValue = $c->typecast($column['DATA_DEFAULT']); + $c->defaultValue = $c->typecastToPhp($column['DATA_DEFAULT']); } } diff --git a/framework/db/pgsql/Schema.php b/framework/db/pgsql/Schema.php index 5af73c6463..0dfad46291 100644 --- a/framework/db/pgsql/Schema.php +++ b/framework/db/pgsql/Schema.php @@ -416,9 +416,9 @@ SQL; } elseif (preg_match("/^'(.*?)'::/", $column->defaultValue, $matches)) { $column->defaultValue = $matches[1]; } elseif (preg_match("/^(.*?)::/", $column->defaultValue, $matches)) { - $column->defaultValue = $column->typecast($matches[1]); + $column->defaultValue = $column->typecastToPhp($matches[1]); } else { - $column->defaultValue = $column->typecast($column->defaultValue); + $column->defaultValue = $column->typecastToPhp($column->defaultValue); } } } diff --git a/framework/db/sqlite/QueryBuilder.php b/framework/db/sqlite/QueryBuilder.php index d97dbc9b05..f27f7f9a9a 100644 --- a/framework/db/sqlite/QueryBuilder.php +++ b/framework/db/sqlite/QueryBuilder.php @@ -80,7 +80,7 @@ class QueryBuilder extends \yii\db\QueryBuilder $vs = []; foreach ($row as $i => $value) { if (!is_array($value) && isset($columnSchemas[$columns[$i]])) { - $value = $columnSchemas[$columns[$i]]->typecast($value); + $value = $columnSchemas[$columns[$i]]->typecastToDatabase($value); } if (is_string($value)) { $value = $this->db->quoteValue($value); diff --git a/framework/db/sqlite/Schema.php b/framework/db/sqlite/Schema.php index 13e9307cb5..ba18cd5448 100644 --- a/framework/db/sqlite/Schema.php +++ b/framework/db/sqlite/Schema.php @@ -251,7 +251,7 @@ class Schema extends \yii\db\Schema $column->defaultValue = new Expression('CURRENT_TIMESTAMP'); } else { $value = trim($info['dflt_value'], "'\""); - $column->defaultValue = $column->typecast($value); + $column->defaultValue = $column->typecastToPhp($value); } }