diff --git a/src/Model.php b/src/Model.php index c2eb3a4..583ffd6 100644 --- a/src/Model.php +++ b/src/Model.php @@ -140,35 +140,17 @@ abstract class Model implements JsonSerializable { */ protected static $_primaryKeys; - /** - * string name of the primary key column - * @var string - */ - protected static $_primaryKey; - /** * true if primary key is an auto-increment column * @var bool */ protected static $_isAutoIncrement = false; - /** - * array of all fully-qualified(table.column) columns - * @var string[] - */ - protected static $_columns; - - /** - * array of all column names - * @var string[] - */ - protected static $_columnNames; - /** * array of all column types * @var string[] */ - protected static $_columnTypes; + protected static $_columns; /** * Array to contain names of modified columns @@ -196,6 +178,24 @@ abstract class Model implements JsonSerializable { */ protected $_validationErrors = array(); + /** + * Cache of lower case column names. Just for performance. + * @var string[] + */ + private static $_lowerCaseColumns = array(); + + /** + * Cache of column names. Just for performance. + * @var string[] + */ + private static $_columnNames = array(); + + /** + * Cache of fully qualified column names. Just for performance. + * @var string[] + */ + private static $_qualifiedColumns = array(); + public function __toString() { return get_class($this) . implode('-', $this->getPrimaryKeyValues()); } @@ -289,7 +289,12 @@ static function getTableName() { * @return array */ static function getColumnNames() { - return static::$_columnNames; + $class = get_called_class(); + if (!isset(self::$_columnNames[$class])) { + self::$_columnNames[$class] = array_keys(static::$_columns); + } + + return self::$_columnNames[$class]; } /** @@ -297,7 +302,14 @@ static function getColumnNames() { * @return array */ static function getColumns() { - return static::$_columns; + $class = get_called_class(); + if (!isset(self::$_qualifiedColumns[$class])) { + self::$_qualifiedColumns[$class] = array_map(function($column_name) { + return static::getTableName() . '.' . $column_name; + }, array_keys(static::$_columns)); + } + + return self::$_qualifiedColumns[$class]; } /** @@ -305,7 +317,7 @@ static function getColumns() { * @return array */ static function getColumnTypes() { - return static::$_columnTypes; + return static::$_columns; } /** @@ -313,18 +325,16 @@ static function getColumnTypes() { * @return string */ static function getColumnType($column_name) { - return static::$_columnTypes[static::normalizeColumnName($column_name)]; + return static::$_columns[static::normalizeColumnName($column_name)]; } - private static $_lowerCaseColumns = array(); - /** * @return bool */ static function hasColumn($column_name) { $class = get_called_class(); if (!isset(self::$_lowerCaseColumns[$class])) { - self::$_lowerCaseColumns[$class] = array_map('strtolower', static::$_columnNames); + self::$_lowerCaseColumns[$class] = array_map('strtolower', static::getColumnNames()); } return in_array( strtolower(static::normalizeColumnName($column_name)), @@ -348,7 +358,10 @@ static function normalizeColumnName($column_name) { * @return array */ static function getPrimaryKey() { - return static::$_primaryKey; + if (count(static::$_primaryKeys) === 1) { + return static::$_primaryKeys[0]; + } + return null; } /** @@ -419,7 +432,7 @@ static function coerceTemporalValue($value, $column_type, DABLPDO $conn = null) * @return static */ static function retrieveByColumn($field, $value) { - $pk = static::$_primaryKey; + $pk = static::getPrimaryKey(); if ($pk) { if ($field === $pk) { return static::retrieveByPK($value); @@ -758,7 +771,7 @@ static function fromResult(PDOStatement $result, $class_name = null, $use_pool = * @param int $startcol */ function fromNumericResultArray($values, &$startcol) { - foreach (static::$_columnNames as &$column_name) { + foreach (static::$_columns as $column_name => &$type) { $this->{$column_name} = $values[$startcol++]; } if (static::$_primaryKeys && !$this->hasPrimaryKeyValues()) { @@ -774,7 +787,7 @@ function fromNumericResultArray($values, &$startcol) { * @param array $values */ function fromAssociativeResultArray($values) { - foreach (static::$_columnNames as &$column_name) { + foreach (static::$_columns as $column_name => &$type) { if (array_key_exists($column_name, $values)) { $this->{$column_name} = $values[$column_name]; } @@ -840,12 +853,12 @@ static function insertBatch() { return 0; } $conn = static::getConnection(); - $columns = static::$_columnNames; + $columns = static::getColumnNames(); $quoted_table = $conn->quoteIdentifier(static::getTableName(), true); $auto_increment = static::isAutoIncrement(); if ($auto_increment) { - $pk = static::$_primaryKey; + $pk = static::getPrimaryKey(); foreach ($columns as $index => &$column_name) { if ($column_name === $pk) { unset($columns[$index]); @@ -1067,7 +1080,7 @@ function fromArray($array) { foreach ($array as $column => &$v) { if ( is_string($column) === false - || !isset(static::$_columnTypes[$column]) + || !isset(static::$_columns[$column]) ) { continue; } @@ -1083,8 +1096,9 @@ function fromArray($array) { */ function toArray() { $array = array(); - foreach (static::$_columnNames as &$column) - $array[$column] = $this->{'get' . $column}(); + foreach (static::$_columns as $column_name => &$type) { + $array[$column_name] = $this->{'get' . $column_name}(); + } return $array; } @@ -1096,11 +1110,11 @@ function toArray() { */ function jsonSerialize() { $array = $this->toArray(); - foreach (static::$_columnTypes as $column => &$type) { - if (!isset($array[$column])) { + foreach (static::$_columns as $column_name => &$type) { + if (!isset($array[$column_name])) { continue; } - $value = &$array[$column]; + $value = &$array[$column_name]; if ($type === Model::COLUMN_TYPE_BOOLEAN) { if (0 === $value) { @@ -1113,14 +1127,14 @@ function jsonSerialize() { || $type === Model::COLUMN_TYPE_INTEGER_TIMESTAMP ) { if (!$value) { - $array[$column] = null; + $array[$column_name] = null; continue; } if (!is_int($value)) { $value = strtotime($value); } if (!is_int($value)) { - throw new RuntimeException('Error parsing date "' . $array[$column] . '"'); + throw new RuntimeException('Error parsing date "' . $array[$column_name] . '"'); } $value = date('c', $value); } @@ -1320,15 +1334,15 @@ function setDirty($bool) { * @return static */ function castInts() { - foreach (static::$_columnTypes as $column => &$type) { - if ($this->{$column} === null || !static::isIntegerType($type)) { + foreach (static::$_columns as $column_name => &$type) { + if ($this->{$column_name} === null || !static::isIntegerType($type)) { continue; } - if ('' === $this->{$column}) { - $this->{$column} = null; + if ('' === $this->{$column_name}) { + $this->{$column_name} = null; continue; } - $this->{$column} = (int) $this->{$column}; + $this->{$column_name} = (int) $this->{$column_name}; } return $this; } @@ -1339,16 +1353,16 @@ function castInts() { */ protected function insert() { $conn = static::getConnection(); - $pk = static::$_primaryKey; + $pk = static::getPrimaryKey(); $fields = array(); $values = array(); $placeholders = array(); - foreach (static::$_columnNames as &$column) { - $value = $this->$column; - if ($value === null && !$this->isColumnModified($column)) + foreach (static::$_columns as $column_name => &$type) { + $value = $this->$column_name; + if ($value === null && !$this->isColumnModified($column_name)) continue; - $fields[] = $conn->quoteIdentifier($column, true); + $fields[] = $conn->quoteIdentifier($column_name, true); $values[] = $value; $placeholders[] = '?'; } diff --git a/tests/ModelTest.php b/tests/ModelTest.php index bcc7f6f..db952d5 100644 --- a/tests/ModelTest.php +++ b/tests/ModelTest.php @@ -25,23 +25,7 @@ class TestModel extends Model { 'id', ); - protected static $_primaryKey = 'id'; - public static $_columns = array( - 'test_model.id', - 'test_model.true_false', - 'test_model.created', - 'test_model.updated' - ); - - public static $_columnNames = array( - 'id', - 'true_false', - 'created', - 'updated' - ); - - public static $_columnTypes = array( 'id' => Model::COLUMN_TYPE_INTEGER, 'true_false' => Model::COLUMN_TYPE_BOOLEAN, 'created' => Model::COLUMN_TYPE_TIMESTAMP, @@ -118,7 +102,7 @@ class TestModel2 extends Model { 'integerTimestamp', ); - public static $_columnTypes = array( + public static $_columns = array( 'nullInteger' => Model::COLUMN_TYPE_INTEGER, 'emptyInteger' => Model::COLUMN_TYPE_INTEGER, 'integer' => Model::COLUMN_TYPE_INTEGER, @@ -346,21 +330,33 @@ public function testGetTableName() { * @covers Model::getColumnNames */ public function testGetColumnNames() { - $this->assertEquals(TestModel::$_columnNames, TestModel::getColumnNames()); + $column_names = array( + 'id' , + 'true_false', + 'created', + 'updated' + ); + $this->assertEquals($column_names, TestModel::getColumnNames()); } /** * @covers Model::getColumns */ public function testGetColumns() { - $this->assertEquals(TestModel::$_columns, TestModel::getColumns()); + $column_names = array( + 'test_model.id' , + 'test_model.true_false', + 'test_model.created', + 'test_model.updated' + ); + $this->assertEquals($column_names, TestModel::getColumns()); } /** - * @covers Model::getColumnTypes + * @covers Model::getColumns */ public function testGetColumnTypes() { - $this->assertEquals(TestModel::$_columnTypes, TestModel::getColumnTypes()); + $this->assertEquals(TestModel::$_columns, TestModel::getColumnTypes()); } /**