8

I am at the point in Drupal experience where I am attempting to solve site design challenges at the custom code level using Drupal and Views APIs. As usual, my apparently simple attempt to solve a problem has demonstrated to me how much I don't know yet!

I have a node-reference field that points to a 'related facts' content used by many different content types and subcategories for each of these types. While I can create a relationship and display the 'related facts' for a view, there are problems. For one, I want the related facts put in a separate block and to display a single list of related facts for the entire list of articles provided by the view. Views does not handle any duplicates for multiple nids with the same 'related facts' reference well. In addition, I would have to generate separate 'related facts' views for each content type and subcategory which will be quite a large number.

If I could create a separate related facts view that can accept a list of nids as an argument, the related facts view could be simplified. So my question is how to go about this. While it may be possible from within views, I am seeking a custom module php solution, so I need to achieve the following:

  1. Extract the results of any of the 'content type' views as a list of arguments. In addition to displaying the view results, I need to load the list of NIDs that are being displayed.

  2. Call the related facts view and pass the list of nids to it to use as a filter or contextual filter in the 'related facts' view.

Additional Information:

Using this strategy I began by defining a view and attempting to extract the results from it. This attempt led to a problem finding the results in the view object (see this question). Once I get the results I will need to generate another view that has those results as filters. I have seen views implemented from code as include files where all the parameters are coded, but have not found examples that define and generate a view and manipulate the results using a php function. Any examples or links would be appreciated.

Thus Far:

Two answers have addressed the process for applying the results of a view and placing it in another view as a contextual filter. But I still face the problem of having dozens of content types with at least a dozen view content pane variations in each. Instead of directly linking each view to the related facts, I will need to have the any of my view1 content views pass its results to a single, separate 'related fact' view.

CONTENT TYPE    SUB-CATEGORY       RELATED FACT (nid)
    Type 1 --------- General Info       101, 105 
                     Specifications     103, 105
                     Inspections        102 
                     Quality  
                     etc...   
   Type 2 ----------General Info       101, 106
                    Specifications     102, 103 
                    Cost factors       107
                    etc... 

View1 finds a specific content type and contains various sub-category articles sorted by the value in a subcategory field. In addition it contains a node reference field for related facts. View one filters for a content type and a subcategory and has exposed fields for display and a hidded field with thte related fact reference nodes.

View2 filters for 'related fact' articles and contains a contextual filter set for nid (although the setting applies to the URL)

Using the code in Letharion's answer, the foreach loop in line 6 is compiling a list of the article ID's, not the related fact id's (the articles hold a reference to related facts, but the related facts do not have a node reference to articles). I need to extract the related fact id's from the facts field in each node. I have included the facts field in the View1 definition, but cannot find the result since the command dpm($node); has been crashing and I don't know where the values are stored in the array.

Since there will be more than one View1 cloned for different content types I thought it may make sense to use hook_views_post_execute and have coded it as follows:

function mymodule_views_post_execute (&$sourceview) {

  $nids = '';
  foreach($sourceview->result as $node) {
    $nids += $node->nid . ',';  //I need field name for $node->facts

  }

  $nids = rtrim($nids, ',');
  $view = views_get_view('get_related');

  //dpm($nids);  // Fatal error: Cannot unset string offsets...

  $view->execute_display('panel_pane_1', array($nids));
  }

Finally, I am not sure if I have to direct the display of the view to the proper location or is this done simply by placing the related facts content pane in the panel location through the Panels UI and let panels theming handle the rest.

  • 2
    Is this Drupal 7? If so I would recommend using EntityFieldQuery to retrieve a list of nodes meeting your criteria. – beth Jun 4 '12 at 20:40
  • Can you point to some example code where this API is used. I am new to the world of Drupal coding and need to follow a real world type example to figure things out. – Ashlar Jun 5 '12 at 20:48
  • drupal.org/node/1343708 is a page called "How to use EntityFieldQueries". – beth Jun 6 '12 at 14:43
3
+100

Just off the top of my head

With views 'get_nids', and 'get_related', get_related taking a nid argument, that is set to accept multiple values. This option is hidden under "more", at the bottom of the configuration window.

Option 1:

$view = views_get_view('get_nids');
// Repeating query, ensure the View is set to cache the results.
$view->preview('display_machine_name', array($arg1, $arg2));

$nids = '';
foreach($view->result as $node) {
  $nids += $node->nid . ',';
}
$nids = rtrim($nids, ',');
$view = views_get_view('get_related');
$view->execute_display('display_machine_name', array($nids));
print $view->render();

Option 2:

Add a "context" display type to get_nids, and pass that context on as the argument to a content pane display of get_related. Unfortunately, I would have to guess that Views contexts lacks support for compressing multiple results into a single context, so that may require a feature request in Ctools.

Option 3:

Beth has an excellent suggestion in a comment, which is using EntityFieldQuery, for when you want a pure code solution, that would also work with MongoDB. Views though has the advantage that most of the work can be done in a UI, which is often convenient.

  • Following the code in views_db_object for the ->execute method(Views.inc line 1060). I do not see anything in the method's code that reads the argument (array($nid)). Also, how do I configure the 'get_related' view to accept the filter values in the array($nids) argument? Do I set filters to 'related content' and contextual filters to accept NIDs? – Ashlar Jun 3 '12 at 20:42
  • Sorry, you are absolutely right, that should have been execute_display, added info about the contextual filter to answer. :) – Letharion Jun 4 '12 at 5:19
  • I added more info to finish up the issue of displaying the content for the related facts in the question. Please see "Thus far". – Ashlar Jun 4 '12 at 16:00
  • Sorry, I don't understand where the problem is. According to your post, the node-reference field is shared among your content types, and as such view 'get_nids' will gather up all the refered entities. If not however, one would need a loop over the first view. – Letharion Jun 4 '12 at 18:08
  • 1
    Hmm! I think I was confused and may be making this more complicated than it needs to be. Thanks – Ashlar Jun 4 '12 at 21:05
2

Seeking out fields within a node and returning a list of NIDs is the exact thing that EntityFieldQueries was born to do. (See also: my own question on the topic).

An example from my code, which runs upon webform submission, and in which I seek out nodes of type "Quiz Anzwer Key" to find the one(s) with field "Quiz Reference" filled in with the NID of the currently-validating webform:

    $arg = arg();
    $nid = $arg[1]; //this finds us the NID of the current page
    $query = new EntityFieldQuery;  // this EntityFieldQuery searches through Entities for Nodes that point to the current Webform.
    $result = $query
        ->entityCondition('entity_type', 'node') // find nodes
        ->propertyCondition('status', 1) // that are published
        ->propertyCondition('type', 'quiz_answer_key')  // of type Quiz Answer Key
        ->fieldCondition('field_answer_quiz', 'nid', $nid, '=') // that point to the current node in their Quiz reference field
        ->execute(); // do the query
    $results        = $query->ordered_results; //grab the results

Then, if you want to actually load values from fields in the nodes, you'd use node_load to grab more info out of the nodes you want, like so:

    $ans_key_id     = $results[0]->entity_id;
    $ans_node       = node_load($ans_key_id);       //once the correct node has been identified, load the contents of that node and suss out the answers 

Now $ans_node is an array (or object, I forget) that contains all the info in all the fields in the node. Voilá!

0

Ok a coded solution (there area few) but here is one:

  1. Create a view that gets all the nid's output these nid's as a comma de-liminated list, you can do this by using fields as your output and setting your style settings to Style Unfomatted, row style fields -> make the nid field inline and use a comma as a separator.
  2. In your module create a function that calls this view and gets the output
  3. Create your second view (or display) use this function as an argument in your second view that actually does the display output, so under arguments the argument should be node:nid, the Action to take should be set to "provide default" and you then use the PHP code setting to call your function: return mymodule_get_nids(); ensure he checkbox "allow multiple terms per argument" is ticked

Step 2 code

function mymodule_get_nids() {
    $view = views_get_view('getmynids')) // View name
        $view->set_display('mynids'); // Display name
        $view->execute();
        if ($view->result) {
         return $view->preview(); // Can't remember if this needs to be echo or return try both.
        }
    }
}

Should this be a separate answer?? or an edit??

  • I am looking for coded solutions. I will clarify the question. – Ashlar Jun 2 '12 at 18:22
  • Please correct me if I'm wrong, but as far as I can tell, this wouldn't even solve the problem, as Ashlar is looking to pull in data from multiple relationships at the same time, while attachments will only the "current" one? (It was a while since I made use of attachments though, so I could be wrong) – Letharion Jun 3 '12 at 17:06
  • Thanks for your effort. I added more info to finish up the issue of displaying the content for the related facts in the question. Please see "Thus far". – Ashlar Jun 4 '12 at 16:01

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.