3

I'm developing a views exposed filter form for searching for items in given geographic locations.

I want to restrict this to a particular country so that cities with the same name in other countries aren't shown in the View results. For example only London, UK not London, Ontario; Portsmouth UK not Portsmouth New Hampshire, USA.

(Note please don't close this topic as being too local - my question would apply to anyone who wants to do this whatever country they are in.)

The simplest approach I want to consider is suffix the user input with the country. For my example this would be Newcastle becomes Newcastle, UK. Given that the site is focused on users in particular country, for user experience (UX) usability reasons I do not want the user to have to enter the country name at the end.

I had tried to add a function to do the suffixing by adding it as a callback in the form[#submit] array in _form_alter and implement the function in my custom module. But this did not alter my submitted input as required. Here is my code snippets:

function mymodule_form_alter(&$form, $form_state, $form_id) {

// keep the standard handler
$temp = $form['#submit'][0];

// put my handler in first
$form['#submit'][0] = '_mymodule_custom_handler_submit';

// restore the standard handler to appear in the array after mine
$form['#submit'][2] = $temp;
}

function _mymodule_custom_handler_submit(&$form, &$form_state) {
    $form['field_geofield_distance']['origin']['#value'] .= ", UK";
}

When I try this I find (using dpm ) that the submitted input is not altered before it gets sent to the View for it to create the results - so I deduce that this code is not running before that, but instead after that.

Can you advise on what I might be doing wrong here?

Also, in the $form['#submit'] array, are the callback functions "chained" together - i.e. in that the first function in the array gets called, it modifies the form submitted input and this is then passed to the next callback. If this were the case I would have expected my code to work.

Is _form_alter the right hook to use for this problem?

Update

Now using debugger (Komodo IDE) connected to my Vagrant VM-based local development environment that's running the site to investigate a solution:

debugging _form_alter

Thanks.

Update 2:

I don't think this form handler approach is going to work, the screenshot below shows a callstack - see bottom right, showing that the views execute display function (presumably the view itself) runs before my code to modify the input

call stack showing views runs before handler

5

First if you want to add submit handler as first in form_alter do

//prepend the handler to array
array_unshift($form['#submit'], '_mymodule_custom_handler_submit');

So you dont overwrite any other callback by some other module.

Second, check that the form input elements dont have overriding submit handlers (" submit action on the buttons")

Third, try to assign the value with form_set_value

$oldValue = $form_state['values']['field_geofield_distance']['origin'];
$value = array('origin' => array('#value' => $oldValue. ', UK')
form_set_value($form['field_geofield_distance'], $value, $form_state);

Syntax above is not correct, but without knowing the structure of the field its impossible to know what kind of array it requires. For example Link module fields can be modified with following.

    // Set first link of the field pointing to google, most likely 
    //unsets all the following ones
  $link = array(
    0 => array(
      'title' => 'Google',
      'url' => 'google.com'
    )
  );
  form_set_value($form['field_link'], $link)), $form_state);

Last but not least, use additional form validation callback instead submit handler, that way its sure that the values get passed to all "targeted(see second)" submit handlers.

Long story short. When form is being built, add input validator to it. Validator will get called after user sends the form and there you can modify values before they get submitted to submit handlers.

Summary interpretating view flow

While the view is being built first time it calls the form (which runs through standard drupal hooks like form_alter) and gets the values from it just in case it has some defaults or accepts 0 filters.

After that it runs the queries, renders the form and the result. When finished you get the view including all the elements without user input. Like clean plate (mayby some contextual filters and stuff is applied but thats irrelevant?).

Next when the user sends the form with custom input, drupal (field widgets/handlers) transforms input to values and store them in $form_state and passes them to validators. Here the custom validator can modify the user input values in $form_state and attach them with form_set_value.

If the validation passes correctly $form_state values(modified) get passed to submit handlers. Most likely views will start building itself from them. Heres more exact flow(pdf)

| improve this answer | |
  • Thanks again - I've looked at this in more depth now. On first your suggestion: this is the same as my suggestion but is a better approach as mine referred to index positions directly but the outcome is the same - my handler function is first. On your second suggestion, I checked (thank you) and according to dpm there aren't any overriding submit handlers. On your third suggestion, thanks for this but I had to make a few typo corrections (see edit), but even after that I got an error about 'values' undefined index in $form_state. – therobyouknow Aug 23 '13 at 10:34
  • I really wish the drupal APIs would display all possible values in an array parameter - in my case $form_state so that I actually see what 'values' should be instead. Ho hum, they don't. So, out I wheel my debugger, Komodo IDE to break on the code and step through... – therobyouknow Aug 23 '13 at 10:36
  • Your 3rd suggestion would not appear to work as there is not an index 'values' in $form_state array - see the bottom left of my debugger screenshot inspecting the variable - see screenshot in update to my question above or here: i.stack.imgur.com/j4QIi.png – therobyouknow Aug 23 '13 at 13:08
  • Values get populated by drupal before validation and carry on to submit handlers, they do not exist before that. form_alter can not be used to modify input. – user20301 Aug 23 '13 at 14:19
  • So where what function/hook should your suggestions go in if it's not _form_alter. My screenshot 2 above (i.stack.imgur.com/Tsghg.png ) shows that the submit handlers are called after the view is built (see call stack on bottom right) so putting the code in submit handlers would never work, surely? – therobyouknow Aug 23 '13 at 14:33
2

There are 2 solutions, depending on what you are trying to do:

  1. For searching in a View of location specific items using geofield: (the specific solution that I was looking for) append ",UK" onto the $location variable in function getSourceValue in geofieldProximityGeocoder.inc in proximity_plugins in views folder of geofield. Notes if interested: This is a hack - it's altering the module code directly, so ideally we'd want to make this override-able in the conventional way - i.e. make the function hook-able so that it can be overridden in a custom module (or theme). I'll try to make a patch for all this. Also written up here: https://drupal.org/node/2070905

  2. Normally, in other exposed filter forms in general, I believe the solution to modify user entered data at the exposed filter would be to use hook_views_query_alter https://api.drupal.org/api/views/views.api.php/function/hook_views_query_alter/7 and modify the required input variable (that came from the user) contained in: exposed_raw_input array. Solutions offered by user20301 in their answer regarding handlers may also work, perhaps also for other behaviour that needs to occur when hitting the submit button. But for my solution I with location I needed something else as here I found that the entered location had already been calculated as I could see the long and lat values in the one of the arrays in the $query variable. So that led me to believe that geofield had already been involved and lo and behold it was.

| improve this answer | |
  • did you wirte that patch in solution #1? I didn;t see it in that thread. I just need to know what line in geofieldProximityGeocoder.inc to modify. I don;t code but I need this hack to get the thing working in the meantime. – Nigel Waters Sep 2 '16 at 0:17
  • Sorry, Nigel, no. My advice would be to see if the issue is still occurring. Perhaps since I worked on this, things have improved to not need my hack. Though I guess you are still seeing the issue, is that the case? – therobyouknow Sep 4 '16 at 10:05
  • Thanks for getting back to me. Unfortunately, the reason I am asking is because the issue is still not resolved in the module. If I can quickly just hack this module to get this working that would be great. I just don;t know what line number to edit to get what I need. I was hoping you could let me know as I am not a coder. – Nigel Waters Sep 5 '16 at 18:09
  • (1/4) @NigelWaters the answer to your question is outlined in point 1 of the my answer above. Sounds like you'd like a little expansion on this as to the detail, here goes: – therobyouknow Sep 9 '16 at 7:26
  • (2/4) The change is to a file in the geofield module. So you'll need to have this module installed on your site to start with. Inside the geofield module folder, open the following file to edit: views/proximity_plugins/geofieldProximityGeocoder.inc and after line 50: $location = (isset($views_plugin->value)) ? $views_plugin->value['origin'] : $views_plugin->options['geofield_proximity_geocoder']; insert line: $location .= ",UK"; I am assuming that the version of the Geofield module you are using is 7.x-2.0 – therobyouknow Sep 9 '16 at 7:26

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.