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),
));
Related
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.
I have this field whose value i have to increment the field value by a specific value.
I am using this
$data['quantity'] = 'Order.quantity+1';
which doesnt works for me quantity is a integer coloumn here.
Also will it work when nothing is in database?.
Regards
Himanshu Sharma
I used updateAll in my code to increment views in an article. Therefore, every time an article is visited, I call the following function from within my view action in my articles controller:
function incrementViewCount($id) {
$this->updateAll(
array('Article.viewed' => 'Article.viewed+1'),
array('Article.id' => $id)
);
}
Then in your controller…
$this->MyModel->incrementViewCount(123);
Basically similar to the tutorial suggested in the previous answer.
you can use updateAll() for this
a little googling reveals this pretty quick:
http://cakephp.1045679.n5.nabble.com/Auto-Increment-A-Field-td3491697.html
You can try this code also. Works fine for simple ++/-- operations without the need of additional querying.
https://gist.github.com/denchev/8209318
Using saveField:
<?php
$this->Article->id = $id;
$this->Article->saveField('viewed', (int)$this->Article->field('viewed') + 1);
?>
I need to use Inflector::slug() over all results fetched from my database, which are, of course, retrieved in an array. Is it possible somehow, or I'll need to loop each result and slugify it?
Thanks!
PHP's array_map() function might do what you need (although it assumes a simple indexed array).
array_map( 'Inflector::slug', $your_result )
If you're looking at something more complex, CakePHP's Set utility class may be helpful in a multi-step implementation.
I haven't tried this in a CakePHP context (i.e. mapping through a CakePHP class method), but I can't think of any reason it wouldn't work off the top of my head. Maybe it'll at least get you started.
Depending on the array you can use array_walk or array_walk_recursive.
Something like this should work.
This is for 5.3+;
array_walk_recursive($posts, function(&$value) {
$value = Inflector::slug($value);
});
If you wanted to limit it to a certain field you could also do something like this:
array_walk_recursive($posts, function(&$value, $key) {
if ($key == 'title') {
$value = Inflector::slug($value);
}
});
I haven't used Cake in a while but like Rob Wilkerson said, you might find that the Set class could make lighter work of this.
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/).
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' ) );