I'm using cakephp. In some query I use these kind of find:
$this->Photo->Behaviors->attach('Containable', array('autoFields' => true));
This is the Contain array that i use in the find:
'contain'=>array(
'User'=>array('fields'=>array('User.Name','User.Username')),
'Like' => array('User'=>array('fields'=>'Name'),
'order'=>'Timestamp DESC'
)),
'recursive' => 2,
The problem is that every time i want the Name of User that liked a photo. Cakephp does this query.
For example: SELECT `User`.`Name` FROM `Users` AS `User` WHERE `User`.`id` = 2175
If i have 300 likes on one photo i will make another 300queries for the User.Name. So, I would like to cache this kind of request. I've installed memcache correctly in my server, it's working normally. But I can't find a way to cache the query that cake make with the Containable Behaviors.
Has some one had this problem?
Thanks
G.
Why not use cakephp's counterCache feature instead?
There is a lot of documentation in the cakephp book about caching queries not just in me cache but many other ways as well such. Check out the CakeCache class.
there are a number of approaches on this topic.
if it is only about belongsTo relations it boils down to manually join tables using bindModel().
here is a good behavior: http://planetcakephp.org/aggregator/items/891-linkable-behavior-taking-it-easy-in-your-db
it takes care of that itself.
Related
I have a db structure like this in MySql. And I use Cake PHP 3.5.
I wolud like to add to table1 a belongsToMany connection to table4. And add its inverse to table4 too.
$this->belongsToMany('Table4', /*What goes here*/);
And what is for table4?
Can I make this Join with a finder in the belongsToMany?
Thanks!
As ndm said in comments Cake does not suport what you want to do, just for a reason, this is not a many to many relation, please create you database by migrations, first of all https://book.cakephp.org/3.0/pt/migrations.html after that (bake migration, execute migration) your database will exist, the you can run a bake for create models, then you will realize that you can build a query like
$this->table1->table2->table3->table4->find()->where([conditions]);
or another like
$this->table1->find()->contain(['table2' => ['table3' => ['table4' => 'conditions' => ['RealConditions']]]])->first();
If you don't want to learn all of this you can go throught the paintfull path. Or just read about it first https://book.cakephp.org/3.0/en/orm/associations.html#belongstomany-associations
Recently I faced with doctrine 2.1 performance issue. In my request I have a lot of "LEFT JOINS", "WHERE" and "WHERE IN" clauses, and I need total count + specific set of records based on limit and offset.
First of all doctrine 2.1 doesn't support MySQL option Limit. I tried to attach Limit to the query, but every time I got "error expected end of string got 'limit'".
I tried to use
$queryBuilder
->setMaxResults(25)
->setFirstResult(10);
as it was suggested in many articles, but as it said in the documentation http://docs.doctrine-project.org/projects/doctrine-orm/en/latest/reference/dql-doctrine-query-language.html#first-and-max-result-items-dql-query-only
If your query contains a fetch-joined collection specifying the result
limit methods are not working as you would expect.
Which mean that if you expect 25 rows per page, you can get for example 18.
Doctine 2.1 doesn't have paginator by default as doctrine 2.2, so everyone suggest to use doctrine extention https://github.com/wiredmedia/doctrine-extensions/blob/master/lib/DoctrineExtensions/Paginate/Paginate.php, but it's also lame and decrease the performance. As I understood, it sends 2 requests: 1 request gets all the date without a limit and offset to count total count and the second request is a "WHERE IN" request with ids of the specific entities. It's too slow to me.
So you probably want to know what is my solution:
$data = $oQuery->getArrayResult();
return array(
'data' => array_slice($data, $iStart, $iLimit),
'count' => count($data)
);
If you have better and faster solution, please share it with me.
While your query is absent from the question, you have only two options: either use raw SQL with all necessary LIMITs or upgrade Doctrine version.
I have a site developed in cakephp 2.0, I have some tables relationed here is an example:
This is my relations:
ingredients (id,name) has many versions
ingredient_properties(id,property_id,version_id) belongs
to properties, versions
properties (id,name,value,group_id,unit_id) has many
ingredient_properties and belongs to groups,units
groups (id,name) has many properties
units (id,name) has many properties
versions (id,name,ingredient_id,active) has many ingredient_properties and belongs to ingredients.
I am in the ingredientController.php and I wanto to retrieve all this data where Version.active=1 and Version.ingredient_id=2.
This is my query:
$this->set(
'ingredient',
$this->Ingredient->Version->find('all', array(
'recursive' => 2,
'conditions' => array(
'Version.active' => 1,
'Version.ingredient_id' => 2
)
))
);
I have many and many queries like this and I want to know if recursive 2 is the best way to retrieve all data of the table that I have explained or there is a better way most quickly (in terms of speed of query not to implement).
I hope that someone can help me to optimize my code because this query works but I don't know if it is the better way to retrieve data of many tables relationed.
Thanks.
It is not the best way to use 'recursive' => 2 if you want to retrieve so much data. I believe it generates too many queries. Containable behaviour has the same drawback. The best way for me was to unbind models associations and construct table joins on the fly. You can look at an example here. But you need to know some SQL to understand what you do.
convert following query into cakephpquery.
"SELECT * FROM user1.user_favourites,esl.esl_lyrics
WHERE
esl_lyrics.id=user_favourites.fav_recordID
AND user_favourites.fav_userID=".$user_id."
AND user_favourites.fav_widgetID=$wid_id";
Models files are esl.php and userFavourite.php
DB are user1 and esl.
DB tables are user_favourites in user1 and esl_lyrics in esl DB.
plz give details.what changes are do in esl.php and userFavourite.php
please Help me...
It will be difficult to determine what to write until you can provide a data map for the various IDs you are using. Since you are not conforming to standards in your SQL, the fields are all named different in the various tables. But here is what I understand so far:
esl_lyrics.id = user_favorites.fav_recordID
From your description there are two models. So you will need to make sure you have relationships between the two. This will require that you determine if it is belongsTo, hasOne, hasMany, etc.
It also appears you are using multiple databases (schemas), so you will need to configure the database.php so that you can access each one.
Once everything is configured you should be able to access the data as:
$this->Model1->Model2->find('all', array('conditions' => array('Model1.id' => 'Model2.id', 'Model2.user_id' => $user_id, 'Model2.widgetID' => $wid_id)));
It will return an array with the data from both models. But until you can share what your models look like and a mapping of ids etc., this will be as good of an answer as you will get.
I have the following relationships set up:
A HABTM B
B belongsTo C
C hasMany B
Now, for a given A, I need all C with the B's attached. I can write the SQL queries, but what's the proper CakePHP way? What method do I call on which model, and with which parameters?
I'd go with Aziz' answer and simply process the data as it comes in. If you need C to be your primary model though, you'll have to do a little workaround. Cake is not terrifically good with conditions on related models yet, especially on removed 3rd cousins kind of queries. It usually only does actual JOIN queries on belongsTo or hasMany relations; not on HABTM relations though, those it gets in separate queries. That means you can't include conditions on related HABTM models.
Your best bet then might be something like this:
// get related records as usual with the condition on A, limit to as little data as necessary
$ids = $this->A->find('first', array(
'conditions' => array('A.id' => 'something'),
'recursive' => 2,
'fields' => array('A.id'),
'contain' => array('B.id', 'B.c_id', 'B.C.id') // not quite sure if B.C.id works, maybe go with B.C instead
));
// find Cs, using the ids we got before as the condition
$Cs = $this->C->find('all', array(
'conditions' => array('C.id' => Set::extract('/B/C/id', $ids)),
'recursive => 1
);
Note that this produces quite a bunch of queries, so it's not really an optimal solution. Writing your own SQL might actually be the cleanest way.
EDIT:
Alternatively, you could re-bind your associations on the fly to make them hasMany/belongsTo relationships, most likely using the join table/model of A and B. That might enable you to use conditions on related models more easily, but it's still tricky to fetch Cs when the condition is on A.
$this->A->find(
'first',
array('conditions'=>array('id'=>'someword'),
'recursive'=>2)
);
like this?
this might work
$this->C->find('all',
array('conditions'=>array('id'=>'someword','B.aid'=>$a.id)));
I'd think of "Containable" behaviour (http://book.cakephp.org/view/474/Containable)... gives a lot control on finding related data.