Updating and deleting data in D7 - drupal-7

I have made a form in D7 using form API, registered some users and retrieved their registered data from database;now what i want is to add an edit and a delete link in front of every row in the retrieved table;i have done that in PHP but how to implement same in Drupal?;anybody having any idea how to do that?
My retrieval code is:
function form_data_menu() {
$items['formdata'] = array(
'title' => 'Form Data',
'page callback' => 'form_data_form',
'access callback' => TRUE,
);
return $items;
}
function form_data_form()
{
$results = db_query('SELECT * FROM {drupal}');
$header = array(t('Id'),t('Name'),t('College'),t('Education'),t('Percentage'),t('Application'));
$rows = array();
foreach($results as $result) {
$rows[] = array(
$result->id,
$result->name,
$result->college,
$result->education,
$result->percentage,
$result->application,
);
}
return theme('table',array('header'=>$header,'rows'=>$rows));
}
I can add links though but the main problem is how to run update and delete queries in D7?
Any help will be appreciated. Thank you!

Start with the example module "dbtng_example.module".
https://www.drupal.org/project/examples
This will give an example of how to set up a module to save to the database. I used this recently to create a custom module to save data to a new database table within drupal. To figure out how to set up the hook_schema, you can look at ".install" files within the drupal core and contributed codebase.
Then to create an edit or delete link, you need to alter your hook_menu to pass in the unique id for that element:
$items['admin/structure/nates-custom-page/update/%'] = array(
'title' => 'Update entry',
'page callback' => 'drupal_get_form',
'page arguments' => array('nates_module_form_update', 5),
'weight' => -5,
'access arguments' => array('administer DFP'),
);
$items['admin/structure/nates-custom-page/delete/%'] = array(
'title' => 'Delete entry',
'page callback' => 'drupal_get_form',
'page arguments' => array('nates_module_form_delete', 5),
'access arguments' => array('administer DFP'),
);
Above is an example where I added the argument (indicated by the percentage sign in the array key, ("%"), that will represent the unique id for that item I want to edit or delete.
Then alter the edit form to load the item you want to edit by the id.
And add a delete form.
Here's an example of a delete form:
function nates_module_form_delete($form, &$form_state) {
$entry = nates_module_entry_load_by_pid(arg(5));
$form = array();
$form['pid'] = array(
'#type' => 'value',
'#value' => arg(5),
);
$output = "";
foreach($entry as $key => $value) {
$output .= "<p><strong>$key</strong>: $value</p>";
}
$form['markup'] = array(
'#type' => 'markup',
'#markup' => $output,
);
return confirm_form(
$form,
t('Are you sure you want to delete this item? '),
'example/list',
t('This action cannot be undone.'),
t('Delete'),
t('Cancel')
);
return $form;
}
Notice I return a confirmation form first.
And here's the submit handler function that processes it after they submit the request:
function nates_module_form_delete_submit($form, &$form_state) {
global $user;
nates_module_entry_delete($form_state['values']['pid']);
drupal_set_message(t("Deleted entry"));
}
Then, edit your listing page to add the edit links and delete links:
function nates_module_list() {
$output = '';
// Get all entries in the dfp_amobee2 table.
if ($entries = nates_module_entry_load_all()) {
$rows = array();
foreach ($entries as $entry) {
// Sanitize the data before handing it off to the theme layer.
$entry->editlink = l('edit','admin/structure/nates-custom-page/update/' . $entry->pid, array('query' => array('destination' => 'admin/structure/nates-custom-page')));
$entry->deletelink = l('delete','admin/structure/nates-custom-page/delete/' . $entry->pid, array('query' => array('destination' => 'admin/structure/nates-custom-page')));
unset($entry->pid);
if(!empty($entry->tid)) {
$entry->alias = l($entry->alias, 'taxonomy/term/'.$entry->tid);
}
else if(isset($entry->pages)) {
if(drupal_valid_path($entry->pages)) {
$entry->alias = l(drupal_lookup_path('alias', $entry->pages),$entry->pages);
} else {
$entry->alias = check_markup($entry->pages);
}
} else {
$entry->alias = "";
}
unset($entry->pages);
if(!$entry->tid) {
$entry->tid = "";
}
$rows[] = (array) $entry;
}
// Make a table for them.
$header = array(t('path'), t('tid'), t('dfp tag machine_name'),t('amobee_as'), '', '');
$output .= '<p>' . t('If the "tid" is filled in, amobee_as will be used on taxonomy pages and on node pages (where the main term id matches). If the path is filled it, will be used on that path. Path supercedes "tid" when there is a conflict.') . '</p>';
$output .= theme('table', array('header' => $header, 'rows' => $rows));
}
else {
drupal_set_message(t('No entries have been added yet.'));
}
return $output;
}

Related

Checkbox values are boolean instead of machine name of menu link in custom module drupal

I am newbie in drupal and i am developing a custom module.Actually i am listing all drupal menu's and their children using fieldset and checkboxes against each menu in a loop.
Here what is i have done so far.
function hide_menu_item_configuration_form($node, &$form_state){
$form = array();
$form['markup'] = array(
'#type'=>'markup',
'#markup'=>t('<p>Select a menu.</p>'),
);
$menus = menu_get_menus($all = TRUE);
foreach ($menus as $key => $value) {
$form['menus'][$value] = array(
'#type'=>'fieldset',
'#title'=>t($value),
'#collapsible' => TRUE,
'#collapsed' => TRUE,
);
$menu_items = menu_load_links($key);
foreach ($menu_items as $key => $values) {
$form['menus'][$value][$values['link_title']] = array(
'#type' => 'checkbox',
'#title' => t($values['link_title']),
'#' => t($values['link_title']),
'#default_value' => 1
);
}
}
$form['config_submit'] = array(
'#type'=>'submit',
'#value'=>'Save configuration',
);
return $form;
}
function hide_menu_item_configuration_form_submit(&$form, &$form_state) {
//here i see values
dsm($form_state);
}
Now what the problem is that on form submit,i am getting boolean value against each menu link like 0 or 1 .In this case,i can't gues which link was checked or not.Because of 0 or 1 which doesn't indicate anything.But i want to get menu machine name and link machine name.
I am stuck here.
Can you please guys help or suggest me some other way to complete this thing?
Please help.
pls changes your code first build the options array using the foreach loop you are running
$options = array();
$menu_items = menu_load_links($key);
foreach ($menu_items as $key => $values) {
$options[$values['link_title']] = $values['link_title'];
}
$form['name']=array(
'#type'=>'checkbox',
'#title'=>'any title',
'#description' => 'any Description',
'#options' => $options,
);

Math drupal module

I'm trying to learn to write drupal modules and am working on writing a simple math module http://nodeone.se/en/the-math-question-module
I've got the GUI down fine but seem to be having issues with the actual math. I never seem to get the correct answer because I think it loads a new set of questions before it checks the current answer.
Here's what I have so far:
<?php
/**
* #file
* Tests users on their math skills through a series of question and answers
*/
/**
* Implements hook_menu().
*/
function math_question_menu() {
// add new navigation menu item
$items['math_question'] = array(
'title' => 'Math questions',
'description' => 'Test you math skills with these questions.',
'page callback' => 'drupal_get_form',
'page arguments' => array('math_question_page'),
'access callback' => 'user_access',
'access arguments' => array('administer_site_configuration'),
);
return $items;
}
$val1 = rand(1,10);
$val2 = rand(1,10);
variable_set('val1', $val1);
variable_set('val2', $val2);
/**
* Builds the form for configuring Math Questions.
*/
function math_question_page() {
global $user;
$num1 = variable_get('val1');
$num2 = variable_get('val2');
$total = $num1 + $num2;
variable_set('total',$total);
$form['math_question'] = array(
'#type' => 'item',
'#markup' => 'What is ' . $num1 . ' + ' . $num2 . ', ' .
check_plain($user->name) . '?',
);
$form['answer'] = array(
'#type' => 'textfield',
'#title' => t('Answer'),
);
$form['submit'] = array(
'#type' => 'submit',
'#value' => t('Check my answer'),
);
return $form;
}
function math_question_page_validate($form, $form_state) {
if (empty($form['answer']['#value'])) {
form_error($form['answer'], t('This field is required.'));
}
if ($form['answer']['#value'] ==
variable_get('total')) {
$msg = t('Good job!');
$type = 'status';
}
else {
$msg = t('Try again...');
$type = 'error';
}
drupal_set_message(check_plain($msg), $type);
}
modified code:
.
.
/**
* Builds the form for configuring Math Questions.
*/
function math_question_page() {
global $user;
$val1 = rand(1,10);
$val2 = rand(1,10);
$total = $val1 + $val2;
$form['math_question'] = array(
'#type' => 'item',
'#markup' => 'What is ' . $val1 . ' + ' . $val2 . ', ' .
check_plain($user->name) . '?',
);
$form['answer'] = array(
'#type' => 'textfield',
'#title' => t('Answer'),
);
$form['total'] = array(
'#type' => 'hidden',
'#value' => $total,
);
$form['submit'] = array(
'#type' => 'submit',
'#value' => t('Check my answer'),
);
return $form;
}
function math_question_page_validate($form, $form_state) {
if (empty($form['answer']['#value'])) {
form_error($form['answer'], t('This field is required.'));
}
if ($form['answer']['#value'] ==
$form['total']['#value']) {
$msg = t('Good job!');
$type = 'status';
}
else {
$msg = t('Try again...');
$type = 'error';
}
drupal_set_message(check_plain($msg), $type);
}
In the validation function math_question_page_validate(), you should access the values from $form_state variable, not from $form.
eg:
if (!$form_state['values']['answer'] == $form_state['values']['total']) {
form_set_error('answer', $error);
}
You can also store the answer in $form_state variable to pass it to the validation function (no need to store the value in $form). if you store it as $form_state['total'], you can access it in the same way (given below).
if (!$form_state['total'] == $form_state['values']['answer']) {form_set_error('answer', $error);}
Thank you very much papirrin for teaching this.
I suggest to use variable_get() to keep the correct answer safe. The random value you keep in the form will not survive the form regeneration.
My working code here.
/**
* Builds the form for configuring Math Questions.
*/
function math_question_page($form, &$form_state) {
global $user;
$val1 = rand(1,10);
$val2 = rand(1,10);
$total = $val1 + $val2;
// Store the correct answer safely away from this form
if (!variable_get('math_question_answer',FALSE)) {
variable_set('math_question_answer', $total);
}
$form['math_question'] = array(
'#type' => 'item',
'#markup' => 'What is ' . $val1 . ' + ' . $val2 . ', ' .
check_plain($user->name) . '?',
);
$form['answer'] = array(
'#type' => 'textfield',
'#title' => t('Answer'),
);
$form['submit'] = array(
'#type' => 'submit',
'#value' => t('Check my answer'),
);
$form_state['redirect'] = FALSE;
return $form;
}
function math_question_page_submit($form, &$form_state) {
if (empty($form['answer']['#value'])) {
form_set_error('answer', t('This field is required.'));
}
else {
if ($form_state['values']['answer'] == variable_get('math_question_answer')) {
$msg = t('Good job!');
$type = 'status';
}
else {
$msg = t('Try again...');
$type = 'error';
}
drupal_set_message(check_plain($msg), $type);
}
variable_del('math_question_answer');
}
Drupal redirects after form submission so your form fields (altogether with your form) are recreated before the validation is called. See details about that in another question.
Your form is created with math_question_page, which does not take any form_state arguments. If you had form_state, then you could detect that math_question_page has not been submitted yet and just keep the state of the last call (last random values).
In order to call math_question_page with a form_state argument, you can use drupal_build_form instead of drupal_get_form in your menu.
Instead of storing the $total in the global variable 'total', try storing it as a hidden field on your form (unless you are worried about your users cheating). You can write:
'#type' => 'hidden,
to create a hidden 'total' field and then check for that value in validate so prevent total to be overwritten.
I am learning to write drupal modules too (Started the tutorial series 2 weeks ago).
I tried to do this same module , and i think that the implementation which saves the random values in the database is NOT correct. The first thing asked in the exercise is this :
Any user visiting the /question path will get a simple add-two-numbers question, such as "What is 4 + 9?".
So acces arguments for the page should be 'access arguments' => array('access content') not 'access arguments' => array('administer_site_configuration').
This comes with the following issue : If there are 2 (or more) users browsing at the same moment this page , the latest user overwrites the values in the database , so the other users won't be able to complete the "question" because his answer will not be equal to the answer in the database. Saving values to database is NOT a option in this case...
Meantime I am trying to make it work without the database , but i have the same situation as this question's starter , the form overwrites the values when i submit it (so , error thrown because the answer is wrong ).
If i'll manage to complete it i'll post the code here , or if someone else managed to complete it without variable_set() and variable_get() , i ask them to post the code here :)

Custom Field with autcomplete

I am trying to build my own node reference custom field - I know several projects out there already do this, I am building this in order to learn... :)
My problem is the autocomplete path, it's not being triggered, I have checked the noderefcreate project and implemented my solution based on that project. But still; nothing is being triggered when I check firebug.
Here is my code:
function nodereference_field_widget_info() {
return array(
'nodereference_nodereference_form' => array(
'label' => t('Node Reference Form'),
'field types' => array('nodereference'),
'behaviors' => array(
'multiple values' => FIELD_BEHAVIOR_DEFAULT,
'default value' => FIELD_BEHAVIOR_DEFAULT,
),
'settings' => array(
'autocomplete_match' => 'contains',
'autocomplete_path' => 'nodereference/autocomplete',
),
),
);
}
function nodereference_field_widget_form(&$form, &$form_state, $field, $instance, $langcode, $items, $delta, $element) {
if ($instance['widget']['type'] == 'nodereference_nodereference_form') {
$widget = $instance['widget'];
$settings = $widget['settings'];
$element += array(
'#type' => 'textfield',
'#default_value' => isset($items[$delta]['nid']) ? $items[$delta]['nid'] : NULL,
'#autocomplete_path' => $instance['widget']['settings']['autocomplete_path'],
);
}
return array('nid' => $element);
}
You need to define method from where auto compete will take suggestions.
It can be done like this:
/**
* implements hook_menu
*/
function your_module_name_menu() {
$items['master_place/autocomplete'] = array(
'page callback' => '_your_module_name_autocomplete',
'access arguments' => array('access example autocomplete'),
'type' => MENU_CALLBACK
);
return $items;
}
/**
* Auto complete method implementation
* #param $string
*/
function _your_module_name_autocomplete($string) {
$matches = array();
// Some fantasy DB table which holds cities
$query = db_select('target_db_table', 'c');
// Select rows that match the string
$return = $query
->fields('c', array('target_column'))
->condition('c.target_column', '%' . db_like($string) . '%', 'LIKE')
->range(0, 10)
->execute();
// add matches to $matches
foreach ($return as $row) {
$matches[$row->city] = check_plain($row->city);
}
// return for JS
drupal_json_output($matches);
}

Populating #options, #header for tableselect in ajax callback function

What I am trying to do is display a table with checkboxes on the press of a button by ajax. The table should be initially hidden and get populated on the fly by a function call.
If initially I load $options1 with some dummy values , then after ajax call it throws in an error saying-
Notice: Undefined index: red in theme_tableselect() (line 3285 of
D:\wamp\www\drupal7\includes\form.inc).
where 'red' is the index of a dummy row value and #options don't get populated with the new values. What is the way to get this working ?
Here is the code for the form-
$form['mltag_new']['tag'] = array(
'#type' => 'button',
'#value' => t("Suggest Tags"),
'#ajax' => array(
'callback' => 'mltag_suggest_tags_ajax',
'wrapper' => 'mltag_suggest_tags_table_div',
'effect' => 'slide',
),
);
$options1 = array(); //initial dummy values
$options1['red']['tag'] = "A red row";
$options1['red']['chi'] = "A red row";
$form['mltag_new']['myselector'] = array (
'#type' => 'tableselect',
'#title' => 'My Selector',
'#header' => $header,
'#options' => $options1,
'#prefix' => '<div id="mltag_suggest_tags_table_div">',
'#suffix' => '</div>',
);
return $form;
and the Ajax callback looks something like this-
function mltag_suggest_tags_ajax($form, $form_state) {
//$content has some content
//pass the content to a function
include_once 'includes/content_tag.inc';
$tags = mltag_content_tag($content, variable_get('algo_type'), 20);
if (empty($tags)) {
$output .= t('Content is insufficient to generate Tags using this algorithm. <br>Please choose other algorithm from Settings Page.');
$form['mltag_new']['sample_text']['#markup'] = $output;
return $form['mltag_new']['sample_text'];
}
else {
$algo = variable_get('algo_type');
if ($algo == 1) {
$header = array(
'tag' => t('Tag'),
'frequency' => t('Frequency'),
);
$options = array();
foreach ($tags as $key => $value) {
$options[$key] = array(
'tag' => $key,
'frequency' => $value,
);
}
}
elseif ($algo == 2) {
$header = array(
'tag' => t('Tag'),
'chi' => t('Chi Square Value'),
);
$options = array();
foreach ($tags as $key => $value) {
$options[$key] = array(
'tag' => $key,
'chi' => $value,
);
}
}
$form['mltag_new']['myselector']['#header'] = $header;
$form['mltag_new']['myselector']['#options'] = $options;
return $form['mltag_new']['myselector'];
}
}
I replied to your post on Drupal.org about how I'm working on a somewhat similar problem. Try adding
$form['mltag_new']['myselector'] =
form_process_tableselect($form['mltag_new']['myselector']);
just before your return. Hopefully that helps you more than it did me. Beware that the #options just get rendered when the block reloads from the ajax, but the original $form object doesn't seem to be aware.
I know that this is a few years later, but I found this while searching for my own solution:
The tableselect module creates checkboxes in the $ form that have to be removed. in the example above, they would be in $form['mltag_new']['myselector'] with keys equal to the original $option1 in your original code. If you unset those, then call
$form['mltag_new']['myselector'] = form_process_tableselect($form['mltag_new']['myselector']);
before your return, it will eliminate the dummy rows.

Can I create a Drupal autocomplete textfield in a block?

I want to create an auto-complete form in my custom module that will be loaded in a block. Drupal doesn't seem to be loading the necessary Javascript libraries to work properly. How do I know what needs to be loaded and how/where do I tell Drupal to load these libraries?
hook_block_view:
function my_module_block_view($delta = '') {
//The $delta parameter tells us which block is being reqested.
switch ($delta) {
case 'my_module_my_block':
$block['subject'] = t('Block Subject');
$block['content'] = drupal_get_form('my_module_my_form');
break;
}
return $block;
}
Form code:
function my_module_my_form($form, &$form_state) {
$form = array();
$form['term'] = array(
'#type' => 'textfield',
'#autocomplete_path' => 'my-module-autocomplete'
);
$form['submit'] = array(
'#type' => 'submit',
'#value' => 'Add',
);
return $form;
}
The form loads, the field is there, but auto-complete isn't working :(
If I call the my-module-autocomplete path I do get a valid response back when compared with a Content Type edit form. The ajax spinner in the input field never appears so the ajax isn't being called. Realistically all I want is the autocomplete field...the submit will be handled manually.
It's probably because you're reseting $form to an empty array at the beginning of the function. In Drupal 7 there's a bunch of stuff added to that element before it's passed through to your form function (that's why $form is passed to your function whereas in Drupal 6 it wasn't).
Just remove $form = array(); and it should work, other than that your code looks perfect.
the following should work;
function mymodule_block_info() {
$blocks['mymodule'] = array(
// The name that will appear in the block list.
'info' => t('My Module'),
// Default setting.
'cache' => DRUPAL_NO_CACHE,
);
return $blocks;
}
function mymodule_block_view($delta = ''){
switch($delta){
case 'mymodule':
if(user_access('access content')){ //good idea to check user perms here
$block['subject'] = t('My Module');
$block['content'] = 'Hi :)';
$block['content'] = drupal_get_form('mymodule_form');
return $block;
}
break;
}
}
function mydmodule_menu() {
$items['module/autocomplete'] = array(
'page callback' => 'mymodule_autocomplete',
'access arguments' => array('access content'),
'type' => MENU_CALLBACK
);
return $items;
}
function mymodule_form($form, &$form_state) {
$form['greenentry'] = array(
'#type' => 'textfield',
'#title' => t('Enter'),
'#autocomplete_path' => 'mymodule/autocomplete',
);
$form['submit'] = array(
'#type' => 'submit',
'#value' => t('Submit'),
);
return $form;
}
function mymodule_autocomplete($string) {
$matches = array();
// Some fantasy DB table which holds cities
$query = db_select('cities', 'c');
// Select rows that match the string
$return = $query
->fields('c', array('city'))
->condition('c.city', '%' . db_like($string) . '%', 'LIKE')
->range(0, 10)
->execute();
// add matches to $matches
foreach ($return as $row) {
$matches[$row->url] = check_plain($row->url);
}
// return for JS
drupal_json_output($matches);
}
this code is so pretty to add an auto-complete filed in block. But i just found a tiny notice here. if someone get an error
An ajax error occurred. http result code 200
then just add
exit();
after the line
drupal_json_output($matches);
hence fix the issue.

Resources