Drupal: another way to fetch the taxonomy tid (apart from URL) - drupal-7

I am using webforms which have as the topic taxonomy terms saved as hidden fields.
Unfortunate, after attaching files using Upload button this terms are lost ('No category'), as ajax is altering the form #action URL from /tid to /file/ajax/submitted/file4/form-gTwVpNbQRszArGEUS1OfuwA8WgSLJOlcWGOuS6r9D5A
From where to read $tid?
Therefore my $tid fail to load from URL
function MYMODULE_form_alter(&$form, &$form_state, $form_id) {
$tid = arg(1);
$term = taxonomy_term_load($tid);
if (!empty($term)) {
$category = i18n_taxonomy_term_name($term, $language->language);
} else {
$category = 'No category';
}
$form['submitted'][$category_fieldkey] = array(
'#type' => 'hidden',
'#value' => $category,
);
}

Related

Updating and deleting data in D7

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;
}

CakePHP: how work the cache groups?

I'm trying to use the cache groups, but the examples in the documentation are not very clear for me.
This is my bootstrap:
Cache::config('default', array(
'engine' => $engine,
'duration' => $duration,
'prefix' => $prefix,
'groups' => array('page', 'photo', 'post')
));
We suppose that I have the model, including articles, pages, photos, etc., and in the various actions the data is written to the cache.
For example, PagesController:
public function index() {
$pages = Cache::read($cache = 'pages_index');
if(empty($pages)) {
$pages = $this->Page->find('all');
Cache::write($cache, $pages);
}
$this->set(array(
'pages' => $pages
));
}
This creates the file
tmp/cache/pages_index
The cache is working correctly, the next request will use the cache.
Others actions write the data for the Page model page.
Again PagesController:
public function view($slug = NULL) {
$page = Cache::read($cache = sprintf('pages_view_%s', $slug));
//If the data are not available from the cache
if(empty($page)) {
$page = $this->Page->find('first', array(
'conditions' => array('slug' => $slug)
));
if(empty($page))
throw new NotFoundException(__('Invalid page'));
Cache::write($cache, $page);
}
$this->set(array(
'page' => $page
));
}
This also works correctly.
Now I wish that editing a page being deleted from the cache all the data about pages. The same should happen for the other models (posts, photos, etc).
So, in my Page model:
public function afterSave($created, $options = array()) {
Cache::clearGroup('pages');
}
But this does not work: no files are deleted from the cache.
Where am I doing wrong? What I do not understand?
Thanks!
Because Your group name is 'page', not 'pages'.

Events and Full Calendar in CakePHP

I set the FullCalendar plugin in CakePHP, i can see it, it's displayed, i'm trying to put the events from my PHP Controller (the view admin feed) to my Full Calendar Plugin . I don't know what's wrong , no events are displayed in my calendar . I will be thankfull if someone can find why my calandar is empty .
Look the screen, this is what i have in my console :
The answer is NULL .
The JS file :
// JavaScript Document
$(document).ready(function() {
$('#calendar').fullCalendar({
header: {
left: 'prev,next today',
center: 'title',
right: 'month,agendaWeek,agendaDay'
},
defaultView: 'agendaWeek',
firstHour: 8,
weekMode: 'variable',
aspectRatio: 2,
editable: true,
events: {
url: FcRoot + '/events/feed',
color: 'yellow', // an option!
textColor: 'black', // an option!
},
eventRender: function(event, element) {
///
}
});
});
EventsController
// The feed action is called from JS to get the list of events (JSON)
public function admin_feed($id=null) {
$this->layout = "ajax";
$vars = $this->params['url'];
$conditions = array('conditions' => array('UNIX_TIMESTAMP(start) >=' => $vars['start'], 'UNIX_TIMESTAMP(start) <=' => $vars['end']));
$events = $this->Event->find('all', $conditions);
foreach($events as $event) {
if($event['Event']['all_day'] == 1) {
$allday = true;
$end = $event['Event']['start'];
} else {
$allday = false;
$end = $event['Event']['end'];
}
$data[] = array(
'id' => $event['Event']['id'],
'title'=>$event['Event']['title'],
'start'=>$event['Event']['start'],
'end' => $end
);
}
$this->set("json", json_encode($data));
}
In View/Events/admin_feed
<?php
echo $json;
?>
The response now :
You should really take advantage of routing and views for this. It allows you to properly organize your code and keep things DRY.
public function admin_feed($id=null) {
$vars = $this->params['url'];
$conditions = array('conditions' => array('UNIX_TIMESTAMP(start) >=' => $vars['start'], 'UNIX_TIMESTAMP(start) <=' => $vars['end']));
$events = $this->Event->find('all', $conditions);
foreach($events as $event) {
if($event['Event']['all_day'] == 1) {
$allday = true;
$end = $event['Event']['start'];
} else {
$allday = false;
$end = $event['Event']['end'];
}
$data[] = array(
'id' => $event['Event']['id'],
'title'=>$event['Event']['title'],
'start'=>$event['Event']['start'],
'end' => $end
);
}
$this->set("events", $data);
}
Now, your admin_feed action is usable as more than just a json feed (even though that may be just want you want). This makes testing easier as well.
Add the following to your routes, to tell Cake that you want to allow the json extension:
Router::parseExtensions('json');
Then, add the RequestHandler to your controller components. This component will automatically switch to your json view and layout when a json extension is found.
Next, add a layout for all json views in /View/Layout/json/default.ctp:
<?php
echo $this->fetch('content');
Then, add your view in /View/Events/json/admin_feed.ctp:
<?php
echo json_encode($events);
That's it. Now, if you want to use admin_feed to view events in HTML, you can by adding a view for it.
Your full calendar url should now be: FcRoot + '/admin/events/feed.json'. Try just visiting it in the browser to see if you see the json.
do not set it, just echo it
echo json_encode($data);
set values are supposed to be used in view, in your case you are just 'returning' as ajax response
for ajax calls, view is not necessary at all, put $this->autoRender = false; in you function: this will prevent 'seeking' for view file.

Check for existing controller

I've written static pages component for my application, where admins can dynamically add/edit/remove static content pages. these are saved in the database.
(e.g. you can create a page called "about" and can visit it at myapplication/about)
This is my routing for these pages:
$page = new StaticPage();
$slugs = $page->find('list', array(
'fields' => array('slug'),
'recursive' => -1,
'order' => 'StaticPage.slug DESC',
));
Router::connect('/:slug',
array('controller' => 'static_pages', 'action' => 'display'),
array(
'pass' => array('slug'),
'slug' => implode($slugs, '|')
)
);
Now i have the problem, that when you create a page which slug matches an existing controller (e.g. users), it overwrites the Route to the UsersController.
so i need something like a blacklist or similar: i began to write a validation rule, where i want to check if that controller exists. for cake 1.3 there was a function "loadController" which return false, if the controller did not exist, but for cake 2.x there is no such an function. am i missing this somehow? does it have a new name or is in a utility library now?
Or are there better ways to solve this?
you should try this : http://www.cleverweb.nl/cakephp/list-all-controllers-in-cakephp-2/
and by getting the list of all controllers you can easily exclude the name of controllers
This is my validation method for now:
$route = Router::parse($check['slug']);
$controllerName = Inflector::camelize($route['controller'] . 'Controller');
$aCtrlClasses = App::objects('controller');
foreach ($aCtrlClasses as $controller) {
if ($controller != 'AppController') {
// Load the controller
App::import('Controller', str_replace('Controller', '', $controller));
// Load the ApplicationController (if there is one)
App::import('Controller', 'AppController');
$controllers[] = $controller;
}
}
if (in_array($controllerName, $controllers)) {
return false;
} else {
return true;
}

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