meet elcodi, the flexible e-commerce components built on symfony2

60
Programming made fun ELCODI

Upload: aldo-chiecchia

Post on 12-Jul-2015

824 views

Category:

Software


1 download

TRANSCRIPT

Page 1: Meet Elcodi, the flexible e-commerce components built on Symfony2

Programming made fun

ELCODI

Page 2: Meet Elcodi, the flexible e-commerce components built on Symfony2

github.com/mmoreram

github.com/alch

github.com/elcodi-bot

@zimage

@elcodi_dev

@mmoreramMarc Morera

Aldo Chiecchia

Elcodi Bot

Page 3: Meet Elcodi, the flexible e-commerce components built on Symfony2

it began as an internal project@befactory

Page 4: Meet Elcodi, the flexible e-commerce components built on Symfony2

LET’s TALK ABOUT…

Hello World!

Simple doctrine mapping

The Cart system

Annotations

Page 5: Meet Elcodi, the flexible e-commerce components built on Symfony2

did you just say Annotations?

Page 6: Meet Elcodi, the flexible e-commerce components built on Symfony2

DON’T PANIC

Page 7: Meet Elcodi, the flexible e-commerce components built on Symfony2

1.HELLO WORLDWhat is my purpose in life?

Page 8: Meet Elcodi, the flexible e-commerce components built on Symfony2

SYMFONY2 ECOMMERCE APPS

S.O.L.I.D. Reusable

Testable Community

Page 9: Meet Elcodi, the flexible e-commerce components built on Symfony2

philosophy

Elcodi was born to be a Symfony project

Symfony components Symfony Framework

Page 10: Meet Elcodi, the flexible e-commerce components built on Symfony2

we love all of symfony…so we are putting our efforts in both

Page 11: Meet Elcodi, the flexible e-commerce components built on Symfony2

coupled to the framework?OMFG!

Why not get the best of both worlds?

Symfony components for advanced devs

Symfony framework for the pragmatic devs

Everybody’s happy

Page 12: Meet Elcodi, the flexible e-commerce components built on Symfony2

Core stuff, only symfony components

Page 13: Meet Elcodi, the flexible e-commerce components built on Symfony2

Web app, frontend

Page 14: Meet Elcodi, the flexible e-commerce components built on Symfony2

Web app, backoffice

Page 15: Meet Elcodi, the flexible e-commerce components built on Symfony2

The playground!

Page 16: Meet Elcodi, the flexible e-commerce components built on Symfony2
Page 17: Meet Elcodi, the flexible e-commerce components built on Symfony2

with symfony-standard

"require": { "elcodi/elcodi": "~0.4", "elcodi/bamboo-fixtures": “~0.1”, “doctrine/doctrine-fixtures-bundle": “v2.2.0"}

composer.json

Page 18: Meet Elcodi, the flexible e-commerce components built on Symfony2

new Doctrine\Bundle\DoctrineCacheBundle\DoctrineCacheBundle(),new Doctrine\Bundle\FixturesBundle\DoctrineFixturesBundle(),new Knp\Bundle\GaufretteBundle\KnpGaufretteBundle(),new Elcodi\Bundle\CoreBundle\ElcodiCoreBundle(),new Elcodi\Bundle\CurrencyBundle\ElcodiCurrencyBundle(),new Elcodi\Bundle\LanguageBundle\ElcodiLanguageBundle(),new Elcodi\Bundle\AttributeBundle\ElcodiAttributeBundle(),new Elcodi\Bundle\ProductBundle\ElcodiProductBundle(),new Elcodi\Bundle\MediaBundle\ElcodiMediaBundle(),

with symfony-standardAppKernel.php

Page 19: Meet Elcodi, the flexible e-commerce components built on Symfony2

doctrine_cache: providers: elcodi: type: arrayknp_gaufrette: adapters: images_storage_adapter: local: directory: %kernel.root_dir%/../web/images create: true filesystems: local: adapter: images_storage_adapter

with symfony-standardconfig.yml

Page 20: Meet Elcodi, the flexible e-commerce components built on Symfony2

$  php  app/console  do:fi:lo  \  -­‐-­‐fixtures=vendor/elcodi/bamboo-­‐fixtures/\  

src/Fixtures/DataFixtures/ORM/Product

Page 21: Meet Elcodi, the flexible e-commerce components built on Symfony2

namespace Elcodi\TrainingBundle\Controller;use Symfony\Bundle\FrameworkBundle\Controller\Controller;use Symfony\Component\HttpFoundation\Response;class HelloController extends Controller{ public function helloAction() { $productRepository = $this->container ->get('elcodi.repository.product'); $storedProduct = $productRepository->find(1); $productObjectManager = $this->container ->get('elcodi.object_manager.product'); $newProduct = $this->container ->get('elcodi.factory.product')->create() ->setName('SymfonyCon ticket')->setSlug(''); $productObjectManager->persist($newProduct); $productObjectManager->flush(); return new Response($newProduct->getId()); }}

Page 22: Meet Elcodi, the flexible e-commerce components built on Symfony2

public function priceAction(){ $productObjectManager = $this->container ->get('elcodi.object_manager.product'); $productRepository = $this->container ->get('elcodi.repository.product'); $storedProduct = $productRepository->find(1); // Currency from a session based wrapper $currency = $this->container ->get('elcodi.currency_wrapper')->getCurrency(); // Money Value Object $newPrice = Money::create(1000, $currency); $storedProduct->setPrice($newPrice); $productObjectManager->flush(); return new Response("Changed price!"); }

Page 23: Meet Elcodi, the flexible e-commerce components built on Symfony2

public function changeMediaAction(){ $productRepository = $this->container ->get('elcodi.repository.product'); $storedProduct = $productRepository->find(1); // This can also be an instance of UploadedFile $file = new File('/tmp/my_image.jpg'); // Factors an Image and sets media meta-data $image = $this->container ->get('elcodi.image_manager') ->createImage($file); $imageObjectManager = $this->container ->get('elcodi.object_manager.image'); $imageObjectManager->persist($image); $imageObjectManager->flush($image); // Stores the image using the underlying // Gaufrette adapter $this->container ->get('elcodi.file_manager') ->uploadFile($image, $image->getContent(), false); $storedProduct->addImage($image); $storedProduct->setPrincipalImage($image); $this->container ->get('elcodi.object_manager.product') ->flush(); return new Response("Changed image!");}

Page 24: Meet Elcodi, the flexible e-commerce components built on Symfony2

extensibility?

Page 25: Meet Elcodi, the flexible e-commerce components built on Symfony2

2.simple Doctrine MappingMaking it… easy :)

Page 26: Meet Elcodi, the flexible e-commerce components built on Symfony2

premises

Assume that a lot of things will be overridden

Even an entity (Class, mapping, manager)

So… auto-mapping, you’re not welcomed!

Say hello to SimpleDoctrineMapping

Page 27: Meet Elcodi, the flexible e-commerce components built on Symfony2
Page 28: Meet Elcodi, the flexible e-commerce components built on Symfony2

auto-mapping = falseWooooo…

Page 29: Meet Elcodi, the flexible e-commerce components built on Symfony2

Why?

We want the responsibility of mapping our model, even for foreign required bundles (like FOS)

Each entity must be defined by a class, a mapping file and the manager assigned

Anyone should be able to modify this information in a very simple way

Page 30: Meet Elcodi, the flexible e-commerce components built on Symfony2

Compiler Pass

Using a compiler pass we add every single Entity configuration, even the Abstracts.

The CompilerPass must extend the foreign entities

Only one method available with 4 required parameters.

Bundle aliasing by short reference : @MyBundle

Page 31: Meet Elcodi, the flexible e-commerce components built on Symfony2

use Mmoreram\SimpleDoctrineMapping\CompilerPass\Abstracts\AbstractMappingCompilerPass;use Symfony\Component\DependencyInjection\ContainerBuilder;/** * Class MappingCompilerPass */class MappingCompilerPass extends AbstractMappingCompilerPass{ /** * You can modify the container here before it is dumped to PHP code. * * @param ContainerBuilder $container * * @api */ public function process(ContainerBuilder $container) { $this ->addEntityMapping( $container, 'default', 'Elcodi\Component\Product\Entity\Product', '@ElcodiProductBundle/Resources/config/doctrine/product.orm.yml', true ) ->addEntityMapping( $container, 'default', 'Elcodi\Component\Product\Entity\Category', '@ElcodiProductBundle/Resources/config/doctrine/category.orm.xml', true ); }}

Page 32: Meet Elcodi, the flexible e-commerce components built on Symfony2

It is not overridable!

Page 33: Meet Elcodi, the flexible e-commerce components built on Symfony2

Let’s think about a way of overriding Symfony Bundle values

Oh, yes! Configuration + Parameters! Let’s do that!

WHAT IF We could override anything?

Page 34: Meet Elcodi, the flexible e-commerce components built on Symfony2

use Mmoreram\SimpleDoctrineMapping\CompilerPass\Abstracts\AbstractMappingCompilerPass;use Symfony\Component\DependencyInjection\ContainerBuilder;/** * Class MappingCompilerPass */class MappingCompilerPass extends AbstractMappingCompilerPass{ /** * You can modify the container here before it is dumped to PHP code. * * @param ContainerBuilder $container * * @api */ public function process(ContainerBuilder $container) { $this ->addEntityMapping( $container, 'elcodi.core.product.entity.product.manager', 'elcodi.core.product.entity.product.class', 'elcodi.core.product.entity.product.mapping_file', 'elcodi.core.product.entity.product.enabled' ) ->addEntityMapping( $container, 'elcodi.core.product.entity.category.manager', 'elcodi.core.product.entity.category.class', 'elcodi.core.product.entity.category.mapping_file', 'elcodi.core.product.entity.category.enabled' ); }}

Page 35: Meet Elcodi, the flexible e-commerce components built on Symfony2

Propose a mapping of a Bundle’s entities

Change the namespace of an entity

Change the specific mapping file (xml or yml)

Change the associated manager class

And now you can

And even… disable it!

Page 36: Meet Elcodi, the flexible e-commerce components built on Symfony2

3.the cart systemEvents FTW!

Page 37: Meet Elcodi, the flexible e-commerce components built on Symfony2

A Cart represents the transient state of a purchase before it is committed.

An Order can be seen as a persisted snapshot of a Cart

Transitions raise events

rationale

Page 38: Meet Elcodi, the flexible e-commerce components built on Symfony2

new Elcodi\Bundle\CartBundle\ElcodiCartBundle(),new Elcodi\Bundle\UserBundle\ElcodiUserBundle(),new Elcodi\Bundle\GeoBundle\ElcodiGeoBundle()

more symfony-standardAppKernel.php

Page 39: Meet Elcodi, the flexible e-commerce components built on Symfony2

$  php  app/console  do:sc:up  -­‐-­‐force

lots of new tables…

Page 40: Meet Elcodi, the flexible e-commerce components built on Symfony2

$  php  app/console  do:fi:lo  \  -­‐-­‐fixtures=vendor/elcodi/bamboo-­‐fixtures/\  src/Fixtures/DataFixtures/ORM/Customer  \  

-­‐-­‐append

Page 41: Meet Elcodi, the flexible e-commerce components built on Symfony2

public function addProductAction(){ $productRepository = $this->container ->get('elcodi.repository.product'); $storedProduct = $productRepository->find(1); $cart = $this->container ->get('elcodi.cart_wrapper')->loadCart(); $this->container ->get('elcodi.cart_manager') ->addProduct($cart, $storedProduct, 1); return new Response('Added to cart!');}

Page 42: Meet Elcodi, the flexible e-commerce components built on Symfony2

cartwrapper

Envelopes a Cart object and provides the logic to retrieve it

If the Customer has pending Carts, the last Cart form this collection is returned

If there is a Cart in session, it is associated with the Customer and is returned

When there is no Cart in session, a new one is factored

Overridable!

Page 43: Meet Elcodi, the flexible e-commerce components built on Symfony2

A new CartLine is factored with the information of the product

“Cart added” events are raised

“Cart loaded” events are raised

The latter is used by specific event listeners to recalculate prices and to perform a flush()

when i add a product

Page 44: Meet Elcodi, the flexible e-commerce components built on Symfony2

class ElcodiCartEvents{ const CART_PRELOAD = 'cart.preload'; const CART_ONLOAD = 'cart.onload'; const CART_ONEMPTY = 'cart.onempty'; const CART_INCONSISTENT = 'cart.inconsistent'; const CARTLINE_ONADD = 'cart_line.onadd'; const CARTLINE_ONEDIT = 'cart_line.onedit'; const CARTLINE_ONREMOVE = 'cart_line.onremove'; const ORDER_PRECREATED = 'order.precreated'; const ORDER_ONCREATED = 'order.oncreated'; const ORDERLINE_ONCREATED = 'order_line.oncreated'; const ORDER_STATE_PRECHANGE = 'order_state.prechange'; const ORDER_STATE_ONCHANGE = 'order_state.onchange'; const ORDERLINE_STATE_PRECHANGE = 'order_line_state.prechange'; const ORDERLINE_STATE_ONCHANGE = 'order_line_state.onchange'; }

Page 45: Meet Elcodi, the flexible e-commerce components built on Symfony2

public function createOrderAction(){ // CartWrapper will look for a customer in order // to "resolve" current cart $customer = $this->container ->get('elcodi.customer_wrapper')->loadCustomer(); $cart = $this->container ->get('elcodi.cart_wrapper')->loadCart(); $order = $this->container ->get('elcodi.cart_order_transformer') ->createOrderFromCart($cart); return new Response( sprintf('Order %d created!', $order->getId()) );}

how do I create an order?

Page 46: Meet Elcodi, the flexible e-commerce components built on Symfony2

more productivity tools?

Page 47: Meet Elcodi, the flexible e-commerce components built on Symfony2

4.AnnotationsTelling stories

Page 48: Meet Elcodi, the flexible e-commerce components built on Symfony2

Why?Always looking for a balance among smartness, efficiency and resolution.

Annotations are part of PHP. Why not?

Elcodi Core is a 3rd party project. Controllers as a services with no annotations

Bamboo is a project example on top of Elcodi, so Annotations would be nice

Symfony Best Practices. Thanks!

PDD principle

Page 49: Meet Elcodi, the flexible e-commerce components built on Symfony2

Why??Oh man! You’re coupling the controllers with the framework.

Ok. How many of you have ever change from one FW to another one with same controllers.

If we use abstract controllers, some logic data is hidden in another file.

Annotations tell us a story in a simple and clean way.

Page 50: Meet Elcodi, the flexible e-commerce components built on Symfony2

Controller Extra Bundle

Set of symfony framework controller annotations

Why ControllerExtraBundle instead of FrameworkExtraBundle?

Controller specific annotations and a platform for creating new ones.

We have the control of the repository. Important, right?

Documented with cool examples.

Page 51: Meet Elcodi, the flexible e-commerce components built on Symfony2

installing

"require": { "mmoreram/controller-extra-bundle": "~1.0", }

composer.json

Page 52: Meet Elcodi, the flexible e-commerce components built on Symfony2

@entity

Like FrameworkExtraBundle, but changes the way a class is defined

By namespace

By DIC parameter (yes, container dependency)

By factory with static or non-static method

By factory as a service with static or non-static method

Page 53: Meet Elcodi, the flexible e-commerce components built on Symfony2

use Mmoreram\ControllerExtraBundle\Annotation\Entity as EntityAnnotation;use Symfony\Component\HttpKernel\Tests\Controller;class AnnotatedController extends Controller{ /** * Simple controller method * * This Controller matches pattern /user/edit/{id}/{username} * * @EntityAnnotation( * class = { * "factory" = my.bundle.factory.myentity_factory, * "method" = "create", * "static" = true, * }, * name = "user", * mapping = { * "id": "~id~", * "username": "~username~" * } * ) */ public function indexAction(User $user) { }}

Page 54: Meet Elcodi, the flexible e-commerce components built on Symfony2

@form

Creates a FormType, a Form or FormView (depending on the parameter type-hinting)

Can be defined with the namespace or with the alias

Can handle the request with a previously defined entity (With @entity or @paramConverter)

Can validate the form and inject the result as an action parameter

Page 55: Meet Elcodi, the flexible e-commerce components built on Symfony2

use Mmoreram\ControllerExtraBundle\Annotation\Form as FormAnnotation;use Symfony\Component\HttpKernel\Tests\Controller;class AnnotatedController extends Controller{ /** * Simple controller method * * @Route( * path = "/user/{id}", * name = "view_user" * ) * @ParamConverter("user", class="MmoreramCustomBundle:User") * @FormAnnotation( * class = "user_type", * entity = "user" * handleRequest = true, * name = "userForm", * validate = "isValid", * ) */ public function indexAction(User $user, Form $userForm, $isValid) { }

Page 56: Meet Elcodi, the flexible e-commerce components built on Symfony2

@paginator

Given an URL, injects a Paginator

In current implementation, some extra info can be also injected, like total available pages.

Pagerfanta compatible (not used in Elcodi)

Page 57: Meet Elcodi, the flexible e-commerce components built on Symfony2

use Mmoreram\ControllerExtraBundle\Annotation\Paginator;use Symfony\Component\HttpKernel\Tests\Controller;class AnnotatedController extends Controller{ /** * Simple controller method * * @Paginator( * class = "MmoreramCustomBundle:User", * wheres = { * {"x", "enabled", "=", true}, * {"x", "age", ">", “~age~”}, * {"x", "name", "LIKE", "Efervescencio"}, * } * ) */ public function indexAction(Paginator $paginator) { } }

Page 58: Meet Elcodi, the flexible e-commerce components built on Symfony2

summing it up

Elcodi is a set of tools to speed up development

It helps you scale out your ideas

Pragmatic driven

Baked with♥

Page 59: Meet Elcodi, the flexible e-commerce components built on Symfony2

questions?

Page 60: Meet Elcodi, the flexible e-commerce components built on Symfony2

ten-queue!See you in Github!