0

I have a custom search form, made with Drupal Form API. It uses ajax, autocomplete, and some other properties defined in the built $form.

I use the data sent from the form to feed a views_embed_view call, and in the View I have defined some contextual filters, for each and every of the input boxes.

The problem is that Contextual filters do not apparently support the operator LIKE for several word or partial word matches, so the search is very restricted. Even putting Search field instead of Content field does not solve the problem completely.

If I use Exposed filters instead of Contextual filters, I don't know how to modify the input boxes to get all the functionality I already have. Maybe with hook_form_alter, but even so I do not know what to do with the sent data (it needs further PHP processing, this is why it was so convenient with Contextual filters).

I also found this piece of code I had already used (but forgotten), but I don't find the solution elegant (even if it works - it is taken from a different Drupal Answers question and adapted. It modifies the Contextual filter query and includes the LIKE operator):

function mymodule_views_query_alter(&$view, &$query) {
if( $view->name == "products_list" ){
    foreach($query->where as $key => $val) {
        $field = $val['conditions'][0]['field'];
        $operator = $val['conditions'][0]['operator'];
        $value = $val['conditions'][0]['value'];
        if(( $field == 'field_data_field_field_rf_producto.field_field_producto_value' || $field == "field_data_field_descripcion_producto.field_descripcion_producto_value") && $operator == '=') {
            $query->where[$key]['conditions'][0]['operator'] = 'LIKE';
            $query->where[$key]['conditions'][0]['value'] = '%' . $value . '%';
        } // if
    } // foreach
  } // if
} // function
4
  • So in essence your question is: "How do I use LIKE queries with multiple arguments and OR concatenation on Views contextual filters"? Commented Oct 7, 2015 at 7:35
  • No, I didn't expressed correctly. I solved the problem with the hook_views_query_alterand apparently works perfectly. The problem is that I am starting to think that the full approach is wrong. For example, the Fuzzy Search module requires the filters to be exposed filters, not Contextual. So I am thinking that my approach beginning with a custom Form is, indeed, ill-fated.
    – Cesar
    Commented Oct 7, 2015 at 7:41
  • Not necessarily. Also keep in mind that filter criteria don't have to be exposed. You could e.g. load the view without initializing it, then change the filter configuration to your desired settings, then initialize and execute it. Commented Oct 7, 2015 at 7:47
  • Yes, that is an approach. However, I started the project with Exposed filters, and when I needed to put Autocomplete, etc., went back to views_embed_view. But with using hook_views_query_alter problem is that I don't know how to further implement the search capabilities. For example, splitting the query into words, and adding OR conditions for each word, so the order of words do not matter. I think it may be done modifying a little the code snippet above. If I got that, I can forget til my contractor demands fuzzy search, in such case I will be lost.
    – Cesar
    Commented Oct 7, 2015 at 7:55

2 Answers 2

1

You can programmatically change the filter configuration before executing the view:

$view_name    = 'my_view_name';
$display_name = 'my_display_name';
$handler_name = 'title';
$terms        = array('foo', 'bar');

$view = views_get_view($view_name);
$view->set_display($display_name);

$handler = $view->display_handler->get_handler('filter', $handler_name);
$handler->value = implode(' ', $terms);

$output = $view->preview();

This will work even without exposing the filter.

3
  • Thank you very much! This approach finally allows me to use Filter instead of Contextual filter, so the Contains ( ´LIKE´ ) can be included by default. Also I have the freedom of processing and arranging $terms of search to fit my needs. What would be other conveniences of $view->preview versus views_embed_view? I have always used the last one and had discarded the previous one, but cannot remember why.
    – Cesar
    Commented Oct 7, 2015 at 10:05
  • The difference is that the above approach allows you to alter the view configuration before executing the view. views_embed_view() encapsulates the logic, providing only the means to pass in arguments for your contextual filters. I'd suggest you take a look at the function body of views_embed_view() to better understand what it does. Commented Oct 7, 2015 at 10:10
  • Yes, it seems that I was at a higher level than desired, in fact, the function uses $view->preview. Instead of using Contextual filter and altering the SQL query, which is horrible for a Search term, I have used your approach, and using a Filter with Search term, and "Contains all words", I get all the functionalities I wanted. Thanks a lot. As for fuzzy search, I will try to see if, now, with this approach, I can accomodate better to the requeriments of modules like Fuzzy Search.
    – Cesar
    Commented Oct 7, 2015 at 10:56
0

I would like to share my piece of code for implementing the idea proposed by user ciss, which has not been straightforward but more than a nightmare - my fault, and possible it can be solved much more easily.

First, I write, in the template, function template_preprocess_page :

$view = views_get_view($view_name);
$output = $view->preview();

Now, and here lies the nightmare, in order to make each Filter defined in the View not to block the list of results, I had to write the following:

function hook_views_pre_view  ( &$view, &$display_id, &$args) {
  if($view->name == "SEARCH_ADVANCED_VIEW"){

    $terms = array('2001');
    $terms2 = array('sport', 'shoe', 'orange');

    $view->set_display("block");

    $array_filters = $view->display_handler->get_option('filters');

    /* if I want to delete filter product_value
       and only keep filter `title` */

    unset($array_filters['field_product_value']);

    $view->display_handler->override_option('filters', $array_filters);


    $handler_name = 'title'; ;
    $handler = $view->display_handler->get_handler('filter', $handler_name);
    $handler->value = implode(' ', $terms);


  } // if
} // function

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

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