regcode.module in Registration codes 8
Same filename and directory in other branches
Main functionality and hooks of regcode module.
File
regcode.moduleView source
<?php
/**
* @file
* Main functionality and hooks of regcode module.
*/
use Drupal\Component\Utility\Html;
use Drupal\Core\Form\FormStateInterface;
// Define validation error codes.
const REGCODE_VALIDITY_NOTEXISTING = 0;
const REGCODE_VALIDITY_NOTAVAILABLE = 1;
const REGCODE_VALIDITY_TAKEN = 2;
const REGCODE_VALIDITY_EXPIRED = 3;
const REGCODE_MODE_REPLACE = 0;
const REGCODE_MODE_SKIP = 1;
const REGCODE_CLEAN_TRUNCATE = 1;
const REGCODE_CLEAN_INACTIVE = 3;
const REGCODE_CLEAN_EXPIRED = 4;
/**
* Implements hook_help().
*/
function regcode_help($path, $arg) {
$output = '';
switch ($path) {
case 'regcode.admin_list':
$output = '<p>' . t('View and manage created registration codes.') . '</p>';
break;
case 'regcode.admin_create':
$output = '<p>' . t('Create manually or generate new registration codes.') . '</p>';
break;
case 'regcode.admin_manage':
$output = '<p>' . t('Provides bulk management features for created registration codes.') . '</p>';
break;
case 'regcode.admin_settings':
$output = '<p>' . t('Configure the registration code module.') . '</p>';
break;
}
return $output;
}
/**
* Implements hook_entity_extra_field_info().
*/
function regcode_entity_extra_field_info() {
$extra = [];
$config = \Drupal::config('regcode.settings');
$extra['user']['user']['form']['regcode'] = [
'label' => $config
->get('regcode_field_title'),
'description' => $config
->get('regcode_field_description'),
'weight' => 10,
'visible' => TRUE,
];
return $extra;
}
/**
* Implements hook_form_FORM_ID_alter() for user_register_form.
*/
function regcode_form_user_register_form_alter(&$form, FormStateInterface $form_state) {
// Only display the regcode field when it's attached to the form display.
if ($form_state
->get('form_display')
->getComponent('regcode')) {
$config = \Drupal::config('regcode.settings');
$form['regcode'] = [
'#type' => 'textfield',
'#title' => Html::escape($config
->get('regcode_field_title')),
'#description' => Html::escape($config
->get('regcode_field_description')),
'#required' => !($config
->get('regcode_optional') || \Drupal::currentUser()
->hasPermission('administer users')),
'#element_validate' => [
'regcode_code_element_validate',
],
];
$form['actions']['submit']['#submit'][] = 'regcode_user_register_form_submit_handler';
// Capture the code from the URL, if present, and inject it into the
// registration form.
if (\Drupal::request()->query
->has('regcode')) {
// The Form API can handle potentially unsafe characters as long as they
// are not printed directly. This code gets trimmed in
// regcode_code_validate().
$form['regcode']['#value'] = \Drupal::request()->query
->get('regcode');
$form['regcode']['#description'] = NULL;
$form['regcode']['#disabled'] = TRUE;
}
}
}
/**
* Validates the content of the code-field on user registration.
*/
function regcode_code_element_validate(array &$element, FormStateInterface $form_state) {
$regcode = $form_state
->getValue('regcode');
if (!empty($regcode)) {
$code = regcode_code_validate($regcode);
if (!is_object($code)) {
$form_state
->setError($element, regcode_errormsg($code));
\Drupal::logger('regcode')
->warning('User entered invalid registration code (@code)', [
'@code' => $regcode,
]);
}
}
}
/**
* Updates data for a regcode in the database.
*/
function regcode_user_register_form_submit_handler(array &$form, FormStateInterface $form_state) {
$regcode = $form_state
->getValue('regcode');
$uid = $form_state
->getValue('uid');
if (!empty($regcode) && !empty($uid)) {
$code = regcode_code_consume($regcode, $uid);
if ($code) {
$username = $form_state
->getValue('name');
\Drupal::logger('regcode')
->info(t('The registration code "@code" was used by user @user with UID @uid.', [
'@code' => $regcode,
'@uid' => $uid,
'@user' => $username,
]));
}
else {
\Drupal::logger('regcode')
->error(t('Error checking code @code.', [
'@code' => $code,
]));
}
}
}
/**
* Returns text message requested by given identifier/constant.
*
* @param int $err
* The error message code.
*
* @return string
* The text of the message.
*/
function regcode_errormsg($err) {
$messages = [
REGCODE_VALIDITY_NOTEXISTING => t('Registration code does not exist'),
REGCODE_VALIDITY_NOTAVAILABLE => t('Registration code is not available'),
REGCODE_VALIDITY_TAKEN => t('Registration code has already been used'),
REGCODE_VALIDITY_EXPIRED => t('Registration code has expired'),
];
return isset($messages[$err]) ? $messages[$err] : FALSE;
}
/**
* Loads a registration code.
*
* @param int|null $id
* The database primary key (rid).
* @param array $conditions
* An associative array containing the search conditions.
*
* @return object|bool
* The regcode object or FALSE if the code does not exist.
*
* @example
* regcode_load(1231); // Loads the regcode with rid=1231
* regcode_load(NULL, ['code'=>'foobar']); // Loads the "foobar" regcode
*/
function regcode_load_single($id, $conditions = []) {
// Build the query.
$query = \Drupal::database()
->select('regcode')
->fields('regcode', [
'rid',
'uid',
'created',
'lastused',
'begins',
'expires',
'code',
'is_active',
'maxuses',
'uses',
])
->range(0, 1);
// Allow mixed search parameters.
if (!empty($id)) {
$query
->condition('rid', $id);
}
else {
foreach ($conditions as $field => $value) {
$query
->condition($field, $value);
}
}
// Run the query and grab a single regcode.
$regcode = $query
->execute()
->fetchObject();
if (!$regcode) {
return FALSE;
}
// Entity loaders expect arrays of objects. entity_load() and
// this function both invoke the hook below.
$reg_codes = [
$regcode->rid => $regcode,
];
\Drupal::moduleHandler()
->invokeAll('regcode_load', [
$reg_codes,
]);
return $reg_codes[$regcode->rid];
}
/**
* Validates a regcode.
*
* @param string $regcode
* The regcode alphanumeric code.
*
* @return bool|int|object
* An error code, or the loaded regcode.
*/
function regcode_code_validate($regcode) {
// Load the code.
$code = regcode_load_single(NULL, [
'code' => trim($regcode),
]);
// Check validity.
if ($code === FALSE) {
return REGCODE_VALIDITY_NOTEXISTING;
}
if ($code->uses >= $code->maxuses && $code->maxuses !== '0') {
return REGCODE_VALIDITY_TAKEN;
}
if (!$code->is_active) {
return REGCODE_VALIDITY_NOTAVAILABLE;
}
if (!empty($code->begins) && $code->begins > \Drupal::time()
->getRequestTime()) {
return REGCODE_VALIDITY_NOTAVAILABLE;
}
if (!empty($code->expires) && $code->expires < \Drupal::time()
->getRequestTime()) {
return REGCODE_VALIDITY_EXPIRED;
}
return $code;
}
/**
* Consumes a regcode and attribute it to a user.
*
* @param string $regcode
* The registration code.
* @param int $account_id
* Optional user id to assign the given code to.
*
* @return mixed
* An error code, or TRUE if the code was assigned successfully.
*/
function regcode_code_consume($regcode, $account_id) {
$code = regcode_code_validate($regcode);
// Check the code validated, otherwise return the error code.
if (!is_object($code)) {
return $code;
}
$code->uses++;
// Mark the code inactive if it's used up.
$active = 1;
if ($code->maxuses != 0 && $code->uses >= $code->maxuses) {
$active = 0;
}
// Use the code.
\Drupal::database()
->update('regcode')
->fields([
'uses' => $code->uses,
'lastused' => \Drupal::time()
->getRequestTime(),
'uid' => $account_id,
'is_active' => $active,
])
->condition('rid', $code->rid)
->execute();
// Trigger the regcode_used hook.
$account = \Drupal::service('entity_type.manager')
->getStorage('user')
->load($account_id);
$account->regcode = $code;
foreach (\Drupal::moduleHandler()
->getImplementations('regcode_used') as $module) {
$hook = $module . '_regcode_used';
$hook($code, $account);
}
return $code;
}
/**
* Saves code in the database and calls the regcode_presave hook.
*
* @param object $code
* A code object (required fields are code, begins, expires, is_active, and
* maxuses.
* @param int $action
* Action to perform when saving the code.
*
* @return bool
* The regcode ID if the code was saved. Otherwise FALSE.
*/
function regcode_save($code, $action = REGCODE_MODE_REPLACE) {
// Sanity check.
if (empty($code) || empty($code->code)) {
return FALSE;
}
// Trigger the regcode_save hook.
foreach (\Drupal::moduleHandler()
->getImplementations('regcode_presave') as $module) {
$hook = $module . '_regcode_presave';
$hook($code);
}
// Insert mode.
if ($action == REGCODE_MODE_REPLACE) {
\Drupal::database()
->delete('regcode')
->condition('code', $code->code)
->execute();
}
// Insert.
$rid = \Drupal::database()
->insert('regcode')
->fields([
'created' => \Drupal::time()
->getRequestTime(),
'begins' => empty($code->begins) ? NULL : (int) $code->begins,
'expires' => empty($code->expires) ? NULL : (int) $code->expires,
'code' => Html::escape($code->code),
'is_active' => isset($code->is_active) ? $code->is_active : 1,
'maxuses' => isset($code->maxuses) ? (int) $code->maxuses : 1,
])
->execute();
return $rid;
}
/**
* Deletes regcode codes.
*
* @param int $op
* The operation ID.
*
* @return bool|object|int
* The number of deleted rows or FALSE if nothing happened or TRUE if tables
* were empty.
*/
function regcode_clean($op) {
$result = FALSE;
switch ($op) {
case REGCODE_CLEAN_TRUNCATE:
\Drupal::database()
->truncate('regcode')
->execute();
$result = TRUE;
break;
case REGCODE_CLEAN_EXPIRED:
$result = \Drupal::database()
->delete('regcode')
->condition('expires', \Drupal::time()
->getRequestTime(), '<')
->execute();
break;
case REGCODE_CLEAN_INACTIVE:
$result = \Drupal::database()
->delete('regcode')
->condition('is_active', 0)
->execute();
break;
}
return $result;
}
/**
* Generates a code.
*/
function regcode_generate($length, $output, $case) {
static $seeded = FALSE;
// Possible seeds.
$outputs['alpha'] = 'abcdefghijklmnopqrstuvwqyz';
$outputs['numeric'] = '0123456789';
$outputs['alphanum'] = 'abcdefghijklmnopqrstuvwqyz0123456789';
$outputs['hexadec'] = '0123456789abcdef';
// Choose seed.
if (isset($outputs[$output])) {
$output = $outputs[$output];
}
// Seed generator (only do this once per invocation).
if (!$seeded) {
list($usec, $sec) = explode(' ', microtime());
$seed = (double) $sec + (double) $usec * 100000;
mt_srand($seed);
$seeded = TRUE;
}
// Generate.
$str = '';
$output_count = strlen($output);
for ($i = 0; $length > $i; $i++) {
$str .= $output[mt_rand(0, $output_count - 1)];
}
if ($case) {
$str = strtoupper($str);
}
return $str;
}
/**
* Regcode delete action.
*/
function regcode_delete_action(&$object, $context = []) {
\Drupal::database()
->delete('regcode')
->condition('rid', $object->rid)
->execute();
}
/**
* Regcode activate action.
*/
function regcode_activate_action(&$object, $context = []) {
\Drupal::database()
->update('regcode')
->fields([
'is_active' => 1,
])
->condition('rid', $object->rid)
->execute();
}
/**
* Regcode deactivate action.
*/
function regcode_deactivate_action(&$object, $context = []) {
\Drupal::database()
->update('regcode')
->fields([
'is_active' => 0,
])
->condition('rid', $object->rid)
->execute();
}
/**
* Gets a list of terms from the registration code vocabulary.
*/
function regcode_get_vocab_terms() {
$tree = \Drupal::service('entity_type.manager')
->getStorage("taxonomy_term")
->loadTree(\Drupal::config('regcode.settings')
->get('regcode_vocabulary'));
$terms = [];
foreach ($tree as $term) {
$terms[$term->tid] = $term->name;
}
return $terms;
}
Functions
Name | Description |
---|---|
regcode_activate_action | Regcode activate action. |
regcode_clean | Deletes regcode codes. |
regcode_code_consume | Consumes a regcode and attribute it to a user. |
regcode_code_element_validate | Validates the content of the code-field on user registration. |
regcode_code_validate | Validates a regcode. |
regcode_deactivate_action | Regcode deactivate action. |
regcode_delete_action | Regcode delete action. |
regcode_entity_extra_field_info | Implements hook_entity_extra_field_info(). |
regcode_errormsg | Returns text message requested by given identifier/constant. |
regcode_form_user_register_form_alter | Implements hook_form_FORM_ID_alter() for user_register_form. |
regcode_generate | Generates a code. |
regcode_get_vocab_terms | Gets a list of terms from the registration code vocabulary. |
regcode_help | Implements hook_help(). |
regcode_load_single | Loads a registration code. |
regcode_save | Saves code in the database and calls the regcode_presave hook. |
regcode_user_register_form_submit_handler | Updates data for a regcode in the database. |