I want to be able to search all data based on multiple or conditions using foreach like below:
function index() {
if ($this->Session->read('Auth.User.group_id') != 1) {
$commune_id = $this->Session->read('Auth.User.commune_id');
$commune_id = $this->Petition->Commune->findbyId($commune_id);
$commune_id = $this->Petition->Commune->find('all',array('conditions' => array('group' => $commune_id['Commune']['group'])));
$count = count($commune_id);
$i=1;
foreach($commune_id as $commune_ids){
if($i != $count){
$this->paginate = array(
'or' => array(
array('Petition.commune_id LIKE' => $commune_ids['Commune']['id'] . ","),
),
'limit' => 10
);
}
$i++;
}
}
$this->Petition->recursive = 0;
$petitions = $this->paginate();
$this->set('petitions', $petitions);
}
I was able to get possible number of matches but was wondering how I can use this array to get results with multiple or conditions with paginator function.
To do pagination in custom situations like this, one normally has to override Model::paginate() and Model::paginateCount() as detailed in the book under Custom Query pagination.
Alternatively, you could use a plugin that already has features such as pagination implemented, such as CakeDC's Search plugin.
Related
I'm using the WP MVC plugin to create a plugin which provides a database of names as part of my Wordpress website.
The below controller retrieves the right information from 2 database tables, but suddenly pagination is not working anymore. Do I need to use paginate() instead of find()? If yes, how would a similar query look using paginate()? Unfortunately there are no examples available.
Thanks!
names_controller.php
<?php
class NamesController extends MvcPublicController {
public function index() {
$objects = $this->Name->find(array(
'joins' => array('Origin'),
'selects' => array('Origin.id', 'Origin.origin', 'Name.id', 'Name.name', 'Name.gender', 'Name.meaning', 'Name.origin_id'),
'page' => 1,
'per_page' => 20,
'conditions' => array(
'Name.name LIKE' => 'A%'
)
));
$this->set('objects', $objects);
}
}
?>
=================== UPDATE ======================
I replaced the find() with paginate() unfortunately the join doesn't work anymore. Furthermore it IGNORES e.g. page, per_page etc parameters.
Anyone an idea?
$params = $this->params;
$params['page'] = empty($this->params['page']) ? 1 : $this->params['page'];
$params['per_page'] = 20;
$params['joins'] = array('Origin');
$params['selects'] = array('Origin.id', 'Origin.origin', 'Name.id', 'Name.name', 'Name.gender', 'Name.meaning', 'Name.origin_id');
$collection = $this->Name->paginate($this->params);
$this->set('objects', $collection['objects']);
$this->set_pagination($collection);
I am coding a search module. I do not know if I am ina good way but ti sound good for now excepted one point.
With the following code I can search only one word.
<?php
class SearchesController extends AppController{
function index(){
if($this->request->is('put') || $this->request->is('post') ){
// Save the send data
$search = $this->request->data['Search']['key'];
//$nbWords = str_word_count($search);
/*
THIS DOES NOT WORKS
if($nbWords > 1){
$searchTerms = explode(' ', $search);
$searchTermBits = array();
foreach ($searchTerms as $term) {
$term = trim($term);
if (!empty($term)) {
$searchTermBits[] = "Page.name LIKE '%$term%' AND Page.content LIKE '%$term%'";
}
}
}else{
$term = $search;
$searchTermBits[] = "Page.name LIKE '%$term%' AND Page.content LIKE '%$term%'";
}
*/
// SEARCH IN Pages TABLE
$this->loadModel('Page');
// SAVE THE RESULT IN
$d['pages'] = $this->Page->find('all', array(
'conditions' => array(
'online'=>'1',
'type'=>'page',
'created <= NOW()',
'id > 1',
'OR' => array(
//implode(' AND ', $searchTermBits)
'Page.name LIKE'=>'%'.$search.'%',
'Page.content LIKE'=>'%'.$search.'%'
)
),
'fields' => array('name','content','created','id','type')
));
//SEARCH IN Posts TABLE
$this->loadModel('Post');
$d['posts'] = $this->Post->find('all', array(
'conditions' => array(
'online'=>'1',
'type'=>'post',
'created <= NOW()',
'OR' => array(
'Post.name LIKE'=>'%'.$search.'%',
'Post.content LIKE'=>'%'.$search.'%'
)
),
'fields'=> array('name','content','created','id','type','slug')
));
// SEND THE VALUES TO THE VIEW
$this->set($d);
}else{
echo 'e';
}
}
}
The problem, I would like to be able to search with different words, for exeple "red car", "house monrain","web html5 development"
With my code, if I enter one word, it return a result, but if I add second word to the first (with a space) , it retuirn no result.
How can I change this
'OR' => array(
'Post.name LIKE'=>'%'.$search.'%',
'Post.content LIKE'=>'%'.$search.'%'
)
to make it able to search in 'name' and 'content' several words?
Thak for your help
Cheers
you can try this:
'OR' => array(
'Post.name' IN ('name1', 'name2'),
'Post.content' IN ('content1', 'content2')
)
Obviously you can put your value in array like this:
$name_arr = array();
$name_arr[] = 'name1';
$name_arr[] = 'name2';
and after:
'OR' => array(
'Post.name' IN ($name_arr),
'Post.content' IN ('content1', 'content2')
)
Change your $search variable
$search = $this->request->data['Search']['key'];
// if keywords "red car" then it will pass to your query %red%car%;
$search = str_replace(" ","%",$search);
Now it will search records having both words.
If you want to search with many words separated by a space, you can do this.
$searches = explode(" ", $search);
foreach ($searches as $search) {
//put your search condition in here
}
You might look into fulltext searching. If you setup your indices correctly, you can run queries such as:
SELECT id, MATCH (title,body) AGAINST ('Tutorial') FROM articles;
Having some problems here, I think I am just overlooking something really simple...
I have a CMS that have multiple categories.
How do I create a variable or array that has the included categories groups that I want to use in my SHOW IF STATEMENT ??
So for example:
<?php
$catsrow = array(
'cat_1' => '41','46','62',
'cat_2' => '41','45','63',
'cat_3' => '41','43','65'
);
?>
<?php if
(catsrow[0] || catsrow[1] || catsrow[2]) == ($row_DetailRS1['category'])
{ echo 'do work' }
else { ?>
Thanks in advance!!
I guess what I am asking is, how do I compare an array with multiple groups inside. I need to compare different grouped categories..
Like $catsArray = ARRAY(cat_1 => '2,3,4' , cat_2 => '5,6,7' , cat_3 => '8,9,10')
if $row['cat_from_page'] == $catsArray (any of the groups) then SHOW THIS { }
????
you may need to explode the parts of the array
Kinda like $parts = explode(',' , $cat);
http://php.net/manual/en/function.explode.php
but you will need to implode the whole thing into one array
Like implode (',', $parts);
http://php.net/manual/en/function.implode.php
My Best guess at what you're trying to do:
$categories = array(
'cat_1' => array(
'41','46','62'
),
'cat_2' => array(
'41','45','63'
),
'cat_3' => array(
'41','43','65'
)
);
$row_DetailRS1['category'] = '41';
foreach($categories as $category => $items) {
foreach($items as $item) {
if($row_DetailRS1['category'] == $item) {
echo "Item: ".$item." found in Category: ".$category."\n";
}
}
}
I want to do something very straight forward and simple. I want to have two different sets of paginated data on the same page. The two different sets depend on different models. For discussion's sake we'll say they are Image and Item.
I can set up two pagers for two models, and get the correct set of objects. I can get the correct pager links. But when it comes to actually following the links to the parameters, both pagers read the parameters and assume they apply to them.
It winds up looking something like this:
$this->paginate = array (
'Item'=>array(
'conditions'=>array('user_id'=>$id),
'limit' => 6,
'order' => array(
'Item.votes'=>'desc',
'Item.created'=>'desc'
),
'contain'=>array(
'User',
'ItemImage' => array (
'order'=>'ItemImage__imageVotes desc'
)
)
),
'Image'=>array(
'limit'=>6,
'contain'=>array(
'User',
'ItemImage'=>array('Item'),
),
'order'=>array(
'Image.votes'=>'desc',
'Image.views'=>'desc'
),
'conditions'=>array(
'Image.isItemImage'=>1,
'Image.user_id'=>$id
)
)
);
$this->set('items', $this->paginate('Item'));
$this->set('images', $this->paginate('Image'));
That's in the controller. In the view I have sort links that look like this:
<div class="control"><?php echo $this->Paginator->sort('Newest', 'Image.created', array('model'=>'Image')); ?></div>
However, that yields a link that looks like this:
http://localhost/profile/37/page:1/sort:Image.created/direction:asc
There's nothing in there to tell the paginator which model I intend to sort. So when I click on the link it attempts to sort both models by Image.created. The result is an error, because Item cannot be sorted by Image.created. Is there something I'm doing wrong? Or is this something that isn't supported by CakePHP's paginator?
You'll need to override the paginate method for the Model of the Controller of that page.
I did something similar, maybe this snippet will help:
function paginate($conditions, $fields, $order, $limit, $page = 1, $recursive = null, $extra = array())
{
$pageParams = compact('conditions', 'fields', 'order', 'limit', 'page', 'recursive', 'group');
$this->contain('ModuleType', 'NodeDescriptor');
$pageItems = $this->find('all',$pageParams);
$pagesOut = array();
foreach($pageItems as $pageItem)
{
$status = $pageItem['SiteAdmin']['status_id'];
$moduleInfo = null;
$nodeTitle = $pageItem['NodeDescriptor']['title'];
$published = $pageItem['NodeDescriptor']['published'];
$pageitemID = $pageItem['SiteAdmin']['id'];
$moduleId = $pageItem['SiteAdmin']['module_id'];
$contName = $pageItem['ModuleType']['controller'];
if($moduleId)
{
$thisModel = ClassRegistry::getObject($moduleType);
$thisModel->contain();
$moduleInfo = $thisModel->read(null,$moduleId);
$moduleInfo = $moduleInfo[$moduleType];
}
$pagesOut[] = array(
'status'=>$status,
'node'=>$nodeTitle,
'published'=>$published,
'info'=>$moduleInfo,
'module_id'=>$moduleId,
'contName'=>$contName,
'pageitem_id'=>$pageitemID);
}
return $pagesOut;
}
By doing it this way, you gain control over the parameters passed to paginate, so you can pass model specific data, control flags etc.
The easiest solution would be to implement both grids as elements that fetch their own data and use AJAX to load the elements into the page.
The only other option would be to modify the params so you pass the params for both grids to each grid when sorting or stepping through pages. The code posted by Leo above is a good start. You can prepend the Model key from the paginate array onto each named param and make sure you pass all url params to the paginate function and you should be headed in the right direction.
I want a simple filter form, and a table below it. When the user changes the option on the select form, the table automaticaly changes. I think thats done with ahah.
I want this (some things can change, like the fieldset containing the table, and other stuff):
But working.. of course..
I'm currently showing that page using one function. It's a complete mess and something like "NEVER DO THIS", but i'm researching and trying some stuff as i'm a drupal learner.
This is the relevant code:
form = array();
ahah_helper_register($form, $form_state);
//query here, build $options for the select
$form['listar_veics'] = array(
'#type' => 'fieldset',
'#prefix' => '<div id="listar-veics-wrapper">',
'#suffix' => '</div>',
'#tree' => TRUE,
);
if (!isset($form_state['values']['listar_veics']['filial']))
$choice = 1;
else
$choice = $form_state['values']['listar_veics']['filial'];
$form['listar_veics']['filial'] = array(
'#type' => 'select',
'#title' => "Listar veĆculos da filial",
'#options' => $filiais,
'#default_value' => $choice,
'#ahah' => array(
'event' => 'change',
'path' => ahah_helper_path(array('listar_veics')),
'wrapper' => 'listar-veics-wrapper',
'method' => 'replace',
),
);
//query for the rows i wanna show
//building $data array, the rows array
//building $header, as an array of strings
$table = theme_table($header, $data);
$page = drupal_render($form);
$page .= $table;
return $page;
So in this code, drupal will only replace the form itself, when i change the option on the select, it shows the new value on the select, but the table isnt rendered again thus not changing.
Thanks, apreciate every suggestion.
I recommend looking at the views module.
http://drupal.org/project/views
With that installed, you can create a custom query.
Add all the fields that you would like displayed on your table. (Placa, Marca)
Then add any filters that you would like to limit your query by. (Listar veiculos da filial)
When adding the filter you "expose" it so that when looking at the query, you can change the options on the page.
Then if you want to view what you just made, you need to add a display. If you make it a page display, you can set the path directly to the table.
For more information might I recommend http://gotdrupal.com/videos/drupal-views-tutorial.
If you want neater exposed fields I might also recommend http://drupal.org/project/better_exposed_filters
To expand Asimov's answer here is a code example (for Drupal 7) that shows a taxonomy term filter for selecting nodes. The selected terms are stored in the session and used in the query to filter the results.
You can put it in a custom module. It doesnt require Views or any other contributed modules.
In the example code below the name of the custom module is tic . Rename tic to the name of your custom module.
Four elements are needed:
A function that outputs the filter and fetches and outputs the results
The filter form
A custom submit function that stores the chosen filter options in the session
A reset function that clears the session
Use hook_menu() to call tic_fetch_results().
Fetch, filter, output results
This example uses a dynamic query because it is easy to extend with conditions.
/**
* Filters, fetches and outputs results
*/
function tic_fetch_results() {
// Adds filter form to the build array.
$form = drupal_get_form('tic_term_filter_form');
$output = drupal_render($form);
$node_types = array('article', 'page', 'blog_post');
// Sets up dynamic query
$query = db_select('node', 'n')
->extend('PagerDefault')
->limit(33)
->fields('n', array('nid', 'title'))
->condition('n.type', $node_types, 'IN')
->condition('n.status', 1);
// Fetches selected values from session and applies them to the query.
if (isset($_SESSION['form_values']['terms']) && count($_SESSION['form_values']['terms']) > 0) {
$query->join('field_data_field_tags', 'tags', 'n.nid = tags.entity_id');
$query->condition('tags.field_tags_tid', $_SESSION['form_values']['terms'], 'IN');
$query->condition('tags.bundle', $node_types, 'IN');
}
$result = $query->execute();
$items = array();
foreach ($result as $row) {
$items[] = array('data' => $row->nid . ' - ' . $row->title);
// do something interesting with the results
}
$output .= theme('item_list', array('items' => $items, 'title' => '', 'type' => 'ul', 'attributes' => array()));
$output .= theme('pager');
return $output;
}
Construct the form
The taxonomy terms options list is populated from the Vocabulary tags
/**
* Implements hook_form().
*/
function tic_term_filter_form($form, &$form_state) {
// Loads terms from the Tags vocabulary and use as select options.
$vocab = taxonomy_vocabulary_machine_name_load('tags');
$terms = taxonomy_get_tree($vocab->vid);
$term_options = array();
foreach ($terms as $term) {
$term_options[$term->tid] = $term->name;
}
// Sets the values that are stored in session as default.
$storage = (isset($_SESSION['form_values']) ? $_SESSION['form_values'] : 0);
$selected_terms = isset($storage['tags']) ? $storage['tags'] : NULL;
$form['terms'] = array(
'#title' => 'Filter by terms',
'#type' => 'select',
'#options' => $term_options,
'#multiple' => TRUE,
'#default_value' => $selected_terms,
);
$form['submit'] = array(
'#type' => 'submit',
'#value' => t('Filter'),
);
$form['reset'] = array(
'#type' => 'submit',
'#value' => t('Reset'),
'#weight' => 30,
'#submit' => array('tic_tools_reset'),
);
return $form;
}
Store selected values in the session
/**
* Implements hook_form_submit().
*/
function tic_term_filter_form_submit(&$form, &$form_state) {
// Stores form values in session.
$_SESSION['form_values'] = $form_state['values'];
}
Reset the filter
/*
* Clears set filters.
*/
function tic_tools_reset() {
if (isset($_SESSION['form_values'])) {
unset($_SESSION['form_values']);
}
drupal_goto(current_path());
drupal_set_message('Filters were reset');
}
The following page on the drupal forum contains a very clear explanation of the drupal form process and what to do in your specific case. See the answer from user Jaypan.
http://drupal.org/node/1770512
To sum his answer up:
Create a submit button on the form to submit the chosen filter. This button has it's own submit function:
$form['submit_filter'] = array(
'#type' => 'submit',
'#value' => 'Apply the filter',
'#submit' => array('apply_filter')
);
Create the submit function for applying your filter. In this function store the value of the filter to save it for the next form building when the page refreshes. Also set $form_state['rebuild'] to TRUE.
function apply_filter($form, &$form_state)
{
// Save the filter
$form_state['filter'] = $form_state['values']['filter'];
$form_state['rebuild'] = TRUE;
}
Now you will have access to the filter value the next time the form is built. Just check for the existence of the value like:
if (isset($form_state['filter']))
{
// do your filtering here
}
Hope this helps.