How to use sql 'between' command with CakePhp requestAction() - cakephp

I have an element that grabs data from mysql. Here is my working code:
$this->requestAction('posts/index/sort:id/direction:desc');
I want to grab only posts between id 1 and 6. How can I run that query via requestAction? Some of scripts that I have tried are below. None is working:
$this->requestAction('posts/index/sort:id/direction:desc', array('id between ? and ?' => array('1,6')));
or
$this->requestAction('posts/index/sort:id/between:1,6/direction:desc');
You may see my project at http://bake.yemeklog.com/ I want this code for third column (Last 30 days faves)

If I was going to be calling it via requestAction (!) then I would write a custom method in my controller, then I'd probably pass the two id's into that method as parameters.
Then you can process the parameters and formulate your query.
$this->Model->find('all', 'conditions' => array('id'=>array(1,2,3,4,5,6)));
Not ideal by any means, but I'm not quite sure how else I would approach this kind of problem.
If it's static id's then perhaps
$this->Model->find('all', null, null, 'order' => 'id ASC LIMIT 0,6');
** Now I'm not sure if that would work as I haven't tried it, but I often hacked little things like this into Cake with some success. So perhaps give it a try, be sure to set debug = 2 so you can see the query, or grab DebugKit from OhLo
PS, Dont forget if you write requestAction methods, to check that $this->params['requested'] is true, so you know it come from a requestAction

Related

Associating multiple models in CakePHP

I am currently working on an application in CakePHP to display (but not modify) the contents of a legacy database. I am not able to change the database structure in any way.
There are six tables I am working with and the relationships are outlined in this awful paint diagram:
I have currently defined the models as follows:
http://pastebin.com/4aEaSnQp
(I decided to put it in a PasteBin as it is a bit of a wall of text, I am happy to edit it into the post if preferred).
What I would like to do is use one controller to pass relevant linked data from my controller to the view from essentially all of these tables. However, even if I set recursion to 2 the links only seem to go so far - for example if I try to find data from the 'Ctit' table with code like this:
$this->set('contracts',$this->Ctit->find('all',
array(
'recursion' => 2,
'conditions' => array('Title.TITNO' => $id),
'fields' => array('Contract.CONNO','Title.TITLE','Contract.CONDATE','Territory.DESCRIPTION')
)
));
The resulting query does not include the "Territory" table and so throws back an error.
What am I doing wrong here? Is it possible to retrieve the data in this way or might I have to run multiple finds or write my own queries (something I am hoping to avoid)?
Thanks in advance,
Kez
So... condensing the comments.
Basically it's a Containable problem. To get everything related to a single model (meaning, the 5 other models), a way to do it would be like
$this->Ctit->find('all', array(
'contain' => array(
'Royalty',
'Title',
'Contract' => array('Publisher', 'Territory')
)
You can also add options to that array, like any other query, for example order, fields, conditions, etc.
Example:
$this->Ctit->find('all', array(
'contain' => array(
'Royalty' => array('order' => 'id DESC'),
'Title' => array('fields' => array('id', 'name'),
'Contract' => array('Publisher',
'Territory' => array('conditions' => array('name' => 'terr'))
)
One thing to have in mind is to always use
public $actsAs = array('Containable');
(mind that s in actsAs, some people have had trouble because of that) otherwise your models won't behave containabl-y and you'd think this whole thing doesn't work.
Containable behaviour is useful for this, because you don't have to do a lot of finds, but keep in mind that cake does a lot of queries behind scenes to use containable. If you want this to be just one big query, use joins (found it!)
Also, be aware that this query might get big real quick. You are basically asking for all records with all 5 associations, when you reach a memory limit notice you are going to remember me. I doubt you want to show all data for every record on one view, so reconsider, maybe a simple paginate first and then a single view for each single record (in that case, the find will be a find('first') and that's lot better than find('all').

Removing a belongsTo from a model shows warning Model 'x' is not associated with model 'y'

I am new to CakePHP and I am having to maintain/develop a CakePHP application and struggling with removing a BelongsTo in one of the models.
The code has been copied from another project that used a lot more related tables. In the new project I do not need the relationships because it is creating LEFT JOINS in the queries that I really want to get rid of in order to speed things up. So I went in to the model and removed the $belongsTo property..
When I go to the home page I now get a warniing:-
Warning (512): Model "Product" is not associated with model "ParentProduct"
[CORE/Cake/Model/Behavior/ContainableBehavior.php, line 343]
If I turn off debugging it is not shown but I would like to know why this message is being generated. I am unable to find any information on how I should go about removing the belongsTo relationships.
Any help appreciated.
So I went in to the model and removed the $belongsTo property
Because you're asking for it
This kind of error is displayed when using the containable behavior incorrectly.
E.g. Consider User hasMany Article, and the following code:
$User->find('all', array(
'contain' => array(
'Article'
)
));
This would return all users and their articles (only), irrespective of any other associations that exist.
If an association is requested that isn't defined:
$User->find('all', array(
'contain' => array(
'Article',
'Comment'
)
));
Containable will generate a warning so that you, the developer, can know that there will be no Comments in your results which either indicates a typo or another kind of development error (Ah... it's User<-Article<-Comment).
This is in-keeping with what you describe since the model associations have been modified but (evidently) not the application code.
The message is been generated (most probably) because in your controller (check the ParentProductsController first) is something like
$this->ParentProductsController->Product->find();
That association of models no longer exists because you wanted to get rid of it, so there's no way for ParentProducts to call Product. You need to change calls like that to
ClassRegistry::init('the_name_of_the_model');
(in this case ClassRegistry::init('Product');) or load the model with
$this->loadModel('Product');
Now, this only is necessary when you call models not related to the current controller. If you are calling Product->find from the ProductsController, there will be no error.
Ok, that's the cause of the error.
But now: I don't recommend you deleting the association. There's really no need and your removing a logical association in the code even though it's still there in the database. There are other ways to avoid left joins and useless queries to the database without cutting someone a limb.
If you want to speed things up, read about Containable Behavior, and set all models to $recursive = -1 (recursive doc). That way you won't get LEFT JOINS unless you explicitly say so.

setSource not taken into account by Cakephp tree behavior

Tree behavior and associations is working well in my application.
I'm trying to switch tree table on runtime, which works well with following code in beforeFind method:
$this->setSource($table);
However, when I'm reordoning the tree using the recover method, the table name is not taken into account for all queries: I'm getting SHOW COLUMN queries on the new table, and SELECT queries on the default one. I tried to disable and clear cache of my application without success.
I'm also changing the table of associated Models, but problem arrises without it too.
Any piece of advice will be appreciated.
Edit:
Here is the model used:
https://github.com/croogo/croogo/blob/1.3/models/taxonomy.php
I disabled (permanently, not at runtime) the Cache behavior.
I traced the problem into recover method, the bindModel does not take into account the useTable.
$Model->bindModel(array('belongsTo' => array('VerifyParent' => array(
'className' => $Model->name,
'foreignKey' => $parent,
'fields' => array($Model->primaryKey, $left, $right, $parent),
))));
I tried without success:
$Model->VerifyParent->useTable = $Model->useTable;
I opened a lighthouse ticket:
https://cakephp.lighthouseapp.com/projects/42648/tickets/3820-cannot-change-table-name-using-treebehaviorrecover-in-shell
belongsTo associations cannot define custom tables for the linked model. You may need to seed ClassRegistry with a properly configured model with the VerifyParent key.
Problem can be fixed by modifying the Tree behavior:
$Model->VerifyParent->setSource($Model->useTable)
This a bug accepted and referenced here:
https://cakephp.lighthouseapp.com/projects/42648/tickets/3820-cannot-change-table-name-using-treebehaviorrecover-in-shell
However, not sure it will be fixed in cakephp source as it is very specific.

How to change a ARO parent in CakePHP

I am having trouble updating the aros table in my CakePHP app. Here is the code I've got:
$aro = new Aro();
$targetAro = $aro->find('first', array('conditions' => array('foreign_key' => intval($user['User']['id']))));
$newParent = $aro->find('first', array('conditions' => array('alias' => $userUpdate->level)));
$targetAro['Aro']['parent_id'] = $newParent['Aro']['id'];
$aro->updateAll($targetAro);
I've put in debug log statements to make sure that I'm getting the correct results from the find calls. But when I check the database after the updateAll call, the data is unchanged. Any ideas what might be going on?
I also tried calling $aro->setParent but I couldn't get that to work either.
I found the problem by tracing through the code that does a similar thing in the cake console. Instead of using $aro->updateAll($targetAro) I should be using $aro->saveAll($targetAro).
updateAll() is used to save changes to a number of entities. The first argument should be an array of values. saveAll() is used when you just want to save the changes to a single entity, as is the case in the code above.
Althought it seems like I should, I couldn't find error output anywhere in the logs or the script output because of the incorrect arguments I was passing to updateAll().

Filtering Containable Model Results

I am trying with the following line of code to filter all the Posts that have certain (irrelevant) conditions, by the tag "who"
$com= $this->Post->find('all', array('conditions' => $conditions, 'contain' => 'Tag.tag="who"'));
However, instead of the results being only the posts with the tags, I get every single post with empty tag arrays for the ones that don't have the tag "who".
I know my question has come up before, but the solutions posted have not worked with my code.
I have tried adapting the code here to my own:
http://web-development-blog.co.uk/2010/09/14/cakephp-habtm-find-with-conditions-and-containable-behavior/, but I get an SQL error stating "Tag.post_id" not found in on clause.
Please help.
Error message when trying to implement code from selected link:
SELECT `Post`.`id`, `Post`.`title`, `Post`.`body`, `Post`.`created`, `Post`.`modified`, `Tag`.`id`, `Tag`.`tag`, `Tag`.`created`, `Tag`.`modified` FROM `posts` AS `Post` LEFT JOIN `tags` AS `Tag` ON (`Tag`.`post_id` = `Post`.`id`) WHERE `Tag`.`tag` = 'who' 1054: Unknown column 'Tag.post_id' in 'on clause'
Which is caused by using this:
$this->Post->bindModel(array('hasOne' => array('Tag')));
$this->Post->contain(array(
'Tag'
));
$com=$this->Post->find('all', array(
'conditions'=>array('Tag.tag'=>'who')
));
Your error is that you are using bindModel wihtout saying the foreignkey or anything, you SHOULD establish the associations in the model and just use this on-the-fly method when is strictly neccesary.
you need to tell cake which foreignkey of not cake will use the default, in your case it will try Tag.post_id.
Also you should use a has many association or at least i think so. I said this beacause i suppose a post may have multiple tags.
once you do the asociation in the model and delete this line
$this->Post->bindModel(array('hasOne' => array('Tag')));
it should work perfectly
OR you can do the association with the correct parameters on the fly read the cookbook for this, the example that shows how to put the classname is the one you seek, just add the other attributes
EDIT:
Sorry, read something wrong... the has many association doesn't do a join so you have to use contain to specify the condition or add a condition to the association on the fly, here is how your code should look after adding the conditions with contain
$contain = array(
'Tag' => array(
'conditions'=> array('Tag.tag'=>'who')
)
);
$com=$this->Post->find('all', array(
'contain'=>$contain
));
REMEMBER contain conditions override the conditions in the associations!! if you want to have extra conditions you must add them on the fly something like:
$this->Post->hasMany['Tag']['conditions'] += array('Tag.tag'=>'who');
Remember that associations on the fly will work for that instance ONLY.
Also you may do a hasmany alias for different types (remember to define always the classname and foreignkey).
Hope it works this time, if not just comment to see it fix ;)

Resources