cf_db_options.module in Common Functionality 7.2
Same filename and directory in other branches
Common Functionality - Database Options module.
File
modules/cf_db_options/cf_db_options.moduleView source
<?php
/**
* @file
* Common Functionality - Database Options module.
*/
/**
* @defgroup cf_db_options Common Functionality - Database Options
* @ingroup cf
* @{
* A library to assist in quickly creating an options table and functions.
*
* Justification:
* Options are normally stored in the php module itself inside of some static
* function. Using a function to get a list of possible options is the simple
* and efficient way to do this under normal circumstances.
*
* Instead of using a function to define the options provided by some module,
* this project uses the database. While this has a cost in performance due to
* using database calls, this provides more flexibility and scalability. For
* example, as of drupal 7, external databases are supported. Lets say that
* for whatever reason these options and tables using them are stored in an
* external database that a third-party application may access. Lets say that
* the third party application is written in Java. That java application will
* have no idea what options are available if they are stored in the php file.
* When the options are defined and stored in the database, all it needs to
* know is where to look for the possible options.
*
* The strategy defined here is to define a unique id, a machine name, a
* human name, and a description for each option. This allows for
* compatibility with the drupal standard practice of using machine names for
* options while still providing a database efficient practice of using
* numeric ids when associating with some option. The most notable downside
* to this strategy is importing and exporting of the database calls. The
* database unique ids for each option are unique only to a single drupal
* installation. To import and export, the machine name must instead be used.
*/
/**
* Builds an options table name.
*
* The option table is created with a generated name.
* Use this function to get the generated name for a given options table.
*
* @param string $table
* A machine name that is prefixed onto the table.
* This is often either the name of the module or the name of the table
* associated with the options.
* @param string $name
* The machine name of the options and is suffixed onto the table.
*
* @return bool|string
* Returns the generated string or FALSE on error.
*/
function cf_db_options_get_options_name($table, $name) {
if (cf_is_empty_or_non_string('table', $table, WATCHDOG_ERROR)) {
if (class_exists('cf_error')) {
cf_error::empty_string('table');
}
return FALSE;
}
if (cf_is_empty_or_non_string('name', $name, WATCHDOG_ERROR)) {
if (class_exists('cf_error')) {
cf_error::empty_string('name');
}
return FALSE;
}
return $table . '_options_' . $name;
}
/**
* Creates a option tables and adds them to the schema.
*
* The option table created here uniquely describes each available option.
*
* This creates the table:
* - The table ${table}_options_${name} with the columns:
* - id: a unique numeric id representing the an option.
* - machine_name: the machine name associated with some option.
* - human_name: a human friendly name associated with some option.
* - description: a description about some option.
*
* @param string $table
* A machine name that is prefixed onto the table.
* This is often either the name of the module or the name of the table
* associated with the options.
* @param string $name
* The machine name of the options and is suffixed onto the table.
* @param array $schema
* The schema array as defined by hook_schema().
*
* @return bool
* Returns TRUE on success, FALSE otherwise.
*
* @see: hook_schema()
*/
function cf_db_options_create_options_schema($table, $name, &$schema) {
$table_name = cf_db_options_get_options_name($table, $name);
if ($table_name === FALSE) {
return FALSE;
}
if (!is_array($schema)) {
$schema = array();
}
$t = get_t();
$schema[$table_name] = array(
'description' => $t("Defines possible %name options.", array(
'%name' => $name,
)),
'fields' => array(
'id' => array(
'description' => $t("The primary key used to represent an option."),
'type' => 'serial',
'size' => 'big',
'unsigned' => TRUE,
'not null' => TRUE,
),
'machine_name' => array(
'description' => $t("This is the machine-friendly name used to represent the option."),
'type' => 'varchar',
'length' => 64,
'not null' => TRUE,
'default' => '',
),
'human_name' => array(
'description' => $t("This is the human-friendly name used to represent the option."),
'type' => 'text',
'size' => 'normal',
'not null' => TRUE,
'default' => '',
),
'description' => array(
'description' => $t("This is a description the option."),
'type' => 'text',
'size' => 'medium',
'not null' => TRUE,
'default' => '',
),
),
'primary key' => array(
'id',
),
'unique keys' => array(
'machine_name' => array(
'machine_name',
),
),
);
// workaround mysql's violation of the SQL standard in a way that does not break standards-compliant databases.
// @see https://dev.mysql.com/doc/refman/5.6/en/data-type-defaults.html
// @see https://bugs.mysql.com/bug.php?id=25520
// @see https://drupal.org/node/1401782
// @see https://drupal.org/node/143881
if (db_driver() == 'mysql') {
unset($schema[$table_name]['fields']['human_name']['default']);
unset($schema[$table_name]['fields']['description']['default']);
}
return TRUE;
}
/**
* Creates a table for many-one relations with an option table.
*
* This creates the table:
* - The table ${table}_${name}s with the columns:
* - id: holds the value from the numeric appropriate numeric id defined in
* the $relation_table.
* - ${name}_id: represents the id associated with a given option.
*
* @param string $table
* A machine name that is prefixed onto the table.
* This is often either the name of the module or the name of the table
* associated with the options.
* @param string $name
* The machine name of the options and is suffixed onto the table.
* @param array $schema
* The schema array as defined by hook_schema().
* @param string $relation_table
* The machine name of the table using or associating with the options.
* @param string $relation_column
* The machine name of the table column numeric id using or associating with
* the options.
*
* @return bool
* Returns TRUE on success, FALSE otherwise.
*
* @see: hook_schema()
*/
function cf_db_options_create_options_relation($table, $name, &$schema, $relation_table, $relation_column) {
if (cf_is_empty_or_non_string('relation_table', $relation_table, WATCHDOG_ERROR)) {
return FALSE;
}
if (cf_is_empty_or_non_string('relation_column', $relation_column, WATCHDOG_ERROR)) {
return FALSE;
}
$table_name = cf_db_options_get_options_name($table, $name);
if ($table_name === FALSE) {
return FALSE;
}
if (!is_array($schema)) {
$schema = array();
}
$t = get_t();
$schema[$table . '_' . $name . 's'] = array(
'description' => $t("Properties of type %name", array(
'%name' => $name,
)),
'fields' => array(
'id' => array(
'description' => $t("The id of the relation."),
'type' => 'int',
'size' => 'big',
'unsigned' => TRUE,
'not null' => TRUE,
),
$name . '_id' => array(
'description' => $t("The options id from {%{table}_options_%{name}}.id.", array(
'%{name}' => $name,
'%{table}' => $table,
)),
'type' => 'int',
'size' => 'big',
'unsigned' => TRUE,
'not null' => TRUE,
),
),
'foreign keys' => array(
'id' => array(
'table' => $relation_table,
'columns' => array(
'id' => $relation_column,
),
),
$name . '_id' => array(
'table' => $table_name,
'columns' => array(
$name . '_id' => 'id',
),
),
),
);
return TRUE;
}
/**
* Populate a specific options table.
*
* @param string $table
* A machine name that is prefixed onto the table.
* This is often either the name of the module or the name of the table
* associated with the options.
* @param string $name
* The machine name of the options and is suffixed onto the table.
* @param array $options
* An array containing an options, with each option having the following keys:
* - machine_name: the machine name associated with some option.
* - human_name: a human friendly name associated with some option.
* - description: a description about some option.
*
* @return bool
* Returns TRUE on success, FALSE otherwise.
*/
function cf_db_options_add_options($table, $name, $options) {
if (cf_is_empty_or_non_array('options', $options, WATCHDOG_ERROR)) {
return FALSE;
}
$table_name = cf_db_options_get_options_name($table, $name);
if ($table_name === FALSE) {
return FALSE;
}
foreach ($options as &$option) {
if (!is_array($option) || empty($option)) {
continue;
}
$query = db_insert($table_name);
$query
->fields($option);
$query
->execute();
}
return TRUE;
}
/**
* Get an array of supported options for a given option type.
*
* @param string $table
* A machine name that is prefixed onto the table.
* This is often either the name of the module or the name of the table
* associated with the options.
* @param string $name
* The machine name of the options and is suffixed onto the table.
* @param int|string|null $option
* (optional) Providing a valid numeric id or machine name string
* will cause the return value to only contain the option that
* matches this string or numeric id.
*
* @return array
* An array of supported options.
* The array keys are the machine names for each option.
*/
function cf_db_options_get_options($table, $name, $option = NULL) {
if (!is_null($option) && cf_is_empty_or_non_string('name', $name, WATCHDOG_ERROR)) {
return array();
}
$options_table = cf_db_options_get_options_name($table, $name);
if ($options_table === FALSE) {
return array();
}
// $options_table is a database table name, so only allow lowercase characters and underscores
if (preg_match('/^(\\w|_)+$/', $options_table) == 0) {
return array();
}
$options =& drupal_static(__FUNCTION__, NULL);
if (isset($options[$options_table])) {
if (!is_null($option)) {
if (is_numeric($option)) {
foreach ($options[$options_table] as $key => &$value) {
if ($value->id == $option) {
return $options[$options_table][$key];
}
}
}
else {
if (isset($options[$options_table][$option])) {
return $options[$options_table][$option];
}
}
return array();
}
return $options[$options_table];
}
$query = db_select($options_table, 'ot');
$query
->fields('ot');
$query
->orderBy('ot.id', 'ASC');
try {
$records = $query
->execute()
->fetchAll();
} catch (Exception $e) {
if (class_exists('cf_error')) {
cf_error::on_query_execution($e);
}
throw $e;
return array();
}
$options[$options_table] = array();
foreach ($records as &$record) {
if (!is_object($record)) {
continue;
}
$options[$options_table][$record->machine_name] =& $record;
}
if (!is_null($option)) {
if (is_numeric($option)) {
foreach ($options[$options_table] as $key => &$value) {
if ($value->id == $option) {
return $options[$options_table][$key];
}
}
}
else {
if (isset($options[$options_table][$option])) {
return $options[$options_table][$option];
}
}
return array();
}
return $options[$options_table];
}
/**
* Returns a list of options.
*
* This is only a list of the machine_name and human_name of the
* select lists.
* Use this for populating select lists, radio buttons, and check
* boxes.
*
* @param string $table
* A machine name that is prefixed onto the table.
* This is often either the name of the module or the name of the table
* associated with the options.
* @param string $name
* The machine name of the options and is suffixed onto the table.
* @param array|null $options
* (optional) Providing a valid array of options as returned by
* cf_db_options_get_options() and it will be properly converted
* into a options list.
*
* @return
* An array of supported options.
* The array keys are the standard machine name and the array value
* is the human name.
*
* @see cf_db_options_get_options()
*/
function cf_db_options_get_options_list($table, $name, $options = NULL) {
if (cf_is_empty_or_non_string('table', $table, WATCHDOG_ERROR)) {
return array();
}
if (cf_is_empty_or_non_string('name', $name, WATCHDOG_ERROR)) {
return array();
}
if (is_null($options)) {
$options = cf_db_options_get_options($table, $name, NULL);
}
elseif (!is_array($options)) {
if (class_exists('cf_error')) {
cf_error::invalid_array('options');
}
return array();
}
$options_list = array();
foreach ($options as $machine_name => $value) {
if (!is_object($value)) {
continue;
}
$options_list[$value->machine_name] = $value->human_name;
}
return $options_list;
}
/**
* Returns the numeric id for a given option machine_name.
*
* Use this to get the numeric id that uniquely represents a particular option.
*
* @param string $table
* A machine name that is prefixed onto the table.
* This is often either the name of the module or the name of the table
* associated with the options.
* @param string $name
* The machine name of the options and is suffixed onto the table.
* @param string $machine_name
* A machine name of the option to get the id of.
*
* @return bool|int
* Returns an number that uniquely identifies the option.
* FALSE is returned on error.
*/
function cf_db_options_machine_name_to_id($table, $name, $machine_name) {
if (cf_is_empty_or_non_string('machine_name', $machine_name, WATCHDOG_ERROR)) {
return FALSE;
}
$options_table = cf_db_options_get_options_name($table, $name);
if ($options_table === FALSE) {
return FALSE;
}
// $options_table is a database table name, so only allow lowercase characters and underscores
if (preg_match('/^(\\w|_)+$/', $options_table) == 0) {
return FALSE;
}
$query = db_select($options_table, 'ot');
$query
->fields('ot', array(
'id',
));
$query
->condition('machine_name', $machine_name);
try {
return $query
->execute()
->fetchField();
} catch (Exception $e) {
if (class_exists('cf_error')) {
cf_error::on_query_execution($e);
}
throw $e;
return FALSE;
}
}
/**
* Returns the machine_name for a given option numeric id.
*
* Use this to get the machine name that uniquely represents a particular option.
*
* @param string $table
* A machine name that is prefixed onto the table.
* This is often either the name of the module or the name of the table
* associated with the options.
* @param string $name
* The machine name of the options and is suffixed onto the table.
* @param int $id
* A numeric id of the option to get the machine_name of.
*
* @return bool|string
* Returns an string that uniquely identifies the option.
* FALSE is returned on error.
*
* @deprecated
* Subqueries are possible by using a new query object then passing
* the object as a condition.
*
* @see: http://drupal.org/node/310086
* @see: http://drupal.org/node/310075
* @see: http://drupal.org/node/310069
*/
function cf_db_options_id_to_machine_name($table, $name, $id) {
if (!cf_is_integer($id)) {
if (class_exists('cf_error')) {
cf_error::invalid_numeric('id');
}
return FALSE;
}
$options_table = cf_db_options_get_options_name($table, $name);
if ($options_table === FALSE) {
return FALSE;
}
// $options_table is a database table name, so only allow lowercase characters and underscores
if (preg_match('/^(\\w|_)+$/', $options_table) == 0) {
return FALSE;
}
$query = db_select($options_table, 'ot');
$query
->fields('ot', array(
'machine_name',
));
$query
->condition('id', $id);
try {
return $query
->execute()
->fetchField();
} catch (Exception $e) {
if (class_exists('cf_error')) {
cf_error::on_query_execution($e);
}
throw $e;
return FALSE;
}
}
/**
* Returns the select query string to be used as a subquery.
*
* The d7 api does not seem to provide a subquery interface for conditions.
* Therefore, subqueries have to be manually created select query strings.
* The query itself will perform a select statement, selecting the id.
*
* @param string $table
* A machine name that is prefixed onto the table.
* This is often either the name of the module or the name of the table
* associated with the options.
* @param string $name
* The machine name of the options and is suffixed onto the table.
* @param string $machine_name
* A machine name of the option to generate a subquery select for.
*
* @return bool|string
* Returns a subquery select string.
* FALSE is returned on error.
*
* @deprecated
* Subqueries are possible by using a new query object then passing
* the object as a condition.
*
* @see: http://drupal.org/node/310086
* @see: http://drupal.org/node/310075
* @see: http://drupal.org/node/310069
*/
function cf_db_options_machine_name_to_id_subquery($table, $name, $machine_name) {
if (cf_is_empty_or_non_string('machine_name', $machine_name, WATCHDOG_ERROR)) {
return FALSE;
}
$options_table = cf_db_options_get_options_name($table, $name);
if ($options_table === FALSE) {
return FALSE;
}
// $options_table is a database table name, so only allow lowercase characters and underscores
if (preg_match('/^(\\w|_)+$/', $options_table) == 0) {
return FALSE;
}
return '(SELECT id FROM {' . $options_table . '}' . ' WHERE machine_name = \'' . $machine_name . '\')';
}
/**
* @} End of '@defgroup cf_db_options Common Functionality - Database Options'.
*/
Functions
Name | Description |
---|---|
cf_db_options_add_options | Populate a specific options table. |
cf_db_options_create_options_relation | Creates a table for many-one relations with an option table. |
cf_db_options_create_options_schema | Creates a option tables and adds them to the schema. |
cf_db_options_get_options | Get an array of supported options for a given option type. |
cf_db_options_get_options_list | Returns a list of options. |
cf_db_options_get_options_name | Builds an options table name. |
cf_db_options_id_to_machine_name Deprecated | Returns the machine_name for a given option numeric id. |
cf_db_options_machine_name_to_id | Returns the numeric id for a given option machine_name. |
cf_db_options_machine_name_to_id_subquery Deprecated | Returns the select query string to be used as a subquery. |