Volver al blog

Una introducción a Sylius User Bundle para Symfony - Parte Uno

Una introducción a Sylius User Bundle para Symfony - Parte Uno

Este post es parte de una serie sobre los bundles fundacionales del framework de eCommerce Sylius/Symfony.

En Odiseo venimos trabajando con Symfony Framework desde hace muchísimo tiempo. La base de la mayoría de nuestros proyectos web está construida sobre Symfony. Nuestro equipo cree en el ecosistema y en la comunidad de Symfony. Hemos liberado como código abierto muchas herramientas para trabajar con Symfony y usamos librerías relevantes de la comunidad en nuestros proyectos.

Construimos muchos tipos de aplicaciones para todas las necesidades de nuestros clientes. Para aplicaciones web de eCommerce usamos Sylius.

"Sylius es un framework de eCommerce de código abierto construido sobre Symfony. La máxima calidad de código, una fuerte cultura de testing, un flujo de trabajo ágil incorporado (BDD: https://solidgeargroup.com/bdd-testing-behat) y una flexibilidad excepcional lo convierten en la mejor solución para aplicaciones hechas a la medida de los requerimientos de tu negocio" Sylius

Y lo hace muy bien, pero Sylius, como framework diseñado para desarrolladores, no se trata solamente de vender productos. También tiene muchas otras funcionalidades que podemos usar y QUE USAMOS en casi todos los proyectos con Symfony. Para devolverle nuestra experiencia a la comunidad de Symfony armamos una serie de posts que explican cómo trabajar con algunas de ellas.

Introducción a las funcionalidades no relacionadas con eCommerce de Sylius: SyliusUserBundle

Los usuarios son una parte importante de casi cualquier proyecto que tenga algún nivel de seguridad o de interacción con personas. Symfony provee una interfaz útil para asegurar tu sistema, pero el resto queda en tus manos.

Sylius, por su parte, tiene un Component y un Bundle que te dan modelos, servicios y eventos para trabajar con usuarios, incluyendo login, registro, oauth y más. ¡Veamos cómo trabajar con eso!

Origen y motivación. ¿Por qué no FOSUserBundle?

Sí, solíamos usar FOSUserBundle. En realidad es un muy buen bundle, pero no sigue la convención de Sylius. Empezamos a sentir que trabajar con usuarios y clientes no se parecía al resto de las entidades de nuestros proyectos. Y por supuesto el core team de Sylius pensó lo mismo:

"Sylius está construido alrededor de convenciones fuertes, lo que significa que todos los modelos de datos tienen la misma estructura de servicios, la misma nomenclatura de eventos y clases, y en general todo funciona de la misma manera para todo, excepto para el modelo User de FOSUserBundle" Blog de Sylius

SyliusUserBundle es una muy buena opción para manejar usuarios y seguridad en un proyecto Symfony. Provee todas las funcionalidades necesarias para tener una seguridad basada en usuarios, y además integra la configuración de SyliusResourceBundle para los usuarios, así que podés administrarlos fácilmente. Si querés saber más sobre el Resource bundle, Sylius ya tiene una buena documentación en su sitio.

Instalación

Podés instalar este bundle con Composer. Con Composer instalado globalmente, ejecutá:

$ composer require sylius/user-bundle

Si no estás usando Symfony Flex, tenés que agregar los bundles requeridos al kernel: `SyliusUserBundle`, `SyliusMailerBundle` y, si no estás usando ningún otro bundle de Sylius, también vas a necesitar agregar ``SyliusResourceBundle`` y sus dependencias al kernel siguiendo su documentación.

Configuración

Configuración básica del bundle:

# config/packages/sylius_user.yaml 
security: 
  encoders:  
    argon2i: argon2i 
    sylius_user:   
      encoder: argon2i

jms_serializer:   
  metadata:       
    directories:           
      sylius-user:               
        namespace_prefix: "Sylius\\Component\\User"               
        path: "@SyliusUserBundle/Resources/config/serializer"

Configurá las extensiones de doctrine que usa el bundle.

# config/packages/stof_doctrine_extensions.yaml 
stof_doctrine_extensions:   
  orm:       
    default:           
      timestampable: true

Modelos

User

Sylius Framework tiene los conceptos de “Customers” y “Users” separados. Eso significa que podrías tener un customer (que en otros proyectos podría ser Cliente, Proveedor, Alumno, etc.) con la información personal. Y la entidad User, que representa a un usuario registrado, debería tener todo lo relativo a las preferencias del usuario de la aplicación y una asociación con un customer (si hiciera falta).

OAuth

La entidad OAuth tiene todos los datos relativos a la cuenta de OAuth. Un usuario puede tener muchas cuentas de OAuth.

Dividiendo los usuarios en AdminUser y AppUser (ShopUser en Sylius).

Con los usuarios seguimos la convención de Sylius, creando 2 tipos:

AdminUser: creado para habilitar cuentas de administrador con acceso al panel de administración.

AppUser: pensado para los clientes que se registraron en el sistema — tienen una cuenta con e-mail y contraseña. Pueden visitar y modificar su cuenta.

AdminUser

La entidad AdminUser simplemente extiende la entidad User.

namespace App\Entity;

use Sylius\Component\User\Model\User;
use Doctrine\ORM\Mapping as ORM;

/**
 * @ORM\Entity
 * @ORM\Table(name="app_admin_user")
 */
class AdminUser extends User
{
    public function __construct()
    {
        parent::__construct();
        $this->roles = ['ROLE_ADMIN'];
    }
}

Configuralo como un tipo de usuario:

sylius_user:
  driver: doctrine/orm
  resources:
    admin:
      user:
        classes:
          model: App\Entity\AdminUser
          repository: Sylius\Bundle\UserBundle\Doctrine\ORM\UserRepository
          form: Sylius\Bundle\UserBundle\Form\Type\UserType
        templates: 'admin/user'

Para actualizar el esquema de tu base de datos, ejecutá el siguiente comando:

$ php bin/console doctrine:schema:update --force

¿Cómo crear un AdminUser programáticamente?

Crear un AdminUser programáticamente es igual que con cualquier otra entidad: tiene su propia factory. Por defecto va a tener asignado un rol de administración (ROLE_ADMIN), como en el ejemplo de arriba.

$admin = $this->container->get('sylius.factory.admin_user')->createNew();
$admin->setEmail('administrator@test.com');
$admin->setPlainPassword('pswd');
$this->container->get('sylius.repository.admin_user')->add($admin);

AppUser (o ShopUser)

Probablemente quieras agregar algunos campos y funciones propias a tu entidad User, así que creemos una personalizada. Podés llamarla FrontendUser, ShopUser, AppUser o simplemente User:

namespace App\Entity;

use Sylius\Component\User\Model\User as BaseUser;
use Sylius\Component\User\Model\UserOAuthInterface;
use Doctrine\ORM\Mapping as ORM;

/**
 * @ORM\Entity
 * @ORM\Table(name="app_user")
 */
class AppUser extends BaseUser
{
    /** @var string|null */
    protected $name;

    /** 
     * Override method to set username as email.
     * 
     * @param string|null $email
     */
    public function setEmail(?string $email): void
    {
        parent::setEmail($email);
        $this->setUsername($email);
    }

    /**
     * Custom method to retrieve Facebook OAuth account.
     * 
     * @return AppUserOAuth|UserOAuthInterface|null
     */
    public function getFacebook(): ?UserOAuthInterface
    {
        return $this->getOAuthAccount('facebook');
    }
}

Configuralo como un tipo de usuario:

sylius_user:
  driver: doctrine/orm
  resources:
    # ... admin_user configuration
    app:
      user:
        classes:
          model: App\Entity\AppUser
    oauth:
      user:
        classes:
          model: Sylius\Component\User\Model\UserOAuth
          interface: Sylius\Component\User\Model\UserOAuthInterface
          controller: Sylius\Bundle\ResourceBundle\Controller\ResourceController
          repository: Sylius\Bundle\UserBundle\Doctrine\ORM\UserRepository
          form: Sylius\Bundle\UserBundle\Form\Type\UserType
        templates: 'admin/user'

Entonces, actualizá de nuevo el esquema de tu base de datos:

$ php bin/console doctrine:schema:update --force

¿Cómo crear un AppUser programáticamente?

Podemos crear una entidad Customer (o Guess) para juntar datos de los invitados no registrados del sistema (aquellos que hicieron algo sin tener una cuenta o que de alguna manera nos dejaron su e-mail).

Asumiendo que ya tenemos una entidad Guess configurada como `app.guess` (traída del repositorio o recién creada), usá una factory para crear un nuevo AppUser, asignale el Guess existente y una contraseña mediante el método ``setPlainPassword()``.

$user = $this->container->get('sylius.factory.app_user')->createNew();
$customer = $this->container->get('app.repository.guess')->findOneBy(['email' => 'guess@test.com']);
$user->setGuess($customer);
$user->setPlainPassword('pswd');
$this->container->get('sylius.repository.app_user')->add($user);

Cambiar la contraseña de un AppUser

La contraseña ya establecida de un AppUser se puede cambiar fácilmente con el método ``setPlainPassword()``.

$user->getPassword(); // returns encrypted password - 'pswd'
$user->setPlainPassword('resu1'); // the password will now be 'resu1' and will become encrypted while saving the user in the database

¡Eso es todo! En el próximo post vamos a continuar y hablar sobre cómo configurar el acceso de seguridad de los usuarios.

Compartir