immersion in the sylius
DESCRIPTION
Sylius is an open source e-commerce solution for PHP, based on the great Symfony2 framework. My first talk ever, at Symfony CAMP UA 2013.TRANSCRIPT
Immersion in the SyliusPaweł Jędrzejewski
Who am I?Paweł Jędrzejewski
Huge beliver in Open Source
Symfony & BDD evangelist
Creator of Sylius
Working for Opensoft on
ŁÓDŹ, POLAND
?
THE PROBLEMPHP has changed
This change created the market for a new e-commerce solution among developers
With the flexibility of modern frameworks and the new way of collaboration we can build something interesting for the business
Sylius reflects this evolution
WHAT IS SYLIUSA short history
Open sourced in 2011 as a set of bundles
Main application in development for ~9 months
Already used in production by developers and companies
FLEXIBILITY QUALITY PEOPLE
FLEXIBILITY QUALITY PEOPLE
QUALITYBehat and phpspec, perfect combination
Most of new features start with an RFC issue
Discussion about the idea and eventual implementation
Behat features
Implementation
FLEXIBILITY QUALITY PEOPLE
BUNDLES vs. MAIN APPLICATION
Set of 19 decoupled and independent bundles
Can be used to create a custom platform
Integrate e-commerce into existing application
Standard webshop experience
Highly customizable
Easy to understand for every Symfony2 developer
Sylius BundlesWhat they can do for you?
EVERY SINGLE SYLIUS FEATURE AVAILABLE FOR YOUR PROJECt
Simpler CRUD for symfonySyliusResourceBundle
Removing tons of duplicated code in controllers for basic CRUD actions.
Removing the manager and manipulator classes, relying on Doctrine instead.
Removing the "frontend" and "backend" controllers.
Supporting different persistence layers.
Make the controllers format agnostic. (API)
ADD YOUR RESOURCE
sylius_resource:
resources:
acme.user:
driver: doctrine/orm
templates: AcmeShopBundle:User
classes:
model: Acme\ShopBundle\Entity\User
repository: Acme\ShopBundle\Entity\UserRepository
controller: Acme\ShopBundle\Controller\UserController
acme.controller.user
showAction
indexAction
createAction
updateAction
deleteAction
acme_user_show:
pattern: /users/{id}
methods: [GET]
defaults:
_controller: acme.controller.user:showAction
acme_profile_show:
pattern: /profile/{username}
methods: [GET]
defaults:
_controller: acme.controller.user:showAction
_sylius:
template: AcmeShopBundle:Profile:show.html.twig
criteria: { username: $username, enabled: true }
acme_profile_show:
pattern: /profile/{username}
methods: [GET]
defaults:
_controller: acme.controller.user:showAction
_sylius:
template: AcmeShopBundle:Profile:show.html.twig
method: findOneForProfilePage
arguments: [$username]
acme_user_disabled_index:
pattern: /users/disabled
methods: [GET]
defaults:
_controller: acme.controller.user:indexAction
_sylius:
template: AcmeShopBundle:User:disabled.html.twig
criteria: { enabled: false }
acme_user_recently_registered:
pattern: /users/recently-registered
methods: [GET]
defaults:
_controller: acme.controller.user:indexAction
_sylius:
template: AcmeShopBundle:User:recentlyRegistered.html.twig
criteria: { enabled: true }
sorting: { createdAt: desc }
paginate: false
limit: 5
acme_user_update_addresses:
pattern: /users/{id}/update-addresses
methods: [GET]
defaults:
_controller: acme.controller.user:updateAction
_sylius:
template: AcmeShopBundle:User:updateAddresses.html.twig
form: acme_user_addresses
redirect:
route: acme_user_index
Docs.sylius.org
CONFIGURATION
sylius_taxation:
driver: doctrine/orm
classes:
tax_rate:
model: Acme\ShopBundle\Entity\TaxRate
controller: Acme\ShopBundle\Controller\TaxRateController
repository: Acme\ShopBundle\Entity\TaxRateRepository
form: Acme\ShopBundle\Form\Type\TaxRateType
validation_groups:
tax_rate: [sylius, acme]
USING CUSTOM MODELS and FORMS
Every model class can be overridden
All repositories, managers and forms are updated automatically
Form class can be customized
OVERRIDING CONTROLLERS
All models use default or slightly customized CRUD controller
Add your own methods
YOUR OWN REPOSITORY
Sylius repositories extend native Doctrine implementations
Override the repositories through configuration
Repositories are services
CHANGE THE RULES, VALIDATION
All Sylius models ship with their own validation mapping under group „sylius”
You can easily override it with your own rules
Consistent translation messages
DOCTRINE RTEL, DYNAMIC RELATIONS
We're using interfaces instead of implementation to define the relations
When you override the model class, all relations get updated automatically
Defaults are turned into entities if you don't provide your own class
WE LOVE EVENTS, YOU SHOULD TOO
The default controller triggers multiple useful events during CRUD actions
sylius.product.pre_createsylius.product.post_create
PRODUCTSSyliusProductBundle
ORDERS AND CARTSyliusOrderBundle + SyliusCartBundle
Generic Order model with support of Adjustments
Cart bundle provides actions and services for customer to interact with the Order entity
The order/cart items can be easily customized to handle different options
COUNTRIES, ZONES AND ADDRESSESSyliusAddressingBundle
Provides a very basic Address model
Countries and their Provinces management
Zones system with a ZoneMatcher service
Useful for taxation and shipping zones
$billingAddress = $order->getBillingAddress();
$zone = $this->zoneMatcher->match($billingAddress);
$address = $location->getAddress();
$zones = $this->zoneMatcher->matchAll($address);
TAKE CARE OF YOUR INVENTORYSyliusInventoryBundle
Built around 1 interface you need to implement
Tracks every single inventory unit
Based on events
Items available on demand
Backorders
HATE IT OR LOVE IT, TAXATIONSyliusTaxationBundle
TaxableInterface = heart of the bundle
Multiple tax categories and rates support
Customizable tax calculators
Tax included in price
MERCHANDISE NEEDS TO BE SHIPPEDSyliusShippingBundle
Integrate through one interface
Manage Shipments and Shipping Methods
Custom shipping rules
Flexible calculators system
class PerItemRateCalculator extends Calculator
{
public function calculate(ShippingSubjectInterface $subject, array $configuration)
{
return $configuration['amount'] * $subject->getShippingItemCount();
}
public function getConfigurationFormType()
{
return 'sylius_shipping_calculator_per_item_rate_configuration';
}
public function setConfiguration(OptionsResolverInterface $resolver)
{
$resolver
->setRequired(array( 'amount'))
->setAllowedTypes(array('amount' => array('numeric')))
;
}
}
CATEGORIZE ALL THIS STUFF, NOWSyliusTaxonomiesBundle
Classify any Model using different Taxonomies
Flexible forms
Based on DoctrineExtensions
JUST FEW STEPS MORESyliusFlowBundle
Useful for anything which takes more than 1
action to complete
Checkouts, installation wizards, complex actions
Used by OroCRM and Akeneo PIM for installers
PROCESS SCENARIO<?php
class CheckoutProcessScenario implements ProcessScenarioInterface
{
public function build(ProcessBuilderInterface $builder)
{
$builder
->add('security', 'sylius_checkout_security')
->add('addressing', 'sylius_checkout_addressing')
->add('shipping', 'sylius_checkout_shipping')
->add('payment', 'sylius_checkout_payment')
->add('finalize', 'sylius_checkout_finalize')
->add('purchase', 'sylius_checkout_purchase')
;
}
}
PAYUM INTEGRATIONSyliusPayumBundle NEW!
Integrates Payum library into Sylius checkout
Replaceable by other bundles in future
PayPal Express Checkout and Stripe support
Omnipay usage through a bridge
Make your app configurable, EASILYSyliusSettingsBundle
You can define settings schema and the form
User edits the settings through UI
You get the access via services and Twig
Settings schema
class GeneralSettingsSchema implements SchemaInterface
{
public function buildSettings(SettingsBuilderInterface $builder)
{
$builder
->setDefaults(array(
'meta_keywords' => 'symfony, sylius, ecommerce, webshop, shopping cart',
'meta_description' => 'Sylius is modern ecommerce solution for PHP.',
))
->setAllowedTypes(array(
'meta_keywords' => array('string'),
'meta_description' => array('string'),
))
;
}
EDITING VIA FORM
public function buildForm(FormBuilderInterface $builder)
{
$builder
->add('meta_keywords', 'text', array(
'constraints' => array(new NotBlank())
))
->add('meta_description', 'textarea', array(
'constraints' => array(new NotBlank())
))
;
}
PROMOTIONS ARE NICESyliusPromotionsBundle
Can be integrated with any Model
Very flexible Actions and Rules system
Support for promotion coupons
PROMOTION STRUCTURE
SUPER AWESOME PROMOTION
ACTION
ACTION
ACTION
RULE
RULE
CUSTOM RULES
interface RuleCheckerInterface
{
/**
* @param PromotionSubjectInterface $subject
* @param array $configuration
*
* @return Boolean
*/
public function isEligible(PromotionSubjectInterface $subject, array $configuration);
/**
* @return string
*/
public function getConfigurationFormType();
}
YOUR OWN ACTIONS
class AddPackageAction implements PromotionActionInterface
{
public function execute(PromotionSubjectInterface $subject, array $configuration)
{
$package = $this->findPackage($configuration);
$item = $this->cartItemRepository->createNew();
$item->setQuantity(1);
$item->setUnitPrice(isset($configuration['price']) ? $configuration['price'] : $package->getGrossPrice());
$item->setPackage($package);
$subject->addItem($item);
}
public function getConfigurationFormType()
{
return 'xyz_promotion_action_add_package_configuration';
}
}
Sylius ApplicationHow to bootstrap Symfony2 shop in minutes? (soon)
Bringing smile back to developer's faces
INSTALLATION
$ composer create-project sylius/sylius -s dev path/to/install
$ cd path/to/install
$ app/console sylius:install
$ composer create-project sylius/sylius-standard -s dev path/to/install
$ cd path/to/install
$ app/console sylius:install
ONE CORE TO RULE THEM ALLSyliusCoreBundle
Integrates all the bundles together
Standard webshop application
Contains all the models and services
THE WEB INTERFACESyliusWebBundle
Provides the default web interface for Sylius
Contains all the templates and menu builders
Splitted into Frontend & Backend parts
THE BACKEND
public function forwardAction(ProcessContextInterface $context)
{
$request = $this->getRequest();
$order = $this->getCurrentCart();
$this->dispatchCheckoutEvent(SyliusCheckoutEvents::ADDRESSING_INITIALIZE, $order);
$form = $this->createCheckoutAddressingForm($order);
if ($request->isMethod('POST') && $form->bind($request)->isValid()) {
$this->dispatchCheckoutEvent(SyliusCheckoutEvents::ADDRESSING_PRE_COMPLETE, $order);
$this->getManager()->persist($order);
$this->getManager()->flush();
$this->dispatchCheckoutEvent(SyliusCheckoutEvents::ADDRESSING_COMPLETE, $order);
return $this->complete();
}
return $this->renderStep($context, $order, $form);
}
TO DO
Documentation, documentation, documentation
New default store look
Rework translations and integrate with CrowdIn
Polish the checkout process
Integrate BazingaHateoasBundle for API
Integrate Symfony CMF and Create.js
COMING SOON...Pull Requests
Customer groups
Subscriptions support
Product reviews
Symfony CMF integration (editable blocks and pages)
Facebook/Amazon and so on...