I'm using FOSUserBundle to authenticate my users.
I'm trying to get the user object inside the Controller to register a trip where I should add the user object to this Trip before save.
I did not found how to do that because next method where I found it in symfony doc:
$user = $this->container->get('security.context')->getToken()->getUser();
renders the username as string, but I need the whole object.
Currently, I use this method, but it's not working properly.
$username = $this->container->get('security.context')->getToken()->getUser();
$em = $this->container->get('doctrine')->getEntityManager();
$user = $em->getRepository('SiteUtilisateurBundle:Utilisateur')->find($username);
How can I correctly do this?
I think Ramon is right. You already have the user object.
Also in Symfony > 2.1.x you can use
$this->getUser();
inside the controller.
The documentation for the getUser method indicates:
either returns an object which implements __toString(), or a primitive string is returned.
And if we look in the FOS\UserBundle\Model\User class over here (the base user class used by the FOSUserBundle) we can see that it does indeed have a __toString method:
public function __toString()
{
return (string) $this->getUsername();
}
I think that you actually get the User object but because it implements a __toString method it can be rendered directly in templates.
In Twig you can use:
{{ dump(user) }}
To see what kind of object you have. But You are actually using an object, not a string.
Solution:
$userManager = $this->container->get('fos_user.user_manager');
$user = $userManager->findUserByUsername($this->container->get('security.context')
->getToken()
->getUser())
In FOSUser 1.3 you can't call directly $this->getUser in SecurityController.
You have to call $this->container->get('security.context')->getToken()->getUser();
And this is enough to access the user object.
No need to call $user = $em->getRepository('SiteUtilisateurBundle:Utilisateur')->find($username);
Furthermore your find method automatically and implicitly cast your initial $username object to string because it doesn't wait an object as argument.
I had the same issue, to resolve it add the FOS classes in your use section i.e:
use FOS\UserBundle\FOSUserEvents;
use FOS\UserBundle\Event\GetResponseUserEvent;
use FOS\UserBundle\Model\UserInterface;
In symfony >= 3.2, documentation states that:
An alternative way to get the current user in a controller is to
type-hint the controller argument with UserInterface (and default it
to null if being logged-in is optional):
use Symfony\Component\Security\Core\User\UserInterface\UserInterface;
public function indexAction(UserInterface $user = null)
{
// $user is null when not logged-in or anon.
}
This is only recommended for experienced developers who don't extend
from the Symfony base controller and don't use the ControllerTrait
either. Otherwise, it's recommended to keep using the getUser()
shortcut.
Here is blog post about it
For FOSUser ^1.3 you can get current user from inside a controller that extends BaseController like this :
$user = $this->container->get('security.token_storage')->getToken()->getUser();
public function indexAction()
{
/* #var $user \FOS\UserBundle\Model\UserInterface */
if ($user = $this->getUser())
{
echo '<pre>';
print_r($user);
print_r($user->getRoles()); // method usage example
exit;
return $this->redirectToRoute('dashboard');
}
return $this->redirectToRoute('login');
}
Related
I want to create a settings page, which only has a form in it. If the form is submitted it only updates settings entity but never creates another one. Currently, I achieved this like:
/**
* #param SettingsRepository $settingsRepository
* #return Settings
*/
public function getEntity(SettingsRepository $settingsRepository): Settings
{
$settings = $settingsRepository->find(1);
if($settings == null)
{
$settings = new Settings();
}
return $settings;
}
In SettingsController I call getEntity() method which returns new Settings entity (if the setting were not set yet) or already existing Settings entity (if setting were set at least once).
However my solution is quite ugly and it has hardcoded entity id "1", so I'm looking for a better solution.
Settings controller:
public function index(
Request $request,
SettingsRepository $settingsRepository,
FlashBagInterface $flashBag,
TranslatorInterface $translator,
SettingsService $settingsService
): Response
{
// getEntity() method above
$settings = $settingsService->getEntity($settingsRepository);
$settingsForm = $this->createForm(SettingsType::class, $settings);
$settingsForm->handleRequest($request);
if ($settingsForm->isSubmitted() && $settingsForm->isValid()) {
$em = $this->getDoctrine()->getManager();
$em->persist($settings);
$em->flush();
return $this->redirectToRoute('app_admin_settings_index');
}
return $this->render(
'admin/settings/index.html.twig',
[
'settings_form' => $settingsForm->createView(),
]
);
}
You could use Doctrine Embeddables here.
Settings, strictly speaking, should not be mapped to entities, since they are not identifiable, nor meant to be. That is, of course, a matter of debate. Really, a Settings object is more of a value object than an entity. Read here for more info.
So, in cases like these better than having a one to one relationship and all that fuzz, you probably will be fine with a simple Value Object called settings, that will be mapped to the database as a Doctrine Embeddable.
You can make this object a singleton by creating instances of it only in factory methods, making the constructor private, preventing cloning and all that. Usually, it is enough only making it immutable, meaning, no behavior can alter it's state. If you need to mutate it, then the method responsible for that should create a new instance of it.
You can have a a method like this Settings::createFromArray() and antoher called Settings::createDefaults() that you will use when you new up an entity: always default config.
Then, the setSettings method on your entity receieves only a settings object as an argument.
If you don't like inmutablity, you can also make setter methods for the Settings object.
In Sonata Admin I need to disable the CSRF token in some of my forms but sometimes I don't want to create a Form Type class, choosing instead to let Sonata generate the form, as such:
/** #var $form \Symfony\Component\Form\Form */
$form = $this->admin->getForm();
How can I disable the CSRF token from this point?
Without a Form Type class, the best way to change the CSRF field would be in the admin Class. For that, it's possible to override this function:
public function getFormBuilder() {
$this->formOptions['data_class'] = $this->getClass();
$this->formOptions['csrf_protection'] = false;
$formBuilder = $this->getFormContractor()->getFormBuilder(
$this->getUniqid(),
$this->formOptions
);
$this->defineFormBuilder($formBuilder);
return $formBuilder;
}
I think it's not possible as from \Symfony\Component\Form\Form instance you have access to object ($form->getConfig()) that implements FormConfigInterface: you can call on it getOptions or getOption but there is no setOption method.
I am using Symfony version 2.7.6. I have created an entity named EmployeeBasicInfo having fields
firstname
lastname
identificationCode etc
I have created a callback function for validating Identification code in EmployeeBasicInfo entity itself which looks like
/**
* #Assert\Callback(groups={"edit_myinfo"})
*/
public function validateIdentificationCode(ExecutionContextInterface $context)
{
if ($this->getEmployeeFirstName() == 'fakename') {
$context->buildViolation('This name sounds totally fake!')
->atPath('employeeFirstName')
->addViolation();
}
}
and this callback function works properly
Actually I want such a callback functionality which checks identidfication code against database. I have added $em = $this->getDoctrine()->getManager(); inside the callback function and the error is like Attempted to call an undefined method named "getDoctrine" of class "XXX\EmployeeBundle\Entity\EmployeeBasicInfo".. Please advise me the effective way
Do not inject the EntityManager in your Entity. One basic concept of the DataMapper-Pattern is, that your entity does not have to know about your data source and its connectors.
I'd suggest to write a custom validation constraint, in which you inject the dependencies you need.
EntityManager, Repository to query, etc. Whatever service suits you.
Have a look at how to create custom constraint validators with dependencies
I would suggest you use a service to do this
class EmployeeUtility($connection)
{
public function __construct($conn) { $this->connection = $v; }
public function validateIdentificationCode($emloyeeId, $validationCode)
{
// Your code here
}
}
In your controller, you inject the service:
$employeeUtility = $this->get('employee.utility');
$employeeUtility->validateIdentificationCode(1,'GF38883dkDdW3373d');
Alternatively, add the code in a repository class.
I have a controller getting a form posted.
public function myPostAction(Request $request)
{
$form = $this->createForm('my_form', $my_object);
$form->handleRequest($request);
#...
I can see my CSRF token posted as parameter
my_form[_token] => lH38HTm5P0Cv3TOc4-9xi2COx-cZ670mpJ_36gR8ccI
I simply need to read it
$form->get('_token')
This tells me
Child "_token" does not exist.
How can I get this token ?
Here is the workaround I'm going to use meanwhile:
$token = $request->get($form->getName())['_token'];
I also noticed by chance that the intention used to generate the token is the form name
$csrf = $this->get('form.csrf_provider');
$intention = $form->getName();
$token = $csrf->generateCsrfToken($intention);
Like #Pierre de LESPINAY said, it is possible to do it by retrieving Token Manager service.
This service can also be injected in your constructor like that :
use Symfony\Component\Security\Csrf\CsrfTokenManagerInterface;
...
public function __construct(CsrfTokenManagerInterface $tokenManager)
{
$this->tokenManager = $tokenManager;
}
And used later like previously demonstrated :
$token = $this->tokenManager->getToken('myformname')->getValue();
You can get it with:
$request->request->get('my_form[_token]');
If you didn't disable CSRF-protection it will be applied and validated automatically and you don't need to check it by self.
How I can authentication in Symfony2 without cookies in a brouser? How can generate some like this http://some.site/hello/roman?PHPSESSID=9ebca8bd62c830d3e79272b4f585ff8f or this http://some.site/9ebca8bd62c830d3e79272b4f585ff8f/hello/roman or some other url that was always available sessionid parameter. Thank you for any help.
You have to to two things. First you must extend the session storage to get the session from the query param.
namespace Elao\BackBundle\Session;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Symfony\Component\HttpFoundation\Session\Storage\NativeFileSessionStorage;
class Storage extends NativeSessionStorage
{
public function __construct($savePath = null, array $options = array(), ContainerInterface $container)
{
$request = $container->get('request');
if ($request->query->has('sessionId')) {
$request->cookies->set(session_name(), 1); // We have to simulate this cookie, in order to bypass the "hasPreviousSession" security check
session_id($request->query->get('sessionId'));
}
return parent::__construct($savePath, $options);
}
}
Source: http://www.elao.com/blog/symfony-2/symfony-2-loading-session-from-query-param.html
The next point, should be replacing the UrlGenerator to generate every url with the session id param. A example to do this, can be found in this answer.
But as nifr in the comment said, it's not a very clean requirement.