Get the entity that represents the current user [symfony2] - php

How do I get the email address of the current user ?
To retrieved the Username or user id is easy , but i didn't found any example that explain how to get the email address of the current use.
$entity = new Post();
$userManager = $this->container->get('fos_user.user_manager');
$usr = $userManager->findUserByUsername($this->container->get('security.context')
->getToken()
->getUser());
$entity->setUsername($usr);

In controller (that extends symfony controller)
$this->getUser();
For services you need to inject security.token_storage service and use
$this->tokenStorage()->getToken()->getUser()
TokenStorage::getToken() can return null, consider it!

Related

Obtaining a given item in a Doctrine ArrayCollection

Developing an API where at the start of every request, the provided API key is used to obtain the Account object which is associated with the request.
$account = $em->getRepository(Entity\Account\Account::class)
->findOneBy(['mainKey'=>$request->getHeaderLine('X-API-Key')]);
This Account entity contains a User's ArrayCollection where each of the User entities contains an username property which is unique for a given Account.
Given the username, how can I obtain the User entity? I can do something like the following, however, feel I should be doing differently.
$user = $em->getRepository(Entity\Account\User::class)
->findOneBy(['accountId'=>$account->getId(), 'username'=>'John.Doe']);
Thanks,
PS. I assume that findOneBy() is using a prepared statement behind the scenes and isn't subject to SQL injection, right?
PSS. I just assumed that an ArrayCollection holds a group of objects, but looking at some of the docs, am now not certain.
If Account is related to User (I suppose it is one-to-one), then Account should have $user property defined. And you can access it kinda:
$user = $account->getUser();
Where getUser is:
public function getUser()
{
return $this->user;
}
Both of these approaches seem to work:
$criteria = \Doctrine\Common\Collections\Criteria::create()
->where(\Doctrine\Common\Collections\Criteria::expr()->eq("username", $username));
$user = $users->matching($criteria)->current();
$expr = new \Doctrine\Common\Collections\Expr\Comparison('username', '=', $username);
$criteria = new \Doctrine\Common\Collections\Criteria();
$criteria->where($expr);
$user = $users->matching($criteria)->current();

Same User, multiple accounts with different roles

I'm creating an application in Symfony 3, that has the following structure:
class Account {
private $id;
private $name;
}
class User {
private $id;
private $email;
private $password;
}
class UserAccount {
private $id;
private $userId;
private $roles;
}
As we can see an user can belong to several accounts with different roles for each account, let's say that for Account 1 it has the role ROLE_ADMIN, and for the Account 2 it has the role ROLE_EDITOR.
The problem is that the user will have a select box where he can change the account, this means that the role needs to be loaded from the database based on a value on session ( since the account ID ) will be set on session.
This also means that when an user logins into the site, there will be no role, since the role is determined by the account selected.
I have tough about using events, but that doesn't seem to work from what I've read.
Does anyone has any thoughts/insights into this?
I have my own custom Authenticator, since I need to support both MD5 and bcrypt passwords.
This means that I have a class that extends SimpleFormAuthenticatorInterface of Symfony, this allows me to have the users login with MD5 and automatically upgrade them to bcrypt.
My User model ( which is an normal one ), and Custom Authenticator: Gist
To sumarize: I need a way in which I can change the roles of the user after he has logged in, without forcing the re login of the user.
So after two days of struggle, here is the solution.
Looking at the question, when the user logins it needs to take a role determined by what is in the UserAccount table, since an user can have several accounts associated to him, the only way to solve this was to first create a post login listener:
/**
* On login
*
* #param InteractiveLoginEvent $event The login event
*
* #return void
*/
public function onSecurityInteractiveLogin(InteractiveLoginEvent $event) {
$user = $this->tokenStorage->getToken()->getUser();
// get the user accounts of the current from the database
$accountsOfUser = $this->em->getRepository('AppBundle\Entity\AccountHasUser')->getAccountsOfUser($user->getId());
foreach ( $accountsOfUser as $accountOfUser ) {
$this->session->set('accountid', $accountOfUser['account_id']);
$user->resetAndAddRole('ROLE_' . $accountOfUser['const']);
break;
}
// We just need to set the new security token
$token = new UsernamePasswordToken(
$user,
null,
'main',
$user->getRoles()
);
// Update the current token to set the new role
$this->tokenStorage->setToken($token);
}
I known that I can only get one record from the database, but this was just for show ( don't blindly copy/paste this to your code ).
So basically I get the first account of the user, get it's role, put the account id on the session ( still got to read a bit more about bags on Symfony sessions ), and procede to generate a new UsernamePasswordToken and adding it to the tokenStorage.
The $user->resetAndAddRole, is a function in my User Model, that has only the following:
/**
* Resets current user roles and add's the new one
*
* #param string $role The role to add
*
* #return AppBundle\Entity\User
*/
public function resetAndAddRole($role) {
$this->roles = array($role);
return $this;
}
Now I also need to allow the user to change between accounts when is logged in, so in a controller:
public function changeAccountAction(Request $request, $id) {
$user = $this->get('security.token_storage')->getToken()->getUser();
$em = $this->getDoctrine()->getManager();
$newAccountRole = $em->getRepository('AppBundle\Entity\AccountHasUser')->getAccountModelByAccountIdANdUserId($id, $user->getId());
$user->resetAndAddRole('ROLE_' . $newAccountRole['const']);
$token = new UsernamePasswordToken(
$user,
null,
'main',
$user->getRoles()
);
// Update the current token to set the new role
$this->get('security.token_storage')->setToken($token);
$this->get('session')->set('accountid', $id);
// $em = $this->getDoctrine()->getManager();
// $accountsList = $em->getRepository('AppBundle\Entity\AccountHasUser')->getAccountsOfUser($user->getId());
// We need to change the users roles right here and how to we do it?
// We simply change the
return new RedirectResponse($this->generateUrl('dashboard'));
}
Basically, get the account that is passed by parameter, change the session value, so we can use this in our queries and every other code that requires the account id, and then create a new UsernamePasswordToken and voilá everything starts to work perfectly.
Later on I'm going to move the code on the controller to a service, which will also be passed to the post login listener, so that way I only have one play to make the changes to.
I really don't know if this is the right way to do this, but for now it seems to work.

phalcon 2.0.13 set data with magic setter to related model

I have a problem with phalcon model magic getter and setter.
I want to update like this tutorial :
https://docs.phalconphp.com/en/latest/reference/models.html#storing-related-records
But the thing is my proj is multi module and separated models folder.
So I have to use alias for hasOne and belongsTo
$this->hasOne('user_id', '\Models\UserProfile', 'user_id', array('alias' => 'UserProfile'));
and
$this->belongsTo('user_id', '\Models\CoreUser', 'user_id', array('alias' => 'CoreUser'));
What i want to do is like this.
$CoreUser = new CoreUser();
$user = $CoreUser->findFirst(array(
//...condition here to find the row i want to update
));
$user->assign($newUserData);
$user->setUserProfile($newProfileData);
$user->update();
But above this code only save user data and don't save Profile data at all. (have profile data -- confirmed)
So do you have any idea what the error is? if u know, Please help me or give me a tip.
I got it now.. when assigning like $user->UserProfile = $newUserProfile;
$newUserProfile should b a Model Object.
So my new code is
$CoreUser = new CoreUser();
$user = $CoreUser->findFirst(array(
//...condition here to find the row i want to update
));
$profile = $user->UserProfile; //$profile is now model object which related to $user
//assign new array data
$profile->assign($newProfileData);
$user->assign($newUserData);
/*
* can also assign one by one like
* $user->first_name = $newProfileData['first_name'];
* but cannot be like $profile = $newProfileData or $user->UserProfile = $newProfile
* since it's gonna override it the model with array
*/
$user->UserProfile = $profile;
$user->update(); // it's working now
Thanks to #Timothy for the tips too .. :)
Instead of doing
$profile = $user->UserProfile;
You should instantiate a new UserProfile object
// find your existing user and assign updated data
$user = CoreUser::findFirst(array('your-conditions'));
$user->assign($newUserData);
// instantiate a new profile and assign its data
$profile = new UserProfile();
$profile->assign($newProfileData);
// assign profile object to your user
$user->UserProfile = $profile;
// update and create your two objects
$user->save();
Note that this will always create a new UserProfile. If you want to use the same code to update and create a UserProfile, you can maybe do something like:
// ...
// instantiate a (new) profile and assign its data
$profile = UserProfile::findFirstByUserId($user->getUserId());
if (!$profile) {
$profile = new UserProfile();
}
$profile->assign($newProfileData);
// ...

Symfony3 doctrine orm find method

I am writing a Symfony3 appusing Doctrine ORM.
SO what i am trying to do is to find if a given email address exists in a table (every email is unique). so i have a user repository with some attributes I can easily persist data to the db but failing to retrive data.
/**
* #param $email
*/
public function findUserByEmail($email)
{
$user = $this->getDoctrine()
->getRepository('TestBundle:TestUser')
->find($email);
if (!$user) {
echo 'Error';die();
}
}
I know the var passed to the function contains a email string, but what i get in return is error and when i var_dump $user before the if statment i get null.
I followed the Symfony docs
Your User probably has a separate primary key field. the find() method on a repo only retrieves by primary key.
Repositories use __call to dynamically process findBy* and findOneBy* methods, so you could call it like this:
$repo = $this->getDoctrine()->getRepository('TestBundle:TestUser');
// magic find method
$user = $repo->findOneByEmail($email);
// explicit find method
$user = $repo->findOneBy(['email' => $email]);
// custom QueryBuilder
$user = $repo->createQueryBuilder('user')
->where('user.email = :email')
->setParameter('email', $email)
->getQuery()
->getSingleResult();
BTW: If you are validating this for a submitted form, there is a contraint that does this check for you: UniqueEntity
I think the problem is because you forgot to call getManager().
So the code would be:
$em = $this->getDoctrine()->getManager();
$user = $em->getRepository('TestBundle:TestUser')->findOneBy(['email' => $email]);
Hope it would help you!

Reuse password broker logic to send activation email

I've got a simple CRUD application in which is possible to add users, through a form, the ideal flow is
an admin fills the form with user name and password
an email is sent to the user with a link to set the password
the user is logged in
Now at the end of the day what I really want is that the PasswordBroker does, but instead to send the emails.passsowrd view I want a different one, and the rest of the logic can be the same
Is there an easy way so create a valid isntace of the passwordBroker and passing a different view?
the property emailWiew is protected so I cannot override it, I tried to create a new instance out of the IoC
$tokens = $this->app['auth.password.tokens'];
$users = $this->app['auth']->driver()->getProvider();
$view = "emails.createPassword";
$password = new PasswordBroker(
$tokens, $users, $this->app['mailer'], $view
);
dd($users->retrieveByCredentials(["email#user.com"])); //i get null and the user email is valid
$response = $password->sendResetLink(["email#user.com"], function (Message $message) {
$message->subject("Set your password");
});
dd($response); // I get "passwords.user" wich is an error
but when I pass the email address I get an invalid user error
any idea?
The problem is that you're not providing the key to retrieve the credentials, so it's trying to get a field in the users table by the name of "0". use the following and it will work:
$response = $password->sendResetLink(
["email" => "email#user.com"],
function (Message $message) {
$message->subject("Set your password");
});

Categories