]> Raphaël G. Git Repositories - userbundle/commitdiff
First version 0.0.1
authorRaphaël Gertz <git@rapsys.eu>
Sun, 1 Jul 2018 07:27:20 +0000 (09:27 +0200)
committerRaphaël Gertz <git@rapsys.eu>
Sun, 1 Jul 2018 07:27:20 +0000 (09:27 +0200)
17 files changed:
Controller/DefaultController.php [new file with mode: 0644]
DependencyInjection/Configuration.php [new file with mode: 0644]
DependencyInjection/RapsysUserExtension.php [new file with mode: 0644]
Entity/Group.php [new file with mode: 0644]
Entity/Title.php [new file with mode: 0644]
Entity/User.php [new file with mode: 0644]
Form/LoginType.php [new file with mode: 0644]
Form/RecoverMailType.php [new file with mode: 0644]
Form/RecoverType.php [new file with mode: 0644]
Form/RegisterType.php [new file with mode: 0644]
RapsysUserBundle.php [new file with mode: 0644]
Resources/config/doctrine/Group.orm.yml [new file with mode: 0644]
Resources/config/doctrine/Title.orm.yml [new file with mode: 0644]
Resources/config/doctrine/User.orm.yml [new file with mode: 0644]
Resources/config/routing.yml [new file with mode: 0644]
Resources/config/services.yml [new file with mode: 0644]
Utils/Slugger.php [new file with mode: 0644]

diff --git a/Controller/DefaultController.php b/Controller/DefaultController.php
new file mode 100644 (file)
index 0000000..d3c2a3f
--- /dev/null
@@ -0,0 +1,376 @@
+<?php
+
+namespace Rapsys\UserBundle\Controller;
+
+use Symfony\Bundle\FrameworkBundle\Controller\Controller;
+use Symfony\Component\HttpFoundation\Request;
+use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
+use Symfony\Component\Security\Core\Encoder\UserPasswordEncoderInterface;
+use Symfony\Component\Security\Http\Authentication\AuthenticationUtils;
+use Symfony\Component\Form\FormError;
+use Rapsys\UserBundle\Utils\Slugger;
+
+class DefaultController extends Controller {
+       public function loginAction(Request $request, AuthenticationUtils $authenticationUtils) {
+               //Get template
+               $template = $this->container->getParameter(($alias = $this->getAlias()).'.login.template');
+               //Get context
+               $context = $this->container->getParameter($alias.'.login.context');
+
+               //Create the form according to the FormType created previously.
+               //And give the proper parameters
+               $form = $this->createForm('Rapsys\UserBundle\Form\LoginType', null, array(
+                       // To set the action use $this->generateUrl('route_identifier')
+                       'action' => $this->generateUrl('rapsys_user_login'),
+                       'method' => 'POST'
+               ));
+
+               //Get the login error if there is one
+               if ($error = $authenticationUtils->getLastAuthenticationError()) {
+                       //Get translator
+                       $trans = $this->get('translator');
+
+                       //Get translated error
+                       $error = $trans->trans($error->getMessageKey());
+
+                       //Add error message to mail field
+                       $form->get('mail')->addError(new FormError($error));
+               }
+
+               //Last username entered by the user
+               if ($lastUsername = $authenticationUtils->getLastUsername()) {
+                       $form->get('mail')->setData($lastUsername);
+               }
+
+               //Render view
+               return $this->render($template, $context+array('form' => $form->createView(), 'error' => $error));
+       }
+
+       public function registerAction(Request $request, UserPasswordEncoderInterface $encoder) {
+               //Get mail template
+               $mailTemplate = $this->container->getParameter(($alias = $this->getAlias()).'.register.mail_template');
+               //Get mail context
+               $mailContext = $this->container->getParameter($alias.'.register.mail_context');
+               //Get template
+               $template = $this->container->getParameter($alias.'.register.template');
+               //Get context
+               $context = $this->container->getParameter($alias.'.register.context');
+               //Get home name
+               $homeName = $this->container->getParameter($alias.'.contact.home_name');
+               //Get home args
+               $homeArgs = $this->container->getParameter($alias.'.contact.home_args');
+               //Get contact name
+               $contactName = $this->container->getParameter($alias.'.contact.name');
+               //Get contact mail
+               $contactMail = $this->container->getParameter($alias.'.contact.mail');
+               //TODO: check if doctrine orm replacement is enough with default classes here
+               //Get class user
+               $classUser = $this->container->getParameter($alias.'.class.user');
+               //Get class group
+               $classGroup = $this->container->getParameter($alias.'.class.group');
+               //Get class title
+               $classTitle = $this->container->getParameter($alias.'.class.title');
+
+               //Create the form according to the FormType created previously.
+               //And give the proper parameters
+               $form = $this->createForm('Rapsys\UserBundle\Form\RegisterType', null, array(
+                       // To set the action use $this->generateUrl('route_identifier')
+                       'class_title' => $classTitle,
+                       'action' => $this->generateUrl('rapsys_user_register'),
+                       'method' => 'POST'
+               ));
+
+               if ($request->isMethod('POST')) {
+                       // Refill the fields in case the form is not valid.
+                       $form->handleRequest($request);
+
+                       if ($form->isValid()) {
+                               //Get translator
+                               $trans = $this->get('translator');
+
+                               //Set data
+                               $data = $form->getData();
+
+                               //Translate title
+                               $mailContext['title'] = $trans->trans($mailContext['title']);
+
+                               //Translate title
+                               $mailContext['subtitle'] = $trans->trans($mailContext['subtitle'], array('%name%' => $data['forename'].' '.$data['surname'].' ('.$data['pseudonym'].')'));
+
+                               //Translate subject
+                               $mailContext['subject'] = $trans->trans($mailContext['subject'], array('%title%' => $mailContext['title']));
+
+                               //Translate message
+                               $mailContext['message'] = $trans->trans($mailContext['message'], array('%title%' => $mailContext['title']));
+
+                               //Create message
+                               $message = \Swift_Message::newInstance()
+                                       ->setSubject($mailContext['subject'])
+                                       ->setFrom(array($contactMail => $contactName))
+                                       ->setTo(array($data['mail'] => $data['forename'].' '.$data['surname']))
+                                       ->setBody($mailContext['message'])
+                                       ->addPart(
+                                               $this->renderView(
+                                                       $mailTemplate,
+                                                       $mailContext+array(
+                                                               'home' => $this->get('router')->generate($homeName, $homeArgs, UrlGeneratorInterface::ABSOLUTE_URL)
+                                                       )
+                                               ),
+                                               'text/html'
+                                       );
+
+                               //Get doctrine
+                               $doctrine = $this->getDoctrine();
+
+                               //Get manager
+                               $manager = $doctrine->getManager();
+
+                               //Init reflection
+                               $reflection = new \ReflectionClass($classUser);
+
+                               //Create new user
+                               $user = $reflection->newInstance();
+
+                               $user->setMail($data['mail']);
+                               $user->setPseudonym($data['pseudonym']);
+                               $user->setForename($data['forename']);
+                               $user->setSurname($data['surname']);
+                               $user->setPassword($encoder->encodePassword($user, $data['password']));
+                               $user->setActive(true);
+                               $user->setTitle($data['title']);
+                               //TODO: see if we can't modify group constructor to set role directly from args
+                               //XXX: see vendor/symfony/symfony/src/Symfony/Component/Security/Core/Role/Role.php
+                               $user->addGroup($doctrine->getRepository($classGroup)->findOneByRole('ROLE_USER'));
+                               $user->setCreated(new \DateTime('now'));
+                               $user->setUpdated(new \DateTime('now'));
+
+                               //Persist user
+                               $manager->persist($user);
+
+                               try {
+                                       //Send to database
+                                       $manager->flush();
+
+                                       //Send message
+                                       if ($this->get('mailer')->send($message)) {
+                                               //Redirect to cleanup the form
+                                               return $this->redirectToRoute('rapsys_user_register', array('sent' => 1));
+                                       }
+                               } catch (\Doctrine\DBAL\Exception\UniqueConstraintViolationException $e) {
+                                       //Add error message mail already exists
+                                       $form->get('mail')->addError(new FormError($trans->trans('Account already exists: %mail%', array('%mail%' => $data['mail']))));
+                               }
+                       }
+               }
+
+               //Render view
+               return $this->render($template, $context+array('form' => $form->createView(), 'sent' => $request->query->get('sent', 0)));
+       }
+
+       public function recoverAction(Request $request, Slugger $slugger) {
+               //Get mail template
+               $mailTemplate = $this->container->getParameter(($alias = $this->getAlias()).'.recover.mail_template');
+               //Get mail context
+               $mailContext = $this->container->getParameter($alias.'.recover.mail_context');
+               //Get template
+               $template = $this->container->getParameter($alias.'.recover.template');
+               //Get context
+               $context = $this->container->getParameter($alias.'.recover.context');
+               //Get url name
+               $urlName = $this->container->getParameter($alias.'.recover.url_name');
+               //Get url args
+               $urlArgs = $this->container->getParameter($alias.'.recover.url_args');
+               //Get home name
+               $homeName = $this->container->getParameter($alias.'.contact.home_name');
+               //Get home args
+               $homeArgs = $this->container->getParameter($alias.'.contact.home_args');
+               //Get contact name
+               $contactName = $this->container->getParameter($alias.'.contact.name');
+               //Get contact mail
+               $contactMail = $this->container->getParameter($alias.'.contact.mail');
+               //Get class user
+               $classUser = $this->container->getParameter($alias.'.class.user');
+
+               //Create the form according to the FormType created previously.
+               //And give the proper parameters
+               $form = $this->createForm('Rapsys\UserBundle\Form\RecoverType', null, array(
+                       // To set the action use $this->generateUrl('route_identifier')
+                       'action' => $this->generateUrl('rapsys_user_recover'),
+                       'method' => 'POST'
+               ));
+
+               if ($request->isMethod('POST')) {
+                       // Refill the fields in case the form is not valid.
+                       $form->handleRequest($request);
+
+                       if ($form->isValid()) {
+                               //Get translator
+                               $trans = $this->get('translator');
+
+                               //Get doctrine
+                               $doctrine = $this->getDoctrine();
+
+                               //Set data
+                               $data = $form->getData();
+
+                               //Translate title
+                               $mailContext['title'] = $trans->trans($mailContext['title']);
+
+                               //Try to find user
+                               if ($user = $doctrine->getRepository($classUser)->findOneByMail($data['mail'])) {
+                                       //Translate title
+                                       $mailContext['subtitle'] = $trans->trans($mailContext['subtitle'], array('%name%' => $user->getForename().' '.$user->getSurname().' ('.$user->getPseudonym().')'));
+
+                                       //Translate subject
+                                       $mailContext['subject'] = $trans->trans($mailContext['subject'], array('%title%' => $mailContext['title']));
+
+                                       //Translate message
+                                       $mailContext['raw'] = $trans->trans($mailContext['raw'], array('%title%' => $mailContext['title'], '%url%' => $this->get('router')->generate($urlName, $urlArgs+array('mail' => $slugger->short($user->getMail()), 'hash' => $slugger->hash($user->getPassword())), UrlGeneratorInterface::ABSOLUTE_URL)));
+
+                                       //Create message
+                                       $message = \Swift_Message::newInstance()
+                                               ->setSubject($mailContext['subject'])
+                                               ->setFrom(array($contactMail => $contactName))
+                                               ->setTo(array($user->getMail() => $user->getForename().' '.$user->getSurname()))
+                                               ->setBody(strip_tags($mailContext['raw']))
+                                               ->addPart(
+                                                       $this->renderView(
+                                                               $mailTemplate,
+                                                               $mailContext+array(
+                                                                       'home' => $this->get('router')->generate($homeName, $homeArgs, UrlGeneratorInterface::ABSOLUTE_URL)
+                                                               )
+                                                       ),
+                                                       'text/html'
+                                               );
+
+                                       //Send message
+                                       if ($this->get('mailer')->send($message)) {
+                                               //Redirect to cleanup the form
+                                               return $this->redirectToRoute('rapsys_user_recover', array('sent' => 1));
+                                       }
+                               //Accout not found
+                               } else {
+                                       //Add error message to mail field
+                                       $form->get('mail')->addError(new FormError($trans->trans('Unable to find account: %mail%', array('%mail%' => $data['mail']))));
+                               }
+                       }
+               }
+
+               //Render view
+               return $this->render($template, $context+array('form' => $form->createView(), 'sent' => $request->query->get('sent', 0)));
+       }
+
+       public function recoverMailAction(Request $request, UserPasswordEncoderInterface $encoder, Slugger $slugger, $mail, $hash) {
+               //Get mail template
+               $mailTemplate = $this->container->getParameter(($alias = $this->getAlias()).'.recover_mail.mail_template');
+               //Get mail context
+               $mailContext = $this->container->getParameter($alias.'.recover_mail.mail_context');
+               //Get template
+               $template = $this->container->getParameter($alias.'.recover_mail.template');
+               //Get context
+               $context = $this->container->getParameter($alias.'.recover_mail.context');
+               //Get url name
+               $urlName = $this->container->getParameter($alias.'.recover_mail.url_name');
+               //Get url args
+               $urlArgs = $this->container->getParameter($alias.'.recover_mail.url_args');
+               //Get home name
+               $homeName = $this->container->getParameter($alias.'.contact.home_name');
+               //Get home args
+               $homeArgs = $this->container->getParameter($alias.'.contact.home_args');
+               //Get contact name
+               $contactName = $this->container->getParameter($alias.'.contact.name');
+               //Get contact mail
+               $contactMail = $this->container->getParameter($alias.'.contact.mail');
+               //Get class user
+               $classUser = $this->container->getParameter($alias.'.class.user');
+
+               //Create the form according to the FormType created previously.
+               //And give the proper parameters
+               $form = $this->createForm('Rapsys\UserBundle\Form\RecoverMailType', null, array(
+                       // To set the action use $this->generateUrl('route_identifier')
+                       'action' => $this->generateUrl('rapsys_user_recover_mail', array('mail' => $mail, 'hash' => $hash)),
+                       'method' => 'POST'
+               ));
+
+               //Get doctrine
+               $doctrine = $this->getDoctrine();
+
+               //Get translator
+               $trans = $this->get('translator');
+
+               //Init not found
+               $notfound = 1;
+
+               //Retrieve user
+               if (($user = $doctrine->getRepository($classUser)->findOneByMail($slugger->unshort($mail))) && $hash == $slugger->hash($user->getPassword())) {
+                       //User was found
+                       $notfound = 0;
+
+                       if ($request->isMethod('POST')) {
+                               // Refill the fields in case the form is not valid.
+                               $form->handleRequest($request);
+
+                               if ($form->isValid()) {
+                                       //Set data
+                                       $data = $form->getData();
+
+                                       //Translate title
+                                       $mailContext['title'] = $trans->trans($mailContext['title']);
+
+                                       //Translate title
+                                       $mailContext['subtitle'] = $trans->trans($mailContext['subtitle'], array('%name%' => $user->getForename().' '.$user->getSurname().' ('.$user->getPseudonym().')'));
+
+                                       //Translate subject
+                                       $mailContext['subject'] = $trans->trans($mailContext['subject'], array('%title%' => $mailContext['title']));
+
+                                       //Set user password
+                                       $user->setPassword($encoder->encodePassword($user, $data['password']));
+
+                                       //Translate message
+                                       $mailContext['raw'] = $trans->trans($mailContext['raw'], array('%title%' => $mailContext['title'], '%url%' => $this->get('router')->generate($urlName, $urlArgs+array('mail' => $slugger->short($user->getMail()), 'hash' => $slugger->hash($user->getPassword())), UrlGeneratorInterface::ABSOLUTE_URL)));
+
+                                       //Get manager
+                                       $manager = $doctrine->getManager();
+
+                                       //Persist user
+                                       $manager->persist($user);
+
+                                       //Send to database
+                                       $manager->flush();
+
+                                       //Create message
+                                       $message = \Swift_Message::newInstance()
+                                               ->setSubject($mailContext['subject'])
+                                               ->setFrom(array($contactMail => $contactName))
+                                               ->setTo(array($user->getMail() => $user->getForename().' '.$user->getSurname()))
+                                               ->setBody(strip_tags($mailContext['raw']))
+                                               ->addPart(
+                                                       $this->renderView(
+                                                               $mailTemplate,
+                                                               $mailContext+array(
+                                                                       'home' => $this->get('router')->generate($homeName, $homeArgs, UrlGeneratorInterface::ABSOLUTE_URL)
+                                                               )
+                                                       ),
+                                                       'text/html'
+                                               );
+
+                                       //Send message
+                                       if ($this->get('mailer')->send($message)) {
+                                               //Redirect to cleanup the form
+                                               return $this->redirectToRoute('rapsys_user_recover_mail', array('mail' => $mail, 'hash' => $hash, 'sent' => 1));
+                                       }
+                               }
+                       }
+               }
+
+               //Render view
+               return $this->render($template, $context+array('form' => $form->createView(), 'sent' => $request->query->get('sent', 0), 'notfound' => $notfound));
+       }
+
+       /**
+        * {@inheritdoc}
+        */
+       public function getAlias() {
+               return 'rapsys_user';
+       }
+}
diff --git a/DependencyInjection/Configuration.php b/DependencyInjection/Configuration.php
new file mode 100644 (file)
index 0000000..14066d1
--- /dev/null
@@ -0,0 +1,210 @@
+<?php
+
+namespace Rapsys\UserBundle\DependencyInjection;
+
+use Symfony\Component\Config\Definition\Builder\TreeBuilder;
+use Symfony\Component\Config\Definition\ConfigurationInterface;
+
+/**
+ * This is the class that validates and merges configuration from your app/config files.
+ *
+ * To learn more see {@link http://symfony.com/doc/current/cookbook/bundles/configuration.html}
+ */
+class Configuration implements ConfigurationInterface {
+       /**
+        * {@inheritdoc}
+        */
+       public function getConfigTreeBuilder() {
+               //Set tree builder
+               $treeBuilder = new TreeBuilder();
+
+               //The bundle default values
+               $defaults = [
+                       'class' => [
+                               'group' => 'Rapsys\\UserBundle\\Entity\\Group',
+                               'title' => 'Rapsys\\UserBundle\\Entity\\Title',
+                               'user' => 'Rapsys\\UserBundle\\Entity\\User'
+                       ],
+                       'contact' => [
+                               'name' => 'John Doe',
+                               'mail' => 'contact@example.com',
+                               'home_name' => 'rapsys_user_homepage',
+                               'home_args' => []
+                       ],
+                       'login' => [
+                               'template' => '@@RapsysUser/security/login.html.twig',
+                               'context' => []
+                       ],
+                       'register' => [
+                               'mail_template' => '@@RapsysUser/mail/register.html.twig',
+                               'mail_context' => [
+                                       'title' => 'Title',
+                                       'subtitle' => 'Hi, %%name%%',
+                                       'subject' => 'Welcome to %%title%%',
+                                       'message' => 'Thanks so much for joining us, from now on, you are part of %%title%%.'
+                               ],
+                               'template' => '@@RapsysUser/security/register.html.twig',
+                               'context' => []
+                       ],
+                       'recover' => [
+                               'mail_template' => '@@RapsysUser/mail/recover.html.twig',
+                               'mail_context' => [
+                                       'title' => 'Title',
+                                       'subtitle' => 'Hi, %%name%%',
+                                       'subject' => 'Recover account on %%title%%',
+                                       'raw' => 'Thanks so much for joining us, to recover your account you can follow this link: <a href="%%url%%">%%url%%</a>'
+                               ],
+                               'url_name' => 'rapsys_user_recover_mail',
+                               'url_args' => [],
+                               'template' => '@@RapsysUser/security/recover.html.twig',
+                               'context' => []
+                       ],
+                       'recover_mail' => [
+                               'mail_template' => '@@RapsysUser/mail/recover.html.twig',
+                               'mail_context' => [
+                                       'title' => 'Title',
+                                       'subtitle' => 'Hi, %%name%%',
+                                       'subject' => 'Account recovered on %%title%%',
+                                       'raw' => 'Your account password has been changed, to recover your account you can follow this link: <a href="%%url%%">%%url%%</a>'
+                               ],
+                               'url_name' => 'rapsys_user_recover_mail',
+                               'url_args' => [],
+                               'template' => '@@RapsysUser/security/recover_mail.html.twig',
+                               'context' => []
+                       ]
+               ];
+
+               //Here we define the parameters that are allowed to configure the bundle.
+               //TODO: see https://github.com/symfony/symfony/blob/master/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Configuration.php for default value and description
+               //TODO: see http://symfony.com/doc/current/components/config/definition.html
+               //TODO: see fosuser DependencyInjection/Configuration.php
+               //XXX: use bin/console config:dump-reference to dump class infos
+
+               //Here we define the parameters that are allowed to configure the bundle.
+               $treeBuilder
+                       //Parameters
+                       ->root('parameters')
+                               ->addDefaultsIfNotSet()
+                               ->children()
+                                       ->arrayNode('rapsys_user')
+                                               ->addDefaultsIfNotSet()
+                                               ->children()
+                                                       ->arrayNode('class')
+                                                               ->isRequired()
+                                                               ->addDefaultsIfNotSet()
+                                                               ->children()
+                                                                       ->scalarNode('group')->isRequired()->defaultValue($defaults['class']['group'])->end()
+                                                                       ->scalarNode('title')->isRequired()->defaultValue($defaults['class']['title'])->end()
+                                                                       ->scalarNode('user')->isRequired()->defaultValue($defaults['class']['user'])->end()
+                                                               ->end()
+                                                       ->end()
+                                                       ->arrayNode('contact')
+                                                               ->isRequired()
+                                                               ->addDefaultsIfNotSet()
+                                                               ->children()
+                                                                       ->scalarNode('name')->isRequired()->defaultValue($defaults['contact']['name'])->end()
+                                                                       ->scalarNode('mail')->isRequired()->defaultValue($defaults['contact']['mail'])->end()
+                                                                       ->scalarNode('home_name')->isRequired()->defaultValue($defaults['contact']['home_name'])->end()
+                                                                       ->arrayNode('home_args')
+                                                                               ->isRequired()
+                                                                               ->treatNullLike($defaults['contact']['home_args'])
+                                                                               ->defaultValue($defaults['contact']['home_args'])
+                                                                               ->scalarPrototype()->end()
+                                                                       ->end()
+                                                               ->end()
+                                                       ->end()
+                                                       ->arrayNode('login')
+                                                               ->isRequired()
+                                                               ->addDefaultsIfNotSet()
+                                                               ->children()
+                                                                       ->scalarNode('template')->isRequired()->defaultValue($defaults['login']['template'])->end()
+                                                                       ->arrayNode('context')
+                                                                               ->isRequired()
+                                                                               ->treatNullLike(array())
+                                                                               ->defaultValue($defaults['login']['context'])
+                                                                               ->scalarPrototype()->end()
+                                                                       ->end()
+                                                               ->end()
+                                                       ->end()
+                                                       ->arrayNode('register')
+                                                               ->isRequired()
+                                                               ->addDefaultsIfNotSet()
+                                                               ->children()
+                                                                       ->scalarNode('mail_template')->isRequired()->defaultValue($defaults['register']['mail_template'])->end()
+                                                                       ->arrayNode('mail_context')
+                                                                               ->isRequired()
+                                                                               ->treatNullLike($defaults['register']['mail_context'])
+                                                                               ->defaultValue($defaults['register']['mail_context'])
+                                                                               ->scalarPrototype()->end()
+                                                                       ->end()
+                                                                       ->scalarNode('template')->isRequired()->defaultValue($defaults['register']['template'])->end()
+                                                                       ->arrayNode('context')
+                                                                               ->isRequired()
+                                                                               ->treatNullLike($defaults['register']['context'])
+                                                                               ->defaultValue($defaults['register']['context'])
+                                                                               ->scalarPrototype()->end()
+                                                                       ->end()
+                                                               ->end()
+                                                       ->end()
+                                                       ->arrayNode('recover')
+                                                               ->isRequired()
+                                                               ->addDefaultsIfNotSet()
+                                                               ->children()
+                                                                       ->scalarNode('mail_template')->isRequired()->defaultValue($defaults['recover']['mail_template'])->end()
+                                                                       ->arrayNode('mail_context')
+                                                                               ->isRequired()
+                                                                               ->treatNullLike($defaults['recover']['mail_context'])
+                                                                               ->defaultValue($defaults['recover']['mail_context'])
+                                                                               ->scalarPrototype()->end()
+                                                                       ->end()
+                                                                       ->scalarNode('url_name')->isRequired()->defaultValue($defaults['recover']['url_name'])->end()
+                                                                       ->arrayNode('url_args')
+                                                                               ->isRequired()
+                                                                               ->treatNullLike($defaults['recover']['url_args'])
+                                                                               ->defaultValue($defaults['recover']['url_args'])
+                                                                               ->scalarPrototype()->end()
+                                                                       ->end()
+                                                                       ->scalarNode('template')->isRequired()->defaultValue($defaults['recover']['template'])->end()
+                                                                       ->arrayNode('context')
+                                                                               ->isRequired()
+                                                                               ->treatNullLike(array())
+                                                                               ->defaultValue($defaults['recover']['context'])
+                                                                               ->scalarPrototype()->end()
+                                                                       ->end()
+                                                               ->end()
+                                                       ->end()
+                                                       ->arrayNode('recover_mail')
+                                                               ->isRequired()
+                                                               ->addDefaultsIfNotSet()
+                                                               ->children()
+                                                                       ->scalarNode('mail_template')->isRequired()->defaultValue($defaults['recover']['mail_template'])->end()
+                                                                       ->arrayNode('mail_context')
+                                                                               ->isRequired()
+                                                                               ->treatNullLike($defaults['recover']['mail_context'])
+                                                                               ->defaultValue($defaults['recover']['mail_context'])
+                                                                               ->scalarPrototype()->end()
+                                                                       ->end()
+                                                                       ->scalarNode('url_name')->isRequired()->defaultValue($defaults['recover']['url_name'])->end()
+                                                                       ->arrayNode('url_args')
+                                                                               ->isRequired()
+                                                                               ->treatNullLike($defaults['recover']['url_args'])
+                                                                               ->defaultValue($defaults['recover']['url_args'])
+                                                                               ->scalarPrototype()->end()
+                                                                       ->end()
+                                                                       ->scalarNode('template')->isRequired()->defaultValue($defaults['recover']['template'])->end()
+                                                                       ->arrayNode('context')
+                                                                               ->isRequired()
+                                                                               ->treatNullLike(array())
+                                                                               ->defaultValue($defaults['recover']['context'])
+                                                                               ->scalarPrototype()->end()
+                                                                       ->end()
+                                                               ->end()
+                                                       ->end()
+                                               ->end()
+                                       ->end()
+                               ->end()
+                       ->end();
+
+               return $treeBuilder;
+       }
+}
diff --git a/DependencyInjection/RapsysUserExtension.php b/DependencyInjection/RapsysUserExtension.php
new file mode 100644 (file)
index 0000000..58c86a6
--- /dev/null
@@ -0,0 +1,80 @@
+<?php
+
+namespace Rapsys\UserBundle\DependencyInjection;
+
+use Symfony\Component\DependencyInjection\ContainerBuilder;
+use Symfony\Component\Config\FileLocator;
+use Symfony\Component\HttpKernel\DependencyInjection\Extension;
+use Symfony\Component\DependencyInjection\Loader;
+
+/**
+ * This is the class that loads and manages your bundle configuration.
+ *
+ * @link http://symfony.com/doc/current/cookbook/bundles/extension.html
+ */
+class RapsysUserExtension extends Extension {
+       /**
+        * {@inheritdoc}
+        */
+       public function load(array $configs, ContainerBuilder $container) {
+               //Load configuration
+               $loader = new Loader\YamlFileLoader($container, new FileLocator(__DIR__.'/../Resources/config'));
+               $loader->load('services.yml');
+
+               //Load configuration
+               $configuration = $this->getConfiguration($configs, $container);
+               $config = $this->processConfiguration($configuration, $configs);
+
+               //Set default config in parameter
+               if (!$container->hasParameter($alias = $this->getAlias())) {
+                       $container->setParameter($alias, $config[$alias]);
+               } else {
+                       $config[$alias] = $container->getParameter($alias);
+               }
+
+               //Transform the two level tree in flat parameters
+               foreach($config[$alias] as $k => $v) {
+                       foreach($v as $s => $d) {
+                               //Set is as parameters
+                               $container->setParameter($alias.'.'.$k.'.'.$s, $d);
+                       }
+               }
+       }
+
+       /**
+        * {@inheritdoc}
+        */
+       public function getAlias() {
+               return 'rapsys_user';
+       }
+
+       /**
+        * The function that parses the array to flatten it into a one level depth array
+        *
+        * @param $array        The config values array
+        * @param $path         The current key path
+        * @param $depth        The maxmium depth
+        * @param $sep          The separator string
+        */
+       /*protected function flatten($array, $path, $depth = 10, $sep = '.') {
+               //Init res
+               $res = array();
+
+               //Pass through non hashed or empty array
+               if ($depth && is_array($array) && ($array === [] || array_keys($array) === range(0, count($array) - 1))) {
+                       $res[$path] = $array;
+               //Flatten hashed array
+               } elseif ($depth && is_array($array)) {
+                       foreach($array as $k => $v) {
+                               $sub = $path ? $path.$sep.$k:$k;
+                               $res += $this->flatten($v, $sub, $depth - 1, $sep);
+                       }
+               //Pass scalar value directly
+               } else {
+                       $res[$path] = $array;
+               }
+
+               //Return result
+               return $res;
+       }*/
+}
diff --git a/Entity/Group.php b/Entity/Group.php
new file mode 100644 (file)
index 0000000..c7000ea
--- /dev/null
@@ -0,0 +1,137 @@
+<?php
+
+// src/Rapsys/UserBundle/Entity/Group.php
+namespace Rapsys\UserBundle\Entity;
+
+class Group extends \Symfony\Component\Security\Core\Role\Role {
+       /**
+        * @var integer
+        */
+       protected $id;
+
+       /**
+        * @var string
+        */
+       protected $role;
+
+       /**
+        * @var \DateTime
+        */
+       protected $created;
+
+       /**
+        * @var \DateTime
+        */
+       protected $updated;
+
+       /**
+        * @var \Doctrine\Common\Collections\Collection
+        */
+       protected $users;
+
+       /**
+        * Constructor
+        * @param string $role The role name
+        */
+       public function __construct($role) {
+               $this->role = (string) $role;
+               $this->users = new \Doctrine\Common\Collections\ArrayCollection();
+       }
+
+       /**
+        * Set role
+        *
+        * @param string $role
+        *
+        * @return User
+        */
+       public function setRole($role) {
+               $this->role = $role;
+
+               return $this;
+       }
+
+       /**
+        * Get role
+        *
+        * @return string
+        */
+       public function getRole() {
+               return $this->role;
+       }
+
+       /**
+        * Set created
+        *
+        * @param \DateTime $created
+        *
+        * @return User
+        */
+       public function setCreated($created) {
+               $this->created = $created;
+
+               return $this;
+       }
+
+       /**
+        * Get created
+        *
+        * @return \DateTime
+        */
+       public function getCreated() {
+               return $this->created;
+       }
+
+       /**
+        * Set updated
+        *
+        * @param \DateTime $updated
+        *
+        * @return User
+        */
+       public function setUpdated($updated) {
+               $this->updated = $updated;
+
+               return $this;
+       }
+
+       /**
+        * Get updated
+        *
+        * @return \DateTime
+        */
+       public function getUpdated() {
+               return $this->updated;
+       }
+
+       /**
+        * Add user
+        *
+        * @param \Rapsys\UserBundle\Entity\User $user
+        *
+        * @return Group
+        */
+       public function addUser(\Rapsys\UserBundle\Entity\User $user) {
+               $this->users[] = $user;
+
+               return $this;
+       }
+
+       /**
+        * Remove user
+        *
+        * @param \Rapsys\UserBundle\Entity\User $user
+        */
+       public function removeUser(\Rapsys\UserBundle\Entity\User $user) {
+               $this->users->removeElement($user);
+       }
+
+       /**
+        * Get users
+        *
+        * @return \Doctrine\Common\Collections\Collection
+        */
+       public function getUsers() {
+               return $this->users;
+       }
+}
diff --git a/Entity/Title.php b/Entity/Title.php
new file mode 100644 (file)
index 0000000..5a2b685
--- /dev/null
@@ -0,0 +1,173 @@
+<?php
+
+namespace Rapsys\UserBundle\Entity;
+
+/**
+ * Title
+ */
+class Title {
+       /**
+        * @var integer
+        */
+       protected $id;
+
+       /**
+        * @var string
+        */
+       protected $short;
+
+       /**
+        * @var string
+        */
+       protected $title;
+
+       /**
+        * @var \DateTime
+        */
+       protected $created;
+
+       /**
+        * @var \DateTime
+        */
+       protected $updated;
+
+       /**
+        * @var \Doctrine\Common\Collections\Collection
+        */
+       protected $users;
+
+       /**
+        * Constructor
+        */
+       public function __construct() {
+               $this->users = new \Doctrine\Common\Collections\ArrayCollection();
+       }
+
+       /**
+        * Get id
+        *
+        * @return integer
+        */
+       public function getId() {
+               return $this->id;
+       }
+
+       /**
+        * Set short
+        *
+        * @param string $short
+        *
+        * @return Title
+        */
+       public function setShort($short) {
+               $this->short = $short;
+
+               return $this;
+       }
+
+       /**
+        * Get short
+        *
+        * @return string
+        */
+       public function getShort() {
+               return $this->short;
+       }
+
+       /**
+        * Set title
+        *
+        * @param string $title
+        *
+        * @return Title
+        */
+       public function setTitle($title) {
+               $this->title = $title;
+
+               return $this;
+       }
+
+       /**
+        * Get title
+        *
+        * @return string
+        */
+       public function getTitle() {
+               return $this->title;
+       }
+
+       /**
+        * Set created
+        *
+        * @param \DateTime $created
+        *
+        * @return Title
+        */
+       public function setCreated($created) {
+               $this->created = $created;
+
+               return $this;
+       }
+
+       /**
+        * Get created
+        *
+        * @return \DateTime
+        */
+       public function getCreated() {
+               return $this->created;
+       }
+
+       /**
+        * Set updated
+        *
+        * @param \DateTime $updated
+        *
+        * @return Title
+        */
+       public function setUpdated($updated) {
+               $this->updated = $updated;
+
+               return $this;
+       }
+
+       /**
+        * Get updated
+        *
+        * @return \DateTime
+        */
+       public function getUpdated() {
+               return $this->updated;
+       }
+
+       /**
+        * Add user
+        *
+        * @param \Rapsys\UserBundle\Entity\User $user
+        *
+        * @return Title
+        */
+       public function addUser(\Rapsys\UserBundle\Entity\User $user) {
+               $this->users[] = $user;
+
+               return $this;
+       }
+
+       /**
+        * Remove user
+        *
+        * @param \Rapsys\UserBundle\Entity\User $user
+        */
+       public function removeUser(\Rapsys\UserBundle\Entity\User $user) {
+               $this->users->removeElement($user);
+       }
+
+       /**
+        * Get users
+        *
+        * @return \Doctrine\Common\Collections\Collection
+        */
+       public function getUsers() {
+               return $this->users;
+       }
+}
diff --git a/Entity/User.php b/Entity/User.php
new file mode 100644 (file)
index 0000000..c6a6cdf
--- /dev/null
@@ -0,0 +1,355 @@
+<?php
+
+// src/Rapsys/UserBundle/Entity/User.php
+namespace Rapsys\UserBundle\Entity;
+
+class User implements \Symfony\Component\Security\Core\User\AdvancedUserInterface, \Serializable {
+       /**
+        * @var integer
+        */
+       protected $id;
+
+       /**
+        * @var string
+        */
+       protected $mail;
+
+       /**
+        * @var string
+        */
+       protected $pseudonym;
+
+       /**
+        * @var string
+        */
+       protected $forename;
+
+       /**
+        * @var string
+        */
+       protected $surname;
+
+       /**
+        * @var string
+        */
+       protected $password;
+
+       /**
+        * @var bool
+        */
+       protected $active;
+
+       /**
+        * @var \DateTime
+        */
+       protected $created;
+
+       /**
+        * @var \DateTime
+        */
+       protected $updated;
+
+       /**
+        * @var \Rapsys\UserBundle\Entity\Title
+        */
+       protected $title;
+
+       /**
+        * @var \Doctrine\Common\Collections\Collection
+        */
+       protected $groups;
+
+       /**
+        * User constructor.
+        */
+       public function __construct() {
+               $this->active = false;
+               $this->groups = new \Doctrine\Common\Collections\ArrayCollection();
+       }
+
+       /**
+        * Get id
+        *
+        * @return integer
+        */
+       public function getId() {
+               return $this->id;
+       }
+
+       /**
+        * Set mail
+        *
+        * @param string $mail
+        *
+        * @return User
+        */
+       public function setMail($mail) {
+               $this->mail = $mail;
+
+               return $this;
+       }
+
+       /**
+        * Get mail
+        *
+        * @return string
+        */
+       public function getMail() {
+               return $this->mail;
+       }
+
+       /**
+        * Set pseudonym
+        *
+        * @param string $pseudonym
+        *
+        * @return User
+        */
+       public function setPseudonym($pseudonym) {
+               $this->pseudonym = $pseudonym;
+
+               return $this;
+       }
+
+       /**
+        * Get pseudonym
+        *
+        * @return string
+        */
+       public function getPseudonym() {
+               return $this->pseudonym;
+       }
+
+       /**
+        * Set forename
+        *
+        * @param string $forename
+        *
+        * @return User
+        */
+       public function setForename($forename) {
+               $this->forename = $forename;
+
+               return $this;
+       }
+
+       /**
+        * Get forename
+        *
+        * @return string
+        */
+       public function getForename() {
+               return $this->forename;
+       }
+
+       /**
+        * Set surname
+        *
+        * @param string $surname
+        *
+        * @return User
+        */
+       public function setSurname($surname) {
+               $this->surname = $surname;
+
+               return $this;
+       }
+
+       /**
+        * Get surname
+        *
+        * @return string
+        */
+       public function getSurname() {
+               return $this->surname;
+       }
+
+       /**
+        * Set password
+        *
+        * @param string $password
+        *
+        * @return User
+        */
+       public function setPassword($password) {
+               $this->password = $password;
+
+               return $this;
+       }
+
+       /**
+        * Get password
+        *
+        * @return string
+        */
+       public function getPassword() {
+               return $this->password;
+       }
+
+       /**
+        * Set active
+        *
+        * @param bool $active
+        *
+        * @return User
+        */
+       public function setActive($active) {
+               $this->active = $active;
+
+               return $this;
+       }
+
+       /**
+        * Get active
+        *
+        * @return bool
+        */
+       public function getActive() {
+               return $this->active;
+       }
+
+       /**
+        * Set created
+        *
+        * @param \DateTime $created
+        *
+        * @return User
+        */
+       public function setCreated($created) {
+               $this->created = $created;
+
+               return $this;
+       }
+
+       /**
+        * Get created
+        *
+        * @return \DateTime
+        */
+       public function getCreated() {
+               return $this->created;
+       }
+
+       /**
+        * Set updated
+        *
+        * @param \DateTime $updated
+        *
+        * @return User
+        */
+       public function setUpdated($updated) {
+               $this->updated = $updated;
+
+               return $this;
+       }
+
+       /**
+        * Get updated
+        *
+        * @return \DateTime
+        */
+       public function getUpdated() {
+               return $this->updated;
+       }
+
+       /**
+        * Set title
+        */
+       public function setTitle($title) {
+               $this->title = $title;
+
+               return $this;
+       }
+
+       /**
+        * Get title
+        */
+       public function getTitle() {
+               return $this->title;
+       }
+
+       /**
+        * Add group
+        *
+        * @param \Rapsys\UserBundle\Entity\Group $group
+        *
+        * @return User
+        */
+       public function addGroup(\Rapsys\UserBundle\Entity\Group $group) {
+               $this->groups[] = $group;
+
+               return $this;
+       }
+
+       /**
+        * Remove group
+        *
+        * @param \Rapsys\UserBundle\Entity\Group $group
+        */
+       public function removeGroup(\Rapsys\UserBundle\Entity\Group $group) {
+               $this->groups->removeElement($group);
+       }
+
+       /**
+        * Get groups
+        *
+        * @return \Doctrine\Common\Collections\Collection
+        */
+       public function getGroups() {
+               return $this->groups;
+       }
+
+       public function getRoles() {
+               return $this->groups->toArray();
+       }
+
+       public function getSalt() {
+               //No salt required with bcrypt
+               return null;
+       }
+
+       public function getUsername() {
+               return $this->mail;
+       }
+
+       public function eraseCredentials() {
+       }
+
+       public function serialize() {
+               return serialize(array(
+                       $this->id,
+                       $this->mail,
+                       $this->password,
+                       $this->active,
+                       $this->created,
+                       $this->updated
+               ));
+       }
+
+       public function unserialize($serialized) {
+               list(
+                       $this->id,
+                       $this->mail,
+                       $this->password,
+                       $this->active,
+                       $this->created,
+                       $this->updated
+               ) = unserialize($serialized);
+       }
+
+       public function isAccountNonExpired() {
+               return true;
+       }
+
+       public function isAccountNonLocked() {
+               return true;
+       }
+
+       public function isCredentialsNonExpired() {
+               return true;
+       }
+
+       public function isEnabled() {
+               return $this->active;
+       }
+}
diff --git a/Form/LoginType.php b/Form/LoginType.php
new file mode 100644 (file)
index 0000000..f3df87a
--- /dev/null
@@ -0,0 +1,37 @@
+<?php
+
+namespace Rapsys\UserBundle\Form;
+
+use Symfony\Component\Form\AbstractType;
+use Symfony\Component\Form\FormBuilderInterface;
+use Symfony\Component\OptionsResolver\OptionsResolver;
+use Symfony\Component\Form\Extension\Core\Type\PasswordType;
+use Symfony\Component\Form\Extension\Core\Type\EmailType;
+use Symfony\Component\Form\Extension\Core\Type\SubmitType;
+use Symfony\Component\Validator\Constraints\Email;
+use Symfony\Component\Validator\Constraints\NotBlank;
+
+class LoginType extends AbstractType {
+       /**
+        * {@inheritdoc}
+        */
+       public function buildForm(FormBuilderInterface $builder, array $options) {
+               return $builder->add('mail', EmailType::class, array('attr' => array('placeholder' => 'Your mail address'), 'constraints' => array(new NotBlank(array('message' => 'Please provide your mail')), new Email(array('message' => 'Your mail doesn\'t seems to be valid')))))
+                       ->add('password', PasswordType::class, array('attr' => array('placeholder' => 'Your password'), 'constraints' => array(new NotBlank(array("message" => "Please provide your password")))))
+                       ->add('submit', SubmitType::class, array('label' => 'Send', 'attr' => array('class' => 'submit')));
+       }
+
+       /**
+        * {@inheritdoc}
+        */
+       public function configureOptions(OptionsResolver $resolver) {
+               $resolver->setDefaults(['error_bubbling' => true]);
+       }
+
+       /**
+        * {@inheritdoc}
+        */
+       public function getName() {
+               return 'rapsys_user_login';
+       }
+}
diff --git a/Form/RecoverMailType.php b/Form/RecoverMailType.php
new file mode 100644 (file)
index 0000000..c39c624
--- /dev/null
@@ -0,0 +1,35 @@
+<?php
+
+namespace Rapsys\UserBundle\Form;
+
+use Symfony\Component\Form\AbstractType;
+use Symfony\Component\Form\FormBuilderInterface;
+use Symfony\Component\OptionsResolver\OptionsResolver;
+use Symfony\Component\Form\Extension\Core\Type\RepeatedType;
+use Symfony\Component\Form\Extension\Core\Type\PasswordType;
+use Symfony\Component\Form\Extension\Core\Type\SubmitType;
+use Symfony\Component\Validator\Constraints\NotBlank;
+
+class RecoverMailType extends AbstractType {
+       /**
+        * {@inheritdoc}
+        */
+       public function buildForm(FormBuilderInterface $builder, array $options) {
+               return $builder->add('password', RepeatedType::class, array('type' => PasswordType::class, 'invalid_message' => 'The password and confirmation must match', 'first_options' => array('attr' => array('placeholder' => 'Your password'), 'label' => 'Password'), 'second_options' => array('attr' => array('placeholder' => 'Your password confirmation'), 'label' => 'Confirm password'), 'options' => array('constraints' => array(new NotBlank(array('message' => 'Please provide your password'))))))
+                       ->add('submit', SubmitType::class, array('label' => 'Send', 'attr' => array('class' => 'submit')));
+       }
+
+       /**
+        * {@inheritdoc}
+        */
+       public function configureOptions(OptionsResolver $resolver) {
+               $resolver->setDefaults(['error_bubbling' => true]);
+       }
+
+       /**
+        * {@inheritdoc}
+        */
+       public function getName() {
+               return 'rapsys_user_recover_mail';
+       }
+}
diff --git a/Form/RecoverType.php b/Form/RecoverType.php
new file mode 100644 (file)
index 0000000..3c14599
--- /dev/null
@@ -0,0 +1,36 @@
+<?php
+
+namespace Rapsys\UserBundle\Form;
+
+use Symfony\Component\Form\AbstractType;
+use Symfony\Component\Form\FormBuilderInterface;
+use Symfony\Component\OptionsResolver\OptionsResolver;
+use Symfony\Component\Form\Extension\Core\Type\PasswordType;
+use Symfony\Component\Form\Extension\Core\Type\EmailType;
+use Symfony\Component\Form\Extension\Core\Type\SubmitType;
+use Symfony\Component\Validator\Constraints\Email;
+use Symfony\Component\Validator\Constraints\NotBlank;
+
+class RecoverType extends AbstractType {
+       /**
+        * {@inheritdoc}
+        */
+       public function buildForm(FormBuilderInterface $builder, array $options) {
+               return $builder->add('mail', EmailType::class, array('attr' => array('placeholder' => 'Your mail address'), 'constraints' => array(new NotBlank(array('message' => 'Please provide your mail')), new Email(array('message' => 'Your mail doesn\'t seems to be valid')))))
+                       ->add('submit', SubmitType::class, array('label' => 'Send', 'attr' => array('class' => 'submit')));
+       }
+
+       /**
+        * {@inheritdoc}
+        */
+       public function configureOptions(OptionsResolver $resolver) {
+               $resolver->setDefaults(['error_bubbling' => true]);
+       }
+
+       /**
+        * {@inheritdoc}
+        */
+       public function getName() {
+               return 'rapsys_user_recover';
+       }
+}
diff --git a/Form/RegisterType.php b/Form/RegisterType.php
new file mode 100644 (file)
index 0000000..6e68583
--- /dev/null
@@ -0,0 +1,47 @@
+<?php
+
+namespace Rapsys\UserBundle\Form;
+
+use Symfony\Component\Form\AbstractType;
+use Symfony\Component\Form\FormBuilderInterface;
+use Symfony\Component\OptionsResolver\OptionsResolver;
+use Symfony\Bridge\Doctrine\Form\Type\EntityType;
+use Symfony\Component\Form\Extension\Core\Type\EmailType;
+use Symfony\Component\Form\Extension\Core\Type\PasswordType;
+use Symfony\Component\Form\Extension\Core\Type\RepeatedType;
+use Symfony\Component\Form\Extension\Core\Type\SubmitType;
+use Symfony\Component\Form\Extension\Core\Type\TextType;
+use Symfony\Component\Validator\Constraints\Email;
+use Symfony\Component\Validator\Constraints\NotBlank;
+
+class RegisterType extends AbstractType {
+       /**
+        * {@inheritdoc}
+        */
+       public function buildForm(FormBuilderInterface $builder, array $options) {
+               return $builder->add('mail', EmailType::class, array('attr' => array('placeholder' => 'Your mail address'), 'constraints' => array(new NotBlank(array('message' => 'Please provide your mail')), new Email(array('message' => 'Your mail doesn\'t seems to be valid')))))
+                       #'RapsysUserBundle:Title'
+                       ->add('title', EntityType::class, array('class' => $options['class_title'], 'choice_label' => 'title', 'attr' => array('placeholder' => 'Your title'), 'constraints' => array(new NotBlank(array('message' => 'Please provide your title')))))
+                       ->add('pseudonym', TextType::class, array('attr' => array('placeholder' => 'Your pseudonym'), 'constraints' => array(new NotBlank(array('message' => 'Please provide your pseudonym')))))
+                       ->add('forename', TextType::class, array('attr' => array('placeholder' => 'Your forename'), 'constraints' => array(new NotBlank(array('message' => 'Please provide your forename')))))
+                       ->add('surname', TextType::class, array('attr' => array('placeholder' => 'Your surname'), 'constraints' => array(new NotBlank(array('message' => 'Please provide your surname')))))
+                       ->add('password', RepeatedType::class, array('type' => PasswordType::class, 'invalid_message' => 'The password and confirmation must match', 'first_options' => array('attr' => array('placeholder' => 'Your password'), 'label' => 'Password'), 'second_options' => array('attr' => array('placeholder' => 'Your password confirmation'), 'label' => 'Confirm password'), 'options' => array('constraints' => array(new NotBlank(array('message' => 'Please provide your password'))))))
+                       ->add('submit', SubmitType::class, array('label' => 'Send', 'attr' => array('class' => 'submit')));
+       }
+
+       /**
+        * {@inheritdoc}
+        */
+       public function configureOptions(OptionsResolver $resolver) {
+               $resolver->setDefaults(['error_bubbling' => true]);
+               $resolver->setRequired('class_title');
+               $resolver->setAllowedTypes('class_title', 'string');
+       }
+
+       /**
+        * {@inheritdoc}
+        */
+       public function getName() {
+               return 'rapsys_user_register';
+       }
+}
diff --git a/RapsysUserBundle.php b/RapsysUserBundle.php
new file mode 100644 (file)
index 0000000..c083bb0
--- /dev/null
@@ -0,0 +1,7 @@
+<?php
+
+namespace Rapsys\UserBundle;
+
+use Symfony\Component\HttpKernel\Bundle\Bundle;
+
+class RapsysUserBundle extends Bundle {}
diff --git a/Resources/config/doctrine/Group.orm.yml b/Resources/config/doctrine/Group.orm.yml
new file mode 100644 (file)
index 0000000..6dfe856
--- /dev/null
@@ -0,0 +1,21 @@
+Rapsys\UserBundle\Entity\Group:
+    type: mappedSuperclass
+    id:
+        id:
+            type: integer
+            generator: 
+                strategy: AUTO
+            options:
+                unsigned: true
+    fields:
+        role:
+            type: string
+            length: 20
+        created:
+            type: datetime
+        updated:
+            type: datetime
+#    manyToMany:
+#        users:
+#            targetEntity: User
+#            mappedBy: groups
diff --git a/Resources/config/doctrine/Title.orm.yml b/Resources/config/doctrine/Title.orm.yml
new file mode 100644 (file)
index 0000000..389e89d
--- /dev/null
@@ -0,0 +1,24 @@
+Rapsys\UserBundle\Entity\Title:
+    type: mappedSuperclass
+    id:
+        id:
+            type: integer
+            generator: 
+                strategy: AUTO
+            options:
+                unsigned: true
+    fields:
+        short:
+            type: string
+            length: 4
+        title:
+            type: string
+            length: 16
+        created:
+            type: datetime
+        updated:
+            type: datetime
+#    oneToMany:
+#        users:
+#            targetEntity: User
+#            mappedBy: title
diff --git a/Resources/config/doctrine/User.orm.yml b/Resources/config/doctrine/User.orm.yml
new file mode 100644 (file)
index 0000000..a6a37f3
--- /dev/null
@@ -0,0 +1,45 @@
+Rapsys\UserBundle\Entity\User:
+    type: mappedSuperclass
+    id:
+        id:
+            type: integer
+            generator: 
+                strategy: AUTO
+            options:
+                unsigned: true
+    fields:
+        mail:
+            type: string
+            unique: true
+            length: 254
+        pseudonym:
+            type: string
+            length: 32
+        forename:
+            type: string
+            length: 32
+        surname:
+            type: string
+            length: 32
+        password:
+            type: string
+            length: 60
+        active:
+            type: boolean
+            options:
+                default: true
+        created:
+            type: datetime
+        updated:
+            type: datetime
+    manyToOne:
+        title:
+            targetEntity: Title
+            inversedBy: users
+    manyToMany:
+        groups:
+            targetEntity: Group
+            inversedBy: users
+#see if usefull: https://stackoverflow.com/questions/34523699/how-to-extend-doctrine-entity-in-another-bundle
+#            joinTable:
+#                name: groups_users
diff --git a/Resources/config/routing.yml b/Resources/config/routing.yml
new file mode 100644 (file)
index 0000000..6962599
--- /dev/null
@@ -0,0 +1,21 @@
+rapsys_user_login:
+    path:     /login
+    defaults: { _controller: RapsysUserBundle:Default:login }
+
+rapsys_user_recover:
+    path:     /recover
+    defaults: { _controller: RapsysUserBundle:Default:recover }
+
+rapsys_user_recover_mail:
+    path:     /recover/{mail}/{hash}
+    defaults: { _controller: RapsysUserBundle:Default:recoverMail }
+
+rapsys_user_register:
+    path:     /register
+    defaults: { _controller: RapsysUserBundle:Default:register }
+
+rapsys_user_logout:
+    path:     /logout
+
+rapsys_user_homepage:
+    path:     /
diff --git a/Resources/config/services.yml b/Resources/config/services.yml
new file mode 100644 (file)
index 0000000..3e9742b
--- /dev/null
@@ -0,0 +1,8 @@
+services:
+    Rapsys\UserBundle\Controller\DefaultController:
+        tags: [ controller.service_arguments ]
+    Rapsys\UserBundle\Utils\Slugger:
+        arguments: [ "@service_container" ]
+#    rapsys_user.example:
+#        class: Rapsys\UserBundle\Example
+#        arguments: ["@service_id", "plain_value", "%parameter%"]
diff --git a/Utils/Slugger.php b/Utils/Slugger.php
new file mode 100644 (file)
index 0000000..f3d8e25
--- /dev/null
@@ -0,0 +1,84 @@
+<?php
+
+namespace Rapsys\UserBundle\Utils;
+
+class Slugger {
+       //The secret parameter
+       private $secret;
+
+       //The offset reduced from secret
+       private $offset;
+
+       //Retrieve secret and set offset from reduction
+       public function __construct(\Symfony\Component\DependencyInjection\ContainerInterface $container) {
+               //Set secret
+               $this->secret = $container->getParameter('secret');
+
+               //Init rev array
+               $rev = array_flip(array_merge(range('0', '9'), range('a', 'z'), range('A', 'Z'), range('!', '~')));
+
+               //Set offset
+               $this->offset = array_reduce(str_split($this->secret), function ($res, $a) use ($rev) { return $res += $rev[$a]; }, count($this->secret)) % count($rev);
+       }
+
+       //Short the string
+       public function short($string) {
+               //Return string
+               $ret = '';
+
+               //Alphabet
+               $alpha = array_merge(range('0', '9'), range('a', 'z'), range('A', 'Z'), range('!', '~'));
+
+               //Reverse alphabet
+               $rev = array_flip($alpha);
+
+               //Number characters
+               $count = count($alpha);
+
+               //Iterate on each character
+               foreach(str_split($string) as $c) {
+                       if (isset($rev[$c]) && isset($alpha[($rev[$c]+$this->offset)%$count])) {
+                               $ret .= $alpha[($rev[$c]+$this->offset)%$count];
+                       }
+               }
+
+               //Send result
+               return str_replace(array('+','/'), array('-','_'), base64_encode($ret));
+       }
+
+       //Unshort the string
+       public function unshort($string) {
+               //Return string
+               $ret = '';
+
+               //Alphabet
+               $alpha = array_merge(range('0', '9'), range('a', 'z'), range('A', 'Z'), range('!', '~'));
+
+               //Reverse alphabet
+               $rev = array_flip($alpha);
+
+               //Number characters
+               $count = count($alpha);
+
+               //Iterate on each character
+               foreach(str_split(base64_decode(str_replace(array('-','_'), array('+','/'), $string))) as $c) {
+                       if (isset($rev[$c]) && isset($alpha[($rev[$c]-$this->offset+$count)%$count])) {
+                               $ret .= $alpha[($rev[$c]-$this->offset+$count)%$count];
+                       }
+               }
+
+               //Send result
+               return $ret;
+       }
+
+       //Crypt and base64uri encode string
+       public function hash($string) {
+               return str_replace(array('+','/'), array('-','_'), base64_encode(crypt($string, $this->secret)));
+       }
+
+       //Convert string to safe slug
+       function slug($string) {
+               return preg_replace('/[\/_|+ -]+/', '-', strtolower(trim(preg_replace('/[^a-zA-Z0-9\/_|+ -]/', '', str_replace(array('\'', '"'), ' ', iconv('UTF-8', 'ASCII//TRANSLIT', $string))), '-')));
+       }
+
+}