Completely Remove Query Cache From CakePHP 2.x - mysql

I have the follow queries taking place
public function test()
{
$uuid = substr( String::uuid() , 4 , rand( 7 , 10 ) );
$name = $uuid;
$event = $this->Event->getEvent( array( "event_id" => "5240e695-9acc-4e32-9b98-1aecb3d0838" ) );
$event[ "event_name" ] = $name;
$this->Event->update( $event );
debug( $this->Event->search( array( "event_id" => $event[ "event_id"] ) )[ 0 ][ "event_name" ] );
debug( $this->Event->search( array( "event_id" => $event[ "event_id"] , "limit" => 1 ) )[ 0 ][ "event_name" ] );
}
I assign a random name to a particular event retrieved from a mySQL ( InnoDB ) table event, assign a random new name to it, and save it back in the database.
When I run the last two statements in this code, the results are not the same, note that the last parameter in the 2nd query simply adds LIMIT 1 to the end of the second query. ( I am not using CakePHP 2.x's typical methods for searching tables ). The result of the 1st search call will produce the previous result from the previous request while the 2nd search call will produce the actual currently updated name in the event table.
I've been searching high and low on how to remove query cacheing COMPLETELY from the datasource objects but can't figure out how. I've tried using flushMethodCache() on the datasource object, but it does nothing, I've tried setting
$cacheQueries = false, $cacheSources = false;
in the AppModel, but that doesn't do anything either. I've tried looking in /App/Config/Core.php and disabling cacheing, and setting the cache time to 0. None of this works.

Found out the problem:
Instead of calling
$model->query( $string );
I needed to call
$model->query( $string, false );

Related

ACF front end form to update term

I want to use ACF frontend form function to create a form with custom fields
I see this issue for create new term, #Alhana
ACF front end form to create term
but I want to generate the form with old data
Well, i didn't see that question, but if it's still actual, here's a solution.
First of all, make sure you have ACF group, linked to your taxonomy. You will need ID of this group, it can be found in url on group edit page, for example:
http://site.ru/wp-admin/post.php?post=340&action=edit
In this case group ID is 340. If you don't want to use hardcoded ID (if your groups are changing from time to time), you can get it, using group name (in this example group name is Technic CPT):
global $wpdb;
$group_ID = $wpdb->get_var( "SELECT ID FROM $wpdb->posts WHERE post_title = 'Technic CPT'" );
Then, you'll need ID of term you're updating. I think, it's not nesessary to write about getting it since it's WP basics :) You'll end with something like this:
$term_id = 405;
And finally, you'll need your taxonomy's slug. In this example it's technic. So, let's render our form!
acf_form_head();
$acf_form_args = array(
'id' => 'technic_edit_form',
'post_id' => 'technic_'.$term_id,
'form' => true,
'submit_value' => 'Update technic',
'field_groups' => array($group_ID),
'updated_message' => 'Technic is updated!';
);
acf_form( $acf_form_args );
Now your term's custom fields will be shown in this form. But to save term data after editing you'll need to add some more code. ACF form assumes that you're saving post data, we'll add some logic to detect saving data for term.
add_filter( 'acf/pre_save_post', 'acf_handle_form_save', 10, 1 );
function acf_handle_form_save( $post_id ) {
// Function accepts id of object we're saving.
// All WordPress IDs are unique so we can use this to check which object it is now.
// We'll try to get term by id.
// We'll get term id with added taxonomy slug, for example 'technic_405'.
// For checking term existence we must cut out this slug.
$cut_post_id = str_replace( 'technic_', '', $post_id );
$test_tax_term = get_term_by( 'id', $cut_post_id, 'technic' );
// If $test_tax_term is true - we are saving taxonomy term.
// So let's change form behaviour to saving term instead of post.
if ( $test_tax_term ) :
// Get array of fields, attached to our taxonomy
global $wpdb;
$group_ID = $wpdb->get_var( "SELECT ID FROM $wpdb->posts WHERE post_title = 'Technic CPT'" );
$acf_fields = acf_get_fields_by_id( $group_ID );
// Then sanitize fields from $_POST
// All acf fields will be in $_POST['acf']
foreach ( $acf_fields as $acf_field ) :
$$acf_field[ 'name' ] = trim( esc_attr( strip_tags( $_POST[ 'acf' ][ $acf_field[ 'key' ] ] ) ) );
endforeach;
// We need to have some fields in our group, which are just duplicates of standard term fields: name, slug, description.
// In this example it's only one field - term name, called 'technic_name'.
$name = 'technic_name';
// Update base term info, in this example - only name.
$term = wp_update_term( $cut_post_id, 'technic', array( 'name' => $$name ) );
// If all is correct, update custom fields:
if ( !is_wp_error( $term ) ) :
foreach ( $acf_fields as $acf_field ) :
update_field( $acf_field[ 'name' ], $$acf_field[ 'name' ], 'technic_' . $cut_post_id );
endforeach;
endif;
else :
// Here is saving usual post data. Do what you need for saving it or just skip this point
endif;
return $post_id;
}
Please note: validation of $_POST data may be more complex. For example, you may have to validate array of values if there are ACF galleries or relationships among your taxonomy fields. In my example i have only common text fields.
Hope that helps!
The answer from Alhana worked for me with one change. The term object works if sent as the the value for the post_id:
$term_obj = get_term($term_id);
$acf_form_args = array(
'post_id' => $term_obj,
'post_title' => false,
'submit_value' => 'Update Term',
'field_groups' => array($group_ID),
);

mysql query for category and date

How can I query the wordpress database so that I'm only display the number of posts from a certain category starting at a certain date?
I’ve tried something like this but it doesn’t work:
<?php
$user_count = $wpdb->get_var( "SELECT COUNT(*) FROM $wpdb->posts WHERE term_id = '4' AND post_date >= '2014-01-01 00:00:00' " );
echo "<p>User count is {$user_count}</p>";
?>
What am I doing wrong?
Use wordpress native WP-Query:
$args = array(
'post_type' => 'post',
'date_query' => array(
'year ' => 2015,
),
'cat' => 5,
'posts_per_page'=> -1
);
$query = new WP_Query( $args );
$numberOfPosts = $query->post_count;
$numberOfPosts should hold the number you are looking for. Just paste this where you used your original code which you've shared with us.
Read more here: https://codex.wordpress.org/Class_Reference/WP_Query
Excerpt from the above mentioned url:
posts_per_page (int) - number of post to show per page (available with Version 2.1, replaced showposts parameter). Use 'posts_per_page'=>-1 to show all posts (the 'offset' parameter is ignored with a -1 value). Set the 'paged' parameter if pagination is off after using this parameter. Note: if the query is in a feed, wordpress overwrites this parameter with the stored 'posts_per_rss' option. To reimpose the limit, try using the 'post_limits' filter, or filter 'pre_option_posts_per_rss' and return -1
You can find a bunch of other options there aswell to tweak your query, to get the desired result. This should give the result you want for now.

How to add combined unique fields validator rule in Laravel 4

I am using Laravel 4.2 and mysql db . I have an exam table in which i am taking Exams entry and the fields are --> id | examdate | batch | chapter | totalmarks
I have made a combined unique key using $table->unique( array('examdate','batch','chapter') ); in schema builder.Now I want to add a validation rule to it. I know i can add unique validation by laravel unique validator rule but the problem is ,it checks only for one field . I want it to add uniqueness to the 3 fields combined(user must not be able to add second row with same value combination of examdate,batch and chapter fields).
Is it even possible to do it in laravel 4 .Is there any workaround if its not possible?
You could write a custom validator rule. The rule could look something like this:
'unique_multiple:table,field1,field2,field3,...,fieldN'
The code for that would look something like this:
Validator::extend('unique_multiple', function ($attribute, $value, $parameters)
{
// Get table name from first parameter
$table = array_shift($parameters);
// Build the query
$query = DB::table($table);
// Add the field conditions
foreach ($parameters as $i => $field)
$query->where($field, $value[$i]);
// Validation result will be false if any rows match the combination
return ($query->count() == 0);
});
You can use as many fields as you like for the condition, just make sure the value passed is an array containing the values of the fields in the same order as declared in the validation rule. So your validator code would look something like this:
$validator = Validator::make(
// Validator data goes here
array(
'unique_fields' => array('examdate_value', 'batch_value', 'chapter_value')
),
// Validator rules go here
array(
'unique_fields' => 'unique_multiple:exams,examdate,batch,chapter'
)
);
It didn't work for me so I adjusted the code a tiny bit.
Validator::extend('unique_multiple', function ($attribute, $value, $parameters, $validator)
{
// Get the other fields
$fields = $validator->getData();
// Get table name from first parameter
$table = array_shift($parameters);
// Build the query
$query = DB::table($table);
// Add the field conditions
foreach ($parameters as $i => $field) {
$query->where($field, $fields[$field]);
}
// Validation result will be false if any rows match the combination
return ($query->count() == 0);
});
The validator looks like this. You don't need a particular order of DB table column names as stated in the other answer.
$validator = Validator::make($request->all(), [
'attributeName' => 'unique_multiple:tableName,field[1],field[2],....,field[n]'
],[
'unique_multiple' => 'This combination already exists.'
]);

Set a value to null, when calling Zend_Db::update() and insert()

My question is the exact same as How to Set a Value to NULL when using Zend_Db
However, the solution given in that question is not working for me. My code looks like the following. I call updateOper on the Model class when update is clicked on the front end. Inside updateOper, I call another function trimData() where I first trim all whitespace and then I also check that if some of the fields are coming in empty or '' I want to set them to default values or NULL values. Therefore I am using new Zend_db_expr('null') and new Zend_db_expr('default') .
The code is as follows:
private function trimData(&$data ) {
//Trim whitespace characters from incoming data.
foreach($data as $key => $val)
{
$data[$key] = trim($val);
if($data['notes'] == '') {
error_log("set notes to null/default value");
$data['notes'] = new Zend_db_expr('DEFAULT');
}
}
}
public function updateOper($data, $id)
{
$result = 0;
$tData = $this->trimData($data);
error_log("going to add data as ".print_r($data, true));
$where = $this->getAdapter()->quoteInto('id = ?', $id);
$result = $this->update($data, $where);
return $result;
}
The error_log statement prints the $data array as follows:
[id] => 10
[name] => alpha
[notes] => DEFAULT
As a result, the notes column has value ='DEFAULT' instead of picking the default value given in the table definition.
I have been trying to figure out what is wrong, but have not been able to find a solution.
I would really appreciate your help.
Thanks so much!
Your $data['notes'] is being changed to the __toString() value of the Zend_Db_Expr instead of preserving the actual object.
Maybe the reference is clogging things up. Else you may need to move the expression declaration into the actual update query.

CakePHP: How can I use a "HAVING" operation when building queries with find method?

I'm trying to use the "HAVING" clause in a SQL query using the CakePHP paginate() method.
After some searching around it looks like this can't be achieved through Cake's paginate()/find() methods.
The code I have looks something like this:
$this->paginate = array(
'fields' => $fields,
'conditions' => $conditions,
'recursive' => 1,
'limit' => 10,
'order' => $order,
'group' => 'Venue.id');
One of the $fields is an alias "distance". I want to add a query for when distance < 25 (e.g. HAVING distance < 25).
I have seen two workarounds so far, unfortunately neither suit my needs. The two I've seen are:
1) Adding the HAVING clause in the "group" option. e.g. 'group' => 'Venue.id HAVING distance < 25'. This doesn't seem to work when used in conjunction with pagination as it messes up the initial count query that is performed. (ie tries to SELECT distinct(Venue.id HAVING distance < 25) which is obviously invalid syntax.
2) Adding the HAVING clause after the WHERE condition (e.g. WHERE 1 = 1 HAVING field > 25) This doesn't work as it seems the HAVING clause must come after the group statement which Cake is placing after the WHERE condition in the query it generates.
Does anyone know of a way to do this with CakePHP's find() method? I don't want to use query() as that would involve a lot of rework and also mean I'd need to implement my own pagination logic!
Thanks in advance
You have to put it with the group conditions. like this
$this->find('all', array(
'conditions' => array(
'Post.length >=' => 100
),
'fields' => array(
'Author.id', 'COUNT(*) as Total'
),
'group' => array(
'Total HAVING Total > 10'
)
));
Hope it helps you
I used the following trick to add my own HAVING clause at the end of my WHERE clause. The "dbo->expression()" method is mentioned in the cake sub-query documentation.
function addHaving(array $existingConditions, $havingClause) {
$model = 'User';
$db = $this->$model->getDataSource();
// Two fun things at play here,
// 1 - mysql doesn't allow you to use aliases in WHERE clause
// 2 - Cake doesn't allow a HAVING clause separate from a GROUP BY
// This expression should go last in the WHERE clause (following the last AND)
$taut = count($existingConditions) > 0 ? '1 = 1' : '';
$having = $db->expression("$taut HAVING $havingClause");
$existingConditions[] = $having;
return $existingConditions;
}
As per the manual, CakePHP/2 supports having at last. It was added as find array parameter on version 2.10.0, released on 22nd July 2017.
From the 2.10 Migration Guide:
Model::find() now supports having and lock options that enable you to
add HAVING and FOR UPDATE locking clauses to your find operations.
Just had the same problem. I know, one is not supposed to modify the internal code but if you open the PaginatorComponent and you modify line 188:
$count = $object->find('count', array_merge($parameters, $extra));
to this:
$count = $object->find(
'count',
array_merge(array("fields" => $fields),$parameters, $extra)
);
Everything will be fixed. You will be able to add your HAVING clause to the 'group' and the COUNT(*) won't be a problem.
Or, make line:
$count = $object->paginateCount($conditions, $recursive, $extra);
to include the $fields:
$count = $object->paginateCount($fields,$conditions, $recursive, $extra);
After that, you can "override" the method on the Model and make sure to include the $fields in the find() and that's it!, =P
Here is another idea that doesn't solve the pagination issue, but it is clean since it just overrides the find command in AppModel. Just add a group and having element to your query and this will convert to a HAVING clause.
public function find($type = 'first', $query = array()) {
if (!empty($query['having']) && is_array($query['having']) && !empty($query['group'])) {
if ($type == 'all') {
if (!is_array($query['group'])) {
$query['group'] = array($query['group']);
}
$ds = $this->getDataSource();
$having = $ds->conditions($query['having'], true, false);
$query['group'][count($query['group']) - 1] .= " HAVING $having";
CakeLog::write('debug', 'Model->find: out query=' . print_r($query, true));
} else {
unset($query['having']);
}
}
return parent::find($type, $query);
}
Found it here
https://groups.google.com/forum/?fromgroups=#!topic/tickets-cakephp/EYFxihwb55I
Using 'having' in find did not work for me. Instead I put into one string with the group
" group => product_id, color_id having sum(quantity) > 2000 " and works like a charm.
Using CakePHP 2.9