14

I try to create an Admin User with FOsUserBundle from command windows with the following command:

php app/console fos:user:create

In my project the Admin User extends other user with mandatory propriety. So, when I choose my username, mail and password, it tells me:

SQLSTATE[23000]: Integrity constraint violation: 1048 Column 'latitude' cannot be null

How can I set the value "latitude" in my AdminUser? I also use PUGXMultiUserBundle.

Gianni Alessandro
  • 860
  • 6
  • 11
  • 28
  • 3
    Have you tried setting the property to a default value at the declaration? Something like "private $latitude = 0". Of course this is not optimal, because it is not really a useful default value. But I guess you have no other choice, other than settings a default value, if you want to use the fos:user:create command. If thats not what you want, I guess you have to create your own user create command, which should not be too hard. – Leif Feb 13 '14 at 18:01
  • @Leif I would avoid to put a default value. How is the way to create a my user create command? Where can I find documentation? – Gianni Alessandro Feb 13 '14 at 18:49

3 Answers3

14

Only possibile way to reach that to me is

1 - override the cli command of FOSUserBundle placed into Command/CreateUserCommand.php
2 - override the user create method of FOSUserBundle placed into Util/UserManipulator.php

// Command/CreateUserCommand.php
protected function execute(InputInterface $input, OutputInterface $output)
{
  $username   = $input->getArgument('username');
  $email      = $input->getArgument('email');
  $password   = $input->getArgument('password');
  $inactive   = $input->getOption('inactive');
  $superadmin = $input->getOption('super-admin');
  $latitude   = $input->getOption('latitude'); //this will be your own logic add

  $manipulator = $this->getContainer()->get('fos_user.util.user_manipulator');
  $manipulator->create($username, $password, $email, $latitude, !$inactive, $superadmin);

  $output->writeln(sprintf('Created user <comment>%s</comment>', $username));
}

and

// Util/UserManipulator.php
public function create($username, $password, $email, $latitude, $active, $superadmin)
{
  $user = $this->userManager->createUser();
  $user->setUsername($username);
  $user->setEmail($email);
  $user->setPlainPassword($password);
  $user->setEnabled((Boolean) $active);
  $user->setSuperAdmin((Boolean) $superadmin);
  $user->setLatitude($latitude);
  $this->userManager->updateUser($user);

  return $user;
 }

Of course when I say override i mean ... override :P So you haven't to modify FOSUserBundle original files (you know, it's dangerous for many reasons) but make your own files by making your bundle extended by FOSUserBundle

Are you wondering how to make your bundle extended by FOSUserBundle?

Into your bundle "mainfile" - is the one you use to register your bundle - just add this lines

public function getParent()
{
  return 'FOSUserBundle';
}

Then you simply recreate the tree structure where your ovverride files lives into original bundle, into your custom bundle's Resources/ directory (same position, same file name, same annotations if any) and .... the magic can start :) (this is valid only for views, please pay attention!)

What "override" means?

Override means that you take an existent function, "shadow" it by redefining elsewhere (declare a function with the same name, no matter how many parameters it accept, no matter the type of paramenters since php doesn't support method overloading [except if you do some "hack"]) and then you can use it instead of the original one. This is a common technique for add extra functionalities to a function or to change the function itself.
Say that we have two classes, A and B with B that is a child class of A. Say also that A have a method called myMethod().

In B we can do something like

public function myMethod() {
  parent::myMethod();
  //add extra functionalities here
}

in that way we're adding extra functionalities as we're calling the parent ("original") method and then execute some extra functionalities

Whereas if in B we make something like

public function myMethod() { //some code here, but not calling parent method }

we're redefining the behaviour of myMethod()

How Symfony2 let me override methods?

As I said previously in my answer, you have to make your bundle a child of the bundle that containts the function(s) you're trying to override (in that case FOSUserBundle). Once you did it, use the Resources directory of your bundle to accomplish what you need. reproduce the "tree-folder-structure" of the original bundle (ie.: same names of the folders) until you reach the class that contains the function you need to override.

Follow your real example: you need to override execute() function contained in Command/CreateUserCommand.php. You have to create, into your bundle folder that path:

PathTo/YourCostumBundle/Command/

and place inside the file CreateUserCommand.php with the content I show you above.

If you don't understand where I find that path, please take a look to FOSUserBundle code and it will be absolutely clear!

Why is dangerous to modify the FOSUserBundle code directly?

Well, there's a lot of answer an critic point that I can show you. Choosing the main (not ordered for importance):

  • What if you need to update FOSUserBundle? You'll use composer and lost every modify that you made to FOSUserBundle code
  • What if you have more than one bundle into your project that need to use FOSUserBundle? Maybe the custom behaviour makes sense for a bundle but not for the other one. Costumizing the behaviour at local bundle level helps you to keep FOSUserBundle logic intact
  • What if you're developing a bundle that you want to share with other user? You need to force them to "take" your own costumized FOSUserBundle version and warn them about updating it

Finally: I perfeclty know that your entity isn't into FOSUserBundle, but I can bet that they extend FOSUserBundle base user so what I told above is applicable to your case.

Hope it's less fuzzy now :)


Documentation: http://symfony.com/doc/current/cookbook/bundles/inheritance.html#overriding-controllers

DonCallisto
  • 29,419
  • 9
  • 72
  • 100
  • Really thank you for your help. I'm very new of Symfony and php, so I don't properly understand when you say "override". Why is dangerous modify the FOSUserBundle? Well, the doubt is: what should I change? Now I use FosUserBundle and PUGXMultiUserBundle, and my User entity is not in the FOSUserBundle, but it is in an UserBundle, and it is extended by two different kind of entity( as user1 and user2). – Gianni Alessandro Feb 15 '14 at 17:37
  • Hi! I have one more doubt. I do how you told me (I created a Acme\MainBundle\Resources\FOSUserBundle\Command\CreateUserCommand.php and a Acme\MainBundle\Resources\FOSUserBundle\Util\UserManipulator.php files and put the parent declaration into \Acme\MainBundle\AcmeMainBundle.php). I clear the cache but the cmd command still doesn't ask me for latitude. Where could I get wrong? How can the cmd that I'm calling the command from MainBundle and not directly the one from FOSUserBundle? – Gianni Alessandro Feb 23 '14 at 13:48
  • I managed to override the templating system, creating the `Acme\MainBundle\Resources\views\layout.html.twig file`; not "adding" the "FOSUserBundle" folder into the Main Bundle. I tried also to change the `protected function configure()` into CreateUserCommand.php adding `new InputArgument('latitude', InputArgument::REQUIRED, 'Latitude')`. – Gianni Alessandro Feb 23 '14 at 14:43
  • Hi @GianniAlessandro: are you wondering how the system can now what command to call? It's easy: is Symfony2 logic. Don't know why your command still not working but I'm sure that what I suggested to you is the right way to accomplish what you asked here. And I'm sure as I do a similr thing into a project of mine and also read about into documentation ;-) – DonCallisto Feb 23 '14 at 15:55
  • But just a clarification. Is it correct to put the files into `Acme\MainBundle\Resources\FOSUserBundle\Util\...` o should I just put it into `Acme\MainBundle\Resources\Util\...` Because reading documentations it seems to me more the second one. – Gianni Alessandro Feb 23 '14 at 20:21
  • 1
    @GianniAlessandro: Hi Gianni. I was making a mistake. Now that i checked into my proget, I saw that only views are overridden with Resources folder. For override controller, just recreate the three-folder-structure directly into your bundle main folder. See the update in my answer if it makes sense to you and please keep me updated. – DonCallisto Feb 23 '14 at 23:06
  • Thanks for the answer. – Zuhayer Tahir Jun 15 '17 at 06:43
2

I always follow the pattern I learned in the symfony documentation itself:

php bin/console fos:user:create usertest mail@domain.com password

and sometimes I need change the "roles" on the table "fos_user"

then

a:0:{}

to

a:1:{i:0;s:10:"ROLE_ADMIN";}
2

After creating a user with:

bash-5.1# bin/console fos:user:create admin admin@mydomain.com password123

Promote the user with the ROLE_ADMIN role:

bash-5.1# bin/console fos:user:promote
Please choose a username:admin
Please choose a role:ROLE_ADMIN
Role "ROLE_ADMIN" has been added to user "admin". This change will not 
apply until the user logs out and back in again.
medunes
  • 541
  • 3
  • 16