View source
<?php
if (!defined("NODE_LIMIT_NO_LIMIT")) {
define("NODE_LIMIT_NO_LIMIT", -1);
}
define("NODE_LIMIT_PERM_ADMIN", "administer node limits");
define("NODE_LIMIT_PERM_OVERRIDE", "override node limits");
define("NODE_LIMIT_LIMIT_DOESNT_APPLY", 0);
define("NODE_LIMIT_LIMIT_DOES_APPLY", 1);
define("NODE_LIMIT_LIMIT_NEUTRAL", 2);
function node_limit_permission() {
return array(
NODE_LIMIT_PERM_ADMIN => array(
'title' => t('Administer node limits'),
'description' => t('Allow administrators to change the node limit values'),
),
NODE_LIMIT_PERM_OVERRIDE => array(
'title' => t('Override node limits'),
'description' => t('Allow users to override all node limits'),
),
);
}
function node_limit_admin_paths() {
if (variable_get('node_admin_theme')) {
$paths = array(
'admin/structure/node_limit' => TRUE,
'admin/structure/node_limit/*' => TRUE,
);
return $paths;
}
}
function node_limit_menu() {
$items = array();
$items['admin/structure/node_limit'] = array(
'title' => 'Node Limits',
'page callback' => 'drupal_get_form',
'page arguments' => array(
'node_limit_list_limits',
),
'access arguments' => array(
NODE_LIMIT_PERM_ADMIN,
),
);
$items['admin/structure/node_limit/list'] = array(
'title' => 'List',
'type' => MENU_DEFAULT_LOCAL_TASK,
'access arguments' => array(
NODE_LIMIT_PERM_ADMIN,
),
'weight' => -10,
);
$items['admin/structure/node_limit/add'] = array(
'title' => 'Add Node Limit',
'page callback' => 'drupal_get_form',
'page arguments' => array(
'node_limit_limit_form',
),
'access arguments' => array(
NODE_LIMIT_PERM_ADMIN,
),
'type' => MENU_LOCAL_TASK,
);
$items['admin/structure/node_limit/%node_limit'] = array(
'title' => 'Edit Node Limit',
'page callback' => 'drupal_get_form',
'page arguments' => array(
'node_limit_limit_form',
3,
),
'access arguments' => array(
NODE_LIMIT_PERM_ADMIN,
),
'type' => MENU_LOCAL_TASK,
);
$items['admin/structure/node_limit/%node_limit/delete'] = array(
'title' => 'Delete Node Limit',
'page callback' => 'drupal_get_form',
'page arguments' => array(
'node_limit_delete_form',
3,
),
'access arguments' => array(
NODE_LIMIT_PERM_ADMIN,
),
'type' => MENU_CALLBACK,
);
$items['admin/structure/node_limit/%node_limit/clone'] = array(
'title' => 'Clone Node Limit',
'page callback' => 'node_limit_clone_limit',
'page arguments' => array(
3,
),
'access arguments' => array(
NODE_LIMIT_PERM_ADMIN,
),
'type' => MENU_CALLBACK,
);
$items['admin/structure/node_limit/settings'] = array(
'title' => 'Node Limits settings',
'page callback' => 'drupal_get_form',
'page arguments' => array(
'node_limit_settings_form',
),
'access arguments' => array(
NODE_LIMIT_PERM_ADMIN,
),
'type' => MENU_LOCAL_TASK,
);
return $items;
}
function node_limit_menu_alter(&$items) {
node_type_cache_reset();
foreach (node_type_get_types() as $type) {
$type_url_str = str_replace('_', '-', $type->type);
variable_set('node_limit_' . $type->type . '_access_callback', $items['node/add/' . $type_url_str]['access callback']);
variable_set('node_limit_' . $type->type . '_access_arguments', $items['node/add/' . $type_url_str]['access arguments']);
$items['node/add/' . $type_url_str]['access callback'] = 'node_limit_access';
$items['node/add/' . $type_url_str]['access arguments'] = array(
$type->type,
);
}
$items['node/add']['access callback'] = '_node_limit_add_access';
}
function node_limit_init() {
if (arg(0) == 'node' && arg(1) == 'add' && ($type_url_str = arg(2))) {
$type = str_replace('-', '_', $type_url_str);
if (!node_limit_access($type)) {
$nodetype = node_type_get_type($type);
node_limit_message($nodetype);
}
}
}
function _node_limit_add_access() {
$types = node_type_get_types();
foreach ($types as $type) {
if (node_hook($type->type, 'form') && node_limit_access($type->type, $context = 'node_add')) {
return TRUE;
}
}
if (user_access('administer content types')) {
return TRUE;
}
return FALSE;
}
function node_limit_access($type, $context = '', $account = NULL) {
global $user;
if (empty($account)) {
$account = $user;
}
$access =& drupal_static(__FUNCTION__, array());
if (!array_key_exists($account->uid, $access)) {
$access[$account->uid] = array();
}
if (!array_key_exists($type, $access[$account->uid])) {
$node = new stdClass();
$node->uid = $account->uid;
$node->type = $type;
$oldCallback = variable_get('node_limit_' . $type . '_access_callback');
$oldArguments = variable_get('node_limit_' . $type . '_access_arguments', array());
$oldAccess = function_exists($oldCallback) ? call_user_func_array($oldCallback, $oldArguments) : TRUE;
$access[$account->uid][$type] = !_node_limit_violates_limit($node, $context) && $oldAccess;
}
return $access[$account->uid][$type];
}
function node_limit_theme() {
return array(
'node_limit_list_limits' => array(
'render element' => 'form',
),
);
}
function node_limit_node_prepare($node) {
if (empty($node->nid) && _node_limit_violates_limit($node)) {
$nodetype = node_type_get_type($node);
node_limit_message($nodetype);
$count = 0;
foreach (node_type_get_types() as $type) {
if (node_limit_access($type->name)) {
$count++;
}
}
if ($count > 1) {
drupal_goto('node/add');
}
else {
drupal_goto('');
}
}
}
function node_limit_node_validate($node, $form, &$form_state) {
if (empty($node->nid) && _node_limit_violates_limit($node)) {
$nodetype = node_type_get_type($node);
form_set_error('title', t("You can't create more content of type !type", array(
'!type' => check_plain($nodetype->name),
)), 'error');
}
}
function _node_limit_violates_limit(&$node, $context = '') {
if ($node->uid == 1 || user_access(NODE_LIMIT_PERM_OVERRIDE)) {
return FALSE;
}
$limits = node_limit_limits($node);
foreach ($limits as $idx => $lid) {
$limit = node_limit_load($lid);
if ($limit['nlimit'] == NODE_LIMIT_NO_LIMIT) {
continue;
}
$select = _node_limit_sql($limit['lid']);
$count = $select
->execute()
->fetchField();
if ($count >= $limit['nlimit'] && empty($context)) {
return TRUE;
}
}
return FALSE;
}
function _node_limit_sql($lid) {
$select = db_select('node', 'n');
$select
->addExpression('COUNT(n.nid)', 'number');
module_invoke_all('node_limit_sql', $lid, $select);
return $select;
}
function node_limit_limits(&$node) {
$user = user_load($node->uid);
$query = db_select('node_limit', 'nl')
->fields('nl')
->orderBy('weight', 'ASC')
->execute();
$applicable_limits = array();
foreach ($query as $row) {
$lid = $row->lid;
$applies = TRUE;
$submodule_applies = module_invoke_all('node_limit_applies_in_context', $lid, $node, $user);
foreach ($submodule_applies as $module => $module_applies) {
if ($module_applies == NODE_LIMIT_LIMIT_DOESNT_APPLY) {
$applies = FALSE;
}
}
if ($applies == TRUE) {
$applicable_limits[] = $lid;
}
}
return $applicable_limits;
}
function theme_node_limit_list_limits($variables) {
$form = $variables['form'];
$rows = array();
foreach (element_children($form['limits']) as $key) {
if (isset($form['limits'][$key]['title'])) {
$limit =& $form['limits'][$key];
$row = array();
$row[] = drupal_render($limit['title']);
$row[] = drupal_render($limit['limit']);
if (isset($limit['weight'])) {
$limit['weight']['#attributes']['class'] = array(
'node_limit-weight',
);
$row[] = drupal_render($limit['weight']);
}
$row[] = drupal_render($limit['edit']);
$row[] = drupal_render($limit['list']);
$row[] = drupal_render($limit['clone']);
$rows[] = array(
'data' => $row,
'class' => array(
'draggable',
),
);
}
}
$header = array(
t('Title'),
);
$header[] = t('Limit');
if (isset($form['save'])) {
$header[] = t('Weight');
drupal_add_tabledrag('node_limit', 'order', 'sibling', 'node_limit-weight');
}
$header[] = array(
'data' => t('Actions'),
'colspan' => '3',
);
return theme('table', array(
'header' => $header,
'rows' => $rows,
'empty' => t('No limit available.') . ' ' . drupal_render($form['create']),
'attributes' => array(
'id' => 'node_limit',
),
)) . drupal_render_children($form);
}
function node_limit_list_limits() {
$weights = array();
for ($i = -10; $i <= 10; $i++) {
$weights[$i] = $i;
}
$form = array(
'#tree' => TRUE,
);
$form['limits'] = array();
$query = db_select('node_limit', 'nl')
->fields('nl')
->orderBy('weight', 'ASC')
->execute();
$nlimit = 0;
foreach ($query as $row) {
$nlimit++;
$form['limits'][$row->lid]['weight'] = array(
'#type' => 'weight',
'#default_value' => $row->weight,
);
$form['limits'][$row->lid]['title'] = array(
'#markup' => check_plain($row->title),
);
$form['limits'][$row->lid]['limit'] = array(
'#markup' => check_plain($row->nlimit),
);
$form['limits'][$row->lid]['edit'] = array(
'#type' => 'link',
'#title' => t('Edit'),
'#href' => 'admin/structure/node_limit/' . $row->lid,
);
$form['limits'][$row->lid]['list'] = array(
'#type' => 'link',
'#title' => t('Delete'),
'#href' => 'admin/structure/node_limit/' . $row->lid . '/delete',
);
$form['limits'][$row->lid]['clone'] = array(
'#type' => 'link',
'#title' => t('Clone'),
'#href' => 'admin/structure/node_limit/' . $row->lid . '/clone',
);
}
if ($nlimit > 0) {
$form['save'] = array(
'#type' => 'submit',
'#value' => t('Save Limits'),
);
}
else {
$form['create'] = array(
'#type' => 'link',
'#title' => t('Add a new node limit'),
'#href' => 'admin/structure/node_limit/add',
);
}
return $form;
}
function node_limit_list_limits_submit($form_id, &$form_state) {
foreach ($form_state['values']['limits'] as $lid => $info) {
$query = db_update('node_limit')
->fields(array(
'weight' => $info['weight'],
))
->condition('lid', $lid)
->execute();
}
drupal_set_message(t('Limits saved!'));
}
function node_limit_limit_form($form, &$form_state, $limit = FALSE) {
if (empty($limit)) {
$limit = array(
'lid' => 0,
'title' => '',
'weight' => 0,
'nlimit' => NODE_LIMIT_NO_LIMIT,
);
}
$form = array();
$form['#tree'] = TRUE;
if ($limit['lid'] > 0) {
$form['lid'] = array(
'#type' => 'hidden',
'#value' => $limit['lid'],
);
}
$form['info']['title'] = array(
'#title' => t('Description'),
'#type' => 'textfield',
'#default_value' => $limit['title'],
'#required' => TRUE,
'#description' => t('The description for this Node Limit'),
);
$form['info']['limit'] = array(
'#title' => t('Limit'),
'#type' => 'textfield',
'#default_value' => isset($limit['nlimit']) ? $limit['nlimit'] : NODE_LIMIT_NO_LIMIT,
'#size' => 10,
'#required' => TRUE,
'#description' => t('The number of nodes for this limit. Must be an integer greater than 0 or %nolimit for no limit', array(
'%nolimit' => NODE_LIMIT_NO_LIMIT,
)),
);
$form['info']['weight'] = array(
'#type' => 'hidden',
'#value' => $limit['weight'],
);
$elements = module_invoke_all('node_limit_element', $limit['lid']);
$form['node_limit_elements'] = array();
foreach ($elements as $module => $element) {
$form['node_limit_elements'][$module]['applies'] = array(
'#type' => 'checkbox',
'#title' => check_plain($element['#title']),
'#default_value' => isset($limit[$module]),
);
$element['#title'] = '';
$form['node_limit_elements'][$module]['element'] = $element;
}
if (empty($form['node_limit_elements'])) {
unset($form['node_limit_elements']);
}
$form['save'] = array(
'#type' => 'submit',
'#value' => $limit['lid'] > 0 ? t('Edit Node Limit') : t('Add Node Limit'),
);
return $form;
}
function node_limit_limit_form_validate($form_id, &$form_state) {
if (!is_numeric($form_state['values']['info']['limit'])) {
form_set_error('info][limit', t('Node limits must be an integer'));
}
elseif (intval($form_state['values']['info']['limit']) != floatval($form_state['values']['info']['limit'])) {
form_set_error('info][limit', t('Node limits must be an integer'));
}
elseif (intval($form_state['values']['info']['limit']) < NODE_LIMIT_NO_LIMIT) {
form_set_error('info][limit', t('Node limits cannot be less that %nolimit', array(
'%nolimit' => NODE_LIMIT_NO_LIMIT,
)));
}
if (trim($form_state['values']['info']['title']) == '') {
form_set_error('info][title', t('Invalid Node Limit title'));
}
if (!empty($form_state['values']['node_limit_elements'])) {
foreach ($form_state['values']['node_limit_elements'] as $module => $element) {
if ($element['applies'] === 1) {
$result = module_invoke($module, 'node_limit_element_validate', $element['element']);
if (is_array($result) && isset($result['error'])) {
$path = $module . '][element';
if (isset($result['element'])) {
$path .= '][' . $result['element'];
}
form_set_error('node_limit_elements][' . $path, $result['error']);
}
}
}
}
}
function node_limit_limit_form_submit($form_id, &$form_state) {
if (isset($form_state['values']['lid'])) {
$lid = $form_state['values']['lid'];
}
else {
$lid = _node_limit_next_limit_id();
}
$limit = array();
$limit['lid'] = $lid;
$limit['nlimit'] = intval($form_state['values']['info']['limit']);
$limit['title'] = $form_state['values']['info']['title'];
$limit['weight'] = $form_state['values']['info']['weight'];
if (!empty($form_state['values']['node_limit_elements'])) {
foreach ($form_state['values']['node_limit_elements'] as $module => $element) {
if ($element['applies']) {
$limit[$module] = $element['element'];
}
}
}
node_limit_save($limit);
$form_state['redirect'] = 'admin/structure/node_limit';
drupal_set_message(t('Saved limit "%limit"', array(
'%limit' => $limit['title'],
)));
}
function node_limit_delete_form($form, &$form_state, $limit) {
if ($limit == FALSE) {
drupal_goto('admin/structure/node_limit');
}
$form = array(
'lid' => array(
'#type' => 'hidden',
'#value' => $limit['lid'],
),
);
return confirm_form($form, t('Are you sure you want to delete %name?', array(
'%name' => $limit['title'],
)), 'admin/structure/node_limit');
}
function node_limit_delete_form_submit($form_id, &$form_state) {
$lid = $form_state['values']['lid'];
node_limit_delete($lid);
$form_state['redirect'] = 'admin/structure/node_limit';
}
function node_limit_clone_limit($limit) {
$old_title = $limit['title'];
$limit['lid'] = _node_limit_next_limit_id();
$limit['title'] = t('Clone of !title', array(
'!title' => $old_title,
));
node_limit_save($limit);
drupal_set_message(t('Cloned limit "%limit"', array(
'%limit' => $old_title,
)));
drupal_goto('admin/structure/node_limit');
}
function _node_limit_next_limit_id() {
$select = db_select('node_limit', 'nl');
$select
->addExpression('MAX(lid)+1', 'lid');
$query = $select
->execute();
$next_lid = $query
->fetchField();
return max($next_lid, 1);
}
function node_limit_load($lid) {
if (!is_numeric($lid)) {
return FALSE;
}
$info = db_select('node_limit', 'nl')
->fields('nl')
->condition('lid', $lid)
->execute()
->fetchAssoc();
if ($info['lid'] == $lid && intval($lid) >= 0) {
$res = module_invoke_all('node_limit_load', $lid);
return array_merge($info, $res);
}
else {
return FALSE;
}
}
function node_limit_delete($lids, $silent = FALSE) {
if (!is_array($lids)) {
$lids = array(
$lids,
);
}
if (empty($lids)) {
return;
}
$num = db_delete('node_limit')
->condition('lid', $lids, 'IN')
->execute();
module_invoke_all('node_limit_delete', $lids);
if ($num > 0 && !$silent) {
drupal_set_message(t('Deleted !num.', array(
'!num' => format_plural((int) $num, '1 limit rule', '@count limit rules'),
)));
}
}
function node_limit_save($limit) {
node_limit_delete($limit['lid'], TRUE);
db_insert('node_limit')
->fields(array(
'lid' => $limit['lid'],
'nlimit' => $limit['nlimit'],
'title' => $limit['title'],
'weight' => $limit['weight'],
))
->execute();
$modules = module_implements('node_limit_save');
foreach ($modules as $module) {
$applies = isset($limit[$module]);
$element = $applies ? $limit[$module] : '';
module_invoke($module, 'node_limit_save', $limit['lid'], $applies, $element);
}
}
function node_limit_settings_form($form, &$form_state) {
$types = array();
$content_types = node_type_get_types();
foreach ($content_types as $type) {
$types[$type->type] = $type->name;
}
$form['node_limit_global_msg'] = array(
'#type' => 'textarea',
'#title' => t('Global message'),
'#required' => TRUE,
'#description' => t('Available variables are: [node_limit:type_name], [node_limit:type_title]'),
'#rows' => 2,
'#default_value' => variable_get('node_limit_global_msg', t("You can't create more content of type [node_limit:type_title]")),
);
$form['node_limit_global_redirect'] = array(
'#type' => 'textfield',
'#title' => t('Global redirect path'),
'#default_value' => variable_get('node_limit_global_redirect', NULL),
'#description' => t("Available variables are: [node_limit:type_name], [node_limit:type_title] (Leave empty if you don't need redirect)"),
);
if (!empty($types)) {
$form['node_limit_custom_msg'] = array(
'#type' => 'checkbox',
'#title' => t('Enable custom error message'),
'#default_value' => variable_get('node_limit_custom_msg', NULL),
);
}
foreach ((array) $types as $machine_name => $title) {
$settings = variable_get('node_limit_settings_' . $machine_name);
$form['custom_msg']['node_limit_settings_' . $machine_name] = array(
'#type' => 'fieldset',
'#title' => $title,
'#collapsible' => TRUE,
'#collapsed' => TRUE,
'#tree' => TRUE,
'#states' => array(
'visible' => array(
':input[name="node_limit_custom_msg"]' => array(
'checked' => TRUE,
),
),
),
);
$form['custom_msg']['node_limit_settings_' . $machine_name]['message_' . $machine_name] = array(
'#type' => 'textarea',
'#title' => t('Message'),
'#rows' => 2,
'#default_value' => $settings['message_' . $machine_name],
);
$form['custom_msg']['node_limit_settings_' . $machine_name]['redirect_' . $machine_name] = array(
'#type' => 'textfield',
'#title' => t('Redirect path'),
'#default_value' => $settings['redirect_' . $machine_name],
);
}
return system_settings_form($form);
}
function node_limit_message($nodetype) {
$custom_msg = variable_get('node_limit_custom_msg', NULL);
if ($custom_msg) {
$settings = variable_get('node_limit_settings_' . $nodetype->type);
$redirect_path = $settings['redirect_' . $nodetype->type];
$text = t($settings['message_' . $nodetype->type], array(
'[node_limit:type_title]' => check_plain($nodetype->name),
'[node_limit:type_name]' => $nodetype->type,
));
}
else {
$text = variable_get('node_limit_global_msg', t("You can't create more content of type [node_limit:type_title]"));
$redirect_path = variable_get('node_limit_global_redirect', NULL);
$text = t($text, array(
'[node_limit:type_title]' => check_plain($nodetype->name),
'[node_limit:type_name]' => $nodetype->type,
));
}
drupal_set_message($text, 'error');
if ($redirect_path != NULL) {
drupal_goto($redirect_path);
}
}