Développer avec le sylius resourcebundle (Symfony live Paris 2015)

3,883 views

Published on

Au cours de son développement Sylius, l'équipe s’est rendu compte qu’elle dupliquait énormément de code pour gérer ses CRUDs. Ne voulant pas réinventer Symfony ou utiliser un admin generator, elle décida de créer un bundle simple et flexible: SyliusResourceBundle. Je présenterai comment gérer ses CRUDs avec ce bundle en écrivant le minimum de code et, surtout, sans en dupliquer! Il a été pensé afin de pouvoir supporter plusieurs types de drivers (DoctrineORM, PHPCR). De plus, il permet de construire rapidement une API grâce au FOSTRestBundle. Je mettrai en avant l’ensemble des composants utilisés par ce bundle comme Doctrine. Il facilite la configuration le ResolveDoctrineTargetEntitiesPass ainsi que la création de MappingDriver. Il utilise aussi l’EventDispatcher: des évènements sont soulevés lorsque une action est exécutée sur une ressource. Il apporte aussi de nouveaux FormType ou FormExtension comme la CollectionExtension qui permet de gérer ses forms collection (js inclus).

Published in: Internet
0 Comments
2 Likes
Statistics
Notes
  • Be the first to comment

No Downloads
Views
Total views
3,883
On SlideShare
0
From Embeds
0
Number of Embeds
246
Actions
Shares
0
Downloads
21
Comments
0
Likes
2
Embeds 0
No embeds

No notes for slide

Développer avec le sylius resourcebundle (Symfony live Paris 2015)

  1. 1. DÉVELOPPER AVEC LE SYLIUSRESOURCEBUNDLE
  2. 2. QUI SUIS-JE ? Arnaud Langlade (@_aRn0D) Développeur Symfony chez Clever Age www.clever-age.com / @CleverAge
  3. 3. SYLIUS Framework E-commerce créé par Paweł Jędrzejewski Ensemble de bundles Symfony et composants PHP e-commerce Sylius Starndard Edition Quelques chiffres : ~200 contributeurs / ~1700 stars
  4. 4. SYLIUSRESOURCEBUNDLE Le SyliusResourceBundle vous permet de gérer rapidement et simplement vos ressources et de les exposer via API REST. Il n'y a pas que des composants e-commerce dans Sylius !
  5. 5. GESTION DES RESSOURCES? Z'AVEZ DIS CRUD? CRUD = Create, Read, Update, Delete
  6. 6. UN CRUD, COMMENT ÇA FONCTIONNE?
  7. 7. POURQUOI LA CRÉATION DE CE BUNDLE? Le back office de Sylius est composé d'énormement de CRUDs Eviter la duplication de code parce que c'est mal! Développer plus vite en automatisant des tâches
  8. 8. UNE SOLUTION? RESOURCECONTROLLER? Création du ResourceController : C'est un contrôleur générique Plus de code, il est intialisé via une configuration Il étend the FOSRestController Utilisation du EventDispatcher (répartiteur d'évènement) : Il permet de personnaliser les actions Solution plus flexible
  9. 9. QUELS SONT ORM/ODM SUPPORTÉS ? Doctrine ORM : Sylius l'utilise par défaut Doctrine Phpcr-ODM : Sylius intègre le CMF pour gérer des contenus Doctrine Mongodb-ODM Bientôt sûrement plus !
  10. 10. ATTENTION! Ce n'est pas un admin generator! Il faut créer vos formulaires, vos templates et le routing (pour le moment!)
  11. 11. CRÉER SON CRUD EN QUELQUES MINUTES ! Par exemple, créons un CRUD pour gérer des clients (customer).
  12. 12. CONFIGURONS NOS RESSOURCES sylius_resource:     resources:         myapp.customer:             driver: doctrine/orm             classes:                 model: AppBundleEntityCustomer                 repository: SyliusBundleResourceBundleDoctrineORMEntityRepository             templates: WebBundle:Backend/Customer         myapp.address:             # ...
  13. 13. MAIS QUE SE PASSE T'IL ? $ php app/console container:debug | grep customer myapp.manager.customer    alias for "doctrine.orm.default_entity_manager" myapp.controller.customer container SyliusBundleResourceBundleControllerResourceController myapp.repository.customer container SyliusBundleResourceBundleDoctrineORMEntityRepository $ php app/console container:debug ­­parameters sylius.config.classes {"myapp.customer": {...}}
  14. 14. CONFIGURONS NOS RESSOURCES sylius_resource:     resources:         myapp.customer:             driver: doctrine/orm             classes:                 model: AppBundleEntityCustomer                 controller: AppBundleControllerCustomerController                 repository: AppBundleRepositoryCustomerRepository             templates: WebBundle:Backend/Customer
  15. 15. CRÉONS NOTRE MODÈLE # AppBundleEntityCustomer.php; /**  * @ORMEntity  * @ORMTable(name="customer")  */ class Customer {     /**      * @ORMColumn(type="string", length=100)      */     protected $firstName;     /**      * @ORMColumn(type="string", length=100)      */     protected $lastName; }
  16. 16. CRÉONS NOTRE FORMULAIRE // AppBundleFormTypeCustomerType.php; class CustomerType extends AbstractResourceType {     public function getName()     {         return 'myapp_customer';     } } Le formulaire doit être défini en tant que service Pattern du nom de formulaire : nom-application_resource AbstractResourceType permet de configurer le data_class et le validation_group
  17. 17. CRÉONS NOS TEMPLATES {# create.html.twig ou update.html.twig #} <form method="POST" action="...">     {{ form_widget(form) }} </form> {# show.html.twig #} <div>     <p>{{ customer.firstname }}</p>     <p>{{ customer.lastname }}</p> </div> {# index.html.twig #} {% for customer in customers %}     {{ customer.fistname }} {{ customer.lastname }} {% endfor %}
  18. 18. CONFIGURONS NOS ROUTES # app/routing.yml myapp_customer_index:     pattern: /customer     defaults:         _controller: myapp.controller.customer:indexAction Pattern des clés des routes : nom-application_resource_action Ne pas oublier que les contrôleurs sont définis en tant que service Actions : index, show, create, update, delete, moveUp, moveDown, revert ou updateState
  19. 19. ET PAF ! ÇA FAIT DES CHOCAPICS ! Notre CRUD est prêt à l'emploi !! On crée notre API ?
  20. 20. EXPOSER SES CLIENTS VIA API REST Configurer le FOSRestBundle # app/config.yml fos_rest:     format_listener:         rules:             ­ { path: '^/', priorities: ['html', 'json'], fallback_format: html} Le ResourceController retourne le données dans le format souhaité GET /customer/57 HTTP/1.1 Host: myshop.com Accept: application/json
  21. 21. CONFIGURER LE SÉRIALISEUR # Resources/config/serializer/Entity.Customer.yml AppBundleEntityCustomer:     exclusion_policy: ALL     properties:         firstName:             expose: true             type: string         lastName:             expose: true             type: string         relations:             ­ rel: address             href:                 route: myapp_address_show                 parameters:                     id: expr(object.getAddress().getId()) HTTP/1.1 200 OK Content­Type: application/json; {     "id": 2,     "firstName": "Arnaud",     "lastName": "Langlade",     "_links": {         "self": {             "href": "/address/2"         }     } }
  22. 22. C'EST TOUT ? Lionframe (Rapid RESTful API Development) Génération automatique des formulaires et du routing
  23. 23. PLUS DE FLEXIBILITÉ ? Le comportement des méthodes du ResourceController est configurable
  24. 24. CONFIGURER LES METHODES DU RESOURCECONTROLLER Ajouter une entrée _sylius dans le tableau defaults des routes # app/routing.yml myapp_customer_create:     defaults:         _sylius:             template: WebBundle:Backend/Customer:custom_create.html.twig
  25. 25. RÉDIRIGER L'UTILISATEUR # app/routing.yml myapp_product_create:     pattern: /new     methods: [GET, POST]         _controller: myapp.controller.product:createAction         _sylius:             redirect: myapp_product_index             # Ou             redirect:                 route: myapp_product_show                 parameters: { name: resource.sku }
  26. 26. RÉCUPÉRER DES DONNÉES DANS LA BDD # app/routing.yml myapp_customer_index:     pattern: /     methods: [GET]     defaults:         _controller: myapp.controller.customer:indexAction         _sylius:             # $repository­>findBy(["group" => 'my_group'])             criteria:                 group: my_group             # $request­>get('criteria')             filterable: true
  27. 27. RÉCUPÉRER DES DONNÉES DANS LA BDD # app/routing.yml myapp_customer_index:     pattern: /     methods: [GET]     defaults:         _controller: myapp.controller.customer:indexAction         _sylius:             # $repository­>findByFilter($request­>get('filter'))             repository:                 method: findByFilter                 arguments: [$filter]
  28. 28. LISTER SES RESSOURCES # app/routing.yml myapp_customer_index:     pattern: /     methods: [GET]     defaults:         _controller: myapp.controller.customer:indexAction         _sylius:             # Trie             sorting:                 updatedAt: desc # Ou asc             # $request­>get('sorting');             sortable: true             # Paginate             paginate: 50
  29. 29. MOTEUR D'EXPRESSION # app/routing.yml myapp_order_index:     path: /orders     methods: [GET]     defaults:         _controller: app.controller.order:indexAction         _sylius:             repository:                 # $repository­>findOrderByCustomer([$customer]);                 method: findOrderByCustomer                 arguments: ["expr:service('security.context').getToken().getUser()"]
  30. 30. VOUS VOULEZ MUTUALISER VOTRE CODE ?
  31. 31. SYLIUS FONCTIONNE AVEC DES BUNDLES Ils doivent être facilement étendables Ils peuvent supporter plusieurs "drivers" (ORM/ODM) Ils ne doivent être couplés les uns aux autres
  32. 32. LA CONFIGURATION SÉMANTIQUE customer_bundle:     driver: doctrine/orm     templates:         customer: CustomerBundle:Backend/Customer         address: ...     validation_groups:         customer: [myapp]         address: ...     classes:         customer:             model: MyappCustomerBundleModelCustomer             controller: SyliusBundleResourceBundleControllerResourceController             repository: SyliusBundleResourceBundleDoctrineORMEntityRepository             form:                 default: MyappCustomerBundleFormTypeCustomerType                 choice: MyappCustomerBundleFormTypeCustomerChoiceType         address: ...
  33. 33. MAIS QUE SE PASSE T'IL? $ php app/console container:debug | grep customer myapp.controller.customer container SyliusBundleResourceBundleControllerResourceController myapp.manager.customer    n/a       alias for doctrine.orm.default_entity_manager myapp.repository.customer container SyliusBundleResourceBundleDoctrineORMEntityRepository myapp.form.type.customer  container myappCustomerBundleFormTypeCustomerType $ php app/console container:debug ­­parameters | grep customer myapp.model.customer.class          myappCustomerBundleModelCustomer myapp.model.customer.class          myappCustomerBundleModelCustomer myapp.controller.customer.class     SyliusBundleResourceBundleControllerResourceController myapp.repository.customer.class     SyliusBundleResourceBundleDoctrineORMEntityRepository myapp.form.type.customer.class      myappCustomerBundleFormTypeCustomerType myapp.validation_group.customer     ["myapp"] myapp_customer.driver               doctrine/orm
  34. 34. ETENDRE FACILEMENT VOTRE BUNDLE Utiliser l'injecteur de dépendences (Dependency Injector) Déclarer votre classe en tant mapped-superclass (évènement loadClassMetadata)
  35. 35. GÉRER PLUSIEURS DRIVERS Créer votre "Doctrine Mapping Driver" Fournir plusieurs implementations Doctrine pour un modèle Vos documents et entités sont dans le même namespace
  36. 36. LIMITER LE COUPLAGE DE VOS BUNDLES Utiliser le Resolve Target Entity Listener Définir des relations entre différentes entités sans les écrire en dur Il ré-écrit les paramètres targetEntity dans le mapping de votre modèle <!­­ Resources/config/doctrine/order.xml ­­> <one­to­many field="orders" target­entity="SyliusComponentOrderModelOrderInterface">     <!­­ ... ­­> </one­to­many>
  37. 37. VOUS ÊTES ÉQUIPÉS POUR CONSTRUIRE VOS BUNDLES!
  38. 38. GO TO THE FUTURE! Refactoring de la SyliusResourceExtension Rendre le système plus flexible Uniformiser la configuration De nouveaux FormType ? Un datagrid ?
  39. 39. VENEZ CONTRIBUER! Merci à tous les contributeurs! N'hésister pas à nous soumettre vos PRs... ... surtout si vous aimez écrire de la doc :D !
  40. 40. MERCI! QUESTIONS ? Arnaud Langlade Twiter @_aRn0D Sylius : www.sylius.org

×