Index: /fORM.php =================================================================== --- /fORM.php (revision 591) +++ /fORM.php (revision 603) @@ -10,5 +10,6 @@ * @link http://flourishlib.com/fORM * - * @version 1.0.0b8 + * @version 1.0.0b9 + * @changes 1.0.0b9 Added caching for performance and changed some method APIs to only allow class names instead of instances [wb, 2009-06-15] * @changes 1.0.0b8 Updated documentation to reflect removal of `$associate` parameter for callbacks passed to ::registerRecordSetMethod() [wb, 2009-06-02] * @changes 1.0.0b7 Added ::enableSchemaCaching() to replace fORMSchema::enableSmartCaching() [wb, 2009-05-04] @@ -60,4 +61,15 @@ /** + * Cache for repetitive computation + * + * @var array + */ + static private $cache = array( + 'parseMethod' => array(), + 'getActiveRecordMethod' => array(), + 'objectify' => array() + ); + + /** * Custom mappings for class <-> table * @@ -159,5 +171,5 @@ static public function callHookCallbacks($object, $hook, &$values, &$old_values, &$related_records, &$cache, &$parameter=NULL) { - $class = self::getClass($object); + $class = get_class($object); if (empty(self::$hook_callbacks[$class][$hook]) && empty(self::$hook_callbacks['*'][$hook])) { @@ -205,5 +217,5 @@ static public function callReflectCallbacks($object, &$signatures, $include_doc_comments) { - $class = self::getClass($object); + $class = get_class($object); if (!isset(self::$reflect_callbacks[$class]) && !isset(self::$reflect_callbacks['*'])) { @@ -242,5 +254,5 @@ * @internal * - * @param mixed $class The name of the class, or an instance of it + * @param string $class The name of the class * @param string $hook The hook to check * @param array $callback The specific callback to check for @@ -249,6 +261,4 @@ static public function checkHookCallback($class, $hook, $callback=NULL) { - $class = self::getClass($class); - if (empty(self::$hook_callbacks[$class][$hook]) && empty(self::$hook_callbacks['*'][$hook])) { return FALSE; @@ -360,5 +370,5 @@ * @internal * - * @param mixed $class The name of the class, or an instance of it + * @param string $class The name of the class * @param string $method The method to get the callback for * @return string|null The callback for the method or `NULL` if none exists - see method description for details @@ -366,22 +376,28 @@ static public function getActiveRecordMethod($class, $method) { - $class = self::getClass($class); + // This caches method lookups, providing a significant performance + // boost to pages with lots of method calls that get passed to + // fActiveRecord::__call() + if (isset(self::$cache['getActiveRecordMethod'][$class . '::' . $method])) { + return (!$method = self::$cache['getActiveRecordMethod'][$class . '::' . $method]) ? NULL : $method; + } + + $callback = NULL; if (isset(self::$active_record_method_callbacks[$class][$method])) { - return self::$active_record_method_callbacks[$class][$method]; - } - - if (isset(self::$active_record_method_callbacks['*'][$method])) { - return self::$active_record_method_callbacks['*'][$method]; - } - - if (preg_match('#[A-Z0-9]#', $method)) { + $callback = self::$active_record_method_callbacks[$class][$method]; + + } elseif (isset(self::$active_record_method_callbacks['*'][$method])) { + $callback = self::$active_record_method_callbacks['*'][$method]; + + } elseif (preg_match('#[A-Z0-9]#', $method)) { list($action, $subject) = self::parseMethod($method); if (isset(self::$active_record_method_callbacks[$class][$action . '*'])) { - return self::$active_record_method_callbacks[$class][$action . '*']; + $callback = self::$active_record_method_callbacks[$class][$action . '*']; } } - return NULL; + self::$cache['getActiveRecordMethod'][$class . '::' . $method] = ($callback === NULL) ? FALSE : $callback; + return $callback; } @@ -410,5 +426,5 @@ * @internal * - * @param mixed $class The class name or instance of the class the column is part of + * @param string $class The class name the column is part of * @param string $column The database column * @return string The column name for the column specified @@ -416,6 +432,4 @@ static public function getColumnName($class, $column) { - $class = self::getClass($class); - if (!isset(self::$column_names[$class])) { self::$column_names[$class] = array(); @@ -438,11 +452,9 @@ * @internal * - * @param mixed $class The class name or instance of the class to get the record name of + * @param string $class The class name to get the record name of * @return string The record name for the class specified */ static public function getRecordName($class) { - $class = self::getClass($class); - if (!isset(self::$record_names[$class])) { self::$record_names[$class] = fGrammar::humanize($class); @@ -496,5 +508,9 @@ static public function objectify($class, $column, $value) { - $class = self::getClass($class); + // This short-circuits computation for already checked columns, providing + // a nice little performance boost to pages with lots of records + if (isset(self::$cache['objectify'][$class . '::' . $column])) { + return $value; + } if (!empty(self::$objectify_callbacks[$class][$column])) { @@ -520,4 +536,7 @@ // Validation exception results in the raw value being saved } + + } else { + self::$cache['objectify'][$class . '::' . $column] = TRUE; } @@ -576,4 +595,8 @@ static public function parseMethod($method) { + if (isset(self::$cache['parseMethod'][$method])) { + return self::$cache['parseMethod'][$method]; + } + if (!preg_match('#^([a-z]+)(.*)$#D', $method, $matches)) { throw new fProgrammerException( @@ -582,5 +605,6 @@ ); } - return array($matches[1], fGrammar::underscorize($matches[2])); + self::$cache['parseMethod'][$method] = array($matches[1], fGrammar::underscorize($matches[2])); + return self::$cache['parseMethod'][$method]; } @@ -617,4 +641,6 @@ self::$active_record_method_callbacks[$class][$method] = $callback; + + self::$cache['getActiveRecordMethod'] = array(); } @@ -733,4 +759,6 @@ self::$objectify_callbacks[$class][$column] = $callback; + + self::$cache['objectify'] = array(); } @@ -849,5 +877,5 @@ * @internal * - * @param mixed $class The class name or instance of the class the column is part of + * @param string $class The class the column is part of * @param string $column The database column * @param mixed $value The value to copy/clone @@ -856,6 +884,4 @@ static public function replicate($class, $column, $value) { - $class = self::getClass($class); - if (!empty(self::$replicate_callbacks[$class][$column])) { return call_user_func(self::$replicate_callbacks[$class][$column], $class, $column, $value); @@ -879,6 +905,11 @@ static public function reset() { + self::$active_record_method_callbacks = array(); + self::$cache = array( + 'parseMethod' => array(), + 'getActiveRecordMethod' => array(), + 'objectify' => array() + ); self::$class_table_map = array(); - self::$active_record_method_callbacks = array(); self::$column_names = array(); self::$hook_callbacks = array(); @@ -928,6 +959,4 @@ static public function tablize($class) { - $class = self::getClass($class); - if (!isset(self::$class_table_map[$class])) { self::$class_table_map[$class] = fGrammar::underscorize(fGrammar::pluralize($class)); Index: /fORMFile.php =================================================================== --- /fORMFile.php (revision 600) +++ /fORMFile.php (revision 603) @@ -10,5 +10,6 @@ * @link http://flourishlib.com/fORMFile * - * @version 1.0.0b12 + * @version 1.0.0b13 + * @changes 1.0.0b13 Updated code for new fORM API [wb, 2009-06-15] * @changes 1.0.0b12 Changed replacement values in preg_replace() calls to be properly escaped [wb, 2009-06-11] * @changes 1.0.0b11 Updated code to use new fValidationException::formatField() method [wb, 2009-06-04] @@ -744,5 +745,5 @@ list ($action, $column) = fORM::parseMethod($method_name); - $class = fORM::getClass($object); + $class = get_class($object); self::processImage($class, $column, $values[$column]); Index: /fDatabase.php =================================================================== --- /fDatabase.php (revision 600) +++ /fDatabase.php (revision 603) @@ -47,5 +47,6 @@ * @link http://flourishlib.com/fDatabase * - * @version 1.0.0b11 + * @version 1.0.0b12 + * @changes 1.0.0b12 Updates to ::unescape() to improve performance [wb, 2009-06-15] * @changes 1.0.0b11 Changed replacement values in preg_replace() calls to be properly escaped [wb, 2009-06-11] * @changes 1.0.0b10 Changed date/time/timestamp escaping from `strtotime()` to fDate/fTime/fTimestamp for better localization support [wb, 2009-06-01] @@ -2280,24 +2281,7 @@ switch ($data_type) { - case 'blob': - case '%l': - $callback = $this->unescapeBlob; - break; - case 'boolean': - case '%b': - $callback = $this->unescapeBoolean; - break; - case 'date': - case '%d': - $callback = $this->unescapeDate; - break; - case 'float': - case '%f': - $callback = $this->unescapeFloat; - break; - case 'integer': - case '%i': - $callback = $this->unescapeInteger; - break; + // Testing showed that strings tend to be most common, + // and moving this to the top of the switch statement + // improved performance on read-heavy pages case 'string': case 'varchar': @@ -2305,13 +2289,37 @@ case 'text': case '%s': - $callback = $this->unescapeString; + return $value; + + case 'boolean': + case '%b': + $callback = $this->unescapeBoolean; break; + + case 'date': + case '%d': + $callback = $this->unescapeDate; + break; + + case 'float': + case '%f': + return $value; + + case 'integer': + case '%i': + return $value; + case 'time': case '%t': $callback = $this->unescapeTime; break; + case 'timestamp': case '%p': $callback = $this->unescapeTimestamp; + break; + + case 'blob': + case '%l': + $callback = $this->unescapeBlob; break; } @@ -2382,40 +2390,4 @@ } return date('Y-m-d', strtotime($value)); - } - - - /** - * Unescapes a float coming out of the database (included for completeness) - * - * @param string $value The value to unescape - * @return float The float - */ - private function unescapeFloat($value) - { - return $value; - } - - - /** - * Unescapes an integer coming out of the database (included for completeness) - * - * @param string $value The value to unescape - * @return integer The integer - */ - private function unescapeInteger($value) - { - return $value; - } - - - /** - * Unescapes a string coming out of the database (included for completeness) - * - * @param string $value The value to unescape - * @return string The string - */ - private function unescapeString($value) - { - return $value; } Index: /fActiveRecord.php =================================================================== --- /fActiveRecord.php (revision 600) +++ /fActiveRecord.php (revision 603) @@ -16,5 +16,6 @@ * @link http://flourishlib.com/fActiveRecord * - * @version 1.0.0b20 + * @version 1.0.0b21 + * @changes 1.0.0b21 Performance tweaks and updates for fORM and fORMRelated API changes [wb, 2009-06-15] * @changes 1.0.0b20 Changed replacement values in preg_replace() calls to be properly escaped [wb, 2009-06-11] * @changes 1.0.0b19 Added `list{RelatedRecords}()` methods, updated code for new fORMRelated API [wb, 2009-06-02] @@ -265,5 +266,7 @@ public function __call($method_name, $parameters) { - if ($callback = fORM::getActiveRecordMethod($this, $method_name)) { + $class = get_class($this); + + if ($callback = fORM::getActiveRecordMethod($class, $method_name)) { return call_user_func_array( $callback, @@ -326,7 +329,7 @@ if (isset($parameters[1])) { - return fORMRelated::associateRecords($this, $this->related_records, $subject, $parameters[0], $parameters[1]); - } - return fORMRelated::associateRecords($this, $this->related_records, $subject, $parameters[0]); + return fORMRelated::associateRecords($class, $this->related_records, $subject, $parameters[0], $parameters[1]); + } + return fORMRelated::associateRecords($class, $this->related_records, $subject, $parameters[0]); case 'build': @@ -335,7 +338,7 @@ if (isset($parameters[0])) { - return fORMRelated::buildRecords($this, $this->values, $this->related_records, $subject, $parameters[0]); - } - return fORMRelated::buildRecords($this, $this->values, $this->related_records, $subject); + return fORMRelated::buildRecords($class, $this->values, $this->related_records, $subject, $parameters[0]); + } + return fORMRelated::buildRecords($class, $this->values, $this->related_records, $subject); case 'count': @@ -344,7 +347,7 @@ if (isset($parameters[0])) { - return fORMRelated::countRecords($this, $this->values, $this->related_records, $subject, $parameters[0]); - } - return fORMRelated::countRecords($this, $this->values, $this->related_records, $subject); + return fORMRelated::countRecords($class, $this->values, $this->related_records, $subject, $parameters[0]); + } + return fORMRelated::countRecords($class, $this->values, $this->related_records, $subject); case 'create': @@ -352,7 +355,7 @@ if (isset($parameters[0])) { - return fORMRelated::createRecord($this, $this->values, $subject, $parameters[0]); - } - return fORMRelated::createRecord($this, $this->values, $subject); + return fORMRelated::createRecord($class, $this->values, $subject, $parameters[0]); + } + return fORMRelated::createRecord($class, $this->values, $subject); case 'inject': @@ -361,7 +364,7 @@ if (isset($parameters[1])) { - return fORMRelated::setRecordSet($this, $this->related_records, $subject, $parameters[0], $parameters[1]); - } - return fORMRelated::setRecordSet($this, $this->related_records, $subject, $parameters[0]); + return fORMRelated::setRecordSet($class, $this->related_records, $subject, $parameters[0], $parameters[1]); + } + return fORMRelated::setRecordSet($class, $this->related_records, $subject, $parameters[0]); case 'link': @@ -370,7 +373,7 @@ if (isset($parameters[0])) { - return fORMRelated::linkRecords($this, $this->related_records, $subject, $parameters[0]); - } - return fORMRelated::linkRecords($this, $this->related_records, $subject); + return fORMRelated::linkRecords($class, $this->related_records, $subject, $parameters[0]); + } + return fORMRelated::linkRecords($class, $this->related_records, $subject); case 'list': @@ -379,7 +382,7 @@ if (isset($parameters[0])) { - return fORMRelated::getPrimaryKeys($this, $this->values, $this->related_records, $subject, $parameters[0]); - } - return fORMRelated::getPrimaryKeys($this, $this->values, $this->related_records, $subject); + return fORMRelated::getPrimaryKeys($class, $this->values, $this->related_records, $subject, $parameters[0]); + } + return fORMRelated::getPrimaryKeys($class, $this->values, $this->related_records, $subject); case 'populate': @@ -388,7 +391,7 @@ if (isset($parameters[0])) { - return fORMRelated::populateRecords($this, $this->related_records, $subject, $parameters[0]); - } - return fORMRelated::populateRecords($this, $this->related_records, $subject); + return fORMRelated::populateRecords($class, $this->related_records, $subject, $parameters[0]); + } + return fORMRelated::populateRecords($class, $this->related_records, $subject); case 'tally': @@ -397,7 +400,7 @@ if (isset($parameters[1])) { - return fORMRelated::setCount($this, $this->related_records, $subject, $parameters[0], $parameters[1]); - } - return fORMRelated::setCount($this, $this->related_records, $subject, $parameters[0]); + return fORMRelated::setCount($class, $this->related_records, $subject, $parameters[0], $parameters[1]); + } + return fORMRelated::setCount($class, $this->related_records, $subject, $parameters[0]); // Error handler @@ -426,4 +429,6 @@ public function __clone() { + $class = get_class($this); + // Copy values and cache, making sure objects are cloned to prevent reference issues $temp_values = $this->values; @@ -431,5 +436,5 @@ $this->values =& $new_values; foreach ($temp_values as $column => $value) { - $this->values[$column] = fORM::replicate($this, $column, $value); + $this->values[$column] = fORM::replicate($class, $column, $value); } @@ -458,5 +463,5 @@ // If we have a single auto incrementing primary key, remove the value - $table = fORM::tablize($this); + $table = fORM::tablize($class); $pk_columns = fORMSchema::retrieve()->getKeys($table, 'primary'); @@ -500,5 +505,5 @@ } - if (fORM::getActiveRecordMethod($this, '__construct')) { + if (fORM::getActiveRecordMethod($class, '__construct')) { return $this->__call('__construct', array($key)); } @@ -516,10 +521,11 @@ } elseif ($key !== NULL) { - $pk_columns = fORMSchema::retrieve()->getKeys(fORM::tablize($this), 'primary'); + $table = fORM::tablize($class); + $pk_columns = fORMSchema::retrieve()->getKeys($table, 'primary'); // If the primary key does not look properly formatted, check to see if it is a UNIQUE key $is_unique_key = FALSE; if (is_array($key) && (sizeof($pk_columns) == 1 || array_keys($key) != $pk_columns)) { - $unique_keys = fORMSchema::retrieve()->getKeys(fORM::tablize($this), 'unique'); + $unique_keys = fORMSchema::retrieve()->getKeys($table, 'unique'); $key_keys = array_keys($key); foreach ($unique_keys as $unique_key) { @@ -537,5 +543,5 @@ throw new fProgrammerException( 'An invalidly formatted primary or unique key was passed to this %s object', - fORM::getRecordName($this) + fORM::getRecordName($class) ); } @@ -569,5 +575,5 @@ // Create an empty array for new objects } else { - $column_info = fORMSchema::retrieve()->getColumnInfo(fORM::tablize($this)); + $column_info = fORMSchema::retrieve()->getColumnInfo(fORM::tablize($class)); foreach ($column_info as $column => $info) { $this->values[$column] = NULL; @@ -577,5 +583,5 @@ $this->old_values, $column, - fORM::objectify($this, $column, $info['default']) + fORM::objectify($class, $column, $info['default']) ); } @@ -584,5 +590,5 @@ fORM::callHookCallbacks( - $this, + $class, 'post::__construct()', $this->values, @@ -646,5 +652,5 @@ protected function constructInsertSQL($sql_values) { - $sql = 'INSERT INTO ' . fORM::tablize($this) . ' ('; + $sql = 'INSERT INTO ' . fORM::tablize(get_class($this)) . ' ('; $columns = ''; @@ -671,5 +677,5 @@ protected function constructUpdateSQL($sql_values) { - $table = fORM::tablize($this); + $table = fORM::tablize(get_class($this)); $sql = 'UPDATE ' . $table . ' SET '; @@ -696,5 +702,7 @@ public function delete() { - if (fORM::getActiveRecordMethod($this, 'delete')) { + $class = get_class($this); + + if (fORM::getActiveRecordMethod($class, 'delete')) { return $this->__call('delete', array()); } @@ -703,5 +711,5 @@ throw new fProgrammerException( 'This %s object does not yet exist in the database, and thus can not be deleted', - fORM::getRecordName($this) + fORM::getRecordName($class) ); } @@ -715,5 +723,5 @@ ); - $table = fORM::tablize($this); + $table = fORM::tablize($class); $inside_db_transaction = fORMDatabase::retrieve()->isInsideTransaction(); @@ -780,5 +788,5 @@ sprintf( "

%1\$s

\n", - self::compose('This %s can not be deleted because:', fORM::getRecordName($this)), + self::compose('This %s can not be deleted because:', fORM::getRecordName($class)), join("\n
  • ", $restriction_messages) ) @@ -825,7 +833,6 @@ // If we just deleted an object that has an auto-incrementing primary key, // lets delete that value from the object since it is no longer valid - $column_info = fORMSchema::retrieve()->getColumnInfo($table); $pk_columns = fORMSchema::retrieve()->getKeys($table, 'primary'); - if (sizeof($pk_columns) == 1 && $column_info[$pk_columns[0]]['auto_increment']) { + if (sizeof($pk_columns) == 1 && fORMSchema::retrieve()->getColumnInfo($table, $pk_columns[0], 'auto_increment')) { $this->values[$pk_columns[0]] = NULL; unset($this->old_values[$pk_columns[0]]); @@ -849,5 +856,5 @@ if ($e instanceof fValidationException) { $message = $e->getMessage(); - $search = self::compose('This %s can not be deleted because:', fORM::getRecordName($this)); + $search = self::compose('This %s can not be deleted because:', fORM::getRecordName($class)); if (stripos($message, $search) === FALSE) { $regex = self::compose('This %s can not be deleted because:', '__'); @@ -855,5 +862,5 @@ $regex = '#(' . preg_quote($regex_parts[0], '#') . ').*?(' . preg_quote($regex_parts[0], '#') . ')#'; - $message = preg_replace($regex, '\1' . strtr(fORM::getRecordName($this), array('\\' => '\\\\', '$' => '\\$')) . '\2', $message); + $message = preg_replace($regex, '\1' . strtr(fORM::getRecordName($class), array('\\' => '\\\\', '$' => '\\$')) . '\2', $message); $find = self::compose("One or more %s references it", '__'); @@ -909,5 +916,6 @@ } - $column_type = fORMSchema::retrieve()->getColumnInfo(fORM::tablize($this), $column, 'type'); + $table = fORM::tablize(get_class($this)); + $column_type = fORMSchema::retrieve()->getColumnInfo($table, $column, 'type'); // Ensure the programmer is calling the function properly @@ -950,5 +958,5 @@ // Make sure we don't mangle a non-float value if ($column_type == 'float' && is_numeric($value)) { - $column_decimal_places = fORMSchema::retrieve()->getColumnInfo(fORM::tablize($this), $column, 'decimal_places'); + $column_decimal_places = fORMSchema::retrieve()->getColumnInfo($table, $column, 'decimal_places'); // If the user passed in a formatting value, use it @@ -981,9 +989,11 @@ public function exists() { - if (fORM::getActiveRecordMethod($this, 'exists')) { + $class = get_class($this); + + if (fORM::getActiveRecordMethod($class, 'exists')) { return $this->__call('exists', array()); } - $pk_columns = fORMSchema::retrieve()->getKeys(fORM::tablize($this), 'primary'); + $pk_columns = fORMSchema::retrieve()->getKeys(fORM::tablize($class), 'primary'); $exists = FALSE; @@ -1009,4 +1019,5 @@ protected function fetchResultFromUniqueKey($values) { + $class = get_class($this); try { if ($values === array_combine(array_keys($values), array_fill(0, sizeof($values), NULL))) { @@ -1014,5 +1025,5 @@ } - $table = fORM::tablize($this); + $table = fORM::tablize($class); $sql = 'SELECT * FROM ' . $table . ' WHERE '; $conditions = array(); @@ -1028,5 +1039,5 @@ throw new fNotFoundException( 'The %s requested could not be found', - fORM::getRecordName($this) + fORM::getRecordName($class) ); } @@ -1043,4 +1054,51 @@ */ protected function get($column) + { + if (!isset($this->values[$column]) && !array_key_exists($column, $this->values)) { + throw new fProgrammerException( + 'The column specified, %s, does not exist', + $column + ); + } + return $this->values[$column]; + } + + + /** + * Takes a row of data or a primary key and makes a hash from the primary key + * + * @param mixed $data An array of the records data, an array of primary key data or a scalar primary key value + * @return string A hash of the record's primary key value + */ + protected function hash($data) + { + $class = get_class($this); + $pk_columns = fORMSchema::retrieve()->getKeys(fORM::tablize(get_class($this)), 'primary'); + + // Build an array of just the primary key data + $pk_data = array(); + foreach ($pk_columns as $pk_column) { + $pk_data[$pk_column] = fORM::scalarize( + $class, + $pk_column, + is_array($data) ? $data[$pk_column] : $data + ); + if (is_numeric($pk_data[$pk_column]) || is_object($pk_data[$pk_column])) { + $pk_data[$pk_column] = (string) $pk_data[$pk_column]; + } + } + + return md5(serialize($pk_data)); + } + + + /** + * Retrieves information about a column + * + * @param string $column The name of the column to inspect + * @param string $element The metadata element to retrieve + * @return mixed The metadata array for the column, or the metadata element specified + */ + protected function inspect($column, $element=NULL) { if (!array_key_exists($column, $this->values)) { @@ -1050,52 +1108,6 @@ ); } - return $this->values[$column]; - } - - - /** - * Takes a row of data or a primary key and makes a hash from the primary key - * - * @param mixed $data An array of the records data, an array of primary key data or a scalar primary key value - * @return string A hash of the record's primary key value - */ - protected function hash($data) - { - $pk_columns = fORMSchema::retrieve()->getKeys(fORM::tablize($this), 'primary'); - - // Build an array of just the primary key data - $pk_data = array(); - foreach ($pk_columns as $pk_column) { - $pk_data[$pk_column] = fORM::scalarize( - $this, - $pk_column, - is_array($data) ? $data[$pk_column] : $data - ); - if (is_numeric($pk_data[$pk_column]) || is_object($pk_data[$pk_column])) { - $pk_data[$pk_column] = (string) $pk_data[$pk_column]; - } - } - - return md5(serialize($pk_data)); - } - - - /** - * Retrieves information about a column - * - * @param string $column The name of the column to inspect - * @param string $element The metadata element to retrieve - * @return mixed The metadata array for the column, or the metadata element specified - */ - protected function inspect($column, $element=NULL) - { - if (!array_key_exists($column, $this->values)) { - throw new fProgrammerException( - 'The column specified, %s, does not exist', - $column - ); - } - - $info = fORMSchema::retrieve()->getColumnInfo(fORM::tablize($this), $column); + + $info = fORMSchema::retrieve()->getColumnInfo(fORM::tablize(get_class($this)), $column); if (!in_array($info['type'], array('varchar', 'char', 'text'))) { @@ -1138,10 +1150,12 @@ public function load() { - if (fORM::getActiveRecordMethod($this, 'load')) { + $class = get_class($this); + + if (fORM::getActiveRecordMethod($class, 'load')) { return $this->__call('load', array()); } try { - $table = fORM::tablize($this); + $table = fORM::tablize($class); $sql = 'SELECT * FROM ' . $table . ' WHERE ' . fORMDatabase::createPrimaryKeyWhereClause($table, $table, $this->values, $this->old_values); @@ -1152,5 +1166,5 @@ throw new fNotFoundException( 'The %s requested could not be found', - fORM::getRecordName($this) + fORM::getRecordName($class) ); } @@ -1170,19 +1184,19 @@ protected function loadFromResult($result) { + $class = get_class($this); $row = $result->current(); - $column_info = fORMSchema::retrieve()->getColumnInfo(fORM::tablize($this)); + $column_info = fORMSchema::retrieve()->getColumnInfo(fORM::tablize($class)); + + $db = fORMDatabase::retrieve(); foreach ($row as $column => $value) { - if ($value === NULL) { - $this->values[$column] = $value; - } else { - $this->values[$column] = fORMDatabase::retrieve()->unescape($column_info[$column]['type'], $value); - } - - $this->values[$column] = fORM::objectify($this, $column, $this->values[$column]); + if ($value !== NULL) { + $value = $db->unescape($column_info[$column]['type'], $value); + } + + $this->values[$column] = fORM::objectify($class, $column, $value); } // Save this object to the identity map - $class = get_class($this); $hash = $this->hash($row); @@ -1247,5 +1261,7 @@ public function populate() { - if (fORM::getActiveRecordMethod($this, 'populate')) { + $class = get_class($this); + + if (fORM::getActiveRecordMethod($class, 'populate')) { return $this->__call('populate', array()); } @@ -1260,5 +1276,5 @@ ); - $table = fORM::tablize($this); + $table = fORM::tablize($class); $column_info = fORMSchema::retrieve()->getColumnInfo($table); @@ -1308,9 +1324,9 @@ } - $column_info = fORMSchema::retrieve()->getColumnInfo(fORM::tablize($this), $column); + $column_info = fORMSchema::retrieve()->getColumnInfo(fORM::tablize(get_class($this)), $column); $column_type = $column_info['type']; // Ensure the programmer is calling the function properly - if (in_array($column_type, array('blob'))) { + if ($column_type == 'blob') { throw new fProgrammerException( 'The column specified, %s, can not be prepared because it is a blob column', @@ -1397,5 +1413,6 @@ $signatures = array(); - $columns_info = fORMSchema::retrieve()->getColumnInfo(fORM::tablize($this)); + $class = get_class($this); + $columns_info = fORMSchema::retrieve()->getColumnInfo(fORM::tablize($class)); foreach ($columns_info as $column => $column_info) { $camelized_column = fGrammar::camelize($column, TRUE); @@ -1552,9 +1569,9 @@ } - fORMRelated::reflect($this, $signatures, $include_doc_comments); + fORMRelated::reflect($class, $signatures, $include_doc_comments); fORM::callReflectCallbacks($this, $signatures, $include_doc_comments); - $reflection = new ReflectionClass(get_class($this)); + $reflection = new ReflectionClass($class); $methods = $reflection->getMethods(); @@ -1663,5 +1680,6 @@ $class = get_class($this); $hash = self::hash($this->values); - + $table = fORM::tablize($class); + // If the object has not been replicated yet, do it now if (!isset(fActiveRecord::$replicate_map[$class])) { @@ -1672,5 +1690,4 @@ // We need the primary key to get a hash, otherwise certain recursive relationships end up losing members - $table = fORM::tablize($class); $pk_columns = fORMSchema::retrieve()->getKeys($table, 'primary'); if (sizeof($pk_columns) == 1 && fORMSchema::retrieve()->getColumnInfo($table, $pk_columns[0], 'auto_increment')) { @@ -1682,6 +1699,4 @@ $parameters = func_get_args(); - - $table = fORM::tablize($this); $recursive = FALSE; @@ -1741,10 +1756,10 @@ 'The related class specified, %1$s, does not appear to be in a many-to-many or one-to-many relationship with %$2s', $parameter, - fORM::getClass($this) + get_class($this) ); } // Get the related records - $record_set = fORMRelated::buildRecords($this, $this->values, $this->related_records, $related_class, $route); + $record_set = fORMRelated::buildRecords($class, $this->values, $this->related_records, $related_class, $route); // One-to-many records need to be replicated, possibly recursively @@ -1763,5 +1778,5 @@ // Cause the related records to be associated with the new clone - fORMRelated::associateRecords($this, $clone->related_records, $related_class, $record_set, $route); + fORMRelated::associateRecords($class, $clone->related_records, $related_class, $record_set, $route); } @@ -1807,9 +1822,10 @@ } - $value = fORM::objectify($this, $column, $value); + $class = get_class($this); + $value = fORM::objectify($class, $column, $value); // Float and int columns that look like numbers with commas will have the commas removed if (is_string($value)) { - $table = fORM::tablize($this); + $table = fORM::tablize($class); $type = fORMSchema::retrieve()->getColumnInfo($table, $column, 'type'); if (in_array($type, array('integer', 'float')) && preg_match('#^(\d+,)+\d+(\.\d+)?$#', $value)) { @@ -1834,5 +1850,7 @@ public function store() { - if (fORM::getActiveRecordMethod($this, 'store')) { + $class = get_class($this); + + if (fORM::getActiveRecordMethod($class, 'store')) { return $this->__call('store', array()); } @@ -1848,5 +1866,5 @@ try { - $table = fORM::tablize($this); + $table = fORM::tablize($class); $column_info = fORMSchema::retrieve()->getColumnInfo($table); @@ -1892,5 +1910,5 @@ $sql_values = array(); foreach ($column_info as $column => $info) { - $value = fORM::scalarize($this, $column, $this->values[$column]); + $value = fORM::scalarize($class, $column, $this->values[$column]); $sql_values[$column] = fORMDatabase::escapeBySchema($table, $column, $value); } @@ -1916,5 +1934,5 @@ // Storing *-to-many relationships - fORMRelated::store($this, $this->values, $this->related_records); + fORMRelated::store($class, $this->values, $this->related_records); @@ -1992,5 +2010,7 @@ public function validate($return_messages=FALSE) { - if (fORM::getActiveRecordMethod($this, 'validate')) { + $class = get_class($this); + + if (fORM::getActiveRecordMethod($class, 'validate')) { return $this->__call('validate', array($return_messages)); } @@ -2012,5 +2032,5 @@ // Validate related records - $related_validation_messages = fORMValidation::validateRelated($this, $this->related_records); + $related_validation_messages = fORMValidation::validateRelated($class, $this->related_records); $validation_messages = array_merge($validation_messages, $local_validation_messages, $related_validation_messages); @@ -2026,5 +2046,5 @@ ); - fORMValidation::reorderMessages($this, $validation_messages); + fORMValidation::reorderMessages($class, $validation_messages); if ($return_messages) { Index: /fORMSchema.php =================================================================== --- /fORMSchema.php (revision 562) +++ /fORMSchema.php (revision 603) @@ -10,5 +10,6 @@ * @link http://flourishlib.com/fORMSchema * - * @version 1.0.0b2 + * @version 1.0.0b3 + * @changes 1.0.0b3 Added routes caching for performance [wb, 2009-06-15] * @changes 1.0.0b2 Backwards Compatiblity Break - removed ::enableSmartCaching(), fORM::enableSchemaCaching() now provides equivalent functionality [wb, 2009-05-04] * @changes 1.0.0b The initial implementation [wb, 2007-06-14] @@ -27,4 +28,14 @@ /** + * A cache for computed information + * + * @var array + */ + static private $cache = array( + 'getRoutes' => array() + ); + + + /** * The schema object to use for all ORM functionality * @@ -204,4 +215,9 @@ static public function getRoutes($table, $related_table, $relationship_type=NULL) { + $key = $table . '::' . $related_table . '::' . $relationship_type; + if (isset(self::$cache['getRoutes'][$key])) { + return self::$cache['getRoutes'][$key]; + } + $valid_relationship_types = array( NULL, @@ -249,4 +265,6 @@ } + self::$cache['getRoutes'][$key] = $routes; + return $routes; } Index: /fGrammar.php =================================================================== --- /fGrammar.php (revision 600) +++ /fGrammar.php (revision 603) @@ -10,5 +10,6 @@ * @link http://flourishlib.com/fGrammar * - * @version 1.0.0b2 + * @version 1.0.0b4 + * @changes 1.0.0b4 Added caching for various methods - provided significant performance boost to ORM [wb, 2009-06-15] * @changes 1.0.0b3 Changed replacement values in preg_replace() calls to be properly escaped [wb, 2009-06-11] * @changes 1.0.0b2 Fixed a bug where some words would lose capitalization with ::pluralize() and ::singularize() [wb, 2009-01-25] @@ -31,4 +32,17 @@ const underscorize = 'fGrammar::underscorize'; + + /** + * Cache for plural <-> singular and underscore <-> camelcase + * + * @var array + */ + static private $cache = array( + 'camelize' => array(0 => array(), 1 => array()), + 'humanize' => array(), + 'pluralize' => array(), + 'singularize' => array(), + 'underscorize' => array() + ); /** @@ -124,4 +138,6 @@ { self::$humanize_rules[$non_humanized_string] = $humanized_string; + + self::$cache['humanize'] = array(); } @@ -139,4 +155,7 @@ self::$underscorize_rules[$camel_case] = $underscore_notation; self::$camelize_rules[$underscore_notation] = $camel_case; + + self::$cache['camelize'] = array(0 => array(), 1 => array()); + self::$cache['underscorize'] = array(); } @@ -165,4 +184,7 @@ self::$plural_to_singular_rules ); + + self::$cache['pluralize'] = array(); + self::$cache['singularize'] = array(); } @@ -177,32 +199,39 @@ static public function camelize($string, $upper) { + $upper = (int) $upper; + if (isset(self::$cache['camelize'][$upper][$string])) { + return self::$cache['camelize'][$upper][$string]; + } + + $original = $string; + // Handle custom rules if (isset(self::$camelize_rules[$string])) { - $camel = self::$camelize_rules[$string]; + $string = self::$camelize_rules[$string]; if ($upper) { - return strtoupper($camel[0]) . substr($camel, 1); + $string = strtoupper($camel[0]) . substr($camel, 1); } - return $camel; - } // Make a humanized string like underscore notation - if (strpos($string, ' ') !== FALSE) { + } elseif (strpos($string, ' ') !== FALSE) { $string = strtolower(preg_replace('#\s+#', '_', $string)); - } // Check to make sure this is not already camel case - if (strpos($string, '_') === FALSE) { + } elseif (strpos($string, '_') === FALSE) { if ($upper) { $string = strtoupper($string[0]) . substr($string, 1); } - return $string; - } - + // Handle underscore notation - $string = strtolower($string); - if ($upper) { - $string = strtoupper($string[0]) . substr($string, 1); - } - return preg_replace('/(_([a-z0-9]))/e', 'strtoupper("\2")', $string); + } else { + $string = strtolower($string); + if ($upper) { + $string = strtoupper($string[0]) . substr($string, 1); + } + $string = preg_replace('/(_([a-z0-9]))/e', 'strtoupper("\2")', $string); + } + + self::$cache['camelize'][$upper][$original] = $string; + return $string; } @@ -216,23 +245,31 @@ static public function humanize($string) { + if (isset(self::$cache['humanize'][$string])) { + return self::$cache['humanize'][$string]; + } + + $original = $string; + if (isset(self::$humanize_rules[$string])) { - return self::$humanize_rules[$string]; - } - - // If there is a space, it is already humanized - if (strpos($string, ' ') !== FALSE) { - return $string; - } - - // If we don't have an underscore we probably have camelCase - if (strpos($string, '_') === FALSE) { - $string = self::underscorize($string); - } - - return preg_replace( - '/(\b(api|css|gif|html|id|jpg|js|mp3|pdf|php|png|sql|swf|url|xhtml|xml)\b|\b\w)/e', - 'strtoupper("\1")', - str_replace('_', ' ', $string) - ); + $string = self::$humanize_rules[$string]; + + // If there is no space, it isn't already humanized + } elseif (strpos($string, ' ') === FALSE) { + + // If we don't have an underscore we probably have camelCase + if (strpos($string, '_') === FALSE) { + $string = self::underscorize($string); + } + + $string = preg_replace( + '/(\b(api|css|gif|html|id|jpg|js|mp3|pdf|php|png|sql|swf|url|xhtml|xml)\b|\b\w)/e', + 'strtoupper("\1")', + str_replace('_', ' ', $string) + ); + } + + self::$cache['humanize'][$original] = $string; + + return $string; } @@ -347,11 +384,26 @@ static public function pluralize($singular_noun) { + if (isset(self::$cache['pluralize'][$singular_noun])) { + return self::$cache['pluralize'][$singular_noun]; + } + + $original = $singular_noun; + $plural_noun = NULL; + list ($beginning, $singular_noun) = self::splitLastWord($singular_noun); foreach (self::$singular_to_plural_rules as $from => $to) { if (preg_match('#' . $from . '#iD', $singular_noun)) { - return $beginning . preg_replace('#' . $from . '#iD', $to, $singular_noun); + $plural_noun = $beginning . preg_replace('#' . $from . '#iD', $to, $singular_noun); + break; } } - throw new fProgrammerException('The noun specified could not be pluralized'); + + if (!$plural_noun) { + throw new fProgrammerException('The noun specified could not be pluralized'); + } + + self::$cache['pluralize'][$original] = $plural_noun; + + return $plural_noun; } @@ -384,5 +436,12 @@ static public function reset() { - self::$camelize_rules = array(); + self::$cache = array( + 'camelize' => array(0 => array(), 1 => array()), + 'humanize' => array(), + 'pluralize' => array(), + 'singularize' => array(), + 'underscorize' => array() + ); + self::$camelize_rules = array(); self::$humanize_rules = array(); self::$join_array_callback = NULL; @@ -439,11 +498,26 @@ static public function singularize($plural_noun) { + if (isset(self::$cache['singularize'][$plural_noun])) { + return self::$cache['singularize'][$plural_noun]; + } + + $original = $plural_noun; + $singular_noun = NULL; + list ($beginning, $plural_noun) = self::splitLastWord($plural_noun); foreach (self::$plural_to_singular_rules as $from => $to) { if (preg_match('#' . $from . '#iD', $plural_noun)) { - return $beginning . preg_replace('#' . $from . '#iD', $to, $plural_noun); + $singular_noun = $beginning . preg_replace('#' . $from . '#iD', $to, $plural_noun); + break; } } - throw new fProgrammerException('The noun specified could not be singularized'); + + if (!$singular_noun) { + throw new fProgrammerException('The noun specified could not be singularized'); + } + + self::$cache['singularize'][$original] = $singular_noun; + + return $singular_noun; } @@ -485,28 +559,35 @@ static public function underscorize($string) { + if (isset(self::$cache['underscorize'][$string])) { + return self::$cache['underscorize'][$string]; + } + + $original = $string; $string = strtolower($string[0]) . substr($string, 1); // Handle custom rules if (isset(self::$underscorize_rules[$string])) { - return self::$underscorize_rules[$string]; - } + $string = self::$underscorize_rules[$string]; // If the string is already underscore notation then leave it - if (strpos($string, '_') !== FALSE) { - return $string; - } + } elseif (strpos($string, '_') !== FALSE) { // Allow humanized string to be passed in - if (strpos($string, ' ') !== FALSE) { - return strtolower(preg_replace('#\s+#', '_', $string)); - } - - do { - $old_string = $string; - $string = preg_replace('/([a-zA-Z])([0-9])/', '\1_\2', $string); - $string = preg_replace('/([a-z0-9A-Z])([A-Z])/', '\1_\2', $string); - } while ($old_string != $string); - - return strtolower($string); + } elseif (strpos($string, ' ') !== FALSE) { + $string = strtolower(preg_replace('#\s+#', '_', $string)); + + } else { + do { + $old_string = $string; + $string = preg_replace('/([a-zA-Z])([0-9])/', '\1_\2', $string); + $string = preg_replace('/([a-z0-9A-Z])([A-Z])/', '\1_\2', $string); + } while ($old_string != $string); + + $string = strtolower($string); + } + + self::$cache['underscorize'][$original] = $string; + + return $string; } Index: /fORMOrdering.php =================================================================== --- /fORMOrdering.php (revision 602) +++ /fORMOrdering.php (revision 603) @@ -10,5 +10,6 @@ * @link http://flourishlib.com/fORMOrdering * - * @version 1.0.0b5 + * @version 1.0.0b6 + * @changes 1.0.0b6 Updated code for new fORM API [wb, 2009-06-15] * @changes 1.0.0b5 Updated class to automatically correct ordering values that are too high [wb, 2009-06-14] * @changes 1.0.0b4 Updated code to use new fValidationException::formatField() method [wb, 2009-06-04] @@ -561,5 +562,5 @@ static public function validate($object, &$values, &$old_values, &$related_records, &$cache, &$validation_messages) { - $class = fORM::getClass($object); + $class = get_class($object); $table = fORM::tablize($class); Index: /fORMRelated.php =================================================================== --- /fORMRelated.php (revision 598) +++ /fORMRelated.php (revision 603) @@ -13,5 +13,6 @@ * @link http://flourishlib.com/fORMRelated * - * @version 1.0.0b6 + * @version 1.0.0b7 + * @changes 1.0.0b7 Updated code for new fORM API, fixed API documentation bugs [wb, 2009-06-15] * @changes 1.0.0b6 Updated code to use new fValidationException::formatField() method [wb, 2009-06-04] * @changes 1.0.0b5 Added ::getPrimaryKeys() and ::setPrimaryKeys(), renamed ::setRecords() to ::setRecordSet() and ::tallyRecords() to ::setCount() [wb, 2009-06-02] @@ -67,5 +68,5 @@ * @internal * - * @param mixed $class The class name or instance of the class to get the related values for + * @param string $class The class to get the related values for * @param array &$related_records The related records existing for the fActiveRecord class * @param string $related_class The class we are associating with the current record @@ -111,5 +112,5 @@ * @internal * - * @param mixed $class The class name or instance of the class to get the related values for + * @param string $class The class to get the related values for * @param array &$values The values for the fActiveRecord class * @param array &$related_records The related records existing for the fActiveRecord class @@ -186,5 +187,5 @@ * @internal * - * @param mixed $class The class name or instance of the class to get the related values for + * @param string $class The class to get the related values for * @param array &$values The values for the fActiveRecord class * @param array &$related_records The related records existing for the fActiveRecord class @@ -242,5 +243,5 @@ * @internal * - * @param mixed $class The class name or instance of the class to get the related values for + * @param string $class The class to create the related record for * @param array $values The values existing in the fActiveRecord class * @param string $related_class The related class name @@ -250,6 +251,5 @@ static public function createRecord($class, $values, $related_class, $route=NULL) { - $table = fORM::tablize($class); - + $table = fORM::tablize($class); $related_table = fORM::tablize($related_class); @@ -265,5 +265,5 @@ * @internal * - * @param mixed $class The class name or instance of the main class + * @param string $class The class name of the main class * @param string $related_class The related class being filtered for * @param string $route The route to the related table @@ -300,5 +300,5 @@ * @internal * - * @param mixed $class The class name or instance of the class to get the related values for + * @param string $class The class to associate the related records to * @param array &$related_records The related records existing for the fActiveRecord class * @param string $related_class The class we are associating with the current record @@ -331,5 +331,5 @@ * @internal * - * @param mixed $class The class name or instance of the class this ordering rule applies to + * @param string $class The class to get the order bys for * @param string $related_class The related class the ordering rules apply to * @param string $route The route to the related table, should be a column name in the current table or a join table name @@ -356,5 +356,5 @@ * @internal * - * @param mixed $class The class name or instance of the class to get the related values for + * @param string $class The class to get the related primary keys for * @param array &$values The values for the fActiveRecord class * @param array &$related_records The related records existing for the fActiveRecord class @@ -448,13 +448,11 @@ * @internal * - * @param mixed $class The class name or instance of the class to get the related class name for - * @param mixed $related_class The related class/class name to get the record name of + * @param string $class The class to get the related class name for + * @param string $related_class The related class to get the record name of * @return string The record name for the related class specified */ static public function getRelatedRecordName($class, $related_class, $route=NULL) { - $table = fORM::tablize($class); - - $related_class = fORM::getClass($related_class); + $table = fORM::tablize($class); $related_table = fORM::tablize($related_class); @@ -476,5 +474,5 @@ * @internal * - * @param mixed $class The class name or instance of the class to get the related values for + * @param string $class The class to get link the related records to * @param array &$related_records The related records existing for the fActiveRecord class * @param string $related_class The related class to populate @@ -551,6 +549,6 @@ static public function overrideRelatedRecordName($class, $related_class, $record_name, $route=NULL) { - $table = fORM::tablize($class); - + $class = fORM::getClass($class); + $table = fORM::tablize($class); $related_class = fORM::getClass($related_class); $related_table = fORM::tablize($related_class); @@ -575,5 +573,5 @@ * @internal * - * @param mixed $class The class name or instance of the class to get the related values for + * @param string $class The class to populate the related records of * @param array &$related_records The related records existing for the fActiveRecord class * @param string $related_class The related class to populate @@ -583,4 +581,5 @@ static public function populateRecords($class, &$related_records, $related_class, $route=NULL) { + $table = fORM::tablize($class); $related_table = fORM::tablize($related_class); $pk_columns = fORMSchema::retrieve()->getKeys($related_table, 'primary'); @@ -590,5 +589,5 @@ $first_pk_column = NULL; - $relationships = fORMSchema::getRoutes($related_table, fORM::tablize($class), '*-to-one'); + $relationships = fORMSchema::getRoutes($related_table, $table, '*-to-one'); foreach ($pk_columns as $pk_column) { foreach ($relationships as $relationship) { @@ -652,5 +651,5 @@ * @internal * - * @param mixed $class The class name or instance of the class this ordering rule applies to + * @param string $class The class to reflect the related record methods for * @param array &$signatures The associative array of `{method_name} => {signature}` * @param boolean $include_doc_comments If the doc block comments for each method should be included @@ -882,4 +881,5 @@ static public function setOrderBys($class, $related_class, $order_bys, $route=NULL) { + $class = fORM::getClass($class); $table = fORM::tablize($class); $related_table = fORM::tablize($related_class); @@ -904,5 +904,5 @@ * @internal * - * @param mixed $class The class name or instance of the class to get the related values for + * @param string $class The class to set the related records count for * @param array &$values The values for the fActiveRecord class * @param array &$related_records The related records existing for the fActiveRecord class @@ -942,5 +942,5 @@ * @internal * - * @param mixed $class The class name or instance of the class to get the related values for + * @param string $class The class to set the related primary keys for * @param array &$related_records The related records existing for the fActiveRecord class * @param string $related_class The class we are setting the records for @@ -975,5 +975,5 @@ * @internal * - * @param mixed $class The class name or instance of the class to get the related values for + * @param string $class The class to set the related records for * @param array &$related_records The related records existing for the fActiveRecord class * @param string $related_class The class we are associating with the current record @@ -1008,7 +1008,7 @@ * @internal * - * @param mixed $class The class name or instance of the class to store the related records for - * @param array &$values The current values for the main record being stored - * @param array &$related_records The related records array + * @param string $class The class to store the related records for + * @param array &$values The current values for the main record being stored + * @param array &$related_records The related records array * @return void */ @@ -1156,11 +1156,10 @@ * @internal * - * @param mixed $class The class name or instance of the class to validate the related records for - * @param array &$related_records The related records array + * @param string $class The class to validate the related records for + * @param array &$related_records The related records array * @return void */ static public function validate($class, &$related_records) { - $class = fORM::getClass($class); $table = fORM::tablize($class); @@ -1196,5 +1195,5 @@ * @internal * - * @param mixed $class The class name or instance of the class these records are related to + * @param string $class The class to validate the related records for * @param string $related_class The name of the class for this record set * @param string $route The route between the table and related table @@ -1254,5 +1253,5 @@ * @internal * - * @param mixed $class The class name or instance of the class these records are related to + * @param string $class The class to validate the related records for * @param string $related_class The name of the class for this record set * @param string $route The route between the table and related table Index: /fSchema.php =================================================================== --- /fSchema.php (revision 597) +++ /fSchema.php (revision 603) @@ -10,5 +10,6 @@ * @link http://flourishlib.com/fSchema * - * @version 1.0.0b19 + * @version 1.0.0b20 + * @changes 1.0.0b20 Add caching of merged info, improved performance of ::getColumnInfo() [wb, 2009-06-15] * @changes 1.0.0b19 Fixed a couple of bugs with ::setKeysOverride() [wb, 2009-06-04] * @changes 1.0.0b18 Added missing support for MySQL mediumint columns [wb, 2009-05-18] @@ -176,4 +177,7 @@ $this->cache->delete($prefix . 'databases'); $this->cache->delete($prefix . 'keys'); + $this->cache->delete($prefix . 'merged_column_info'); + $this->cache->delete($prefix . 'merged_keys'); + $this->cache->delete($prefix . 'relationships'); $this->cache->delete($prefix . 'tables'); } @@ -192,8 +196,15 @@ $prefix = $this->makeCachePrefix(); - $this->column_info = $this->cache->get($prefix . 'column_info', array()); - $this->databases = $this->cache->get($prefix . 'databases', NULL); - $this->keys = $this->cache->get($prefix . 'keys', array()); - $this->tables = $this->cache->get($prefix . 'tables', NULL); + $this->column_info = $this->cache->get($prefix . 'column_info', array()); + $this->databases = $this->cache->get($prefix . 'databases', NULL); + $this->keys = $this->cache->get($prefix . 'keys', array()); + + if (!$this->column_info_override && !$this->keys_override) { + $this->merged_column_info = $this->cache->get($prefix . 'merged_column_info', array()); + $this->merged_keys = $this->cache->get($prefix . 'merged_keys', array()); + $this->relationships = $this->cache->get($prefix . 'relationships', array()); + } + + $this->tables = $this->cache->get($prefix . 'tables', NULL); } @@ -1714,4 +1725,8 @@ $this->findOneToManyRelationships($table); } + + if ($this->cache) { + $this->cache->set($this->makeCachePrefix() . 'relationships', $this->relationships); + } } @@ -1772,11 +1787,20 @@ public function getColumnInfo($table, $column=NULL, $element=NULL) { - $valid_elements = array('type', 'not_null', 'default', 'valid_values', 'max_length', 'decimal_places', 'auto_increment'); - if ($element && !in_array($element, $valid_elements)) { - throw new fProgrammerException( - 'The element specified, %1$s, is invalid. Must be one of: %2$s.', - $element, - join(', ', $valid_elements) - ); + // Return the saved column info if possible + if (!$column && isset($this->merged_column_info[$table])) { + return $this->merged_column_info[$table]; + } + if ($column && isset($this->merged_column_info[$table][$column])) { + if ($element !== NULL) { + if (!isset($this->merged_column_info[$table][$column][$element]) && !array_key_exists($element, $this->merged_column_info[$table][$column])) { + throw new fProgrammerException( + 'The element specified, %1$s, is invalid. Must be one of: %2$s.', + $element, + join(', ', array('type', 'not_null', 'default', 'valid_values', 'max_length', 'decimal_places', 'auto_increment')) + ); + } + return $this->merged_column_info[$table][$column][$element]; + } + return $this->merged_column_info[$table][$column]; } @@ -1786,15 +1810,4 @@ $table ); - } - - // Return the saved column info if possible - if (!$column && isset($this->merged_column_info[$table])) { - return $this->merged_column_info[$table]; - } - if ($column && isset($this->merged_column_info[$table][$column])) { - if ($element !== NULL) { - return $this->merged_column_info[$table][$column][$element]; - } - return $this->merged_column_info[$table][$column]; } @@ -2218,4 +2231,8 @@ } } + + if ($this->cache) { + $this->cache->set($this->makeCachePrefix() . 'merged_column_info', $this->merged_column_info); + } } @@ -2236,4 +2253,8 @@ } $this->merged_keys[$table] = array_merge($this->merged_keys[$table], $info); + } + + if ($this->cache) { + $this->cache->set($this->makeCachePrefix() . 'merged_keys', $this->merged_keys); } Index: /fORMValidation.php =================================================================== --- /fORMValidation.php (revision 598) +++ /fORMValidation.php (revision 603) @@ -10,5 +10,6 @@ * @link http://flourishlib.com/fORMValidation * - * @version 1.0.0b8 + * @version 1.0.0b9 + * @changes 1.0.0b9 Updated code for new fORM API [wb, 2009-06-15] * @changes 1.0.0b8 Updated code to use new fValidationException::formatField() method [wb, 2009-06-04] * @changes 1.0.0b7 Updated ::validateRelated() to use new fORMRelated::validate() method and ::checkRelatedOneOrMoreRule() to use new `$related_records` structure [wb, 2009-06-02] @@ -230,5 +231,5 @@ static private function checkAgainstSchema($object, $column, &$values, &$old_values) { - $class = fORM::getClass($object); + $class = get_class($object); $table = fORM::tablize($class); @@ -282,5 +283,5 @@ * Validates against a conditional validation rule * - * @param mixed $class The class name or instance of the class this validation rule applies to + * @param string $class The class this validation rule applies to * @param array &$values An associative array of all values for the record * @param string $main_column The column to check for a value @@ -316,5 +317,5 @@ * Validates a value against the database data type * - * @param mixed $class The class name or instance of the class the column is part of + * @param string $class The class the column is part of * @param string $column The column to check * @param mixed $value The value to check @@ -387,5 +388,5 @@ * Validates values against foreign key constraints * - * @param mixed $class The class name or instance of the class to check the foreign keys for + * @param string $class The class to check the foreign keys for * @param string $column The column to check * @param array &$values The values to check @@ -426,5 +427,5 @@ * Validates against a one-or-more validation rule * - * @param mixed $class The class name or instance of the class the columns are part of + * @param string $class The class the columns are part of * @param array &$values An associative array of all values for the record * @param array $columns The columns to check @@ -458,5 +459,5 @@ * Validates against an only-one validation rule * - * @param mixed $class The class name or instance of the class the columns are part of + * @param string $class The class the columns are part of * @param array &$values An associative array of all values for the record * @param array $columns The columns to check @@ -504,5 +505,5 @@ static private function checkPrimaryKeys($object, &$values, &$old_values) { - $class = fORM::getClass($object); + $class = get_class($object); $table = fORM::tablize($class); @@ -570,5 +571,5 @@ * Validates against a *-to-many one or more validation rule * - * @param mixed $class The class name or instance of the class we are checking + * @param string $class The class we are checking * @param array &$related_records The related records array to check * @param string $related_class The name of the related class @@ -604,5 +605,5 @@ static private function checkUniqueConstraints($object, $column, &$values, &$old_values) { - $class = fORM::getClass($object); + $class = get_class($object); $table = fORM::tablize($class); @@ -700,5 +701,5 @@ * @internal * - * @param mixed $class The class name or an instance of the class to initilize the arrays for + * @param string $class The class to initilize the arrays for * @return void */ @@ -717,5 +718,5 @@ * @internal * - * @param mixed $class The class to check + * @param string $class The class to check * @param string $column The column to check * @return boolean If the column is set to be case insensitive @@ -723,8 +724,5 @@ static private function isCaseInsensitive($class, $column) { - if (!isset(self::$case_insensitive_columns[$class][$column])) { - return FALSE; - } - return TRUE; + return isset(self::$case_insensitive_columns[$class][$column]); } @@ -735,12 +733,10 @@ * @internal * - * @param mixed $class The class name or an instance of the class to reorder messages for - * @param array &$validation_messages An array of one validation message per value + * @param string $class The class to reorder messages for + * @param array &$validation_messages An array of one validation message per value * @return void */ static public function reorderMessages($class, &$validation_messages) { - $class = fORM::getClass($class); - if (!isset(self::$message_orders[$class])) { return; @@ -882,5 +878,5 @@ static public function validate($object, $values, $old_values) { - $class = fORM::getClass($object); + $class = get_class($object); $table = fORM::tablize($class); @@ -932,11 +928,10 @@ * @internal * - * @param mixed $class The class name or instance of the class to validate - * @param array &$related_records The related records to validate + * @param string $class The class to validate + * @param array &$related_records The related records to validate * @return array An array of validation messages */ static public function validateRelated($class, &$related_records) { - $class = fORM::getClass($class); $table = fORM::tablize($class); Index: /fORMColumn.php =================================================================== --- /fORMColumn.php (revision 598) +++ /fORMColumn.php (revision 603) @@ -10,5 +10,6 @@ * @link http://flourishlib.com/fORMColumn * - * @version 1.0.0b3 + * @version 1.0.0b4 + * @changes 1.0.0b4 Updated code for new fORM API [wb, 2009-06-15] * @changes 1.0.0b3 Updated code to use new fValidationException::formatField() method [wb, 2009-06-04] * @changes 1.0.0b2 Fixed a bug with objectifying number columns [wb, 2008-11-24] @@ -331,5 +332,6 @@ list ($action, $column) = fORM::parseMethod($method_name); - $column_info = fORMSchema::retrieve()->getColumnInfo(fORM::tablize($object), $column); + $class = get_class($object); + $column_info = fORMSchema::retrieve()->getColumnInfo(fORM::tablize($class), $column); $value = $values[$column]; @@ -365,5 +367,5 @@ list ($action, $column) = fORM::parseMethod($method_name); - $class = fORM::getClass($object); + $class = get_class($object); $table = fORM::tablize($class); @@ -540,5 +542,6 @@ list ($action, $column) = fORM::parseMethod($method_name); - $column_info = fORMSchema::retrieve()->getColumnInfo(fORM::tablize($object), $column); + $class = get_class($object); + $column_info = fORMSchema::retrieve()->getColumnInfo(fORM::tablize($class), $column); $value = $values[$column]; @@ -594,7 +597,10 @@ if (isset(self::$number_columns[$class])) { + + $table = fORM::tablize($class); + foreach(self::$number_columns[$class] as $column => $enabled) { $camelized_column = fGrammar::camelize($column, TRUE); - $type = fORMSchema::retrieve()->getColumnInfo(fORM::tablize($class), $column, 'type'); + $type = fORMSchema::retrieve()->getColumnInfo($table, $column, 'type'); // Get and set methods