Combined ANY/ALL (AND/OR) in GravityForms GFAPI::get_entries? - gravity-forms-plugin

Can GFAPI::get_entries take a NESTED set of field_filters, so the top filter uses 'mode' => 'all' and the child filter uses 'mode' => 'any' ?
My goal is to find entries where
Color = 'Red' AND City = 'Chicago' OR 'Boston'
The docs for GFAPI do not mention this capability, but there are not many examples anyway. I tried the following code, but it results in a 500-error.
$form_id = '11';
$search_criteria = array(
'field_filters' => array(
'mode' => 'all' // 'and'; default
array(
'key' => '23', // color
'value' => 'red'
),
array(
'mode' => 'any', // 'or'
array(
'key' => '12', // city
'value' => 'Chicago'
),
array(
'key' => '12',
'value' => 'Boston'
),
),
) // field_filters
); // $search_criteria
$entries = GFAPI::get_entries( $form_id, $search_criteria );
Alternatively, I can do the 2nd filter (for City) separately, in a foreach ($entries as $entry), if necessary.
Wondering if anyone has tried something like this and could advise.
Thanks.

This isn't possible with the GFAPI::get_entries method; however, if you're willing to go beneath the hood a little further, you can use the GF_Query class to do complex clauses as you've described.
Take a look at this simple form export. I've setup two Drop Down fields, each with three choices. I've submitted three sample entries:
Now, let's say we only want to get entries where Drop Down A is "First Choice" and Drop Down B is "Second Choice" or "Third Choice". That'd look something like this:
$form_id = 387;
$gf_query = new GF_Query( $form_id );
$gf_query->where( call_user_func_array( array( 'GF_Query_Condition', '_and' ), array(
new GF_Query_Condition(
new GF_Query_Column( '1' ),
GF_Query_Condition::EQ,
new GF_Query_Literal( 'First Choice' )
),
call_user_func_array( array( 'GF_Query_Condition', '_or' ), array(
new GF_Query_Condition(
new GF_Query_Column( '2' ),
GF_Query_Condition::EQ,
new GF_Query_Literal( 'Second Choice' )
),
new GF_Query_Condition(
new GF_Query_Column( '2' ),
GF_Query_Condition::EQ,
new GF_Query_Literal( 'Third Choice' )
),
) ),
) ) );
$entries = $gf_query->get();
This is the same basic structure as your example with the color and city. Just update the form ID, field IDs, and field values and you'll be good to go.

Related

Get_term with meta_query

I can figure out this query : my purpose is to have a list of taxonomys (category like) with the number posts related to. Something like :
Concerts (4)
Theater (10)
Cinema (12)
...
"Events" posts are store in a CPT 'event' and they all have an "event_start_date" ACF field. If I don't use the meta_query the "get_term" output well all the post by taxonomy. As soon as I try to get all posts from today's date (with the meta_query), nothing appear.
$terms = get_terms( array(
'post_type' => 'events',
'hide_empty' => false,
'taxonomy' => 'events_category',
// 'orderby' => 'name',
// 'order' => 'ASC',
// 'meta_query' => $meta_query_array_from_today,
'meta_query' => array(
array(
'key' => 'event_start_date',
'value' => date( "Ymd"),
'type' => 'date',
'compare' => 'LIKE',
),
)
) );
I've read a lot of answers but i can't make it works, some of answers found do a ne WP-Query but I don't want post, I need a list of taxonomy (using term->count).
If anyone can guide me, I would be grateful.
Thank's !

How can I save dynamically created Gravity Form fields into entries content?

The code below successfully creates a dynamic field and for a Gravity Form, and on submission the dynamic field data is included in the email content sent. However the dynamic field isn't saved in the "entries" data for that form submission, only the fields created manually using the plugin are. Anyone know how to include this data in the entries data saved?
add_filter('gform_pre_render_5', 'populate_wines');
add_filter('gform_pre_validation_5', 'populate_wines');
function populate_wines($form) {
// create dynamic select field
$props = array(
'id' => 51,
'type' => 'select',
'label' => 'Dynamic field label',
'choices' => array(
array(
'text' => '',
'value' => '',
),
array(
'text' => '1',
'value' => '1',
),
array(
'text' => '2',
'value' => '2',
),
array(
'text' => '3',
'value' => '3',
),
)
);
$new_field = GF_Fields::create( $props );
$form['fields'][] = $new_field;
return $form;
}
Edit: Dave's solution below works great for the above function (thanks!!), but adding to the function to include the looped wine list (code below), it doesn't work, any ideas?
function populate_wines($form) {
// options for select lists
$select_choices = array(
array(
'text' => '',
'value' => '',
),
array(
'text' => '1',
'value' => '1',
),
array(
'text' => '2',
'value' => '2',
),
array(
'text' => '3',
'value' => '3',
),
);
// loop through wine list
if( have_rows('wine_options') ):
$wine_count = 50;
while( have_rows('wine_options') ) : the_row();
$wine_ID = get_sub_field('wine_option');
$wine_name = get_the_title($wine_ID);
// create wine select field
$props = array(
'id' => $wine_count,
'type' => 'select',
'label' => $wine_name,
'choices' => $select_choices
);
$new_field = GF_Fields::create( $props );
$form['fields'][] = $new_field;
$wine_count++;
endwhile;
endif;
if ( GFForms::get_page() !== 'form_editor' ) {
return $form;
}
}
You'll need to call the same function on the gform_admin_pre_render filter. My recommendation would be to also add a check to exclude it from being output in the form editor but you may want that. If you don't, it'd look something like this:
if ( GFForms::get_page() !== 'form_editor' ) {
return $form;
}

Backend TCA: possible to make a field nullable?

I need a backend field where users can enter a time (ie "23:13:46", hours, minutes, seconds). But it should also be possible to not enter a time at all (which should of course be different from 00:00:00). Is it possible to make a field nullable?
What I have so far is this:
$GLOBALS['TCA']['tx_something_domain_model_delivery'] = array(
'columns' => array(
'deadline' => array(
'exclude' => 1,
'label' => 'Deadline',
'config' => array(
'dbType' => 'time',
'type' => 'input',
),
),
...
),
);
But if I enter nothing in the Deadline field, it stores "00:00:00" to the database. The database looks like this:
CREATE TABLE IF NOT EXISTS `tx_something_domain_model_delivery` (
`uid` int(11) NOT NULL,
`pid` int(11) NOT NULL DEFAULT '0',
`deadline` time DEFAULT NULL,
...
);
so deadline is nullable, but I don't know how to achieve this.
BTW: I'm a newbie at typo3, so if you think the way I create the field is retarded or there is a much better way, I'd be thankful for any suggestions.
First: You are creating the field exactly in the intended way :-)
Second: You need to use the eval property in the configuration of the field. Add the setting null to it. Your config should then look like this:
$GLOBALS['TCA']['tx_something_domain_model_delivery'] = array(
'columns' => array(
'deadline' => array(
'exclude' => 1,
'label' => 'Deadline',
'config' => array(
'dbType' => 'time',
'type' => 'input',
'eval' => 'null',
),
),
...
),
);
There are more settings for the eval setting that might be of interest to you.

MongoDB Aggregation query doesn't return all fields

I am trying to use the aggregation function to display info in a chart. For this example, a document in the collection looks like this (excluding unnecessary fields for this query):
{
'locid' : <someid>, #Reference to a city & state collection
'collat' : <dateobj>, #a date object when this entry was saved
'pid' : <someid>, #Reference to a person collection
'pos' : <int> #Value I am interested in matching with location & date
}
So I basically start with a pid. I use this as my first $match parameter to limit the amount of data that gets thrown into the pipeline.
array(
'$match' => array(
'pid' => new \MongoId($pid)
)
),
So now that I have selected the correct pid, I tell it I only want/need certain fields:
array(
'$project' => array(
'pos' => 1,
'collat' => 1,
'locid' => 1
)
),
The second match is to say I only care about these locations right now ($ids contains an array of locid):
array(
'$match' => array(
'locid' => array('$in' => $ids)
)
),
And finally, I am saying group all the returned documents by collat and locid
array(
'$group' => array(
'_id' => array(
'locid' => '$locid',
'collat' => '$collat'
)
)
)
While the query completes OK and returns data, I am not getting the pos field back, it is only returning the locid and collat.
Questions
Isn't that what $project is for? I use it to tell the driver what fields I want returned?
Once I get the pos field returning as well, how can I tell the driver I only want the lowest value for each locid & collat combo pair? So say there are two entries for that date, location, and person: 4 & 8. I only care about pos=4
My end goal is to create a line chart with the X-Axis as the dates (from collat) and the Y-Axis will be the pos field, and each line will plot individual locid data.
Here is the entire parameters being sent to the aggregation driver.
$ops = array(
array(
'$match' => array(
'pid' => new \MongoId($pid)
)
),
array(
'$project' => array(
'pos' => 1,
'collat' => 1,
'locid' => 1
)
),
array(
'$match' => array(
'locid' => array('$in' => $ids)
)
),
array(
'$group' => array(
'_id' => array(
'locid' => '$locid',
'collat' => '$collat'
)
)
)
);
$out = $myCollection->aggregate($ops);
Update This is the way I got it to group & return pos without throwing an error. I need to spot check it though to make sure it's actually returning the correct values though.
array(
'$group' => array(
'_id' => array(
'locid' => '$locid',
'collat' => '$collat'
),
array('$min' => '$pos')
)
)
Aggregation query is like an SQL statement group by. You are telling {$group} what field(s) you want to 'GROUP BY' but you are not telling it how you want to aggregate the grouped information.
The {$group} you want is probably something like:
{$group : { _id : { locid: "$locid", collat: "$collat"},
pos : {$min : "$pos"}
}
}

Are there any examples using the Zend/Code/Generator component

I use Symfony's console component together with the Zend_CodeGenerator component. There was very few examples but I got it work -- http://framework.zend.com/manual/1.12/en/zend.codegenerator.html. Of course it didn't handle namespaces and use statements. Today I figured I try Zend/Code/Generator. I found an old post here http://mwop.net/blog/261-Code-Generation-with-ZendCodeGenerator.html.
So using Composer I installed the component and went about updated my code (see below). I'm having issues with doc blocks not being generated (see new version). There's no resulting errors indicating the parameters are wrong just no docblocks. I quickly reviewed the source code, api and even some the unit tests. So before I give up on this and stick with ZF1 CodeGenerator I wondered if there are any examples out there using docblocks.
Old Version
<?php
$class = new Zend_CodeGenerator_Php_Class();
$docblock = new Zend_CodeGenerator_Php_Docblock(array(
'shortDescription' => 'Index controller',
'tags' => array(
array(
'name' => 'category',
'description' => 'Controller',
),
array(
'name' => 'package',
'description' => 'Application\Controller',
),
),
));
$methods = array(
array(
'name' => 'indexAction',
'docblock' => new Zend_CodeGenerator_Php_Docblock(array(
'shortDescription' => 'Index action',
'tags' => array(
new Zend_CodeGenerator_Php_Docblock_Tag_Return(array(
'datatype' => 'void',
)),
),
)),
),
);
$class->setName("Admin_IndexController")
// Additional step needed to add namespace and use statement
->setExtendedClass('Action')
->setDocblock($docblock)
->setMethods($methods);
$file = new Zend_CodeGenerator_Php_File(array(
'classes' => array($class),
));
$code = $file->generate();
// Remove all that extra blank lines
$code = preg_replace("/(^[\r\n]*|[\r\n]+)[\s\t]*[\r\n]+/", "\n", $code);
if (file_put_contents('application/modules/admin/controllers/IndexController.php', $code)) {
$this->output->writeln(
'Controller generated ' . realpath('application/modules/admin/controllers/IndexController.php')
);
}
New Version
<?php
$classGenerator = new ClassGenerator();
$classGenerator->setName('Admin_IndexController')
->setExtendedClass('Action')
->setDocBlock(
new DocBlockGenerator(
'Index controller',
'',
array(
new Tag(
array(
'name' => 'category',
'description' => 'Controller'
)
),
new Tag(
array(
'name' => 'package',
'description' => 'Application\Controller'
)
)
)
)
)
->addMethods(
array(
new MethodGenerator(
'indexAction',
array(),
null,
null,
new DocBlockGenerator(
'Index action'
)
)
)
);
$fileGenerator = new FileGenerator();
$fileGenerator->setUse('Application\Controller\Action')
->setClass($classGenerator);
$code = $fileGenerator->generate();
// ...