Create an Admin User with FosUserBundle

Gianni Alessandro picture Gianni Alessandro · Feb 13, 2014 · Viewed 16.7k times · Source

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.

Answer

DonCallisto picture DonCallisto · Feb 13, 2014

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