Drupal 7.x & Views: Modifying a DatabaseCondition?

I’ve created my own custom module called “foobar_module” and in it, I’m trying to override an AJAX-driven exposed filter value that expects user target_ids. The reason I’m trying to do this is because I’m modifying the exposed filter to allow users to filter actual human names instead of target_ids of users.

To do all this, I’ve used HOOK_views_query_alter(&$view, &$query). It gives me access to everything I need except the
following object:

$query->where[1]['conditions'][3]['field']->conditions

…which turns out to be protected.

From what I can tell from other developers who experienced the same situation, they used &DatabaseCondition::conditions() to access the protected data structure. I tried to do this against my $query variable
like so:

$blah = $query->conditions();
dpm($blah);

…and with…

$blah = $query->where[1]['conditions'][3]['field']->conditions->conditions();
dpm($blah);

…both of which generate the following error:

An AJAX HTTP error occurred. HTTP Result Code: 200 Debugging
information follows. Path: /projects/foobar/views/ajax StatusText: OK
ResponseText: Fatal error: Cannot access protected property
DatabaseCondition::$conditions in
C:\www\projects\foobar\sites\all\modules\foobar_module\foobar_module.module
on line 33

The docs for &DatabaseCondition::conditions() found here indicate that the conditions() method should should be applied to a pass-by-reference variable. Since the HOOK I’m trying to execute from passes $query by reference, I’m not entirely sure what I’m doing wrong here… Maybe the docs are completely wrong now?

Long story short, I just need to modify $query->where[1][‘conditions’][3][‘field’]->conditions to change what gets submitted to replace the human names with the target_ids of the users the names match against via a query I used on the side for searching for users (which returns target_ids of those found).

Apparently viewing protected variables isn’t a problem. By using print_r, I can at least see what’s in this protected variable:

Array
(
    [0] => Array
        (
            [field] => node.status
            [value] => 1
            [operator] => =
        )

    [1] => Array
        (
            [field] => node.type
            [value] => Array
                (
                    [0] => foobar_page
                )

            [operator] => in
        )

    [2] => Array
        (
            [field] => node.title
            [value] => blah
            [operator] => NOT LIKE
        )

    [3] => Array
        (
            [field] => DatabaseCondition Object
                (
                    [conditions:protected] => Array
                        (
                            [#conjunction] => OR
                            [0] => Array
                                (
                                    [field] => CONCAT_WS(' ', node.title, ' ', field_data_field_foobar_value, ' ', field_data_field_foobar_ppl.field_data_field_foobar_ppl_target_id) LIKE :views_combine
                                    [value] => Array
                                        (
                                            [:views_combine] => %Don%
                                        )

                                    [operator] => 
                                )

                            [1] => Array
                                (
                                    [field] => CONCAT_WS(' ', node.title, ' ', field_data_field_foobar_value, ' ', field_data_field_foobar_ppl.field_data_field_foobar_ppl_target_id) LIKE :views_combine1
                                    [value] => Array
                                        (
                                            [:views_combine1] => %Jill%
                                        )

                                    [operator] => 
                                )

                        )

                    [arguments:protected] => Array
                        (
                        )

                    [changed:protected] => 1
                    [queryPlaceholderIdentifier:protected] => 
                )

            [value] => 
            [operator] => 
        )

)

I’m thinking that a method surely exists to modify these values… So I’m hoping that someone out there has an answer…

Thoughts? I’ve posted about this in some other forums, so if I get any good leads from them, I’ll update this with the answer. :blush:

(Thanks in advance.)

That sounds like you should be using a custom plugin to convert the incoming data back to the type expected by the filter. More complex of a process but ultimately more reusable and robust. Either that or modify the other end so that the sender of the data sends user IDs rather than user name strings. It is difficult to recommend anything specific without clear details.

Any idea which hook I would need to use to grab the AJAX-filter’s submitted values to substitute them with my own custom SQL query’s results BEFORE the filter actually processes? If I could do that, I think that might work… I’m just not sure which hook I’d need to use since this is an AJAX filter. (I think the AJAX filters are a bit different in terms of handling them with hooks vs. the normal standard forms, though I might be wrong.)

Is this a contextual filter or a filter that is exposed via a form field for filtering the view?

if it is the later is this for a node entity with an entity reference field by chance?

Better yet take a screenshot of the view form in the admin to configure the view and circle the filter you’re talking about.

1.) It’s a global combine exposed AJAX filter. The global combine filters allow users to search multiple fields using only one field (it’s actually in Drupal core now or at least, Views core).

2.) 2 of the 3 fields are standard fields but the third is an entity reference field which keys off user target_ids.

Here’s an image of the actual results:

If you can’t see the text, it says the following:

The “Team Filters” key off the title, text, and user reference fields (global combine filter). When searching for people, I want to allow users to be able to use first and or last names in the filter. Right now, the filter will only find a person if a person’s target_id is submitted (and not an actual name).

So, I need to trap the submitted filter values before the filter itself is executed so that I can run a query substitution which searches for the users based off the names people submit. I already have the query and it works flawlessly, but I just can’t change the protected DatabaseCondition variable in HOOK_views_query_alter() to make the actual substitution of the necessary conditions.

However, if I can trap the filter values from the point where they’re submitted but before the time in which the filter is actually executed, I could then run my query at the proper point and then substitute the submitted names for the target_ids my query returns for the combine filter routine to use, thereby correctly retrieving the correct people matching.

Bear in mind that I’ve used 2 block views that I embedded into 1 page. In the above image I posted of the main page, the right-side “non-team filter” block is the view I’m messing with in all this. Here’s its configuration screen:

Thanks again. I’m beginning to suspect that I need to revisit the form_alter approach to make the swap of values between form submit and filter processing… Would you agree? I just can’t figure out how to override the DatabaseCondition variable values and judging by what I’m seeing from Google, nobody else knows how to, either…

You will need to create a custom filter that extends the class views_handler_filter_combine and overrides the query method. The query method contains the logic to build the views query which can be adapted to fit the desired functionality with some customization.

Excellent. Thanks, oddz!

(Also exploring the form_alter approach, too. I’ll post back if something good comes from it.)

oddz et al, I figured it out! I was approaching everything from the wrong angle…

The first thing I needed was a custom module so that I could properly execute the correct HOOKs. This I had. Maybe it goes without saying but something I realized during all this is that A.) certain HOOKs can only be executed from within custom modules and not from template.php–I’m not yet sure how to distinguish between the ones that can be used from either-or, but it’s true, and B.) validation and submit callbacks reveal different data structures. (See below.)

Instead of using HOOK_views_query_alter(&$view, &$query) to hack away at things like I was originally trying to do, I instead switched over to HOOK_form_alter(&$form, &$form_state, $form_id) with a validation callback. The validation callback is the secret here: without it, I wouldn’t have had access to the correct data structures I needed via using HOOK_form_alter() alone. The callback is absolutely mandatory in my case. Also note that a submit callback wouldn’t have worked either–for reasons I’m assuming stem from how Drupal organizes things, it had to be a validation callback. The reason for this is because $form would have the actual values from within the validation callback that I was trying to change but would not have the actual values in the submit callback. I’m not sure why but again, I’m guessing it’s got something to do with how Drupal separates concerns.

With that in mind, I started with HOOK_form_alter(). In there, I did various data massaging, condition handling, etc. to the values I was trying to change in all this (aka, my payload). For me, the ultimate goal here was to convert actual names of people to target_ids that the exposed global combine AJAX-driven filter expected amidst the other filter value types that it allowed. So toward the end of this HOOK, I added an element to my $form variable called $form[‘#saved_value’] and assigned it my altered values that I extracted from some custom SQL I executed earlier in the HOOK. By doing this, I could later access my altered payload from within the validation callback (it’s basically a screwy way of passing a parameter into the callback–you could probably use Drupal’s getter and setter functions if you want or some other approach).

From within the validation callback, the only thing I did there was call form_set_value() using the following 3 parameters:
1.) $form[‘’]. (It’s the $form element that contains everything from the field I was trying to change values of.)
2.) $form[‘’]. (Keep in mind that multi-value payloads need space between separators if the global combine field is set to use “Contains any word,” as this allows for multi-item single payload submissions [aka comma-separated value].)
3.) $form_state. (The basic $form_state variable you use from within HOOK_form_alter()).

At this point, as long as spacing was preserved between multi-value payload values (i.e. - “Value1, Value2”), the filter executed as expected.

If anyone has any questions about this, feel free to contact me. I’ll be happy to help out wherever I can.

This topic was automatically closed 91 days after the last reply. New replies are no longer allowed.