I've reached a problem with query the database correctly. I can't find it answered anywhere else.
My datamaodel contains three tables one with the Image data and another with tags.
The third table joins the two tables creting a many to many relationship:
[Image] - 1 --- * ->[ImageTagJoin] <- * --- 1 - [Tag]
From a user input of a set of tags I want to get every image contaning all of the tags. The following code works for one tag
viewModel.Tags = db.Tags.Where(
s =>
s.Name == searchString)
.Include(i => i.Images.Select( ii => ii.Image));
viewModel.Images = t.Images.Select(x => x.Image);
The only solution I have is if, input is tag1, tag2, tag3, the controller iterated over each tag.
Get set of images with the tag tag1
From that set of images of tag1 get the subset of images with tag2
From that set get the subset of images with tag3
Now I have a set of images with the tags tag1, tag2 and tag3. Though that this solution works but not as elegant because it requires to search the database once for every tag and every image row gets looked up for every tag in the input.
Conclusion: How can I query a many-to-many relationship between images and tags, where I select all images that have the subset of n tags given from the user.
Thanks.
With a bit of sweat and time I solved it. What I wanted was a IEnumreble from the database, an data stream not a collection wich is divided over each tag.
Solution:
/*
* tagSet is an array of string with all the tags
*/
viewModel.Tags = db.Tags.Where(
s =>
tagSet.Contains(s.Name))
.Include(i => i.Images.Select(ii => ii.Image));
// a is the image, aa i the users inputted tag, aaa is the tag in the image
viewModel.Images = db.Images.Where( //All images..
a =>
viewModel.Tags.All( //..where every tag the user inputed ..
aa =>
a.Tags.Any(aaa => aaa.Tag.Name == aa.Name) //exist in the image set of tag
)
);
First get a IEumreble with the tags the user inputed from the database. Then for every image that contans the set of all the users inputed tags in the set of tags related to the image. It works as I described it and as I understand it crafts one sql command that then returns the set of images from the database instead of the controller doing the lookup in an ICollection type of lookup.
Related
I am doing some customization for catching gravity form results on form submission. I get feed['meta'] array on form submission. But some fields have merge tag values like '{form_title}'. I need to get real value of the field instead of tokens. Following is the array I get on form submission.
Array
(
[name] => contact_test
[form_id] => 1
[contact_count] => 2
[type] => Contacts
[signature_text_2] => {Name (Prefix):2.2}{Name (Suffix):2.8}
[signature_html_2] => {Name (Suffix):2.8}{Name (Prefix):2.2}
)
I am having issues with last 2 fields where merge tags tokens are present. I need to fetch value of the corresponding fields.
GFCommon::replace_variables() worked for me. Just need to pass the token like {Name (Prefix):2.2}, form object, lead object. Remaining all are format specific options. The function is in gravityforms common.php file.
I have a Drupal content type which contains a number of computed fields. Some (but not all) items are being added to this content type via a cron-triggered RSS feed importer. I'm trying to trigger computed field generation for new items in hook_cron. The following code grabs all items that haven't been tagged as 'submitted', loads and re-saves the node, and then marks the node as 'submitted'.
$query = db_select('node', 'n');
$query->fields('n', array('nid'));
$table_alias = $query->join('field_data_field_submitted', 'r', 'n.nid = r.entity_id AND r.field_submitted_value = 0');
$result = $query->execute();
foreach ($result as $record){
$q = $record->nid;
$n = node_load($q);
node_save($n);
$query = db_update('field_data_field_submitted')
->fields(array('field_submitted_value' => 1))
->condition('entity_id', $q)
->execute();
}
This code works the way I expect it to if I call it from a module-generated page (created using hook_menu with a page callback function). Nodes are resubmitted, and the computed field data is generated. When I put this code in my hook_cron function, the query works, it loops through the records and updates the 'submitted' value, but the computed fields are not computed. I'm confused as to why this would not get triggered in cron. Any help?
Doh! Finally realized that this was completely my own doing. Due to the nature of this content type, where we allow anonymous users to create new content, but explicitly do not trigger the computed fields when they create the content (long story, but short form is that authenticated users then verify & enhance this content, which is where the computed fields come in). So, as I was setting up the initial content, I disabled the computed fields for anonymous users (if $user->uid > 0), and completely forgot about that. Once I tweaked that logic to allow computed fields to be processed on import (triggering it with a field that has a value for the imported content, but not for other content), the problem was solved.
The cron run has access to the full bootstrap so there's no logical reason why your code would produce different results in that context.
That said, you're only updating the field_data_field_submitted table when you also need to update the field_revision_field_submitted table, so that might somehow account for the discrepancy.
Drupal provides an API for the field system so that these sorts of problems can be avoided completely. The same code you've used, rewritten the 'Drupal' way, would be:
$query = new EntityFieldQuery;
$query->entityCondition('entity_type', 'node')
->fieldCondition('field_submitted', 'value', 0);
$results = $query->execute();
if (!empty($results['node'])) {
$nodes = node_load_multiple(array_keys($results['node']));
foreach ($nodes as $node) {
$node->field_submitted[$node->language][0]['value'] = 1;
node_save($node);
}
}
I can't think of a good reason why the above code would fail on cron either so it might be worth giving it a whirl.
I am creating a form where i have to populate "X" form elements (text-fields to be specific) based on values in the database (X number of elements, properties of each element etc). Is there a way to do this using the Drupal Form API or should i start from somewhere else.
I tried using a for() loop in the form generating function but this doesn't work. Please post you suggestions and any related links.
sure you can, just put the #default_value with the value coming from the DB.
$form['text'] = array(
'#type' => 'textfield',
'#default_value' => $db->val,
);
EDIT
say you have a questionnaire object ($questionnaire) that contains a param named "question_list" where you have stored all your questions; what you can do is run a foreach on the list like:
$form['questionnaire'] = array('#type'=>'fieldset','#title'=>$questionnaire->title,);
foreach($questionnaire->question_list as $id=>$question_obj){
$form['questionnaire']['question_'.$id]=array(
'#type'=>'textfield',
'#title'=>$question->question,
'#default_value'=>$form_state['values']['question_'.$id],
);
}
At the end you will have an associative array where each question is identified by 'question_'.$id
I hope this is what you're looking for. :)
I have views 2 installed and I have created a view that is displayed in the front page.
The view displays some page links ( 1 | 2 | 3 | 4 | ... etc). I want to know if it's possible to make the view start at a random page instead of always starting at page 1.
Note: I don't want to randomize the display I really just want to randomize the page it loads.
Thanks
Possible Solution:
In the views_pre_execute hook I used this:
$view->query->pager->set_current_page([random value]);
I am not sure I can determine the number of total pages in the pager at this time but I am going to keep investigating (The $view object given in the hook has tons of properties with arrays and other objects which makes this complicated)
I do not know how to do this from the Views UI, but you should be able to achieve this using one of the views module hooks, in this case probably hook_views_pre_execute. Unfortunately, the documentation for these is practically non existing, so you'd need to implement the hook in a custom module and inspect the passed in view object via the debugger (or print, var_dump, etc. statements).
You should look for $view->pager['current_page'], which you can set to a random page. Unfortunately, if I read the code correctly, the count query that determines the possible number of pages is not yet run at this point, so you'll either have to use a 'best guess', or come up with a different way to determine the proper range to select from...
NOTE: This is in no way meant as an 'authoritative' answer - just a pointer where I'd start looking, since nobody else has answered this so far. I might well be missing a more obvious/easy solution :/
Another option would be to randomize the entries in your views. So your page would always be page 1 but it achieves your objective of seeing something different every time come on your site.
In your sort criteria (in the Global Group) add
Global: Random -- Randomize the display order.
(Inspired by suggestion at http://mydrupal.com/random_node_or_front_page_in_drupal_like_stumbleupon )
I have just created a custom pager that goes automatically to last page and I think it is related to what your are trying to do :
In project.info :
files[] = plugins/views_plugin_pager_last.inc
In project.module :
function cvoxm_views_plugins(){
return array(
'pager' => array(
'last' => array(
'title' => t('Paged output, full pager and last by default'),
'short title' => t('Full & Last'),
'help' => t('Paged output, full Drupal style and last by default'),
'handler' => 'views_plugin_pager_last',
'help topic' => 'pager-last',
'uses options' => TRUE,
),
)
);
}
And the content of plugins/views_plugin_pager_last.inc is :
class views_plugin_pager_last extends views_plugin_pager_full {
function pre_execute(&$query) {
if(!isset($_GET['page'])){ // TODO: Should use pager_id
// Go to last page
$this->set_current_page($this->get_total_items() / $this->get_items_per_page() - 1 );
$this->query(); // Rebuild query
$this->update_page_info(); // Update info
}
}
}
can somebody help me how to customize the search result of a apache solr search. i was only able to access these variables [comment_count] => [created] => [id] => [name] => [nid] => [title] => [type] => [uid] => [url] => [score] => [body].
how can i access other variable like status, vote .... from the index ( i don't want to access the database for retrieving these values, i want to get it from the index itself)
i need to display no of votes for that specific node in the result snippet
i need to understand
1. how to index votes field
2. how to show the vote, status... in result snippet.
Votes are a poor choice for indexing for a couple of reasons:
Votes can change quickly
When a vote is made, the node is not updated. As such, apachesolr won't know to re-index the node to pick up the change.
If by 'status' you mean the node->status value, then the answer is that it will always be 1. Unpublished nodes are never indexed.
Now, if you want to add something else to the index, you want hook_apachesolr_update_index(&$document, $node) - this hook gets called as each node is being indexed, and you can add fields to $document from $node to get the values into the solr index. However, you want to use the pre-defined field prefixes - look at schema.xml to find the list.
Below is example of code to add fields for sorting, and for output.
/**
* Implementation of hook_apachesolr_update_index()
* Here we're adding custom fields to index, so that they available for sorting. To make this work, it's required to re-index content.
*/
function somemodule_apachesolr_update_index(&$document, $node) {
if ($node->type == 'product') {
$document->addField('sm_default_qty', $node->default_qty);
$document->addField('sm_sell_price', $node->sell_price);
$document->addField('sm_model', $node->model);
foreach ($node->field_images AS $image) {
//$imagecached_filepath = imagecache_create_path('product', $image['filepath']);
$document->addField('sm_field_images', $image['filepath']);
}
}
}
/**
* Implementation of hook_apachesolr_modify_query()
* Here we point what additional fields we need to get from solr
*/
function somemodule_apachesolr_modify_query(&$query, &$params, $caller) {
$params['fl'] .= ',sm_default_qty,sm_field_images,sm_sell_price,sm_model';
}
If you want to totally customize output, you should do following:
1) Copy search-results.tpl.php and search-result.tpl.php from /modules/search to your theme's folder.
2) Use the $result object as needed within search-result.tpl.php
3) Don't forget to clear the theme registry by visiting admin/build/themes
Or as mentioned about, you can override using preprocessor hooks.
Regards, Slava
Another option is to create a view(s) of your liking with input argument nid, then create the following preprocess in your template.php file:
function MYTHEME_preprocess_search_result(&$vars) {
$vars['myView'] = views_embed_view('myView', 'default', $vars['result']['node']->nid);
}
Matching the view name 'myView' with the variable name makes sense to me. Then you can use the variable $myView in your search-results.tpl.php file.
Here's a video by the makers of the Solr Search Integration module with an overview on how to customise what nodes and fields are indexed, and what Solr spits out as a search result...
For Drupal 6:
http://sf2010.drupal.org/conference/sessions/apache-solr-search-mastery.html
And Drupal 7:
http://www.acquia.com/resources/acquia-tv/conference/apache-solr-search-mastery
It all looks very customisable!