/** * Sets a column to be an ordering column * * There can only be one ordering column per class/table and it must be * part of a single or multi-column `UNIQUE` constraint. * * @param mixed $class The class name or instance of the class * @param string $column The column to set as an ordering column * @return void */ public static function configureOrderingColumn($class, $column) { $class = fORM::getClass($class); $table = fORM::tablize($class); $data_type = fORMSchema::retrieve()->getColumnInfo($table, $column, 'type'); $unique_keys = fORMSchema::retrieve()->getKeys($table, 'unique'); if ($data_type != 'integer') { throw new fProgrammerException('The column specified, %1$s, is a %2$s column. It must be an integer column to be set as an ordering column.', $column, $data_type); } $found = FALSE; foreach ($unique_keys as $unique_key) { settype($unique_key, 'array'); if (in_array($column, $unique_key)) { $other_columns = array_diff($unique_key, array($column)); $found = TRUE; break; } } if (!$found) { throw new fProgrammerException('The column specified, %s, does not appear to be part of a unique key. It must be part of a unique key to be set as an ordering column.', $column); } fORM::registerHookCallback($class, 'post::validate()', self::validate); fORM::registerHookCallback($class, 'post-validate::store()', self::reorder); fORM::registerHookCallback($class, 'pre-commit::delete()', self::delete); fORM::registerReflectCallback($class, self::reflect); fORM::registerActiveRecordMethod($class, 'inspect' . fGrammar::camelize($column, TRUE), self::inspect); // Ensure we only ever have one ordering column by overwriting self::$ordering_columns[$class]['column'] = $column; self::$ordering_columns[$class]['other_columns'] = $other_columns; }
/** * Sets a column to be formatted as an fMoney object * * @param mixed $class The class name or instance of the class to set the column format * @param string $column The column to format as an fMoney object * @param string $currency_column If specified, this column will store the currency of the fMoney object * @return void */ public static function configureMoneyColumn($class, $column, $currency_column = NULL) { $class = fORM::getClass($class); $table = fORM::tablize($class); $schema = fORMSchema::retrieve($class); $data_type = $schema->getColumnInfo($table, $column, 'type'); $valid_data_types = array('float'); if (!in_array($data_type, $valid_data_types)) { throw new fProgrammerException('The column specified, %1$s, is a %2$s column. Must be %3$s to be set as a money column.', $column, $data_type, join(', ', $valid_data_types)); } if ($currency_column !== NULL) { $currency_column_data_type = $schema->getColumnInfo($table, $currency_column, 'type'); $valid_currency_column_data_types = array('varchar', 'char', 'text'); if (!in_array($currency_column_data_type, $valid_currency_column_data_types)) { throw new fProgrammerException('The currency column specified, %1$s, is a %2$s column. Must be %3$s to be set as a currency column.', $currency_column, $currency_column_data_type, join(', ', $valid_currency_column_data_types)); } } $camelized_column = fGrammar::camelize($column, TRUE); fORM::registerActiveRecordMethod($class, 'encode' . $camelized_column, self::encodeMoneyColumn); fORM::registerActiveRecordMethod($class, 'prepare' . $camelized_column, self::prepareMoneyColumn); if (!fORM::checkHookCallback($class, 'post::validate()', self::validateMoneyColumns)) { fORM::registerHookCallback($class, 'post::validate()', self::validateMoneyColumns); } fORM::registerReflectCallback($class, self::reflect); fORM::registerInspectCallback($class, $column, self::inspect); $value = FALSE; if ($currency_column) { $value = $currency_column; if (empty(self::$currency_columns[$class])) { self::$currency_columns[$class] = array(); } self::$currency_columns[$class][$currency_column] = $column; if (!fORM::checkHookCallback($class, 'post::loadFromResult()', self::makeMoneyObjects)) { fORM::registerHookCallback($class, 'post::loadFromResult()', self::makeMoneyObjects); } if (!fORM::checkHookCallback($class, 'pre::validate()', self::makeMoneyObjects)) { fORM::registerHookCallback($class, 'pre::validate()', self::makeMoneyObjects); } fORM::registerActiveRecordMethod($class, 'set' . $camelized_column, self::setMoneyColumn); fORM::registerActiveRecordMethod($class, 'set' . fGrammar::camelize($currency_column, TRUE), self::setCurrencyColumn); } else { fORM::registerObjectifyCallback($class, $column, self::objectifyMoney); } if (empty(self::$money_columns[$class])) { self::$money_columns[$class] = array(); } self::$money_columns[$class][$column] = $value; }
/** * Sets a column to be an ordering column * * There can only be one ordering column per class/table and it must be * part of a single or multi-column `UNIQUE` constraint. * * @param mixed $class The class name or instance of the class * @param string $column The column to set as an ordering column * @return void */ public static function configureOrderingColumn($class, $column) { $class = fORM::getClass($class); $table = fORM::tablize($class); $schema = fORMSchema::retrieve($class); $info = $schema->getColumnInfo($table, $column); $unique_keys = $schema->getKeys($table, 'unique'); if ($info['type'] != 'integer') { throw new fProgrammerException('The column specified, %1$s, is a %2$s column. It must be an integer column to be set as an ordering column.', $column, $data_type); } if ($info['min_value'] && $info['min_value']->eq(0)) { throw new fProgrammerException('The column specified, %1$s, does not allow for negative values. Please adjust the data type to an integer type that allows for negative values.', $column); } $found = FALSE; foreach ($unique_keys as $unique_key) { settype($unique_key, 'array'); if (in_array($column, $unique_key)) { $other_columns = array_diff($unique_key, array($column)); $found = TRUE; break; } } if (!$found) { throw new fProgrammerException('The column specified, %s, does not appear to be part of a unique key. It must be part of a unique key to be set as an ordering column.', $column); } if (!fORM::checkHookCallback($class, 'post::validate()', self::validate)) { fORM::registerHookCallback($class, 'post::validate()', self::validate); } if (!fORM::checkHookCallback($class, 'post-validate::store()', self::reorder)) { fORM::registerHookCallback($class, 'post-validate::store()', self::reorder); } if (!fORM::checkHookCallback($class, 'pre-commit::delete()', self::delete)) { fORM::registerHookCallback($class, 'pre-commit::delete()', self::delete); } fORM::registerReflectCallback($class, self::reflect); fORM::registerActiveRecordMethod($class, 'inspect' . fGrammar::camelize($column, TRUE), self::inspect); self::$ordering_columns[$class][$column] = $other_columns; }
/** * Sets a column to be an image upload column * * This method works exactly the same as ::configureFileUploadColumn() * except that only image files are accepted. * * @param mixed $class The class name or instance of the class * @param string $column The column to set as a file upload column * @param fDirectory|string $directory The directory to upload to * @param string $image_type The image type to save the image as: `NULL`, `'gif'`, `'jpg'`, `'png'` * @return void */ public static function configureImageUploadColumn($class, $column, $directory, $image_type = NULL) { $valid_image_types = array(NULL, 'gif', 'jpg', 'png'); if (!in_array($image_type, $valid_image_types)) { $valid_image_types[0] = '{null}'; throw new fProgrammerException('The image type specified, %1$s, is not valid. Must be one of: %2$s.', $image_type, join(', ', $valid_image_types)); } self::configureFileUploadColumn($class, $column, $directory); $class = fORM::getClass($class); $camelized_column = fGrammar::camelize($column, TRUE); fORM::registerActiveRecordMethod($class, 'process' . $camelized_column, self::process); if (empty(self::$image_upload_columns[$class])) { self::$image_upload_columns[$class] = array(); } self::$image_upload_columns[$class][$column] = $image_type; self::addFUploadMethodCall($class, $column, 'setMimeTypes', array(array('image/gif', 'image/jpeg', 'image/pjpeg', 'image/png'), self::compose('The file uploaded is not an image'))); }
/** * Sets a column to be an image upload column * * This method works exactly the same as ::configureFileUploadColumn() * except that only image files are accepted. * * To alter an image, including the file type, use ::addFImageMethodCall(). * * @param mixed $class The class name or instance of the class * @param string $column The column to set as a file upload column * @param fDirectory|string $directory The directory to upload to * @return void */ public static function configureImageUploadColumn($class, $column, $directory) { self::configureFileUploadColumn($class, $column, $directory); $class = fORM::getClass($class); $camelized_column = fGrammar::camelize($column, TRUE); fORM::registerActiveRecordMethod($class, 'process' . $camelized_column, self::process); if (empty(self::$image_upload_columns[$class])) { self::$image_upload_columns[$class] = array(); } self::$image_upload_columns[$class][$column] = TRUE; self::addFUploadMethodCall($class, $column, 'setMimeTypes', array(array('image/gif', 'image/jpeg', 'image/pjpeg', 'image/png'), self::compose('The file uploaded is not an image'))); }
/** * Sets the ordering to use when returning an fRecordSet of related objects * * @param mixed $class The class name or instance of the class this ordering rule applies to * @param string $related_class The related class we are getting info from * @param array $order_bys An array of the order bys for this table.column combination - see fRecordSet::build() for format * @param string $route The route to the related table, this should be a column name in the current table or a join table name * @return void */ public static function setOrderBys($class, $related_class, $order_bys, $route = NULL) { fActiveRecord::validateClass($related_class); fActiveRecord::forceConfigure($related_class); $class = fORM::getClass($class); $table = fORM::tablize($class); $related_class = fORM::getRelatedClass($class, $related_class); $related_table = fORM::tablize($related_class); $schema = fORMSchema::retrieve($class); $route = fORMSchema::getRouteName($schema, $table, $related_table, $route, '*-to-many'); if (!isset(self::$order_bys[$table])) { self::$order_bys[$table] = array(); } if (!isset(self::$order_bys[$table][$related_table])) { self::$order_bys[$table][$related_table] = array(); } self::$order_bys[$table][$related_table][$route] = $order_bys; }
/** * Sets a timestamp column to store the timezone in another column * * Since not all databases support timezone information in timestamp * columns, this method allows storing the timezone in another columns. * When the timestamp and timezone are retrieved from the database, they * will be automatically combined together into an fTimestamp object. * * @param mixed $class The class name or instance of the class to set the column format * @param string $timestamp_column The timestamp column to store the timezone for * @param string $timezone_column The column to store the timezone in * @return void */ public static function configureTimezoneColumn($class, $timestamp_column, $timezone_column) { $class = fORM::getClass($class); $table = fORM::tablize($class); $schema = fORMSchema::retrieve($class); $timestamp_data_type = $schema->getColumnInfo($table, $timestamp_column, 'type'); if ($timestamp_data_type != 'timestamp') { throw new fProgrammerException('The timestamp column specified, %1$s, is a %2$s column. Must be a %3$s to have a related timezone column.', $timestamp_column, $data_type, 'timestamp'); } $timezone_column_data_type = $schema->getColumnInfo($table, $timezone_column, 'type'); $valid_timezone_column_data_types = array('varchar', 'char', 'text'); if (!in_array($timezone_column_data_type, $valid_timezone_column_data_types)) { throw new fProgrammerException('The timezone column specified, %1$s, is a %2$s column. Must be %3$s to be set as a timezone column.', $timezone_column, $timezone_column_data_type, join(', ', $valid_timezone_column_data_types)); } if (!fORM::checkHookCallback($class, 'post::validate()', self::validateTimezoneColumns)) { fORM::registerHookCallback($class, 'post::validate()', self::validateTimezoneColumns); } if (!fORM::checkHookCallback($class, 'post::loadFromResult()', self::makeTimestampObjects)) { fORM::registerHookCallback($class, 'post::loadFromResult()', self::makeTimestampObjects); } if (!fORM::checkHookCallback($class, 'pre::validate()', self::makeTimestampObjects)) { fORM::registerHookCallback($class, 'pre::validate()', self::makeTimestampObjects); } fORM::registerInspectCallback($class, $timezone_column, self::inspect); fORM::registerActiveRecordMethod($class, 'set' . fGrammar::camelize($timestamp_column, TRUE), self::setTimestampColumn); fORM::registerActiveRecordMethod($class, 'set' . fGrammar::camelize($timezone_column, TRUE), self::setTimezoneColumn); if (empty(self::$timestamp_columns[$class])) { self::$timestamp_columns[$class] = array(); } self::$timestamp_columns[$class][$timestamp_column] = $timezone_column; if (empty(self::$timezone_columns[$class])) { self::$timezone_columns[$class] = array(); } self::$timezone_columns[$class][$timezone_column] = $timestamp_column; }
/** * Allows setting the order that the list items in a message will be displayed * * All string comparisons during the reordering process are done in a * case-insensitive manner. * * @param mixed $class The class name or an instance of the class to set the message order for * @param array $matches This should be an ordered array of strings. If a line contains the string it will be displayed in the relative order it occurs in this array. * @return void */ public static function setMessageOrder($class, $matches) { $class = fORM::getClass($class); // Handle the alternate form allowed with fValidation::setMessageOrder() $args = func_get_args(); array_shift($args); if (count($args) != 1) { $matches = $args; } uasort($matches, array('self', 'sortMessageMatches')); self::$message_orders[$class] = $matches; }
/** * Sets a class to use a database other than the "default" * * Multiple database objects can be attached for the ORM by passing a * unique `$name` to the ::attach() method. * * @param mixed $class The name of the class, or an instance of it * @param string $database_name The name given to the database when passed to ::attach() * @return void */ public static function mapClassToDatabase($class, $database_name) { $class = fORM::getClass($class); self::$class_database_map[$class] = $database_name; }
/** * Sets a column to be a random string column - a random string will be generated when the record is saved * * @param mixed $class The class name or instance of the class * @param string $column The column to set as a random column * @param string $type The type of random string, must be one of: `'alphanumeric'`, `'alpha'`, `'numeric'`, `'hexadecimal'` * @param integer $length The length of the random string * @return void */ public static function configureRandomColumn($class, $column, $type, $length) { $class = fORM::getClass($class); $table = fORM::tablize($class); $schema = fORMSchema::retrieve($class); $data_type = $schema->getColumnInfo($table, $column, 'type'); $valid_data_types = array('varchar', 'char', 'text'); if (!in_array($data_type, $valid_data_types)) { throw new fProgrammerException('The column specified, %1$s, is a %2$s column. Must be one of %3$s to be set as a random string column.', $column, $data_type, join(', ', $valid_data_types)); } $valid_types = array('alphanumeric', 'alpha', 'numeric', 'hexadecimal'); if (!in_array($type, $valid_types)) { throw new fProgrammerException('The type specified, %1$s, is an invalid type. Must be one of: %2$s.', $type, join(', ', $valid_types)); } if (!is_numeric($length) || $length < 1) { throw new fProgrammerException('The length specified, %s, needs to be an integer greater than zero.', $length); } fORM::registerActiveRecordMethod($class, 'generate' . fGrammar::camelize($column, TRUE), self::generate); if (!fORM::checkHookCallback($class, 'pre::validate()', self::setRandomStrings)) { fORM::registerHookCallback($class, 'pre::validate()', self::setRandomStrings); } fORM::registerInspectCallback($class, $column, self::inspect); if (empty(self::$random_columns[$class])) { self::$random_columns[$class] = array(); } self::$random_columns[$class][$column] = array('type' => $type, 'length' => (int) $length); }
/** * Sets the ordering to use when returning an fRecordSet of related objects * * @param mixed $class The class name or instance of the class this ordering rule applies to * @param string $related_class The related class we are getting info from * @param array $order_bys An array of the order bys for this table.column combination - see fRecordSet::build() for format * @param string $route The route to the related table, this should be a column name in the current table or a join table name * @return void */ public static function setOrderBys($class, $related_class, $order_bys, $route = NULL) { $class = fORM::getClass($class); $table = fORM::tablize($class); $related_table = fORM::tablize($related_class); $route = fORMSchema::getRouteName($table, $related_table, $route, '*-to-many'); if (!isset(self::$order_bys[$table])) { self::$order_bys[$table] = array(); } if (!isset(self::$order_bys[$table][$related_table])) { self::$order_bys[$table][$related_table] = array(); } self::$order_bys[$table][$related_table][$route] = $order_bys; }
/** * Allows setting the order that the list items in a message will be displayed * * All string comparisons during the reordering process are done in a * case-insensitive manner. * * @param mixed $class The class name or an instance of the class to set the message order for * @param array $matches This should be an ordered array of strings. If a line contains the string it will be displayed in the relative order it occurs in this array. * @return void */ public static function setMessageOrder($class, $matches) { $class = fORM::getClass($class); uasort($matches, array('self', 'sortMessageMatches')); self::$message_orders[$class] = $matches; }