CGridView filter by year of date - search

Sorry for long text but my problem is long :-) I made grid like this
$this->widget('zii.widgets.grid.CGridView', array(
'dataProvider'=>$model->search(),
'filter'=>$model,
'columns'=>array(
array(
'name'=>'title',
'type'=>'raw',
'value'=>'CHtml::link(CHtml::encode($data->title), $data->url)'
),
array(
'name'=>'create_time',
'type'=>'raw',
'value' => 'Yii::app()->dateFormatter->format("yyyy", $data->create_time)',
),
),
));
and then i want to filtering by date like title filtering, by textfield.
I made controller with code
$model=new Post('search');
if(isset($_GET['Post']))
$model->attributes=$_GET['Post'];
$this->render('admin',array(
'model'=>$model,
));
and search methode in model
public function search()
{
$criteria=new CDbCriteria;
$criteria->compare('title',$this->title,$partialMatch=true);
$criteria->compare('create_time',$this->create_time,$partialMatch=true);
return new CActiveDataProvider('Post', array(
'criteria'=>$criteria,
'sort'=>array(
'defaultOrder'=>'status, update_time DESC',
),
));
}
i don't forget abount rules()
array('title, create_time', 'safe', 'on'=>'search')
I have got two records wiht today's date. Title filtering works fine but when i type '2015' in 'create_time' column filter textfield and press enter i get "no results found".
I tried this:
array(
'name'=>'create_time',
'type'=>'raw',
'value' => 'Yii::app()->dateFormatter->format("dd MMMM yyyy", $data->create_time)',
'filter' => CHtml::listData(Post::model()->findAll(array('order'=>'create_time')), 'create_time', 'create_time'),
),
and it's seems to work but in my database, create_time is integer(11) (required) and listdata values is number not date and represents full date, not only year.
I controller i made array with unique year values from create_time record's values. Outputs array like $rok['2015'] => '2015'
$model_post = new Post;
$wyniki = $model_post::model() -> findAllBySql('SELECT create_time FROM tbl_post');
for($i=0;$i<count($wyniki);$i++)
{
$rok_temp[$i] = Yii::app()->dateFormatter->format("yyyy", $wyniki[$i]->create_time);
$rok[$rok_temp[$i]] = $rok_temp[$i];
}
$rok = array_unique($rok);
I send $rok to view and
array(
'name'=>'create_time',
'type'=>'raw',
'value' => 'Yii::app()->dateFormatter->format("dd MMMM yyyy", $data->create_time)',
'filter' => $rok,
),
and
$criteria->compare('create_time',Yii::app()->dateFormatter->format("yyyy", $this->create_time));
but then i get "no results found" when filtering.
What i made wrong?

Your time is stored as a UNIX timestamp. You therefore have to do some conversion on the input from the filter to change it to UNIX also. First, create a variable to hold the year in your model
class MyModel extends ... {
public $create_year;
}
Then add this variable to your rules:
array('create_year', 'safe', 'on' => 'search')
array('create_year', 'numerical', 'integerOnly' => true)
Next add the conversion rules for the year to your search() i.e
public function search() {
...
if ($this->create_year) {
$criteria->addBetweenCondition('create_time',
strtotime($this->create_year.'-01-01 00:00:00'),
strtotime($this->create_year.'-12-31 23:59:59')
);
}
...
}
Lastly change your filter to a dropdown to reduce invalid entries:
'filter' => CHtml::activeDropDownList(
$model,
'create_year',
array_combine(range(1900, 2099), range(1900, 2099),
array('prompt' => 'Any year')
)

Related

Wordpress Custom taxonomy dropdown list array to tagdiv composer

I am currently working on a new wordpress website which uses the Newspaper theme, which lets me compose pages with the tagdiv composer plugin.
This plugin makes it fairly easy to show posts of your choosing; with blocks/modules that have built in filters, that allow you to select the posts to be shown based upon the categories, authors, etc. that you choose.
However I would like to show custom taxonomies in there as well, so that I can choose for instance album reviews, which have the custom taxonomy of the letter A attached to it.
For my client I would need to do that since he requested a glossary (alphabetical index).
So far I have created a custom taxonomy called "alphabetical_letter", which houses all 26 characters with the linked posts to it.
The code which I need to alter is this one, preferrably I'd have a drop down list. However I keep failing in getting it right. Could anyone point me in the right direction please ?
/**
* the filter array (used by blocks and by the loop filters)
* #return array
*/
static function get_map_filter_array ($group = 'Filter') {
return array(
array(
"param_name" => "separator",
"type" => "text_separator",
'heading' => 'Filters',
"value" => "",
"class" => "",
'group' => $group
),
array(
"param_name" => "post_ids",
"type" => "textfield",
"value" => '',
"heading" => 'Post ID filter:',
"description" => "Filter multiple posts by ID. Enter here the post IDs separated by commas (ex: 10,27,233). To exclude posts from this block add them with '-' (ex: -7, -16)",
"holder" => "div",
"class" => "tdc-textfield-big",
'group' => $group
),
array(
"param_name" => "category_id",
"type" => "dropdown",
"value" => td_util::get_category2id_array(),
"heading" => 'Category filter:',
"description" => "A single category filter. If you want to filter multiple categories, use the 'Multiple categories filter' and leave this to default",
"holder" => "div",
"class" => "tdc-dropdown-big",
'group' => $group
),
array(
"param_name" => "category_ids",
"type" => "textfield",
"value" => '',
"heading" => 'Multiple categories filter:',
"description" => "Filter multiple categories by ID. Enter here the category IDs separated by commas (ex: 13,23,18). To exclude categories from this block add them with '-' (ex: -9, -10)",
"holder" => "div",
"class" => "tdc-textfield-big",
'group' => $group
),
array(
"param_name" => "alphabetical_letter_id",
"type" => "dropdown",
"value" => td_util::get_alphabetical_letter_id_array(),
"heading" => 'Custom taxonomy:',
"description" => "alphabetical letter custom taxonomy",
"holder" => "div",
"class" => "tdc-dropdown-big",
'group' => $group
),
array(
"param_name" => "tag_slug",
"type" => "textfield",
"value" => '',
"heading" => 'Filter by tag slug:',
"description" => "To filter multiple tag slugs, enter here the tag slugs separated by commas (ex: tag1,tag2,tag3)",
"holder" => "div",
"class" => "tdc-textfield-big",
'group' => $group
),`enter code here`
Edit:
in the meantime I have tried to figure out the td_util I keep seeing.
There is a file called td_util.php one folder up from where this file is, and it mentions the category2id_array so I am currently trying to find out if the problem lies here.
for completeness, this is the bit of text that refers to the category2id array function above (or the other way around more likely).
/**
* generates a category tree, only on /wp_admin/, uses a buffer
* #param bool $add_all_category = if true ads - All categories - at the begining of the list (used for dropdowns)
* #return array
*/
private static $td_category2id_array_walker_buffer = array();
static function get_category2id_array($add_all_category = true) {
if (is_admin() === false) {
return array();
}
if (empty(self::$td_category2id_array_walker_buffer)) {
$categories = get_categories(array(
'hide_empty' => 0,
'number' => 1500
));
$td_category2id_array_walker = new td_category2id_array_walker;
$td_category2id_array_walker->walk($categories, 4);
self::$td_category2id_array_walker_buffer = $td_category2id_array_walker->td_array_buffer;
}
if ($add_all_category === true) {
$categories_buffer['- All categories -'] = '';
return array_merge(
$categories_buffer,
self::$td_category2id_array_walker_buffer
);
} else {
return self::$td_category2id_array_walker_buffer;
}
}
And a bit further down the file it pops up one last time
class td_category2id_array_walker extends Walker {
var $tree_type = 'category';
var $db_fields = array ('parent' => 'parent', 'id' => 'term_id');
var $td_array_buffer = array();
function start_lvl( &$output, $depth = 0, $args = array() ) {
}
function end_lvl( &$output, $depth = 0, $args = array() ) {
}
function start_el( &$output, $category, $depth = 0, $args = array(), $id = 0 ) {
$this->td_array_buffer[str_repeat(' - ', $depth) . $category->name . ' - [ id: ' . $category->term_id . ' ]' ] = $category->term_id;
}
function end_el( &$output, $page, $depth = 0, $args = array() ) {
}
}

symfony 2.5 form validation error

I have a form type A with some widgets and mapped to class C1. I need a new widget in this form which is not mapped to this class( i.e mapped to another class C2). So i have created a new form type B. This new form type B is included in form type A.
Form Type B:
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder->add('join_event', 'date', array(
'label' => 'employee.form.join_event.label',
'required' => true,
'widget' => 'single_text',
'attr' => array(
'data-date-format' => 'MM-DD-YYYY'
)
));
}
FormType A including FormType B:
$builder->add('event', new FormTypeB(), array(
'label' => false,
'mapped' => false
));
The form display is well as expected but there is a validation error on submission with message "This value is not valid."
I think the problem is related to the date-field itself.
See http://symfony.com/doc/current/reference/forms/types/date.html#format how to define the format.
Maybe sth like 'format' => 'MM-dd-yyyy' will work.

extend wordpress search query

I have a working search query with offset and post_per_page (the user can go through pages)
$args = array(
'post_type' => 'type',
's'=>$the_str,
'posts_per_page' => $the_count,
'offset' => ($the_count*$the_c_page )-$the_count
);
$the_query = new WP_Query( $args );
It works great.
But now I need to add a meta field to the search function. It should get all post where s=>$query OR meta-field=>$query
Something like this:
$args = array(
'post_type' => 'type',
'posts_per_page' => $the_count,
'offset' => ($the_count*$the_c_page )-$the_count,
'meta_query' => array(
'relation' => 'OR',
's'=>$the_str,
array(
'key' => 'key',
'value' => $the_str
)
);
$the_query = new WP_Query( $args );
Unfortunately this will only search after the second condition. Does anybody have an idea?
If you crack open query.php you'll see that it really isn't built with this in mind. It isn't that it isn't a great idea, it's just that each individual query part is concatenated onto the main WHERE using an AND. So "title contains XYZ" AND "whatever the meta query is" AND "whatever the tax query is", etc. Meta and Tax both have sub logic within them that supports AND and OR but there's no way to perform this between these outer parts.
However, you might be able to do what you're looking for by tapping into one of the filters, possibly get_meta_sql. The meta query returns a statement that puts in the AND that you want to be an OR so you can just look for that and replace it:
function change_and_to_or_for_meta( $meta_query, $type, $primary_table, $primary_id_column, $context )
{
if( 0 === strpos( $meta_query['where'], ' AND' ) )
{
$meta_query['where'] = ' OR' . substr( $meta_query['where'], 4 );
}
return $meta_query;
}
//Add our filter to replace the AND at the start with OR
add_filter( 'get_meta_sql', 'change_and_to_or_for_meta', 10, 5 );
$query = new WP_Query( $args );
//Remove our filter so we don't mess other things up
remove_filter( 'get_meta_sql', 'change_and_to_or_for_meta', 10 );

CakePHP Search Plugin, search for a value equal or higher than the given in the search

I'm using the CakePHP Search Plugin, and there's something I can't get to work. I would like to have a search field (let's call it age) where a user can input a value (like 24, for example) and get as a result all the elements with a value in the age field of the table who have age 24 or higher. How can I do that?
So far I can perform normal searches, like by name or by an exact value (if you want age 24 exactly then it works fine).
Here's the code related with the Search Plugin that I have so far:
- model:
class Person extends AppModel{
var $name = 'Person';
public $actsAs = array('Searchable');
public $filterArgs = array(
array('name' => 'name', 'type' => 'like'),
array('name' => 'age', 'type' => 'value'),
);
}
- controller:
class PersonsController extends AppController {
var $name = 'Persons';
var $components = array('Search.Prg');
public $presetVars = array(
array('field' => 'name', 'type' => 'value'),
array('field' => 'age', 'type' => 'value'),
);
function index() {
$this->set('persons', $this->Person->find('all'));
}
/* ---------------- SEARCH PLUGIN --------------*/
public function find() {
$this->Prg->commonProcess();
$this->paginate['conditions'] = this->Game->parseCriteria($this->passedArgs);
$this->set('persons', $this->paginate());
}
}
- find.ctp:
//apart from the code below, I have all the code to show the results
echo $form->create('Game', array(
'url' => array_merge(array('action' => 'find'), $this->params['pass'])
));
echo $form->input('name', array('div' => false));
echo $form->input('age', array('div' => false));
echo $form->submit(__('Search', true), array('div' => false));
echo $form->end();
To sum up: with the code above, I can perfomr a search of an exact value for the age field. How do I change that to perform a search of 'age >= value entered'?
THank you so much in advance!
So this is how I solved it (or at least it seems to work with all the test I've done so far):
Changed the 'age' line by the following line in the filterArgs array in the model:
array('name' => 'age', 'type' => 'query', 'method' => 'findByAge', 'field' => 'Person.age'),
Added the following method in the same model:
public function findByAge($data = array()) {
$query = array(
'Person.age >=' => $data['age'],
);
return $query;
}
That's it! With the 'query' type, any complex query can be added to the main query using a method. Thanks to satyrwilder for pointing in the right direction!
From your presetVars -
array('field' => 'age', 'type' => 'value'),
-- filters down to your find() method from your commonProcess() method, which I presume constructs a generalized find like conditions=>array($key=>$val)?
Cake sees array key=>val pair assignments as an indication to generate a "WHERE $key=$val" condition.
To do a fuzzier pull, wherever you construct that generic find() - add a method or something just to roll those two into
'conditions'=>array("name LIKE '%{$name}%'", "{$age}>={$val}")
or whatever you've got going on. String the arguments together for the desired effect on your query and I'm sure you can extrapolate further ways to abstract that query, if needed.
If you need a more complex solution, Cake provides elegant built-in, extremely powerful subquery generation. It seems like you're working awfully hard to achieve a lot of built-in functionality, but then again I don't know how complicated your situation is.
http://book.cakephp.org/view/1030/Complex-Find-Conditions
HTH
I know this has been answered but there is another method that may be more suitable to this situation.
From the documentation
'expression' type: useful if you want to add condition that will generate by some method, and condition field contain several parameter like in previos sample used for 'range'. Field here contains 'Article.views BETWEEN ? AND ?' and Article::makeRangeCondition returns array of two values.
Full Article Here
I had to accomplish the same thing you did but with 5 different fields. I did not want to have to write a query for each one. Here is how I accomplished the same thing with the expression type. This is in the filterArgs array.
array(
'name'=>'bathrooms',
'type'=>'expression',
'method'=>'returnNumber',
'field'=>'House.bathrooms >= ?'
)
Then I created this function in the model that simply returns the number the user submitted. When called, returnNumber will be passed two arrays.
Looks something like this.
Array
(
[0] => Array
(
[bathrooms] => 6
[bedrooms] => 5
[acres] => 12
[city] => Greenville
[year] => 2009
)
[1] => Array
(
[name] => bathrooms
[type] => expression
[method] => returnNumber
[field] => House.bathrooms >= ?
)
)
Now for the actual function. You can use the debug statement to see what you are actually passing the function.
function returnNumber($arg, $name){
// debug(func_get_args());
// exit;
return $arg[$name['name']];
}

Search in BELONGS_TO model column with CGridView, Yii

I have a CGridView widget for Lesson model
$this->widget('zii.widgets.grid.CGridView', array(
'id'=>'lesson-grid',
'dataProvider'=>$model->search(),
'filter'=>$model,
... and Lesson has relation to the User model:
'user' => array(self::BELONGS_TO, 'User', 'user_id'),
... and the CGridView has a column with user's lastname from the BELONGS_TO model described above
'columns'=>array(
...
array(
'name' => 'user',
'header'=>'Teacher',
'value' => '$data->user->lastname',
),
So, I can't symply search with CGridView in this column, but I need it.
How to search in '$data->user->secondname' with CGridView?
I think that I should extend search method in Lesson model, but how?
Now it looks like this:
public function search()
{
// Warning: Please modify the following code to remove attributes that
// should not be searched.
$criteria=new CDbCriteria;
$criteria->compare('id',$this->id);
$criteria->compare('student',$this->student,true);
$criteria->compare('comment',$this->comment,true);
return new CActiveDataProvider(get_class($this), array(
'criteria'=>$criteria,
));
}
This should work, add it to your search criteria in the search() method:
$criteria->with[]='user';
$criteria->addSearchCondition("user.secondname",$this->user_id);
This is what I do though:
if(!intval($this->user_id) && is_string($this->user_id) && strlen($this->user_id) > 0) {
$criteria->with[]='user';
$criteria->addSearchCondition("user.secondname",$this->user_id);
} else
$criteria->compare('t.user_id',$this->user_id);
And here is the CGridView definition:
'columns'=>array(
...
array(
'name' => 'user_id',
'header'=>'User',
'sortable'=>false, // since it would still be sorting based on ID
// 'value' => '$data->user->lastname', // basic version
'value'=>'CHtml::link((isset($data->user))?$data->user->username:$data->user_id,array("user/view","id"=>$data->user_id))', // link version
),
It's a fun little trick: if the search term is a string and NOT an intval(), it searches for the user by their secondname, via the "user" relation. But if you enter a user_id, it will find the user by their user_id - the default search() functionality.
NOTE: This will enable filtering, but it will still sort based on ID. You will need to implement something additional to get the sorting to work.
There are surely other ways to do this, but this is how I do it. I suspect there is a "right" to do this using the relation, but my technique works solid.

Resources