How to choose one field from one retrieved row in CakePHP? - cakephp

$users = TableRegistry::get('Users');
if ($this->request->data) {
$query = $users->findByEmail($this->request->getData('email'));
In the code above, I have retrieved one row from my table where the user's email matches the requested email.
Next, I want to write the code below to check if the password of the selected user is same as the requested password.
PasswordOfSelectedRow == md5($this->request->getData('password')))
What should I put instead of PasswordOfSelectedRow?

The following line returns a query object from a dynamic finder
$query = $users->findByEmail($this->request->getData('email'));
From the docs:
Once you have a query object from a dynamic finder, you’ll need to call first() if you want the first result.
So you could write something like this to retrieve the user:
$user = $query->first();
And then to compare to the request data:
$user->password == md5($this->request->getData('password')))

Related

Drupal 7, block on all profile pages. Printing fields from 'viewed user' not 'current user'

I'm trying to print a few fields in a block on each profile page.
The block needs to display the fields of the user being viewed, not the logged in user.
$account = user_load($node->uid); - doesn't work. user->uid doesn't either.
Globals user will return the logged in users info.
Not exactly sure how I'm supposed to load anything into a block. Any idea?
Assuming you're viewing a user profile with a URL path like this
drupal/user/USER_ID
You can do as follows :
// Option 1
$user = explode('/', current_path());
$user_id = end($user);
// Option 2
// $path = explode('/', current_path());
// $user_id = $path[count($path)-1];
$account = user_load($user_id, true);
Documentation current_path()
This way you get the last part of the URL and pass it to the user_load function. We set true as second parameter so it loads from the DB and not the cache.
Another way to do the same without breaking the URL into pieces is to use arg() to get the parameters
In this case the code would look like this
// Option 3
// drupal/user/USER_ID
// drupal = arg(0)
// user = arg(1)
// USER_ID = arg(2)
$account = user_load(arg(2), true);
In both cases check that $user_id is an integer, do not let it pass at least is an integer, then you can check the result of user_load.
Update
If you are using the user's name in the URL you can load a full user object by using user_load_by_name()
So the code would change a little bit. Try this :
$account = user_load_by_name(arg(2));
I used arg for simplicity, you can get the user's name from URL as you want.
Hope it helps.

Doctrine fetching indirectly associated objects

I am trying to fetch associated objects through 3 tables (user, client, account). User has a one-to-many relationship to client, client has a one-to-many relationship to account. I easily fetch all the clients for one specific user using this simple code:
$user = $this->getUser();
$id = $user->getId();
$user = $this->getDoctrine()->getRepository('AcmeUserBundle:User')->find($id);
$clients = $user->getClients();
Similarly, I have no issue retrieving all accounts for one specific client using this code:
$client = $this->getDoctrine()->getRepository('AcmeUserBundle:Client')->find($clientref);
$accounts = $client->getAccounts();
Now I want to obtain directly all accounts related to one user. How do I do so? I tried the following:
$user = $this->getUser();
$id = $user->getId();
$user = $this->getDoctrine()->getRepository('AcmeUserBundle:User')->find($id);
$client = $user->getClients();
$accounts = $client->getAccounts();
But I get the following error 'Attempted to call method "getAccounts" on class "Doctrine\ORM\PersistentCollection"'.
I believe I am missing something because "Accounts" may not be lazy loaded by Doctrine when I fetch the user, only "Clients" are. What is the best way to achieve this? Could you give me an example of code that would work (e.g. iteration or DQL query)?
Thanks.
That's correct behavior. A collection is returned by $user->getClients(), not a single object. Doctrine's collections do not proxy method calls to their members. There are two ways to solve your problem:
The simpler one. Rely on Doctrine's lazy load. Let's say you use data like this:
foreach ($client as $user->getClients()) {
foreach ($account as $client->getAccounts()) {
echo $account->getId();
}
}
ORM will fetch accounts automatically, running a separate query to database for each client. This will do only if you don't care about performance: O(N) requests are bad.
The better one. Use LEFT JOIN to get all the data with one query to database.
$qb = $this->getDoctrine()->getManager()->createQueryBuilder()
->select('u, c, a')
->from('AcmeUserBundle:User', 'u')
->leftJoin('u.clients', 'c')
->leftJoin('c.accounts', 'a')
->where('u.id = :id');
$user = $qb->getQuery()
->setParameter('id', $id)
->getOneOrNullResult();

Receive model data inside a CakePHP model callback function

I try to use existing model data inside a models callback function in CakePHP 2.1 but can't get it working.
What I do is I try to get a users role in the beforeValidate() callback and check if it's empty. If yes, I'll set it. Normally I do it like this, and for the first creation of the record it works pretty well.
if (empty($this->data[$this->alias]['role']))
$this->data[$this->alias]['role'] = 'user';
The problem is, every time an existing record (user) gets updated, the role will be set again.
Question: So, how do I check if the field role is already set in the record data, not the post data (seems like $this->data[$this->alias] only contains POST data)?
There are three solutions to this problem as I can see it.
Set a default value in the database column (easiest, best?)
Add role to your inputs everytime.
Lookup the user and add a role if it's missing
The first two options seem obvious, so I'll just illustrate the last.
public function beforeValidate() {
if (!empty($this->id) {
$this->data[$this->alias][$this->primaryKey] = $this->id;
}
if (!empty($this->data[$this->alias][$this->primaryKey])) {
// user exists, check their data
$id = $this->data[$this->alias][$this->primaryKey];
$user = $this->find('first', array(
'conditions' => array($this->primaryKey => $id)
));
$this->data[$this->alias]['role'] = $user[$this->alias]['role'];
}
if (empty($this->data[$this->alias]['role'])) {
// new user but missing a role
$this->data[$this->alias]['role'] = 'user';
}
return true;
}
This callback will check if an ID was passed, and if so it will look up the user and populate the role field. Then, it checks for an empty role and fills it with the default if necessary. Obviously he more code you have, the more possibilities for bugs, so I suggest the first option for default column values.
try:
if (empty($this->data[$this->alias]['role']) && empty($this->role)) {
$this->data[$this->alias]['role'] = 'user';
}

how to display the data returned by get_by_user_id() in DataMapper Code Igniter?

I am new to code igniter data mapper. I have a table called user, and I am trying to retrieve data from the database table and show them to the user.
Here is what I have in the model:
$u=new User();
$results=$u->get_by_user_id($id);
//$results here will be set to huge bunch of none sense data( which also includes the row that I am looking for as well)
if ($u->exists())
{
foreach ($results->all as $row){
$data['user']['first_name']=($row->user_first); //this where I am stuck ..
$data['user']['last_name']=($row->user_last);//this is also where I am stuck..
}
I don't know how to treat results to get a required fields I am looking for and store them in the $data I am passing to the user to view.
Thanks!
When you call get_by_x() on the model, the fields will be populated with data and you can access them like this:
$u = new User();
$u->get_by_user_id($id);
if($u->exists())
{
// you can access the table columns as object fields
$data['user']['first'] = $u->first;
$data['user']['last'] = $u->last;
}
else
{
$data['error'] = 'No such user!';
}
Have a look at the documentation which is really helpful: see Get and Get By.
Also, DataMapper expects all tables to have an id column: see Table Naming Rules. If your column is named id you should then call $u->get_by_id($id) instead of $u->get_by_user_id($id).

CakePHP user session not updating but database yes

I'm developing with cakePhP and I have the following problem:
When a user logs in with his name and password to the account system that I've created, he can save items (images) as favorites. This is saved in a text field into the database. What is saved is the image ID.
The saving process works perfectly, the user clicks on the images and they're added to that field (it actually saves all the IDs as a text array that I process later).
The problem comes when removing images. When the user does it (I'll post the code below), the images is removed correctly from the database (I go to PHP MyAdmin and I see it). This means that the array that holds the favorite images IDs is updated instantly. However, when I reload that array from the website, it hasn't been updated. It's like it's stored in the caché or something. Then, if the user logs out and logs in again, then he can see the correct one. The thing is that I have other things in my website that work in a similar way and they all get updated instantly, so I can't see why this doesn't.
This is the code that I use to remove the ID from the database:
function remove_favorite($pictureID) {
$this->User->id = $this->Auth->User('id'); //We get the ID of the current user
$favoritesArray = $this->User->deleteFavoritePicture($this->User->id, $pictureID); //This function retrieves the array (string) of pictures from the user's table, and deletes all the images with the ID passed as parameter, returning the updated array (string)
$fields = array('images_favorites' => $favoritesArray, 'modified' => true); //We indicate the field that we're going to update in the users table
//We save the new string that doesn't contain the deleted image anymore
if($this->User->save($fields, false, array('images_favorites'))) {
$this->Session->setFlash(__('The image has been removed from your favorites', true));
} else {
$this->Session->setFlash(__('Error removing image from favorites, please try again', true));
}
$this->redirect(array('action' => 'manage_favorites',$this->User->id));
}
This is how the deleteFavoritePicture function looks like:
function deleteFavoritePicture($userID, $pictureID) {
$userInfo = $this->find("id = $userID");
$favoritePicturesString = $userInfo['User']['images_favorites'];
$favoritePicturesArray = explode(",", $favoritePicturesString); //Array
$i = 0;
while ($i < count($favoritePicturesArray)) {
//We remove from the array the images which ID is the one we receive to delete
if ($favoritePicturesArray[$i] == $pictureID) unset($favoritePicturesArray[$i]);
$i++;
}
$favoritePicturesString = implode(",", $favoritePicturesArray); //String
return ($favoritePicturesString);
}
That's it. Does anyone now what can be going on? Thanks so much in advance for any clue!
EDIT
Ok, I think I found something that may give a clue of what's going on here:
This is the code for the manage_favorites action:
function manage_favorites($id) {
//$user = $this->User->find("id = $id");
$user = $this->Auth->user();
$this->set('user', $user);
}
That is the action that is called for the page when a user wants to modify his favorites. The same action is called once the user removes a favorite. Here's the thing:
If I use the $id parameter in the manage_favorites function and the $user = $this->User->find("id = $id"); line (the one quoted now), then the problem does not exist! This is how I used to have it. HOWEVER, I had to change it because it was a big security flaw, since the user id ($id) was a visible parameter who anyone could change, and then access other users accounts. What I did was changing the way I obtain the user array of favorite images, using the following line: $user = $this->Auth->user();. This is how I have it now (well, and also without the $id parameter in the function header), so the user information (including the favorites array) comes from the Auth component, instead directly from the database.
So, the problem is clear: when the user deletes a favorite, it's doing it on the array in the database. WHen I show the result of that operation, the array I'm retrieving is not the one in the DB, it's the one in the session. That's why it's not showing the changes.
How can I avoid this without using a non-secure method like the one I had before?
When you save, the array passed to the save method of the model should look like this:
[User] => array(
[field] => value,
[field2] => value2,
...
)
In your example, you clearly haven't added the [User] key.
Also, is your modified field actually the default Cake modified field? That is, the DATETIME field which changes to the current time when the row is updated?
Lastly, maybe you have debugging set to 2 in config.php. try changing this to 0 (as in production) and see if caching persists.
Hope some of the points I have mentioned above will solve your problem. Please let me know!
There could be two things wrong with this.
What does your deleteFavoritePicture method look like? There could be something being done wrong there.
You're passing false as the second parameter to the User::save method, which means that you don't want to validate. Unless there is a SQL error, then this will return true even if it doesn't validate properly, I believe. Try changing this false to true and see if your results differ.

Resources