Creare un semplice form di registrazione con Symfony e Doctrine.
Il form è funzionante e pronto all’uso.
0. Se è la prima volta che utilizziamo il DB, procediamo con il setup come mostrato nella lezione precedente a:
www.lucedigitale.com/blog/symfony-databases-and-the-doctrine-orm/
1. Creiamo il Database da PhpMyAdmin:
Database: test_project
Tabella: app_users
Campi:
– Id char(11) AUTO_INCREMENT
– username char (25) UNIQUE
– password char (60) UNIQUE
– email char (60) UNIQUE
2. Creiamo l’entità User in src/AppBundle/Entity/User.php
<?php // src/AppBundle/Entity/User.php namespace AppBundle\Entity; use Doctrine\ORM\Mapping as ORM; // uso Doctrine use Symfony\Component\Validator\Constraints as Assert; // Uso la validazione use Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntity; // Uso la validazione use Symfony\Component\Security\Core\User\UserInterface;// usa il sistema Symfony per gestire gli utenti /** * @ORM\Entity * @ORM\Table(name="app_users") * @UniqueEntity(fields="email", message="Email already taken") * @UniqueEntity(fields="username", message="Username already taken") */ class User implements UserInterface// aggiungi i metodi seguenti alla classe UserInterface di Symfony { /** * @ORM\Id * @ORM\Column(type="integer") * @ORM\GeneratedValue(strategy="AUTO") */ private $id; /** * @ORM\Column(type="string", length=255, unique=true) * @Assert\NotBlank() * @Assert\Email() */ private $email; /** * @ORM\Column(type="string", length=255, unique=true) * @Assert\NotBlank() */ private $username; /** * @Assert\NotBlank() * @Assert\Length(max=4096) */ private $plainPassword; // la password in chiaro, non è salvata nel DB, infatti non abbiamo @ORM ma solo una validazione /** * The below length depends on the "algorithm" you use for encoding * the password, but this works well with bcrypt. * * @ORM\Column(type="string", length=64) */ private $password; // la password criptata con bcript // other properties and methods // metodi GET e SET necessari per il funzionamento del form di Symfony public function getEmail() { return $this->email; } public function setEmail($email) { $this->email = $email; } public function getUsername() { return $this->username; } public function setUsername($username) { $this->username = $username; } public function getPlainPassword() { return $this->plainPassword; } public function setPlainPassword($password) { $this->plainPassword = $password; } public function getPassword() { return $this->password; } public function setPassword($password) { $this->password = $password; } // ritorna NULL percho bcrypt gestisce il seme per criptare le password public function getSalt() { // The bcrypt algorithm doesn't require a separate salt. // You *may* need a real salt if you choose a different encoder. return null; } // other methods, including security methods like getRoles() public function getRoles()// i ruoli concessi all'utente { return array('ROLE_USER'); } public function eraseCredentials()// rimuove i dati sensibili dell'utente { } // Serialize // Alla fine di ogni - request - l'oggetto User viene trasformato in un array (serialize) e salvato nella sessione // Alla richiesta successiva viene ricaricato dalla sessione e riconvertito (unserialize) /** @see \Serializable::serialize() */ public function serialize() { return serialize(array( $this->id, $this->username, $this->password, // see section on salt below // $this->salt, )); } /** @see \Serializable::unserialize() */ public function unserialize($serialized) { list ( $this->id, $this->username, $this->password, // see section on salt below // $this->salt ) = unserialize($serialized); } }// END Class
Come funziona?
Indico a Symfony dove trovare questo file che contiene la classe che sarà caricata come namespace
// src/AppBundle/Entity/User.php namespace AppBundle\Entity;
Carico i namespace
use Doctrine\ORM\Mapping as ORM; // uso Doctrine use Symfony\Component\Validator\Constraints as Assert; // Uso la validazione use Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntity; // Uso la validazione use Symfony\Component\Security\Core\User\UserInterface;// usa il sistema Symfony per gestire gli utenti
Aggiungo i metodi alla classe UserInterface di Symfony
class User implements UserInterface...
Dichiaro le proprietà della classe e le loro caratteristiche SQL
/** * @ORM\Id * @ORM\Column(type="integer") * @ORM\GeneratedValue(strategy="AUTO") */ private $id;
Metodi GET e SET necessari a Symfony
public function getEmail() { return $this->email; } public function setEmail($email) { $this->email = $email; }
Altre note:
getSalt() – non serve per il bcrypt ma va esplicitata obbligatoriamente o ritorna errore
getRoles() – anche se NULL va esplicitata obbligatoriamente o ritorna errore
eraseCredentials() – anche se NULL va esplicitata obbligatoriamente o ritorna errore
$plainPassword – non viene salvata nel DB ma solo validata @Assert\NotBlank() …
3. Modifichiamo app/config/security.yml, configuro i parametri di security per puntare a User.php e al DB app_users
In particolare notiamo:
– encoders: AppBundle\Entity\User: algorithm: bcrypt
-> usa l’algoritmo bcrypt per criptare la password
– app_users: entity: class: AppBundle:User property: username
-> come gli utenti vengono caricati tradotto -> ‘nometabella’: in ‘AppBundle/Entity/User.php’ proprietà ‘username’
# To get started with security, check out the documentation: # http://symfony.com/doc/current/security.html # app/config/security.yml security: encoders: AppBundle\Entity\User: algorithm: bcrypt # http://symfony.com/doc/current/security.html#b-configuring-how-users-are-loaded providers: in_memory: memory: ~ app_users: entity: class: AppBundle:User property: username # if you're using multiple entity managers # manager_name: customer firewalls: # disables authentication for assets and the profiler, adapt it according to your needs dev: pattern: ^/(_(profiler|wdt)|css|images|js)/ security: false main: anonymous: ~ # activate different ways to authenticate pattern: ^/ http_basic: ~ # http://symfony.com/doc/current/security.html#a-configuring-how-your-users-will-authenticate #http_basic: ~ # http://symfony.com/doc/current/cookbook/security/form_login_setup.html #form_login: ~
4. Creiamo in src/AppBundle/Form/UserType.php il form come classe in modo che sia riusabile con facilità
<?php // src/AppBundle/Form/UserType.php namespace AppBundle\Form; // carico User.php use AppBundle\Entity\User; // carico i namespace per il creare il form use Symfony\Component\Form\AbstractType; use Symfony\Component\Form\FormBuilderInterface; use Symfony\Component\OptionsResolver\OptionsResolver; use Symfony\Component\Form\Extension\Core\Type\EmailType; use Symfony\Component\Form\Extension\Core\Type\TextType; use Symfony\Component\Form\Extension\Core\Type\RepeatedType; use Symfony\Component\Form\Extension\Core\Type\PasswordType; class UserType extends AbstractType // Estende la classe Symfony AbstractType{} { public function buildForm(FormBuilderInterface $builder, array $options) // metodo di AbstractType{} { $builder ->add('email', EmailType::class) // la casella email ->add('username', TextType::class) // la casella username // la casella password e repeat password ->add('plainPassword', RepeatedType::class, array( 'type' => PasswordType::class, 'first_options' => array('label' => 'Password'), 'second_options' => array('label' => 'Repeat Password'), )) ; } public function configureOptions(OptionsResolver $resolver) { $resolver->setDefaults(array( 'data_class' => User::class, )); } }
5. Creiamo il controller per renderizzare il form a src/AppBundle/Controller/RegistrationController.php
<?php // src/AppBundle/Controller/RegistrationController.php namespace AppBundle\Controller; use AppBundle\Form\UserType;// UserType.php use AppBundle\Entity\User; // User.php use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route; // @Route use Symfony\Bundle\FrameworkBundle\Controller\Controller; use Symfony\Component\HttpFoundation\Request; class RegistrationController extends Controller { /** * @Route("/register", name="user_registration") */ public function registerAction(Request $request) { // 1) build the form $user = new User(); // istanziamo l'oggetto di User.php $form = $this->createForm(UserType::class, $user); // 2) controlla se il bottone - submit - è stato premuto $form->handleRequest($request); // se l'oggetto user è submit AND validato if ($form->isSubmitted() && $form->isValid()) { // 3) Encode the password (you could also do this via Doctrine listener) $password = $this->get('security.password_encoder') ->encodePassword($user, $user->getPlainPassword()); $user->setPassword($password); // 4) save the User! $em = $this->getDoctrine()->getManager(); $em->persist($user);// prepara in cache i dati $em->flush(); // scrivi i dati nel DB // ... do any other work - like sending them an email, etc // maybe set a "flash" success message for the user return $this->redirect('http://symfony.com'); } return $this->render( 'registration/register.html.twig', array('form' => $form->createView()) ); } }
6. Creiamo il Template app/Resources/views/registration/register.html.twig
{# app/Resources/views/registration/register.html.twig #} {{ form_start(form) }} {{ form_row(form.username) }} {{ form_row(form.email) }} {{ form_row(form.plainPassword.first) }} {{ form_row(form.plainPassword.second) }} <button type="submit">Register!</button> {{ form_end(form) }}
7. Puntiamo il browser a: http://localhost/symfonytest/first_test_symfony/web/register
Il form in automatico restituirà un messaggio di errore all’utente se:
– username è già stato preso
– email è già stata presa
– password è già stata presa
– password e repeat password non sono uguali
Il mio sito ufficiale:
lucedigitale.com
Bibliografia:
symfony.com/doc/current/doctrine/registration_form.html