CakeDC Search Plugin producting duplicate conditions - cakephp

So I'm using the (totally awesome) Cake DC Search plugin. Among other things, I want to have a 'min' and 'max' input, and search for records where 'amount' is within 'min' and 'max', if both are set, or greater-than/less-than min/max if only one is set.
I've got it working - the only problem is that the condition is being included twice in the SQL query. It's pretty obvious why... here's my model code:
public $filterArgs = array(
'range_min' => array('type' => 'query', 'method' => 'findByAmountRange'),
'range_max' => array('type' => 'query', 'method' => 'findByAmountRange'),
// Other rules go here
);
public function findByAmountRange($data = array()) {
// Returns a condition something like 'Model.amount BETWEEN 1 and 100'
}
So because both the 'range_min' and 'range_max' keys of $filterArgs both use the same method (findByAmountRange), then the condition is being included twice.
So, there are three solutions:
Don't worry about it, let the condition be there twice
Create a instance variable in the model, like findByAmountRangeHasBeenCalled, and set it true the first time the method is called, so we know not to call it again in future
Find a more elegant solution. Does the Search plugin have any way to deal with this? Can you set it to make two fields share a common filterArgs method, so that it only gets called once?
Thanks in advance.
PS - I know the test cases for the Search Plugin include a 'make range condition' example, but that's not what I want - I want two fields, with the user able to input into both of them.

OK, so it doesn't look like I'll get a proper answer. So, I've gone for option 1 - just leaving the duplicate condition in the query. Apparently MySQL will run a query optimiser prior to executing, and remove the duplicate condition, and so it won't affect speed in any significant way.

Related

cakephp: how can i set an fields-options like "only fields not null"

is there an option in the find-method of cake, where i can say "give me only fields that ore not null"? I dont want to put this condition seperatly for every field in the condition-array, better to set this as an option in the fields array like this.
$this->find('first',array(
'fields' => array("not" => null)
));
Or even to exclude fields like this.
$this->find('first' array(
'fields' => array('not' => array('id','created','modified'))
));
Thanks,
Guido
It's going to have to be a condition (why is it a problem as a condition?).
But, you can put it in a beforeFind() method, so you don't have to add the condition to each query. Putting it in a beforeFind() will make the condition get appended to every query before it actually runs the find. Sounds like what I assume you really want, since "but not as a condition" doesn't really give much reasoning why it can't be.

What is the difference between the way data in input and hidden form types are handled?

Finally, a simple, straight-answer question :D
Background: My company has changed the way that that they handle when certain sites are used. Previously, certain sites were only delivered to on certain weeks; now, every site delivers every week. They have asked me to get rid of the weeks field on their "add new site" form. The link between week and site is still necessary for the code to work, however, so I am trying to hide the field and populate it with every single week.
Auto-populating it is simple. I just do this:
echo $this->Form->input('Week', array('value'=>array('1','2','3','4','5')));
And when I debug the data getting sent from the form, I get the following, which is exactly the way I want it to work.
'Week' => array(
'Week' => array(
(int) 0 => '1',
(int) 1 => '2',
(int) 2 => '3',
(int) 3 => '4',
(int) 4 => '5'
)
So the next step is simply hide that input. Easy, right? I just do one of the following two things to the form:
echo $this->Form->hidden('Week', array('value'=>array('1','2','3','4','5')));
or
echo $this->Form->input('Week', array('value'=>array('1','2','3','4','5'), 'type'=>'hidden'));
All I have done is change the type to hidden. But now, the data returned from debugging the data from the form looks like this:
'Week' => array(
'Week' => '1 2 3 4 5'
So my question is, what is the difference in the way data is handled between a normal "input" field and a "hidden" field. Why does that difference occur, and why is it important? And for this particular issue, how do I get hidden data to behave in the same way as normal input data?
As you said in the comments, Week is a multiple choice input, so that's why the difference in value handling. If the input is something that allows multiple choice (like multiple select or checkboxes), then it's logical all values comes as an array. But the hidden type is basically a hidden text input (ok, maybe not, but I'm simplifying). Look, if you put
echo $this->Form->input('Week', array('type'=>'text', 'value'=>array('1','2','3','4','5')));
you'll get the same string as you have with the input field, so it isn't a matter of if it's hidden or not.
Now, for your case, you can add the week values as an string and change the way you handle the value on post, as a string instead of an array.
But, if by some reason that's not a possibility (too much code to change, etc), then keep the same code you have now, and hide it with css. Something like
echo $this->Form->input('Week', array('value'=>array('1','2','3','4','5'),
'div'=>array('style'=>'display:none')));
should do the trick (maybe a few more styles needs to be added, try with just that first).
I don't like the css solution that much, browsers can interpret css different ways and etc etc... But it fits your needs and you don't have to change anything else.
EDIT
On second though, it is possible to achieve the same array output with just hidden fields. It isn't pretty though. You have to change the name of every input to tell php it's an array, like this
echo $this->Form->input('Week1', array('type'=>'hidden', 'value'=>1, 'name'=>'data[Week][Week][]'));
echo $this->Form->input('Week2', array('type'=>'hidden', 'value'=>3, 'name'=>'data[Week][Week][]'));
echo $this->Form->input('Week3', array('type'=>'hidden', 'value'=>4, 'name'=>'data[Week][Week][]'));
The important part is the name option for every input, see the array reference? Specially the last empty []. This is actually how cakephp sends all data as an array. Have you tried to create a form without the FormHelper in cake? You wouldn't get the post data in $this->request->data['form_name'] unless you set the input names for all your form fields.
Cake sends all post data inside the $data array by naming all the inputs with <input name="data[ModelName][field_name]" and for multiple inputs is <input name="data[ModelName][field_name][]" (with the empty array at the end, so it gets numerically indexed). You can see that using any html inspector on any other form created with the formhelper in cake.
I hope it's clear... I'll stick with the css solution here. The multiple hidden inputs seems messier.

findAll in CakePHP 1.1

I'm working with a legacy CakePHP 1.1 application, and ideally need to modify some of the database queries. I'm much more used to working with 1.2 and 1.3 though, so I'm finding some of the "old style" code difficult to work with. The following query works in 1.1:
$events = $this->Event->findAll(array('Event.id'=>$event_ids));
I want to add another condition to that array, e.g., 'Event.start >' => [date]', but any attempt at all to do so seems to result in the query returning a null.
To add to my confusion, the Cake 1.1 Cookbook suggests that findAll works as follows:
findAll
string $conditions
array $fields
string $order
int $limit
int $page
int $recursive
If the $conditions parameter should be a string, then how come it often tends to come in the form of an array (not just in this application, I've seen it quite a lot elsewhere on the net)? What's the best route to getting the results I want from CakePHP 1.1? Short of upgrading the whole thing to a modern version of Cake?
Looking at the CakePHP 1.1 API it suggests the first parameter, $conditions, takes a mixed value.
However, circa CakePHP 1.2 RC2, the comparison operator moved from the right to the left (or the from the value to the key) to save concatenation.
The following should hopefully work for you:
$events = $this->Event->findAll(array(
'Event.id' => $event_ids,
'Event.start' => '> ' . gmdate(DATE_ATOM),
));

Tree Behavior : how to quickly reorder existing data by a certain field?

I have a cakephp app with a category model that acts as a Tree. I imported ~100 categories through a csv file.
I want to be able to quickly reorder all the categories by name so that my index view is ordered correctly.
I tried the reorder method from the Tree behavior :
$this->Category->reorder(array(
'id' => null,
'field' => 'Category.name',
'order' => 'ASC'
));
But it doesn't do anything. Am I missing something here ?
Thanks :)
I have just been looking into this and have come to the conclusion it is not possible to order the results in the generatetreelist() method - at least no easy way without looping through and manually moving each node. The best way to go about this is use the normal find method with the first argument as 'threaded', then you can apply SQL ordering like you would any query. I have this method in my Category model:
public function getThreaded($conditions = array()) {
return $this->find('threaded', array(
'order' => 'Category.name ASC',
'contain' => false
));
}
This returns me an array of all my parent categories alphabetically-ordered, with a 'children' key containing another array all the children of that category, in alphabetical order too! I use contain => false to cut down on the data returned (threaded returns data about each node's parent, which we don't need to know), you could alter it to include extra data if need be.
I understand this isn't 100% the same as generatetreelist(), but it's certainly tidier and a lot more flexible as you control the output. If you really needed to emulate generatetreelist()'s behavior, you could just loop through the array from above like so:
$treeArray = array();
foreach($category as $parent) {
$treeArray[] = $parent['Category']['name'];
if(!empty($parent['children']) {
foreach($parent['children'] as $childCategory) {
$treeArray[] = ' - '.$childCategory['Category']['name'];
}
}
}
Hope this helps.
Just a reminder: the reorder() method from the Tree behavior only modifies the left and right fields of a tree following MPTT logic (which is the type of tree used by this behavior). It does not make all find() in that model magically deliver the order defined by your reorder() method. You still need to pass an order parameter in the find() options to actually use the updated left and right values.
Suppose you are using the default column names used by TreeBehavior: lft for the left field and rght for the right field. After running once the reorder() method given in the question, to get the ordered data from your Model to pass to your View, you would use something like:
$this->Category->find('all', array(
'order' => array(
'Category.lft' => 'ASC'
)
));
Of course replacing the find type if you want to use something else than 'all'.
Ordering by Category.lft will in fact show you the order you would get by making a depth-first search, left to right - not an arbitrary order defined by the database like would happen if you had no order parameter, or if you used a simple 'order' => 'Category.name' in the find options which would ignore the tree structure.
P.S.: I know the question is 2 years old, but since nobody else explained what reorder() actually does, I think this would be useful.
If you are using the TreeLi helper to turn the results of generateTreeList into a UL/LI list, you can then use the jQuery plugin TinySort to sort the tree (http://tinysort.sjeiti.com/).

Pagination by conditions in cakephp

i am having a doubt in using pagination like thing in my application..
where mytable looks like
Entry Firstname Last Name Residential Address Degree Gender Submitter
1 Aruna Chinnamuthu MDu BE Female aruna#gmail.com
2 Nisha Durgaeni MS BE Female nisha#gmail.com
3 Nathiya N Mumbai BE Female nathiya#gmail.com
In my view i am trying to bring the First entry at first and on clicking the next link in the View it must show the Entries for the second submitter and goes on ..
I have seen the pagination concepts in book.cakephp.org. But in all those they have mentioned only to paginate by using limit and order and not by using conditions.. how to do so..
It is possible ??
My submitters is in the array as
function view($formid){
$submitters=$this->Result->find('all',array('conditions'=>array('Result.form_id'=>$formid),'group'=>array('Result.submitter_id')));
foreach($submitters as $submitter)
{
echo $submitter['Result']['submitter_id'];
}
}
That is i am trying to paginate by SUbmitters of my form .. Is it possible in cakephp??Please suggest me..
I think you might be looking to use the Containable behavior. That will let you specify conditions that will apply to the model's data retrievals.
I can't quite discern the rest of your code, as the formatting didn't make it from the OP very well, but I think your conditions are limited to form_id=$formid, right? I'd suggest (before that line) dynamically attaching a Containable behavior that limits the forms to just $formid.
I'm not 100% that this is what you're after, but I might be understanding the question incorrectly.
I am unsure of the CakePHP version that you are using, but in CakePHP 1.2, the Paginate method takes a second parameter. This is the conditions array:
$this->paginate('Result', array( 'id' => 1, 'someOtherCondition' => 'condition' ) );

Resources