Développer avec le sylius resourcebundle

Post on 17-Jul-2015

1.025 views 3 download

Transcript of Développer avec le sylius resourcebundle

DÉVELOPPER AVEC LE SYLIUSRESOURCEBUNDLE

QUI SUIS-JE ?

Arnaud Langlade (@_aRn0D)

Développeur Symfony chez Clever Age

www.clever-age.com / @CleverAge

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

SYLIUSRESOURCEBUNDLELe 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 !

GESTION DES RESSOURCES? Z'AVEZ DIS CRUD?

CRUD = Create, Read, Update, Delete

UN CRUD, COMMENT ÇA FONCTIONNE?

POURQUOI LA CRÉATION DE CE BUNDLE?Le back office de Sylius est composé d'énormement de CRUDsEviter la duplication de code parce que c'est mal!Développer plus vite en automatisant des tâches

UNE SOLUTION? RESOURCECONTROLLER?Création du ResourceController :

C'est un contrôleur génériquePlus de code, il est intialisé via une configurationIl étend the FOSRestController

Utilisation du EventDispatcher (répartiteur d'évènement) :

Il permet de personnaliser les actionsSolution plus flexible

QUELS SONT ORM/ODM SUPPORTÉS ?Doctrine ORM : Sylius l'utilise par défautDoctrine Phpcr-ODM : Sylius intègre le CMF pour gérer des contenusDoctrine Mongodb-ODMBientôt sûrement plus !

ATTENTION!Ce n'est pas un admin generator!

Il faut créer vos formulaires, vos templates et le routing (pour le moment!)

CRÉER SON CRUD EN QUELQUES MINUTES !Par exemple, créons un CRUD pour gérer des clients (customer).

CONFIGURONS NOS RESSOURCES sylius_resource: resources: myapp.customer: driver: doctrine/orm classes: model: AppBundle\Entity\Customer repository: Sylius\Bundle\ResourceBundle\Doctrine\ORM\EntityRepository templates: WebBundle:Backend/Customer myapp.address: # ...

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 Sylius\Bundle\ResourceBundle\Controller\ResourceControllermyapp.repository.customer container Sylius\Bundle\ResourceBundle\Doctrine\ORM\EntityRepository

$ php app/console container:debug ­­parameters

sylius.config.classes "myapp.customer": ...

CONFIGURONS NOS RESSOURCES sylius_resource: resources: myapp.customer: driver: doctrine/orm classes: model: AppBundle\Entity\Customer controller: AppBundle\Controller\CustomerController repository: AppBundle\Repository\CustomerRepository templates: WebBundle:Backend/Customer

CRÉONS NOTRE MODÈLE # AppBundle\Entity\Customer.php;

/** * @ORM\Entity * @ORM\Table(name="customer") */class Customer /** * @ORM\Column(type="string", length=100) */ protected $firstName;

/** * @ORM\Column(type="string", length=100) */ protected $lastName;

CRÉONS NOTRE FORMULAIRE // AppBundle\Form\Type\CustomerType.php;

class CustomerType extends AbstractResourceType public function getName() return 'myapp_customer';

Le formulaire doit être défini en tant que servicePattern du nom de formulaire : nom-application_resourceAbstractResourceType permet de configurer le data_class et le validation_group

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 %

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_actionNe pas oublier que les contrôleurs sont définis en tant que serviceActions : index, show, create, update, delete, moveUp, moveDown, revert ou updateState

ET PAF ! ÇA FAIT DES CHOCAPICS !Notre CRUD est prêt à l'emploi !! On crée notre API ?

EXPOSER SES CLIENTS VIA API RESTConfigurer 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.1Host: myshop.comAccept: application/json

CONFIGURER LE SÉRIALISEUR # Resources/config/serializer/Entity.Customer.yml

AppBundle\Entity\Customer: 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 OKContent­Type: application/json;

"id": 2, "firstName": "Arnaud", "lastName": "Langlade", "_links": "self": "href": "/address/2"

C'EST TOUT ?Lionframe (Rapid RESTful API Development)Génération automatique des formulaires et du routing

PLUS DE FLEXIBILITÉ ?Le comportement des méthodes du ResourceController est configurable

CONFIGURER LES METHODES DU RESOURCECONTROLLERAjouter 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

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

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

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]

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

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()"]

VOUS VOULEZ MUTUALISER VOTRE CODE ?

SYLIUS FONCTIONNE AVEC DES BUNDLESIls doivent être facilement étendablesIls peuvent supporter plusieurs "drivers" (ORM/ODM)Ils ne doivent être couplés les uns aux autres

LA CONFIGURATION SÉMANTIQUE customer_bundle: driver: doctrine/orm templates: customer: CustomerBundle:Backend/Customer address: ... validation_groups: customer: [myapp] address: ... classes: customer: model: Myapp\CustomerBundle\Model\Customer controller: Sylius\Bundle\ResourceBundle\Controller\ResourceController repository: Sylius\Bundle\ResourceBundle\Doctrine\ORM\EntityRepository form: default: Myapp\CustomerBundle\Form\Type\CustomerType choice: Myapp\CustomerBundle\Form\Type\CustomerChoiceType address: ...

MAIS QUE SE PASSE T'IL? $ php app/console container:debug | grep customer

myapp.controller.customer container Sylius\Bundle\ResourceBundle\Controller\ResourceControllermyapp.manager.customer n/a alias for doctrine.orm.default_entity_managermyapp.repository.customer container Sylius\Bundle\ResourceBundle\Doctrine\ORMEntityRepositorymyapp.form.type.customer container myapp\CustomerBundle\Form\Type\CustomerType

$ php app/console container:debug ­­parameters | grep customer

myapp.model.customer.class myapp\CustomerBundle\Model\Customermyapp.model.customer.class myapp\CustomerBundle\Model\Customermyapp.controller.customer.class Sylius\Bundle\ResourceBundle\Controller\ResourceControllermyapp.repository.customer.class Sylius\Bundle\ResourceBundle\Doctrine\ORMEntityRepositorymyapp.form.type.customer.class myapp\CustomerBundle\Form\Type\CustomerTypemyapp.validation_group.customer ["myapp"]myapp_customer.driver doctrine/orm

ETENDRE FACILEMENT VOTRE BUNDLEUtiliser l'injecteur de dépendences (Dependency Injector)Déclarer votre classe en tant mapped-superclass (évènement loadClassMetadata)

GÉRER PLUSIEURS DRIVERSCréer votre "Doctrine Mapping Driver"Fournir plusieurs implementations Doctrine pour un modèleVos documents et entités sont dans le même namespace

LIMITER LE COUPLAGE DE VOS BUNDLESUtiliser le Resolve Target Entity ListenerDéfinir des relations entre différentes entités sans les écrire en durIl 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="Sylius\Component\Order\Model\OrderInterface"> <!­­ ... ­­></one­to­many>

VOUS ÊTES ÉQUIPÉS POUR CONSTRUIRE VOS BUNDLES!

GO TO THE FUTURE!Refactoring de la SyliusResourceExtension

Rendre le système plus flexibleUniformiser la configuration

De nouveaux FormType ?Un datagrid ?

VENEZ CONTRIBUER!Merci à tous les contributeurs!N'hésister pas à nous soumettre vos PRs...... surtout si vous aimez écrire de la doc :D !

MERCI! QUESTIONS ?

Arnaud Langlade

Twiter @_aRn0D

Sylius : www.sylius.org