diff --git a/Command/CreateUserByTypeCommand.php b/Command/CreateUserByTypeCommand.php new file mode 100644 index 0000000..4c4e303 --- /dev/null +++ b/Command/CreateUserByTypeCommand.php @@ -0,0 +1,139 @@ +setName('pugx:user:create-by-type') + ->setDescription('Create a user by type.') + ->setDefinition(array( + new InputArgument('type', InputArgument::REQUIRED, 'The user type'), + new InputArgument('username', InputArgument::REQUIRED, 'The username'), + new InputArgument('email', InputArgument::REQUIRED, 'The email'), + new InputArgument('password', InputArgument::REQUIRED, 'The password'), + new InputOption('super-admin', null, InputOption::VALUE_NONE, 'Set the user as super admin'), + new InputOption('inactive', null, InputOption::VALUE_NONE, 'Set the user as inactive'), + )) + ->setHelp(<<pugx:user:create-by-type command creates a user: + + php app/console pugx:user:create-by-type buyer matthieu + +This interactive shell will ask you for an email and then a password. + +You can alternatively specify the email and password as the second and third arguments: + + php app/console pugx:user:create-by-type buyer matthieu matthieu@example.com mypassword + +You can create a super admin via the super-admin flag: + + php app/console pugx:user:create-by-type admin gerard --super-admin + +You can create an inactive user (will not be able to log in): + + php app/console pugx:user:create-by-type buyer thibault --inactive + +EOT + ); + } + + /** + * @see Command + */ + protected function execute(InputInterface $input, OutputInterface $output) + { + $type = $input->getArgument('type'); + $username = $input->getArgument('username'); + $email = $input->getArgument('email'); + $password = $input->getArgument('password'); + $inactive = $input->getOption('inactive'); + $superadmin = $input->getOption('super-admin'); + + $manipulator = $this->getContainer()->get('pugx_multi_user.util.user_manipulator'); + $manipulator->createByType($type, $username, $password, $email, !$inactive, $superadmin); + + $output->writeln(sprintf('Created user %s', $username)); + } + + /** + * @see Command + */ + protected function interact(InputInterface $input, OutputInterface $output) + { + if (!$input->getArgument('type')) { + $type = $this->getHelper('dialog')->askAndValidate( + $output, + 'Please choose a type:', + function($type) { + if (empty($type)) { + throw new \Exception('Type can not be empty'); + } + + return $type; + } + ); + $input->setArgument('type', $type); + } + + if (!$input->getArgument('username')) { + $username = $this->getHelper('dialog')->askAndValidate( + $output, + 'Please choose a username:', + function($username) { + if (empty($username)) { + throw new \Exception('Username can not be empty'); + } + + return $username; + } + ); + $input->setArgument('username', $username); + } + + if (!$input->getArgument('email')) { + $email = $this->getHelper('dialog')->askAndValidate( + $output, + 'Please choose an email:', + function($email) { + if (empty($email)) { + throw new \Exception('Email can not be empty'); + } + + return $email; + } + ); + $input->setArgument('email', $email); + } + + if (!$input->getArgument('password')) { + $password = $this->getHelper('dialog')->askAndValidate( + $output, + 'Please choose a password:', + function($password) { + if (empty($password)) { + throw new \Exception('Password can not be empty'); + } + + return $password; + } + ); + $input->setArgument('password', $password); + } + } +} diff --git a/Controller/ProfileManager.php b/Controller/ProfileManager.php new file mode 100644 index 0000000..b23f6aa --- /dev/null +++ b/Controller/ProfileManager.php @@ -0,0 +1,81 @@ +userDiscriminator = $userDiscriminator; + $this->container = $container; + $this->controller = $controller; + $this->formFactory = $formFactory; + } + + /** + * + * @param string $class + * @return \Symfony\Component\HttpFoundation\RedirectResponse + */ + public function profile($class) + { + $this->userDiscriminator->setClass($class); + + $this->controller->setContainer($this->container); + $result = $this->controller->editAction($this->container->get('request')); + if ($result instanceof RedirectResponse) { + return $result; + } + + $template = $this->userDiscriminator->getTemplate('profile'); + if (is_null($template)) { + $engine = $this->container->getParameter('fos_user.template.engine'); + $template = 'FOSUserBundle:Profile:edit.html.'.$engine; + } + + $form = $this->formFactory->createForm(); + return $this->container->get('templating')->renderResponse($template, array( + 'form' => $form->createView(), + )); + } +} diff --git a/DependencyInjection/Configuration.php b/DependencyInjection/Configuration.php index 115ae8c..2cec1e5 100644 --- a/DependencyInjection/Configuration.php +++ b/DependencyInjection/Configuration.php @@ -21,7 +21,7 @@ public function getConfigTreeBuilder() $rootNode = $treeBuilder->root('pugx_multi_user'); $supportedDrivers = array('orm'); - + $rootNode-> children() ->scalarNode('db_driver') @@ -31,7 +31,14 @@ public function getConfigTreeBuilder() ->thenInvalid('The driver %s is not supported. Please choose one of '.json_encode($supportedDrivers)) ->end() ->end(); - + + $rootNode-> + children() + ->scalarNode('user_manager') + ->defaultValue('pugx_user.manager.orm_user_manager.default') + ->end() + ->end(); + $rootNode-> children() ->arrayNode('users')->prototype('array') @@ -40,7 +47,7 @@ public function getConfigTreeBuilder() ->children() ->scalarNode('class')->isRequired()->cannotBeEmpty()->end() ->scalarNode('factory')->defaultValue('PUGX\MultiUserBundle\Model\UserFactory')->end() - ->end() + ->end() ->end() ->end() ->children() @@ -80,11 +87,11 @@ public function getConfigTreeBuilder() ->end() ->end() ->end() - + ->end() ->end() ->end(); - + return $treeBuilder; } } diff --git a/DependencyInjection/PUGXMultiUserExtension.php b/DependencyInjection/PUGXMultiUserExtension.php index 2adf3b4..46d0c7b 100644 --- a/DependencyInjection/PUGXMultiUserExtension.php +++ b/DependencyInjection/PUGXMultiUserExtension.php @@ -21,13 +21,95 @@ public function load(array $configs, ContainerBuilder $container) { $configuration = new Configuration(); $config = $this->processConfiguration($configuration, $configs); - + + /** Extract parameters from config file */ $users = $config['users']; + /** Default users */ $container->setParameter('pugx_user_discriminator_users', $users); + /** Build Conf from parameters in config file */ + $conf = $this->buildConf($users); + $container->setParameter('pugx_user.discriminator.conf', $conf); + + /** Build User Types from parameters in config file */ + $userTypes = $this->buildUserTypes($users); + $container->setParameter('pugx_user.discriminator.user_types', $userTypes); + + /** Alias default manager */ + $container->setAlias('pugx_user.manager.orm_user_manager', $config['user_manager']); + $loader = new Loader\YamlFileLoader($container, new FileLocator(__DIR__.'/../Resources/config')); $loader->load('services.yml'); - + $loader->load(sprintf('%s.yml', $config['db_driver'])); } + + + /** + * + * @param array $entities + * @param array $registrationForms + * @param array $profileForms + */ + protected function buildConf(array $users) + { + foreach ($users as $user) { + + $class = $user['entity']['class']; + + if (!class_exists($class)) { + throw new \InvalidArgumentException(sprintf('UserDiscriminator, configuration error : "%s" not found', $class)); + } + + $conf[$class] = array( + 'factory' => $user['entity']['factory'], + 'registration' => array( + 'form' => array( + 'type' => $user['registration']['form']['type'], + 'name' => $user['registration']['form']['name'], + 'validation_groups' => $user['registration']['form']['validation_groups'], + ), + 'template' => $user['registration']['template'], + ), + 'profile' => array( + 'form' => array( + 'type' => $user['profile']['form']['type'], + 'name' => $user['profile']['form']['name'], + 'validation_groups' => $user['profile']['form']['validation_groups'], + ), + 'template' => $user['profile']['template'], + ), + ); + } + + return $conf; + + } + + /** + * Extract the user types from the pugx multi user configuration parameters into an array + * 'type' => 'class' + * e.g. array( + * 'user_one' => 'Acme\UserBundle\Entity\UserOne', + * 'user_two' => 'Acme\UserBundle\Entity\UserTwo', + * ) + * + * @param array $entities + */ + protected function buildUserTypes(array $parameters) + { + + $userTypes = array(); + while ($user = current($parameters)) { + $class = $user['entity']['class']; + if (!class_exists($class)) { + throw new \InvalidArgumentException(sprintf('ControllerListener, configuration error : "%s" not found', $class)); + } + $userType = strtolower(trim(key($parameters))); + $userTypes[$userType]= $class; + next($parameters); + } + return $userTypes; + } + } diff --git a/Doctrine/UserManager.php b/Doctrine/UserManager.php index e58c640..3847400 100644 --- a/Doctrine/UserManager.php +++ b/Doctrine/UserManager.php @@ -17,16 +17,16 @@ * @author eux (eugenio@netmeans.net) */ class UserManager extends BaseUserManager -{ +{ /** * - * @var ObjectManager + * @var ObjectManager */ protected $om; - + /** * - * @var UserDiscriminator + * @var UserDiscriminator */ protected $userDiscriminator; @@ -44,10 +44,10 @@ public function __construct(EncoderFactoryInterface $encoderFactory, Canonicaliz { $this->om = $om; $this->userDiscriminator = $userDiscriminator; - + parent::__construct($encoderFactory, $usernameCanonicalizer, $emailCanonicalizer, $om, $class); } - + /** * * {@inheritDoc} @@ -57,6 +57,18 @@ public function createUser() return $this->userDiscriminator->createUser(); } + /** + * + * {@inheritDoc} + */ + public function createUserByType($type) + { + $user = $this->userDiscriminator + ->createUserByType($type); + + return $user; + } + /** * {@inheritDoc} */ @@ -71,23 +83,23 @@ public function getClass() public function findUserBy(array $criteria) { $classes = $this->userDiscriminator->getClasses(); - + foreach ($classes as $class) { $repo = $this->om->getRepository($class); - + if (!$repo) { throw new \LogicException(sprintf('Repository "%s" not found', $class)); } - + $user = $repo->findOneBy($criteria); - + if ($user) { $this->userDiscriminator->setClass($class); return $user; } } - + return null; } @@ -119,14 +131,14 @@ public function findUsers() protected function findConflictualUsers($value, array $fields) { $classes = $this->userDiscriminator->getClasses(); - + foreach ($classes as $class) { $repo = $this->om->getRepository($class); - + $users = $repo->findBy($this->getCriteria($value, $fields)); - - if (count($users) > 0) { + + if (count($users) > 0) { return $users; } } diff --git a/Model/UserDiscriminator.php b/Model/UserDiscriminator.php index 2269d27..e5bb4ac 100644 --- a/Model/UserDiscriminator.php +++ b/Model/UserDiscriminator.php @@ -6,159 +6,184 @@ /** * Description of UserDiscriminator - * + * * @author leonardo proietti (leonardo.proietti@gmail.com) * @author eux (eugenio@netmeans.net) */ class UserDiscriminator { - const SESSION_NAME = 'pugx_user.user_discriminator.class'; - + const SESSION_NAME = 'pugx_user.user_discriminator.class'; + /** * - * @var SessionInterface + * @var SessionInterface */ protected $session; - + /** * - * @var array + * @var array Configuration built from the parameters in config file */ protected $conf = array(); - + + /** + * + * @var array of user types. e.g. array('user_type' => 'user_entity', ..) + */ + protected $userTypes = array(); + /** * - * @var Symfony\Component\Form\Form + * @var Symfony\Component\Form\Form */ protected $registrationForm = null; - + /** * - * @var Symfony\Component\Form\Form + * @var Symfony\Component\Form\Form */ protected $profileForm = null; - + /** * - * @var string + * @var string */ protected $class = null; - + /** * Current form - * @var type + * @var type */ protected $form = null; /** * * @param SessionInterface $session - * @param array $parameters + * @param array $conf The configuration of PUGXMultiUserBundle + * @param array $userTypes An array containing key-value pairs like this ('user_type' => 'user_entity') */ - public function __construct(SessionInterface $session, array $parameters) + public function __construct(SessionInterface $session, array $conf, array $userTypes) { - $this->session = $session; - $this->buildConfig($parameters); + $this->session = $session; + $this->conf = $conf; + $this->userTypes = $userTypes; } - + /** * - * @return array + * @return array */ public function getClasses() - { + { $classes = array(); foreach ($this->conf as $entity => $conf) { $classes[] = $entity; } - + return $classes; } - + /** * - * @param string $class + * @param string $class */ public function setClass($class, $persist = false) { if (!in_array($class, $this->getClasses())) { throw new \LogicException(sprintf('Impossible to set the class discriminator, because the class "%s" is not present in the entities list', $class)); } - + if ($persist) { $this->session->set(static::SESSION_NAME, $class); } - + $this->class = $class; } - + /** * - * @return string + * @return string */ public function getClass() - { + { if (!is_null($this->class)) { return $this->class; } - + $storedClass = $this->session->get(static::SESSION_NAME, null); if ($storedClass) { $this->class = $storedClass; } - + if (is_null($this->class)) { $entities = $this->getClasses(); $this->class = $entities[0]; } - + return $this->class; } - + /** * - * @return type + * @return type */ public function createUser() { $factory = $this->getUserFactory(); $user = $factory::build($this->getClass()); - + + return $user; + } + + /** + * + * @return type + */ + public function createUserByType($type) + { + /** Check that the user type exists */ + if (!array_key_exists($type, $this->userTypes)){ + throw new \InvalidArgumentException('This user type does not exist'); + } + $class = $this->userTypes[$type]; + $factory = $this->getUserFactory(); + $user = $factory::build($class); + return $user; } - + /** - * + * * @return string */ public function getUserFactory() { return $this->conf[$this->getClass()]['factory']; } - + /** - * + * * @param string $name - * @return + * @return * @throws \InvalidArgumentException */ public function getFormType($name) { $class = $this->getClass(); $className = $this->conf[$class][$name]['form']['type']; - + if (!class_exists($className)) { throw new \InvalidArgumentException(sprintf('UserDiscriminator, error getting form type : "%s" not found', $className)); } $type = new $className($class); - + return $type; } - + /** - * + * * @param string $name * @return string */ @@ -166,9 +191,9 @@ public function getFormName($name) { return $this->conf[$this->getClass()][$name]['form']['name']; } - + /** - * + * * @param type $name * @return type */ @@ -178,48 +203,12 @@ public function getFormValidationGroups($name) } /** - * + * * @return string */ public function getTemplate($name) { return $this->conf[$this->getClass()][$name]['template']; } - - /** - * - * @param array $entities - * @param array $registrationForms - * @param array $profileForms - */ - protected function buildConfig(array $users) - { - foreach ($users as $user) { - - $class = $user['entity']['class']; - - if (!class_exists($class)) { - throw new \InvalidArgumentException(sprintf('UserDiscriminator, configuration error : "%s" not found', $class)); - } - - $this->conf[$class] = array( - 'factory' => $user['entity']['factory'], - 'registration' => array( - 'form' => array( - 'type' => $user['registration']['form']['type'], - 'name' => $user['registration']['form']['name'], - 'validation_groups' => $user['registration']['form']['validation_groups'], - ), - 'template' => $user['registration']['template'], - ), - 'profile' => array( - 'form' => array( - 'type' => $user['profile']['form']['type'], - 'name' => $user['profile']['form']['name'], - 'validation_groups' => $user['profile']['form']['validation_groups'], - ) - ) - ); - } - } + } diff --git a/Resources/config/orm.yml b/Resources/config/orm.yml index bb950b5..4df8846 100644 --- a/Resources/config/orm.yml +++ b/Resources/config/orm.yml @@ -3,6 +3,15 @@ services: pugx_user.manager.orm_user_manager: class: PUGX\MultiUserBundle\Doctrine\UserManager arguments: ["@security.encoder_factory", "@fos_user.util.username_canonicalizer", "@fos_user.util.email_canonicalizer", "@fos_user.entity_manager", %fos_user.model.user.class%, "@pugx_user.manager.user_discriminator"] - + + # aliases pugx_user_manager: - alias: pugx_user.manager.orm_user_manager \ No newline at end of file + alias: pugx_user.manager.orm_user_manager + + # user manipulator + pugx_multi_user.util.user_manipulator: + class: PUGX\MultiUserBundle\Util\UserManipulator + arguments: + userManager: "@pugx_user_manager" + conf: %pugx_user.discriminator.conf% + userTypes: %pugx_user.discriminator.user_types% diff --git a/Resources/config/services.yml b/Resources/config/services.yml index 5143a87..9742c03 100644 --- a/Resources/config/services.yml +++ b/Resources/config/services.yml @@ -1,44 +1,54 @@ services: - + # to discriminate users types pugx_user.manager.user_discriminator: class: PUGX\MultiUserBundle\Model\UserDiscriminator - arguments: ["@session", %pugx_user_discriminator_users%] - + arguments: + session: "@session" + conf: %pugx_user.discriminator.conf% + userTypes: %pugx_user.discriminator.user_types% + #manage registration pugx_multi_user.registration_manager: class: PUGX\MultiUserBundle\Controller\RegistrationManager arguments: ["@pugx_user.manager.user_discriminator", "@service_container", "@pugx_multi_user.registration_controller", "@fos_user.registration.form.factory"] - - #simply wrap + + #manage profile + pugx_multi_user.profile_manager: + class: PUGX\MultiUserBundle\Controller\ProfileManager + arguments: ["@pugx_user.manager.user_discriminator", "@service_container", "@pugx_multi_user.profile_controller", "@fos_user.profile.form.factory"] + + #registration controller pugx_multi_user.registration_controller: class: FOS\UserBundle\Controller\RegistrationController - + + #profile controller + pugx_multi_user.profile_controller: + class: FOS\UserBundle\Controller\ProfileController + #form factories pugx_multi_user.registration_form_factory: class: PUGX\MultiUserBundle\Form\FormFactory arguments: ["@pugx_user.manager.user_discriminator", "@form.factory", "registration"] - + pugx_multi_user.profile_form_factory: class: PUGX\MultiUserBundle\Form\FormFactory arguments: ["@pugx_user.manager.user_discriminator", "@form.factory", "profile"] - + #listener pugx_multi_user.listener.authentication: class: PUGX\MultiUserBundle\Listener\AuthenticationListener arguments: ["@pugx_user.manager.user_discriminator"] tags: - { name: kernel.event_subscriber } - + #validator pugx_multi_user.orm.validator.unique: class: PUGX\MultiUserBundle\Validator\Constraints\UniqueEntityValidator arguments: [ "@doctrine" ] tags: - { name: validator.constraint_validator, alias: pugx.orm.validator.unique } - + # alias pugx_user_discriminator: alias: pugx_user.manager.user_discriminator - - \ No newline at end of file diff --git a/Util/UserManipulator.php b/Util/UserManipulator.php new file mode 100644 index 0000000..b4333fa --- /dev/null +++ b/Util/UserManipulator.php @@ -0,0 +1,52 @@ +userManager = $userManager; + } + /** + * Creates a user by type and returns it. + * + * @param string $type + * @param string $username + * @param string $password + * @param string $email + * @param Boolean $active + * @param Boolean $superadmin + * + * @return \FOS\UserBundle\Model\UserInterface + */ + public function createByType($type, $username, $password, $email, $active, $superadmin) + { + $user = $this->userManager->createUserByType($type); + + $user->setUsername($username); + $user->setEmail($email); + $user->setPlainPassword($password); + $user->setEnabled((Boolean) $active); + $user->setSuperAdmin((Boolean) $superadmin); + $this->userManager->updateUser($user); + + return $user; + } + +}