I am wondering, is there a function that allows me to check instantly if a record in the database exists?
Right now I am using the following piece of code to detect if a record exists, but I can imagine there is a simpler/better way.
$conditions = array(
'conditions' => array(
'User.id' => $this->Session->read('User.id'),
'User.activation_key' => $this->Session->read('User.key')
)
);
$result = $this->User->find('first', $conditions);
if (isset($result['User'])){
//do something
}
Is there something like:
$conditions = array(
'conditions' => array(
'User.id' => $this->Session->read('User.id'),
'User.security_key' => $this->Session->read('User.key')
)
);
if ($this->User->exists($conditions)){
//do something
}
Okay, yes there is. It's called exists(), but I need the same, but with parameters, so I can add my own conditions to the check.
I have searched google, but I can't find any topic about this. Well, a lot about php and mysql, but not about cakephp. I need a cake specific answer.
Thanks for your time :)
What you are looking for is Model::hasAny
Usage:
$conditions = array(
'User.id' => $this->Session->read('User.id'),
'User.security_key' => $this->Session->read('User.key')
);
if ($this->User->hasAny($conditions)){
//do something
}
Related
I have this on a HABTM statement:
$this->set('usergroups', $this->User->find('first', array('conditions' => array('User.id' => $this->Auth->user('id')))));
This gets groups that are associated to the user id via a courses_users table.
This works perfectly find, except I also need to find all groups that a user doesn't belong to. How do I get the opposite of the statement above?
I used 'not' as a condition, and it still gave me the same result.
Thanks!
Something like this should work:
$user = $this->User->find('first', array(
'conditions' => array(
'User.id' => $this->Auth->user('id')
)
));
$otherGroups = $this->Group->find('all', array(
'conditions' => array(
'NOT' => array('id' => Hash::extract($user, '{n}.Group.id'))
)
));
Side Note: You should really be setting recursive to -1 in your AppModel and not relying on recursive to return additional data. Instead, use CakePHP's Containable Behavior.
I have a CakePHP controller like this:
$this->loadModel('Project');
$list2 = $this->Project->find( 'list', array(
'fields' => array('Project.project'),
'conditions' => array('Project.user_id' => $userId)
));
$this->set($list2, 'list2');
$this->loadModel('Distance');
if(!empty($this->request->data)){
$this->Distance->create();
if ($this->Distance->save($this->request->data)) {
$this->Session->setFlash('Saved.');
// $this->redirect(array('action' => 'index'));
} else {
$this->Session->setFlash('FAILED');
}
}else{
// $this->Session->setFlash('test');
}
and a view like this:
echo $this->Form->input('Distance.project', array('options' => $list2, 'label' => false, 'empty' => '(choose one)' ;
But I get inserted to the database the id of the project instead of the project name.
I never have such problems working with the fields - just with a list of data.
Any idea why it happens?
It's normal ... The $list2 it's and array ... and the values of the options are the indexes from that array.
If you want to insert only the project name you need to change $list2 with $list2['project_name']. You need to remove or replace the indexes of $list2.
LE: take iexiak example. He change also the code for you.
$list2 = $this->Project->find( 'list', array(
'fields' => array('Project.project'),
'conditions' => array('Project.user_id' => $userId)
)
);
This is because $list2 automatically creates a list of ID => project; and when you use that as input for your form it automatically creates the drop down to reflect this. This is generally the best practice, to link to ID's instead of to descriptions, as ID's do not change as often. The below should get you exactly what you want though:
$list2 = $this->Project->find( 'list', array(
'fields' => array('Project.project','Project.project'),
'conditions' => array('Project.user_id' => $userId)
)
);
The following query returns an array containing the proper ids, but null for all values.
If I remove the aggregation function (AVG()), it returns values (not the averaged ones of course), if I choose e.g. find('all') it returns the average, but not in the list format I want (I could work with that, but I want to try to do it with 'list' first).
$progress = $this->Trial->find('list', array(
'fields' => array(
'Trial.session_id',
'AVG(Trial.first_reaction_time_since_probe_shown) AS average_reaction_time'
),
'group' => 'Trial.session_id',
'conditions' => array(
'Trial.first_valid_response = Trial.probe_on_top',
'TrainingSession.user_id IS NOT NULL'
),
'contain' => array(
'TrainingSession' => array(
'conditions' => array(
'TrainingSession.user_id' => $this->Auth->user('id')
)
)
),
'recursive' => 1,
));
The generated SQL query returns exactly the result I want, when I send it to the DB via PhpMyAdmin.
SELECT
`Trial`.`session_id`,
AVG(`Trial`.`first_reaction_time_since_probe_shown`) AS average_reaction_time
FROM
`zwang`.`trials` AS `Trial`
LEFT JOIN
`zwang`.`training_sessions` AS `TrainingSession` ON (
`Trial`.`session_id` = `TrainingSession`.`id` AND
`TrainingSession`.`user_id` = 1
)
WHERE
`Trial`.`first_valid_response` = `Trial`.`probe_on_top`
GROUP BY
`Trial`.`session_id`
I've examined the source for find('list'). I think it's due to the "array path" for accessing the list getting screwed up when using functions in the query, but I couldn't fix it yet (or recognise my abuse of CakePHP logic).
Once I posted the question, Stackoverflow started relating the correct answers to me.
Apparently, it can't be done with 'list' without virtualFields.
I didn't expect that because it worked using the other find-types.
$this->Trial->virtualFields = array(
'average_reaction_time' => 'AVG(Trial.first_reaction_time_since_probe_shown)'
);
$progress = $this->Trial->find('list', array(
'fields' => array('Trial.session_id','average_reaction_time')
/* etc... */
));
This is my first question on stackoverflow so be nice if i'm doing some mistakes. Here's my problem :
I'm working on a messaging system and in my inbox function i want to list every conversations owned by the current logged in user. This is not a problem but then i want, for each conversation, list every users that owns it too (= recipients).
Here is how i'm dealing with it :
function inbox()
{
$conversationIDs = $this->ConversationUser->find('list', array(
'fields' => array('ConversationUser.conversation_id'),
'conditions' => array('user_id' => $this->Session->read('Auth.User.id')),
'recursive' => -1
));
$i = 0;
foreach($conversationIDs as $conversation)
{
$array = $this->ConversationUser->find('first', array(
'fields' => array('ConversationUser.conversation_id', 'ConversationUser.user_id', 'Conversation.subject', 'User.username'),
'conditions' => array('ConversationUser.conversation_id' => $conversation,
'NOT' => array('ConversationUser.user_id' => $this->Session->read('Auth.User.id'))
),
'recursive' => 1
));
$result[$i] = $array;
$i++;
$this->set(compact('result'));
}
}
I'm gathering every conversation's id that the current user owns then "foreach" theses ids to find every users in these conversations.
Actually it is working very fine but i find the solution a bit dirty. Is there a better way to foreach in controller then pass this in view better than this ?
Or maybe my approach is very bad and i should do in a completely other way ?
Edit :
In my Conversation Model :
public function getConversations($userID)
{
$conversationsIDs = $this->ConversationUser->find('list', array(
'fields' => array('ConversationUser.conversation_id'),
'conditions' => array('ConversationUser.user_id' => $userID),
'recursive' => -1,
));
$conversations = $this->find('all', array(
'conditions' => array(
'Conversation.id IN('.implode(",", $conversationsIDs).')'
),
'contain' => array(
'LastMessage' => array(
'User' => array(
'fields' => array('User.username')
)
),
'ConversationUser' => array(
'User' => array(
'fields' => array('User.username')
)
)
)
));
return $conversations;
}
In my Conversation controller :
function inbox()
{
$conversations = $this->Conversation->getConversations($this->Session->read('Auth.User.id'));
$this->set(compact("conversations"));
}
What do you think about it ? Actually it's working really fine for me. :)
The problem about your approach is that it will invoke N+1 queries, where N is the number of conversations. The first query will retrieve the conversation ids, and then for every conversation it will retrieve recipients. You can optimize this by one of the following:
Use Join to retrieve all the conversations and their recipients all at once: http://book.cakephp.org/view/1047/Joining-tables
Use WHERE ConversationUser.user_id IN (id1,id2,id3) sql condition in the second query to retrieve the recipients for all the conversations in a single query.
I like to implement
"SELECT * FROM TABLE_NAME
WHERE
name like '$query_string' or
title like '%$query_string%' or
tags like '%$query_string%'"
to mongoDB, and I tried
$condition = array('$or' =>
array('writer'=> array('name'=>"$query_string"),
'title'=> new MongoRegex("/$query_string/"),
'tags' => new MongoRegex("/$query_string/") ));
and this does not work.
What is proper way to implement that SQL to mongoDB?
Here's how I construct a case-insensitive, "contains" term
$containsTerm = new MongoRegex(sprintf('/%s/i', preg_quote($term, '/')));
So your condition might look like
$condition = array('$or' => array(
'writer.name' => $term,
'title' => $containsTerm,
'tags' => $containsTerm
));
Apologies if the condition array is wrong, I typically use the Doctrine ODM