Archives de
Tag: symfony2

API Platform + FOSUserBundle + LexikJWTAuthenticationBundle

API Platform + FOSUserBundle + LexikJWTAuthenticationBundle

  • Symfony: 3.2.2
  • API Platform: 2.0.3
  • FOSUserBundle: 2.0.0-beta2
  • LexikJWTAuthenticationBundle: 2.1.1

En premier lieu nous allons cloner le dépôt API Plaftorm:

composer create-project api-platform/api-platform bookshop-api

Une fois fait, nous installons FOSUserBundle et LexikJWTAuthenticationBundle via composer:

composer require friendsofsymfony/user-bundle:2.0.0-beta-2
composer require lexik/jwt-authentication-bundle

Puis nous activons les bundles fraichement installé dans AppKernel.php:

public function registerBundles()
{
    return array(
        // ...
        new FOS\UserBundle\FOSUserBundle(),
        new Lexik\Bundle\JWTAuthenticationBundle\LexikJWTAuthenticationBundle(),
    );
}

Nous créons notre entité User.php:

<?php

namespace AppBundle\Entity;

use ApiPlatform\Core\Annotation\ApiResource;
use Doctrine\ORM\Mapping as ORM;
use FOS\UserBundle\Model\User as BaseUser;
use FOS\UserBundle\Model\UserInterface;
use Symfony\Component\Serializer\Annotation\Groups;

/**
 * @ORM\Entity
 * @ApiResource(attributes={
 *     "normalization_context"={"groups"={"user", "user-read"}},
 *     "denormalization_context"={"groups"={"user", "user-write"}}
 * })
 */
class User extends BaseUser
{
    /**
     * @ORM\Id
     * @ORM\Column(type="integer")
     * @ORM\GeneratedValue(strategy="AUTO")
     */
    protected $id;

    /**
     * @Groups({"user"})
     */
    protected $email;

    /**
     * @ORM\Column(type="string", length=255, nullable=true)
     * @Groups({"user"})
     */
    protected $fullname;

    /**
     * @Groups({"user-write"})
     */
    protected $plainPassword;

    /**
     * @Groups({"user"})
     */
    protected $username;

    public function setFullname($fullname)
    {
        $this->fullname = $fullname;

        return $this;
    }
    public function getFullname()
    {
        return $this->fullname;
    }

    public function isUser(UserInterface $user = null)
    {
        return $user instanceof self && $user->id === $this->id;
    }
}

Nous poursuivons par la génération des clés, notez bien la pass phrase qu’il faudra copié dans le fichier parameters.yml

mkdir -p var/jwt # For Symfony3+, no need of the -p option
openssl genrsa -out var/jwt/private.pem -aes256 4096
openssl rsa -pubout -in var/jwt/private.pem -out var/jwt/public.pem

Nous mettons a jours les fichier suivants:

config.yml:

framework:
    translator:      { fallbacks: ["%locale%"] }

fos_user:
    db_driver: orm # other valid values are 'mongodb', 'couchdb' and 'propel'
    firewall_name: main
    user_class: AppBundle\Entity\User

lexik_jwt_authentication:
    private_key_path: '%jwt_private_key_path%'
    public_key_path:  '%jwt_public_key_path%'
    pass_phrase:      '%jwt_key_pass_phrase%'
    token_ttl:        '%jwt_token_ttl%'

routing.yml

api:
    resource: '.'
    type:     'api_platform'

app:
    resource: '@AppBundle/Action/'
    type:     'annotation'

api_login_check:
    path: /api/login_check

fos_user_security:
    resource: "@FOSUserBundle/Resources/config/routing/security.xml"

fos_user_profile:
    resource: "@FOSUserBundle/Resources/config/routing/profile.xml"
    prefix: /profile

fos_user_register:
    resource: "@FOSUserBundle/Resources/config/routing/registration.xml"
    prefix: /register

fos_user_resetting:
    resource: "@FOSUserBundle/Resources/config/routing/resetting.xml"
    prefix: /resetting

fos_user_change_password:
    resource: "@FOSUserBundle/Resources/config/routing/change_password.xml"
    prefix: /profile

security.yml

security:
    encoders:
        FOS\UserBundle\Model\UserInterface: bcrypt

    role_hierarchy:
        ROLE_READER: ROLE_USER
        ROLE_ADMIN: ROLE_READER

    providers:
        fos_userbundle:
            id: fos_user.user_provider.username_email

    firewalls:
        login:
            pattern:  ^/login
            stateless: true
            anonymous: true
            provider: fos_userbundle
            form_login:
                check_path: /login_check
                username_parameter: _username
                password_parameter: _password
                success_handler: lexik_jwt_authentication.handler.authentication_success
                failure_handler: lexik_jwt_authentication.handler.authentication_failure
                require_previous_session: false

        main:
            pattern: ^/
            provider: fos_userbundle
            stateless: true
            anonymous: true
            lexik_jwt: ~

        # disables authentication for assets and the profiler, adapt it according to your needs
        dev:
            pattern: ^/(_(profiler|wdt)|css|images|js)/
            security: false

    access_control:
        - { path: ^/login, role: IS_AUTHENTICATED_ANONYMOUSLY }
        - { path: ^/books, roles: [ ROLE_READER ] }
        - { path: ^/, roles: [ ROLE_READER ] }

parameters.yml.dist et parameters.yml, n’oubliez pas la pass phrase pour les clés

parameters:
    # ...
    jwt_private_key_path: '%kernel.root_dir%/../var/jwt/private.pem' # ssh private key path
    jwt_public_key_path:  '%kernel.root_dir%/../var/jwt/public.pem'  # ssh public key path
    jwt_key_pass_phrase:  ''                                         # ssh key pass phrase
    jwt_token_ttl:        3600

Puis nous mettons à jour la base de données et créons notre premier utilisateur:

php bin/console doctrine:schema:update --force
php bin/console fos:user:create testuser test@example.com p@ssword
php bin/console fos:user:promote testuser ROLE_READER

Pour tester ca un petit coup de Curl:

curl -X POST http://127.0.0.1:8000/login_check -d _username=test@example.com -d _password=p@ssword

Et comme réponse nous avons:

{"token":"eyJhbGciOiJSUzI1NiJ9.eyJyb2xlcyI6WyJST0xFX1JFQURFUiIsIlJPTEVfVVNFUiJdLCJ1c2VybmFtZSI6InRlc3R1c2VyIiwiZXhwIjoxNDg2NDk5MjczLCJpYXQiOjE0ODY0OTU2NzN9.RL8VS8MuKhvg0uW23TPnlxsZusUIE86YuE_cg44F4rToe8c7zV6s-2lmuOhP5CyeB50IVfLlb4-RC1frKQFTIrEA1LJ2FewxKFO2Mb2sIQwQonAew3MTwnxbnPRWrS0sQCsb1NbXTxohc5WH-BU1U3IkuAjuTVLcB3g7JlPor0yedUU766BRXjIhklN7IuILKsjhteqGK6F9Ilg0zmLyjQV3-BUg1nnWygQ-O4BLrU_InvhpHZVOnPfikMftcKVAhn_Z4GKGVVORQxplhc4i0lJgzdV83AaImYqOzn3WBJxKnzmitb6rnOJ-SKXjdAYRix_rFwqIzzWNdcAg1-C731b08I3qcfWXmmadI2GsygVpemlagH8v6tcFjwVsyazblqFCA8oy37N0CfSVt7av8GIbenWtIDUS5Tl3a0SMxmcwg6rlTL_1pE0-E8mPa8ZbLho-nON2hKoQcG1LhIeuatzIi7lUSLCQv_uzy29Hpq7PPJ_43cZZDdex-vk3BVHbjZCOcggVxp-mDDTcU7VxZFwmi8AiP9ZAg8AFXviKcfM7D5Er2tB2k3HHsnCqTSGRJe9czNs-GaW55748BK_u0UiEBvBdDHUgmbGw4UTRw8aNTY8p8M_tavezC36p5zilyd2CB6knsLtm0aRkqyZaiK27uvajYMt65BpxqsmXzLw"}

Et voila !!!

Disponible sur github.

Vagrant et Symfony2

Vagrant et Symfony2

Suite au formatage de mon Windows et au futur formatage de mon Mac, je me suis dit qu’il serait vraiment temps de regarder du côté de Vagrant pour ne pas avoir à reconfigurer à chaque fois un nouvel environnement de travail.

Vagrant est un outil permettant de gérer facilement des machines virtuelles. Pour l’installation rien de plus simple, il faut installer VirtualBox puis Vagrant.

Afin d’avoir automatiquement la bonne version des VirtuablBox Guest, installe le plugin vagrant-vbguest en ligne de commande avec :

vagrant plugin install vagrant-vbguest

Dans cet article je ne parlerais que de Mac, je ferais un autre article pour Windows.

Afin d’accéder aux sites web rajouter la ligne suivant dans votre fichier hosts :

127.0.0.1       www.pma.local sonata.fr

Afin d’utiliser Vagrant il nous faut créer un fichier Vagrantfile. Ce fichier est écrit en Ruby et fournit à Vagrant les informations nécessaires à la création et au provisionnement de la machine virtuelle.

# -*- mode: ruby -*-
# vi: set ft=ruby :

VAGRANTFILE_API_VERSION = "2"

Vagrant.configure(VAGRANTFILE_API_VERSION) do |config|
  config.vm.box = "centos64"
  config.vm.box_url = "http://puppet-vagrant-boxes.puppetlabs.com/centos-64-x64-vbox4210-nocm.box"

  config.vm.network :forwarded_port, guest: 80, host: 80
  config.vm.network :forwarded_port, guest: 443, host: 443

  config.vm.provider "virtualbox" do |v|
	v.customize ["modifyvm", :id, "--natdnshostresolver1", "on"]
    v.customize ["modifyvm", :id, "--natdnsproxy1", "on"]
  end

  config.vm.network "private_network", ip: "10.11.12.13"
  config.vm.synced_folder ".", "/vagrant", nfs: true
  config.nfs.map_uid = Process.uid
  config.nfs.map_gid = Process.gid

  config.vm.provision "shell", path: "app/config/vagrant.sh"
end

Dans ce fichier Vagrantfile plusieurs choses sont importantes:

  • Les lignes 7 et 8 définissent l’image de machine virtuelle à utiliser et où la télécharger si elle n’est pas disponible sur la machine
  • Les lignes 10 et 11 permettent de rediriger les ports de la machine physique vers la machine virtuelle
  • Les lignes 13 à 16 permettent de changer les paramètres de la machine virtuelle, dans notre cas cela concerne les dns
  • La ligne 18 définit un réseau privé avec l’adresse IP de la VM
  • La ligne 19 monte le répertoire courant de la machine physique dans le répertoire /vagrant le la machine virtuelle en utilisant NFS
  • Les lignes 20 et 21 servent à configurer les droits d’accès aux fichiers
  • La ligne 23 définit quel script sera exécuté lors de l’étape de provisionnement

La ligne 23 fait référence à un fichier vagrant.sh, nous allons le voir en détail. Ce fichier va installer et configurer les différents logiciels pour notre machine virtuelle :

  • Mise à jour des paquets
  • Installation des dépendances pour la compilation d’Apache et de PHP
  • Compilation et configuration d’Apache et PHP (APC, Xdebug)
  • Installation de composer et phpMyAdmin
  • Préconfiguration de l’application Symfony2

Afin de créer la machine virtuelle, ouvrez une ligne de commande dans le dossier ou ce situe le fichier Vagrantfile puis lancez vagrant up .

Une fois la machine virtuelle créée vous pourrez vous rendre sur :

Pour exécuter des lignes de commande, utilisez vagrant ssh afin de vous connectez dans la machine virtuelle.

Et voilà. Le dépôt GitHub est à jour.

Formulaire Symfony2 et Javascript [FR]

Formulaire Symfony2 et Javascript [FR]

J’ai récemment du faire face a une question lors d’un rendu de formulaire avec symfony2.

Il me fallait faire un traitement Javascript en fonction d’un choix de radio bouton. Ma première pensée a été de customiser le rendu du formulaire pour arriver à mes besoins.

Je me suis vite rendu compte qu’insérer du code Javascript customisé dans ma surcharge twig de form_row à travers le formbuilder n’était pas la bonne solution.

Dans mon cas la bonne solution fut de rendre les valeurs de mes radio boutons une à une afin qu’elles ne soient pas alignées grâce au code suivant :

{{ form_row(form.radio[0]) }}
{{ form_row(form.radio[1]) }}

Puis à l’aide de jQuery j’ai lié les événements click des radio boutons à des fonctions Javascript.

$(document).ready(function(){
    $("#formname_radio_0").click(function(){
        alert('radio  0');
    });
    $("#formname_radio_1").click(function(){
        alert('radio  1');
    });
});

 

Ajouter un champ a un utilisateur avec le bundle sonatauserbundle [FR]

Ajouter un champ a un utilisateur avec le bundle sonatauserbundle [FR]

Si vous utilisez le bundle sonata-user-bundle il y a de fortes chances pour que vous ayez utilisé le bundle sonata-easy-extends afin de généré votre bundle de gestion des utilisateurs.

J’ai découvert ce weekend qu’afin d’ajouter un nouveau champ sur un utilisateur lors de l’utilisation du bundle sonatauserbundle, il faut modifier le fichier Application/Sonata/UserBundle/Resources/config/doctrine/User.orm.xml

 

Le tri par défaut dans Sonata Admin

Le tri par défaut dans Sonata Admin

J’ai récemment dû ajouter un tri par défaut sur une de mes classes admin du bundle sonata admin. Après une petite recherche, j’ai finalement trouvé qu’il suffit de surcharger une variable:

protected $datagridValues = array(
        '_sort_order' => 'DESC',
        '_sort_by' => 'day'
    );

Mes données serons dorénavant ordonnées en fonction du la valeur day dans l’ordre décroissant.