Sylius
Sylius
Sylius
Release
Contents
The Book
1.1 The Book . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
3
3
33
33
83
83
Cookbook
4.1 Cookbook . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
85
85
Integrations
5.1 Integrations . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
89
89
Migration Guide
6.1 The Migration Guide . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
91
91
Bundles
7.1 Symfony2 Ecommerce Bundles . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
93
93
Components
239
8.1 PHP E-Commerce Components . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 239
Contributing
331
9.1 Contributing . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 331
ii
Sylius, Release
Contents
Sylius, Release
Contents
CHAPTER 1
The Book
Sylius, Release
Sylius Platform
This book is about our full-stack e-commerce platform, which is a standard Symfony application providing the most
common webshop and a foundation for custom systems.
Leveraging Symfony2 Bundles
If you prefer to build your very custom system step by step and from scratch, you can integrate the standalone Symfony2 bundles. For the installation instructions, please refer to the appropriate bundle documentation.
E-Commerce Components for PHP
If you use a different framework than Symfony, you are welcome to use Sylius components, which will make it much
easier to implement a webshop with any PHP application and project. They provide you with default models, services
and logic for all aspects of e-commerce, completely separated and ready to use.
Final Thoughts
Depending on how you want to use Sylius, continue reading The Book, which covers the usage of the full stack
solution, browse the Bundles Reference or learn about The Components.
You can access the website in production mode via the /app.php file in your website root (web/) or just / path.
(on Apache)
Sylius, Release
Staging
Staging environment or staging should be your before-production environment. It is very similar to the production
env, except that it redirects e-mails to your configured address and uses test APIs (payment etc.) wherever possible.
To run Sylius console in staging environment, add the following parameters to every command call:
$ app/console --env=staging --no-debug cache:clear
You can access the website in staging mode via the /app_staging.php file in the web/ directory. (under your
website root)
Test
Test environment or test is used for automated testing. Most of the time you will not access it directly.
To run Sylius console in test environment, add the following parameters to every command call:
$ app/console --env=test cache:clear
Final Thoughts
You can read more about Symfony environments in this cookbook article.
1.1.3 Installation
The Sylius main application can serve as end-user app, as well as a foundation for your custom e-commerce application.
This article assumes youre familiar with Composer, a dependency manager for PHP. It also assumes you have Composer installed globally.
Note: If you downloaded the Composer phar archive, you should use php composer.phar where this guide uses
composer.
It can be installed using two different approaches, depending on your use case.
Install to Contribute
To install Sylius main application from our main repository and contribute, run the following command:
$ composer create-project -s dev sylius/sylius
This will create a new sylius project in sylius. When all the dependencies are installed, youll be asked to fill the
parameters.yml file via interactive script. Please follow the steps. After everything is in place, run the following
commands:
# Move to the newly created directory
$ cd sylius
$ php app/console sylius:install
The sylius:install command actually runs several other commands, which will ask you some questions and
check if everything is setup to run Sylius properly.
Sylius, Release
This package contains our main Sylius development repository, with all the components and bundles in the src/
folder.
For the contributing process questions, please refer to the Contributing Guide.
Bootstrap A New Sylius Project
To create a new project using Sylius Standard Edition, run this command:
$ composer create-project -s dev sylius/sylius-standard acme
This will create a new Symfony project in acme directory. When all the dependencies are installed, youll be asked
to fill the parameters.yml file via interactive script. Please follow the steps. After everything is in place, run the
following commands:
# Move to the newly created directory
$ cd acme
$ php app/console sylius:install
This package has the whole sylius/sylius package in vendors, so you can easily updated it and focus on your
custom development.
Accessing the Shop
In order to see the shop, access the web/app_dev.php file via your web browser.
Tip:
If you use PHP 5.4 or higher, you can also use the build-in webserver for Symfony.
app/console server:run command and then access http://localhost:8000.
For every resource you have three very important services available:
Manager
Sylius, Release
Repository
Controller
Let us take the product resource as an example.
By default, It is represented
Sylius\Component\Core\Model\Product class and implement proper ProductInterface.
by
Manager The manager service is just an alias to appropriate Doctrines ObjectManager and can be accessed via the
sylius.manager.product id. API is exactly the same and you are probably already familiar with it:
<?php
public function myAction()
{
$manager = $this->container->get('sylius.manager.product');
$manager->persist($product1);
$manager->remove($product2);
$manager->flush(); // Save changes in database.
}
Repository Repository is defined as a service for every resource and shares the API with standard Doctrine ObjectRepository. It contains two additional methods for creating a new object instance and a paginator provider.
The repository service is available via the sylius.repository.product id and can be used like all the repositories you
have seen before.
<?php
public function myAction()
{
$repository = $this->container->get('sylius.repository.product');
Every Sylius repository supports paginating resources. To create a Pagerfanta instance use the createPaginator
method.
<?php
public function myAction(Request $request)
{
$repository = $this->container->get('sylius.repository.product');
$products = $repository->createPaginator();
$products->setMaxPerPage(3);
$products->setCurrentPage($request->query->get('page', 1));
// Now you can return products to template and iterate over it to get products from current page.
}
Paginator can be created for a specific criteria and with desired sorting.
Sylius, Release
<?php
public function myAction(Request $request)
{
$repository = $this->container->get('sylius.repository.product');
$products = $repository->createPaginator(array('foo' => true), array('createdAt' => 'desc'));
$products->setMaxPerPage(3);
$products->setCurrentPage($request->query->get('page', 1));
}
To create a new object instance, you can simply call the createNew() method on the repository.
Now lets try something else than product, well create a new TaxRate model.
<?php
public function myAction()
{
$repository = $this->container->get('sylius.repository.tax_rate');
$taxRate = $repository->createNew();
}
Note: Creating resources via this factory method makes the code more testable, and allows you to change the model
class easily.
Controller This service is the most important for every resource and provides a format agnostic CRUD controller
with the following actions:
[GET] showAction() for getting a single resource
[GET] indexAction() for retrieving a collection of resources
[GET/POST] createAction() for creating new resource
[GET/PUT] updateAction() for updating an existing resource
[DELETE] deleteAction() for removing an existing resource
As you can see, these actions match the common operations in any REST API and yes, they are format agnostic. That
means, all Sylius controllers can serve HTML, JSON or XML, depending on what do you request.
Additionally, all these actions are very flexible and allow you to use different templates, forms, repository methods
per route. The bundle is very powerful and allows you to register your own resources as well. To give you some idea
of what is possible, here are some examples!
Displaying a resource with custom template and repository methods:
# routing.yml
app_product_show:
path: /products/{slug}
methods: [GET]
defaults:
_controller: sylius.controller.product:showAction
_sylius:
template: AppStoreBundle:Product:show.html.twig # Use a custom template.
repository:
method: findForStore # Use custom repository method.
arguments: [$slug] # Pass the slug from the url to the repository.
Sylius, Release
All other methods have the same level of flexibility and are documented in the [SyliusResourceBundle guide].
Core and Web Interface
Main application is constructed from two main bundles:
SyliusCoreBundle, which is the glue for all other bundles. It is the integration layer of Core component - the heart
of Sylius, providing the whole e-commerce framework. SyliusWebBundle, which contains the default web interface,
assets, templates and menu builders.
Third Party Libraries
Sylius uses a lot of libraries for various tasks:
[SymfonyCMF] for content management
[Gaufrette] for filesystem abstraction (store images locally, Amazon S3 or external server)
[Imagine] for images processing, generating thumbnails and cropping
[Snappy] for generating PDF files
[HWIOAuthBundle] for facebook/amazon/google logins
[Pagerfanta] for pagination
Final Thoughts
...
Learn more
...
Sylius, Release
States
...
Transitions
...
Callbacks
...
Configuration
...
Final Thoughts
...
Learn more
...
1.1.6 Channels
In the modern world of e-commerce your website is no longer the only point of sale for your goods. Sylius supports
multiple-channels and in this guide you will understand them from a technical point of view.
Channel model represents a single sales channel, which can be one of the following things:
Webstore
Mobile application
Cashier in your physical store
Or pretty much any other channel type you can imagine.
The default model has the following basic properties:
code An unique code identifying this channel
name The human readable name of the channel
description Short description
color: Color representation
url: The url pattern used to identify the channel
enabled: Is the channel currently enabled?
createdAt Date of creation
updateAt Timestamp of the most recent update
10
Sylius, Release
1.1.7 Products
Product model represents unique products in your Sylius store. Every product can have different variations or attributes and has following values:
name - The full name of the product
slug - Urlized version of the name
description - Description of the product
shortDescription - Simple description of the product for lists and banners
metaDescription - Description for search engines
metaKeywords - SEO keywords
createdAt - Date of creation
updateAt - Timestamp of the most recent update
Options
In many cases, you will have product with different variations. The simplest example would be a T-Shirt available in
different sizes and colors. In order to automatically generate appropriate variants, you need to define options.
Every option type is represented by ProductOption and references multiple ProductOptionValue entities.
Size
S
M
L
XL
XXL
Color
Red
11
Sylius, Release
Green
Blue
Variants
ProductVariant represents a unique combination of product options and can have its own pricing configuration,
inventory tracking etc.
You are also able to use product variations system without the options at all.
Master Variant
Each product has a master variant, which tracks the same information as any other variant. It exists to simplify the
internal Sylius logic. Whenever a product is created, a master variant for that product will be created too.
Attributes
Attributes allow you to define product specific values.
Prototypes
...
Images
...
Final Thoughts
...
Learn more
...
1.1.8 Addresses
Every address in Sylius is represented by Address model. Default structure has the following fields:
firstname
lastname
street
city
postcode
reference to Country
reference to Province (optional)
12
Sylius, Release
createdAt
updatedAt
Countries
Every country to which you will be shipping your goods lives as Country entity. Country consists of name and
isoName.
Provinces
Province is a smaller area inside of a Country. You can use it to manage provinces or states and assign it to an address
as well.
Attribute
id
name
country
createdAt
updatedAt
Description
Unique id of the province
Reference to a country
Date when province was created
Date of last update
Zones
This library allows you to define Zones, which represent a specific geographical area.
Zone Model
Description
Unique id of the zone
String type of zone
Zone members
Date when zone was created
Date of last update
13
Sylius, Release
Matching a Zone
Zones are not very useful by themselves, but they can be part of a complex taxation/shipping or any other system. A
service implementing the ZoneMatcherInterface is responsible for matching the Address to a specific Zone.
<?php
$zoneMatcher = $this->get('sylius.zone_matcher');
$zone = $zoneMatcher->match($user->getAddress());
Zone matcher can also return all matching zones. (not only the best one)
<?php
$zoneMatcher = $this->get('sylius.zone_matcher');
$zones = $zoneMatcher->matchAll($user->getAddress());
Internally, Sylius uses this service to define the shipping and billing zones of an Order, but you can use it for many
different things and it is totally up to you.
Final Thoughts
...
Learn more
...
1.1.9 Inventory
Sylius leverages a very simple approach to inventory management. The current stock of an item is stored on the
ProductVariant entity.
It is always accessible via simple API:
<?php
echo $productVariant->getOnHand(); // Prints current inventory.
Every variant also has an unique SKU and can be available on demand, if you do not want to have strict inventory
tracking.
<?php
$variant = $product->getMasterVariant();
$variant->setAvailableOnDemand(false);
if ($variant->isAvailableOnDemand()) {
// Order any amount you want!
}
InventoryUnit
Every item sold in the store is represented by InventoryUnit, which has many different states:
14
Sylius, Release
$inventoryUnits is now ArrayCollection with 6 instances of InventoryUnit, referencing the ProductVariant and
with state backordered.
InventoryOperator
Inventory operator is the service responsible for managing the stock amounts of every ProductVariant with following
methods:
increase(variant, quantity)
hold(variant, quantity)
release(variant, quantity)
decrease(InventoryUnit[])
Backorders
...
Inventory On Hold
Final Thoughts
...
Learn more
...
15
Sylius, Release
1.1.10 Orders
Order model is one of the most important in Sylius, it represents the order placed via your store! It has a very consistent
and clear API, which allows you to easily manipulate and process orders.
Customer Reference
Order holds a reference to specific User, which is available through getUser() method:
echo $order->getUser()->getEmail(); // john@example.com
When creating order programatically, you can define the user yourself:
$order = $this->get('sylius.repository.order')->createNew();
$john = $this->get('sylius.repository.user')->find(3);
$order->setUser($john);
Order may not have reference to User in case when Order was created by guest.
Billing and Shipping Address
By default, every order has its own billing and shipping address, which are heavily used through whole process. Both
of them are represented by Address model.
$shippingAddress = $order->getShippingAddress();
echo 'Shipped to: '.$shippingAddress->getCountry();
Order Contents
Order holds a collection of OrderItem instances.
OrderItem model has the attributes listed below:
Attribute
id
order
variant
product
unitPrice
quantity
adjustments
adjustmentsTotal
total
createdAt
updatedAt
Description
Unique id of the item
Reference to an Order
Reference to Variant
Product loaded via Variant
The price of a single unit
Quantity of sold item
Collection of Adjustments
Total value of adjustments
Order grand total
Date when order was created
Date of last change
16
Sylius, Release
Shipments
...
Shipping State
...
Payments
...
Payment State
...
The Order State Machine
Order has also its general state, which can have the following values:
cart
pending
released
confirmed
shipped
abandoned
cancelled
returned
Final Thoughts
...
Learn more
...
1.1.11 Shipments
...
The Shipment State Machine
...
17
Sylius, Release
Shipping Methods
...
Shipping Cost Calculators
...
Default Calculators
...
Shipping Zones
...
Examples
...
Product and ProductVariant Configuration
...
Final Thoughts
...
Learn more
...
1.1.12 Payments
Sylius contains a very flexible payments management system with support for many gateways. (payment providers) We
are using very powerful payment abstraction library, called [Payum], which handles all sorts of capturing, refunding
and recurring payments logic.
On Sylius side, we integrate it into our checkout and manage all the payment data.
Payment
Every payment in Sylius, successful or failed, is represented by Payment model, which contains basic information and
reference to appropriate order.
Payment has following attributes:
id
18
Sylius, Release
currency (code)
amount
reference to PaymentMethod
reference to Order
state
reference to [PaymentSource] (optional)
createdAt
updatedAt
All these properties are easily accessible through simple API:
<?php
echo $payment->getAmount() . $payment->getCurrency();
$order = $payment->getOrder(); // Get the order.
echo $payment->getMethod()->getName(); // Get the name of payment method used.
19
Sylius, Release
gateway
configuration
environment
feeCalculator
feeCalculatorConfiguration
createdAt
updatedAt
Gateway and Configurations
...
Payment Processing
...
Supported Gateways
...
Final Thoughts
...
Learn more
...
1.1.14 Troubleshoooting
Sylius stores payment output inside the details column of the sylius_payment table. It can provide valuable info when
debugging the payment process.
PayPal Error Code 10409
Also known as Checkout token was issued for a merchant account other than yours. You most likely changed the
PayPal credentials from config.yml during the checkout process. Clear the cache and try again:
app/console cache:clear
1.1.15 Taxation
Sylius has a very flexible taxation system, which allows you to apply appropriate taxes for different items, billing
zones and use custom calculators.
20
Sylius, Release
Tax Categories
In order to process taxes in your store, you need to configure at least one TaxCategory, which represents a specific
type of merchandise. If all your items are taxed with the same rate, you can have a simple Taxable Goods category
assigned to all items.
If you sell various products and some of them have different taxes applicable, you could create multiple categories.
For example, Clothing, Books and Food.
Tax Zones
Additionally to tax categories, you can have different tax zones, in order to apply correct taxes for customers coming
from any country in the world. To understand how zones work, please refer to the Zones chapter of this book.
Tax Rates
A tax rate is essentially a percentage amount charged based on the sales price. Tax rates also contain other important
information:
Whether product prices are inclusive of this tax
The zone in which the order address must fall within
The tax category that a product must belong to in order to be considered taxable
Calculator to use for computing the tax
Default Tax Zone
...
Examples
...
Calculators
...
Final Thoughts
...
Learn more
...
21
Sylius, Release
1.1.16 Pricing
Pricing is the part of Sylius responsible for calculating the product prices for the cart. This functionality comes from
the SyliusPricingBundle.
ProductVariant implements the PriceableInterface and has following attributes available:
pricingCalculator
pricingConfiguration
Note: All prices in Sylius are represented by integers, so 14.99$ is stored as 1499 in the database.
First parameter holds the name of calculator type and second contains the configuration array for this particular calculator.
For example, if you have a product without any variations, its master variant can have a simple setup with:
price = 2099
pricingCalculator = group_based
pricingConfiguration = [23 => 2499, 85 => 2999]
Calculators
A calculator is a very simple service implement PriceCalculatorInterface and has a very important calculate(priceable, configuration, context) method.
Every time product is added, removed to cart and generally on every cart modification event, this method is used to
calculate the unit price. It takes the appropriate calculator configured on the product, together with the configuration
and context. Context is taken from the product as well, but context is coming from the cart.
Currently the context is really simple and contains the following details:
quantity of the cart item
user
groups
You can easily [implement your own pricing calculator] and allow store managers to define complex pricing rules for
any merchandise.
Final Thoughts
...
Learn more
...
1.1.17 Promotions
...
22
Sylius, Release
Promotion Rules
...
Promotion Actions
...
Coupons
...
Examples
...
Exclusive Promotions
Final Thoughts
...
Learn more
...
23
Sylius, Release
$manager = $this->container->get('sylius.manager.user');
$manager->persist($user);
$manager->flush(); // Save changes in database.
}
Setting billing and shipping addresses is easy. First you need an Address object. This is created by calling the
createNew() method on the repository.
Afterwards you can set all the data and assign the Address object to the user by using either
setShippingAddress() or setBillingAddress().
<?php
public function myAction(Request $request)
{
$userRepository = $this->container->get('sylius.repository.user');
$user = $userRepository->find(1);
$addressRepository = $this->container->get('sylius.repository.address');
$address = $addressRepository->createNew();
$address->setFirstName('John');
$address->setLastName('Doe');
$address->setCity('New York');
$address->setPostcode(2000);
$address->setStreet('Times Sq. 137');
$user->setBillingAddress($address);
$manager = $this->container->get('sylius.manager.user');
$manager->persist($user);
$manager->flush(); // Save changes in database.
}
Groups
To create a new group instance, you can simply call the createNew() method on the repository.
Do not forget setting a name for the group, it is a required field as it is not nullable. The name for the group must also
be unique.
<?php
public function myAction(Request $request)
{
$repository = $this->container->get('sylius.repository.group');
$group = $repository->createNew();
$group->setName('Premium customers');
}
You can now start adding users to your newly made group.
<?php
public function myAction(Request $request)
{
$groupRepository = $this->container->get('sylius.repository.group');
$group = $groupRepository->findOneBy(array('name' => 'Premium customers');
24
Sylius, Release
$userRepository = $this->container->get('sylius.repository.user');
$user = $userRepository->find(1);
$user->addGroup($group);
$manager = $this->container->get('sylius.manager.group');
$manager->persist($user);
$manager->flush(); // Save changes in database.
}
Final Thoughts
...
Learn more
...
1.1.19 Currencies
Sylius supports multiple currencies per store and makes it very easy to manage them.
There are several approaches to processing several currencies, but we decided to use the simplest solution we store all
money values in the default currency and convert them to different currency with current rates or specific rates.
Every currency is represented by Currency entity and holds basic information:
id
code
exchangeRate
enabled
createdAt
updatedAt
The default currency has exchange rate of 1.000.
Currency Context
By default, user can switch his current currency in the frontend of the store.
To manage the currently used currency, we use CurrencyContext.
sylius.context.currency id.
<?php
public function fooAction()
{
$currency = $this->get('sylius.context.currency')->getCurrency();
}
To change the currently used currency, you can simply use the setCurrency() method of context service.
25
Sylius, Release
<?php
public function fooAction()
{
$this->get('sylius.context.currency')->setCurrency('PLN');
}
The currency context can be injected into your custom service and give you access to currently used currency.
Product Prices
...
Available Currencies Provider
The default menu for selecting currency is using a special service called sylius.currency_provider, which
returns all enabled currencies. This is your entry point if you would like override this logic and return different
currencies for various scenarios.
<?php
public function fooAction()
{
$currencies = $this->get('sylius.currency_provider')->getAvailableCurrencies();
foreach ($currencies as $currency) {
echo $currency->getCode();
}
}
Final Thoughts
...
Learn more
...
1.1.20 Locales
To support multiple site languages, we use Locale model with the following set of fields:
id
code
enabled
createdAt
updatedAt
26
Sylius, Release
Locale Context
With the default configuration, customers are able to change the store language in the frontend.
To manage the currently used language, we use LocaleContext.
sylius.context.locale id.
<?php
public function fooAction()
{
$locale = $this->get('sylius.context.locale')->getLocale();
echo $locale; // pl_PL
}
To change the locale, you can simply use the setLocale() method of the context service.
<?php
public function fooAction()
{
$this->get('sylius.context.locale')->setLocale('de_DE'); // Store will be displayed in German.
}
The locale context can be injected into your custom service and give you access to currently used locale.
Available Locales Provider
Service sylius.locale_provider is responsible for returning all languages available to the current user. By
default, it filters out all disabled locales. You can easily modify this logic by overriding this component.
<?php
public function fooAction()
{
$locales = $this->get('sylius.locale_provider')->getAvailableLocales();
foreach ($locales as $locale) {
echo $locale->getCode();
}
}
To get all languages configured in the store, including the disabled ones, you can simply use the repository.
<?php
$locales = $this->get('sylius.repository.locale')->findAll();
Final Thoughts
...
Learn more
...
27
Sylius, Release
1.1.21 Content
...
SymfonyCMF and PHPCR
...
Static Content
...
Pages
...
Blocks
...
Final Thoughts
...
Learn more
...
1.1.22 E-Mails
Sylius is sending various e-mails and this chapter is a reference about all of them. Continue reading to learn what emails are sent, when and how to customize the templates. To understand how e-mail sending works internally, please
refer to SyliusMailerBundle documentation.
User Confirmation E-Mail
Every time new customer registers via registration form or checkout, user_confirmation e-mail is sent to him.
The default template is
SyliusWebBundle:Email:userConfirmation.html.twig
28
Sylius, Release
Order Confirmation
This e-mail is sent when order is paid. Unique code is order_confirmation. Template name is:
SyliusWebBundle:Email:orderConfirmation.html.twig
1.1.23 Settings
...
General Settings
...
29
Sylius, Release
Taxation Settings
...
Final Thoughts
...
Learn more
...
Introduction to Sylius
Installation
Architecture Overview
State Machine
Channels
Products
Addresses
Inventory
Orders
Shipments
Payments
Taxation
Pricing
Promotions
Users and Groups
Currencies
Locales
Content
E-Mails
Settings
Introduction to Sylius
Installation
Architecture Overview
State Machine
Channels
Products
Addresses
30
Sylius, Release
Inventory
Orders
Shipments
Payments
Taxation
Pricing
Promotions
Users and Groups
Currencies
Locales
Content
E-Mails
Settings
31
Sylius, Release
32
CHAPTER 2
2.1.2 Authorization
This part of documentation is about authorization to Sylius platform through API.
OAuth2
Sylius has configured OAuth2 authorization. The authorization process is standard procedure. Authorize as admin and
enjoy the API!
Note: User has to have ROLE_API role in order to access /api resources
33
Sylius, Release
Tip: If you use Guzzle check out OAuth2 plugin and use Password Credentials.
GET /oauth/v2/token?client_id=4fugw85qtim8c48s88g00s0gc040s4s4k8wk4kswowkksg0skw&client_secret=s8tg70
Example response
{
access_token: "Y2Y2NmNlNGExNzc1YmRiNzY3MDFlNmU0NjVjZjAxZjMwOTQ0MDZlODVhMTJlYTc4MDU3ZDFjMmExZjU3YT
expires_in: 3600
token_type: "bearer"
scope: null
refresh_token: "YzYzNDYyZmFiN2QyYTk3OTM4ZTFjODA2ZWJkMDFiZmIwZjE2Yzc4MTBkZWFlYzM3ZDU4YTE5ODcwMTc3M
}
You can now access any resource you want under /api prefix
Example
GET /api/users/
Authorization: Bearer Y2Y2NmNlNGExNzc1YmRiNzY3MDFlNmU0NjVjZjAxZjMwOTQ0MDZlODVhMTJlYTc4MDU3ZDFjMmExZjU
Refresh token
Sylius, Release
GET /oauth/v2/token?client_id=4fugw85qtim8c48s88g00s0gc040s4s4k8wk4kswowkksg0skw&client_secret=s8tg70
Example response You can now use new token to send requests
{
access_token: "MmE1YmJkMmVjNWI4YTUyZWU2OTM2NzljM2Y2N2FkMTVkMTQ2Y2ViYmZhNTQ4OTYzODVmN2UzMjEwNjU3NW
expires_in: 3600
token_type: "bearer"
scope: null
refresh_token: "OGQyMWZhYzkzYTZlNWY2YjA5MzRjMTk2MTNkNjM2Y2Y5ODg3ZjRlZmVlY2IyMmY1OGZkNGMxMjAwZjRmZ
}
Parameters
35
Sylius, Release
"next":{
"href":"\/api\/channels\/?page=2"
}
},
"_embedded":{
"items":[
{
"code": "WEB-UK",
"color": "Red",
"created_at": "2014-11-26T23:00:15+0000",
"currencies": [
],
"enabled": true,
"id": 91,
"locales": [
],
"name": "UK Webstore",
"payment_methods": [
],
"shipping_methods": [
],
"type": "web",
"updated_at": "2014-11-26T23:00:15+0000"
}
]
}
}
Response
STATUS: 200 OK
{
"code": "WEB-UK",
"color": "Red",
"created_at": "2014-11-26T23:00:15+0000",
"currencies": [
],
"enabled": true,
"id": 91,
"locales": [
],
"name": "UK Webstore",
"payment_methods": [
],
"shipping_methods": [
],
"type": "web",
"updated_at": "2014-11-26T23:00:15+0000"
}
36
Sylius, Release
Create an channel
To create a new channel, you can execute the following request:
POST /api/channels/
Parameters
Updating a channel
You can update an existing channel using PUT or PATCH method:
PUT /api/channels/92
PATCH /api/channels/92
37
Sylius, Release
Parameters
Deleting a channel
You can delete (soft) a channel from the system by making the following DELETE call:
DELETE /api/channels/92
Response
STATUS: 204 NO CONTENT
Parameters
38
Sylius, Release
STATUS: 200 OK
{
"page":1,
"limit":10,
"pages":12,
"total":120,
"_links":{
"self":{
"href":"\/api\/orders\/?page=1"
},
"first":{
"href":"\/api\/orders\/?page=1"
},
"last":{
"href":"\/api\/orders\/?page=12"
},
"next":{
"href":"\/api\/orders\/?page=2"
}
},
"_embedded":{
"items":[
{
"id":301,
"completed_at":"2014-11-26T23:00:33+0000",
"number":"000000048",
"items":[
{
"id":1353,
"quantity":3,
"unit_price":9054,
"adjustments":[
],
"adjustments_total":0,
"total":27162,
"immutable":false,
"variant":{
"id":13099,
"master":false,
"object":{
"id":2107,
"name":"T-Shirt \"voluptas\"",
"description":"Non molestias voluptas quae nemo omnis totam. Impedit
"created_at":"2014-11-26T23:00:17+0000",
"updated_at":"2014-11-26T23:00:17+0000",
"masterVariant":{
"id":13085,
"master":true,
"options":[
],
"created_at":"2014-11-26T23:00:17+0000",
"updated_at":"2014-11-26T23:00:17+0000",
"available_on":"2014-08-27T08:51:04+0000",
"sku":"43596"
},
39
Sylius, Release
40
Sylius, Release
"updated_at":"2014-11-26T23:00:15+0000",
},
"shipping_address":{
},
"billing_address":{
},
"payments":[
],
"shipments":[
],
"currency":"GBP",
"checkout_state":"cart"
}
]
}
}
Response
STATUS: 200 OK
{
"id":301,
"completed_at":"2014-11-26T23:00:33+0000",
"number":"000000048",
"items":[
{
"id":1353,
"quantity":3,
"unit_price":9054,
"adjustments":[
],
"adjustments_total":0,
"total":27162,
"immutable":false,
"variant":{
"id":13099,
"master":false,
"object":{
"id":2107,
"name":"T-Shirt \"voluptas\"",
"description":"Non molestias voluptas quae nemo omnis totam. Impedit ad perferend
"created_at":"2014-11-26T23:00:17+0000",
"updated_at":"2014-11-26T23:00:17+0000",
"masterVariant":{
"id":13085,
"master":true,
"options":[
41
Sylius, Release
],
"created_at":"2014-11-26T23:00:17+0000",
"updated_at":"2014-11-26T23:00:17+0000",
"available_on":"2014-08-27T08:51:04+0000",
"sku":"43596"
},
"short_description":"Quos in dignissimos in fugit culpa vitae."
},
"created_at":"2014-11-26T23:00:17+0000",
"updated_at":"2014-11-26T23:00:34+0000",
"available_on":"2013-12-10T09:16:56+0000",
"sku":"8808"
},
"inventory_units":[
{
"id":4061,
"inventory_state":"onhold",
"created_at":"2014-11-26T23:00:34+0000",
"updated_at":"2014-11-26T23:00:34+0000",
"_links":{
"order":{
"href":"\/app_dev.php\/api\/orders\/301"
}
}
},
{
"id":4062,
"inventory_state":"onhold",
"created_at":"2014-11-26T23:00:34+0000",
"updated_at":"2014-11-26T23:00:34+0000",
"_links":{
"order":{
"href":"\/app_dev.php\/api\/orders\/301"
}
}
},
{
"id":4063,
"inventory_state":"onhold",
"created_at":"2014-11-26T23:00:34+0000",
"updated_at":"2014-11-26T23:00:34+0000",
"_links":{
"order":{
"href":"\/app_dev.php\/api\/orders\/301"
}
}
}
],
"_links":{
"product":{
"href":"\/app_dev.php\/api\/products\/2107"
},
"variant":{
"href":"\/app_dev.php\/api\/products\/2107\/variants\/13099"
}
}
}
],
42
Sylius, Release
"items_total":97783,
"adjustments":[
{
"id":1011,
"type":"tax",
"description":"EU VAT (23%)",
"amount":22490,
"neutral":false,
"locked":false,
"created_at":"2014-11-26T23:00:33+0000",
"updated_at":"2014-11-26T23:00:34+0000"
},
{
"id":1012,
"type":"shipping",
"description":"UPS Ground",
"amount":2500,
"neutral":false,
"locked":false,
"created_at":"2014-11-26T23:00:33+0000",
"updated_at":"2014-11-26T23:00:34+0000"
},
{
"id":1013,
"type":"promotion",
"description":"New Year Sale for 3 and more items.",
"amount":-500,
"neutral":false,
"locked":false,
"created_at":"2014-11-26T23:00:33+0000",
"updated_at":"2014-11-26T23:00:34+0000"
},
{
"id":1014,
"type":"promotion",
"description":"Christmas Sale for orders over 100 EUR.",
"amount":-250,
"neutral":false,
"locked":false,
"created_at":"2014-11-26T23:00:33+0000",
"updated_at":"2014-11-26T23:00:34+0000"
}
],
"comments":[
],
"adjustments_total":24240,
"total":122023,
"confirmed":true,
"created_at":"2014-04-30T10:41:14+0000",
"updated_at":"2014-11-26T23:00:34+0000",
"state":"pending",
"email":"ygrant@example.com",
"expires_at":"2014-11-27T02:00:33+0000",
"user":{
"id":476,
"username":"ygrant@example.com",
"username_canonical":"ygrant@example.com",
43
Sylius, Release
"email":"ygrant@example.com",
"email_canonical":"ygrant@example.com",
"enabled":false,
"groups":[
],
"locked":false,
"expired":false,
"roles":[
],
"credentials_expired":false
},
"channel":{
"id":91,
"code":"WEB-UK",
"name":"UK Webstore",
"type":"web",
"color":"Red",
"enabled":true,
"created_at":"2014-11-26T23:00:15+0000",
"updated_at":"2014-11-26T23:00:15+0000",
},
"shipping_address":{
},
"billing_address":{
},
"payments":[
],
"shipments":[
],
"currency":"GBP",
"checkout_state":"cart"
}
Create an order
To create a new order (cart), you need to execute the following request:
POST /api/orders/
Parameters
44
Sylius, Release
{
"id":304,
"items":[
],
"items_total":0,
"adjustments":[
],
"comments":[
],
"adjustments_total":0,
"total":0,
"confirmed":true,
"created_at":"2014-11-29T12:29:07+0000",
"updated_at":"2014-11-29T12:29:08+0000",
"state":"cart",
"email":"chelsie.witting@example.com",
"expires_at":"2014-11-29T15:29:07+0000",
"user":{
"id":481,
"username":"chelsie.witting@example.com",
"username_canonical":"chelsie.witting@example.com",
"email":"chelsie.witting@example.com",
"email_canonical":"chelsie.witting@example.com",
"enabled":true,
"groups":[
],
"locked":false,
"expired":false,
"roles":[
],
"credentials_expired":false
},
"channel":{
"id":91,
"code":"WEB-UK",
"name":"UK Webstore",
"type":"web",
"color":"Red",
"enabled":true,
"created_at":"2014-11-26T23:00:15+0000",
"updated_at":"2014-11-26T23:00:15+0000",
},
"payments":[
],
"shipments":[
],
"currency":"USD",
"checkout_state":"cart"
}
45
Sylius, Release
DELETE /api/orders/24
Response
STATUS: 204 NO CONTENT
Parameters
46
Sylius, Release
"order": {
"href": "/app_dev.php/api/orders/52"
}
},
"created_at": "2014-12-15T13:18:48+0000",
"id": 829,
"inventory_state": "checkout",
"updated_at": "2014-12-15T13:18:48+0000"
},
{
"_links": {
"order": {
"href": "/app_dev.php/api/orders/52"
}
},
"created_at": "2014-12-15T13:18:48+0000",
"id": 830,
"inventory_state": "checkout",
"updated_at": "2014-12-15T13:18:48+0000"
}
],
"quantity": 3,
"total": 0,
"unit_price": 500000,
"variant": {
"available_on": "2014-04-01T06:43:02+0000",
"created_at": "2014-12-03T09:54:35+0000",
"id": 779,
"master": true,
"object": {
"attributes": [
{
"id": 238,
"name": "Book author",
"presentation": "Author",
"value": "Marlen Yost"
},
{
"id": 239,
"name": "Book ISBN",
"presentation": "ISBN",
"value": "326ccbc7-92d1-3aec-b3af-df8afdc5651d"
},
{
"id": 240,
"name": "Book pages",
"presentation": "Number of pages",
"value": "149"
}
],
"created_at": "2014-12-03T09:54:35+0000",
"description": "Et eveniet voluptas ut magni vero temporibus nihil. Omnis possimus accusa
"id": 101,
"name": "Book \"Quidem\" by \"Marlen Yost\"",
"options": [],
"short_description": "Distinctio quos est eaque fugit totam repellendus.",
"updated_at": "2014-12-03T09:54:35+0000"
},
47
Sylius, Release
"options": [],
"sku": "326ccbc7-92d1-3aec-b3af-df8afdc5651d",
"updated_at": "2014-12-03T09:54:35+0000"
}
}
Response
STATUS: 204 NO CONTENT
Parameters
48
Sylius, Release
49
Sylius, Release
"self": {
"href": "/app_dev.php/api/channels/3"
}
},
"code": "WEB-US",
"color": "Pink",
"created_at": "2014-12-03T09:54:28+0000",
"enabled": true,
"id": 3,
"name": "United States Webstore",
"type": "web",
"updated_at": "2014-12-03T09:58:29+0000"
},
"checkout_state": "addressing",
"comments": [],
"confirmed": true,
"created_at": "2014-12-15T13:15:22+0000",
"currency": "USD",
"email": "xschaefer@example.com",
"expires_at": "2014-12-15T16:15:22+0000",
"id": 52,
"items": [],
"items_total": 1500000,
"payments": [],
"shipments": [],
"state": "cart",
"total": 1499750,
"updated_at": "2014-12-15T13:37:29+0000",
"user": {
"credentials_expired": false,
"email": "xschaefer@example.com",
"email_canonical": "xschaefer@example.com",
"enabled": true,
"expired": false,
"groups": [],
"id": 5,
"locked": false,
"roles": [],
"username": "xschaefer@example.com",
"username_canonical": "xschaefer@example.com"
}
}
Shipping step
When order contains the address information, we are able to determine the stock locations and available shipping
methods. You can get these informations by first calling a GET request on the checkout unique URL.
GET /api/checkouts/44
STATUS: 200 OK
[
{
"methods": [
{
"_links": {
50
Sylius, Release
"self": {
"href": "/app_dev.php/api/shipping-methods/4"
},
"zone": {
"href": "/app_dev.php/api/zones/4"
}
},
"calculator": "flexible_rate",
"category_requirement": 1,
"configuration": {
"additional_item_cost": 500,
"additional_item_limit": 10,
"first_item_cost": 4000
},
"created_at": "2014-12-03T09:54:28+0000",
"enabled": true,
"id": 4,
"name": "FedEx World Shipping",
"updated_at": "2014-12-03T09:54:28+0000"
}
],
"shipment": {
"_links": {
"order": {
"href": "/app_dev.php/api/orders/52"
}
},
"created_at": "2014-12-15T14:11:32+0000",
"state": "checkout"
}
}
]
Response contains the proposed shipments and for each, it also has a list of shipping methods available.
Next step is updating the order with the types of shipping method that we have selected. To do so, you need to call
another PUT request, but this time with different set of parameters.
You need to pass an id of shipping method for every id, you should obtain them in the previous request.
PUT /api/checkouts/44
Parameters
51
Sylius, Release
"billing_address": {
},
"channel": {
},
"checkout_state": "shipping",
"comments": [],
"confirmed": true,
"created_at": "2014-12-15T13:15:22+0000",
"currency": "USD",
"email": "xschaefer@example.com",
"expires_at": "2014-12-15T16:15:22+0000",
"id": 52,
"items": [
],
"items_total": 1500000,
"payments": [],
"shipments": [
{
"_links": {
"method": {
"href": "/app_dev.php/api/shipping-methods/4"
},
"order": {
"href": "/app_dev.php/api/orders/52"
},
"self": {
"href": "/app_dev.php/api/shipments/51"
}
},
"created_at": "2014-12-15T14:30:40+0000",
"id": 51,
"method": {
"_links": {
"self": {
"href": "/app_dev.php/api/shipping-methods/4"
},
"zone": {
"href": "/app_dev.php/api/zones/4"
}
},
"calculator": "flexible_rate",
"category_requirement": 1,
"configuration": {
"additional_item_cost": 500,
"additional_item_limit": 10,
"first_item_cost": 4000
},
"created_at": "2014-12-03T09:54:28+0000",
"enabled": true,
"id": 4,
"name": "FedEx World Shipping",
"updated_at": "2014-12-03T09:54:28+0000"
},
"state": "checkout",
"updated_at": "2014-12-15T14:30:41+0000"
}
],
"shipping_address": {
52
Sylius, Release
},
"state": "cart",
"total": 1504750,
"updated_at": "2014-12-15T14:30:41+0000",
"user": {
}
}
Payment step
When we are done with shipping choices and we know the final price of an order, we can select a payment method.
To obtain a list of available payment methods for this order, simply call a GET request again:
GET /api/checkouts/44
STATUS: 200 OK
{
"methods": {
"1": {
"_links": {
"self": {
"href": "/app_dev.php/api/payment-methods/1"
}
},
"created_at": "2014-12-03T09:54:28+0000",
"id": 1,
"name": "Dummy",
"updated_at": "2014-12-03T09:54:28+0000"
},
"2": {
"_links": {
"self": {
"href": "/app_dev.php/api/payment-methods/2"
}
},
"created_at": "2014-12-03T09:54:28+0000",
"id": 2,
"name": "Paypal Express Checkout",
"updated_at": "2014-12-03T09:54:28+0000"
},
"3": {
"_links": {
"self": {
"href": "/app_dev.php/api/payment-methods/3"
}
},
"created_at": "2014-12-03T09:54:28+0000",
"id": 3,
"name": "Stripe",
"updated_at": "2014-12-03T09:54:28+0000"
},
"4": {
"_links": {
"self": {
"href": "/app_dev.php/api/payment-methods/4"
53
Sylius, Release
}
},
"created_at": "2014-12-03T09:54:28+0000",
"id": 4,
"name": "Be2bill",
"updated_at": "2014-12-03T09:54:28+0000"
},
"5": {
"_links": {
"self": {
"href": "/app_dev.php/api/payment-methods/5"
}
},
"created_at": "2014-12-03T09:54:28+0000",
"id": 5,
"name": "Stripe Checkout",
"updated_at": "2014-12-03T09:54:28+0000"
}
},
"payment": {
"_links": {
"order": {
"href": "/app_dev.php/api/orders/52"
}
},
"amount": 1504750,
"created_at": "2014-12-15T14:57:28+0000",
"currency": "USD",
"state": "new"
}
}
With that information, another PUT request with the id of payment method is enough to proceed:
PUT /api/checkouts/44
Parameters
54
Sylius, Release
"confirmed": true,
"created_at": "2014-12-15T13:15:22+0000",
"currency": "USD",
"email": "xschaefer@example.com",
"expires_at": "2014-12-15T16:15:22+0000",
"id": 52,
"items": [
],
"items_total": 1500000,
"payments": [
{
"_links": {
"order": {
"href": "/app_dev.php/api/orders/52"
},
"payment-method": {
"href": "/app_dev.php/api/payment-methods/1"
},
"self": {
"href": "/app_dev.php/api/payments/51"
}
},
"amount": 1504750,
"created_at": "2014-12-15T15:02:54+0000",
"currency": "USD",
"id": 51,
"method": {
"_links": {
"self": {
"href": "/app_dev.php/api/payment-methods/1"
}
},
"created_at": "2014-12-03T09:54:28+0000",
"id": 1,
"name": "Dummy",
"updated_at": "2014-12-03T09:54:28+0000"
},
"state": "new",
"updated_at": "2014-12-15T15:02:55+0000"
}
],
"shipments": [
],
"shipping_address": {
},
"state": "cart",
"total": 1504750,
"updated_at": "2014-12-15T15:02:55+0000",
"user": {
}
}
Finalize step
Now your order is fully constructed, you can get its latest snapshot by calling your last GET request:
55
Sylius, Release
GET /api/checkouts/44
STATUS: 200 OK
{
"adjustments": [
{
"amount": 0,
"created_at": "2014-12-15T13:37:29+0000",
"description": "No tax (0%)",
"id": 205,
"type": "tax",
"locked": false,
"neutral": false,
"updated_at": "2014-12-15T13:37:29+0000"
},
{
"amount": 5000,
"created_at": "2014-12-15T14:30:41+0000",
"description": "FedEx World Shipping",
"id": 207,
"type": "shipping",
"locked": false,
"neutral": false,
"updated_at": "2014-12-15T14:30:41+0000"
},
{
"amount": -250,
"created_at": "2014-12-15T14:30:41+0000",
"description": "Christmas Sale for orders over 100 EUR.",
"id": 208,
"type": "promotion",
"locked": false,
"neutral": false,
"updated_at": "2014-12-15T14:30:41+0000"
}
],
"adjustments_total": 4750,
"billing_address": {
"_links": {
"country": {
"href": "/app_dev.php/api/countries/9"
}
},
"city": "New York",
"created_at": "2014-12-15T13:37:28+0000",
"first_name": "John",
"id": 106,
"last_name": "Doe",
"postcode": "12435",
"street": "Test",
"updated_at": "2014-12-15T13:37:29+0000"
},
"channel": {
"_links": {
"self": {
"href": "/app_dev.php/api/channels/3"
}
56
Sylius, Release
},
"code": "WEB-US",
"color": "Pink",
"created_at": "2014-12-03T09:54:28+0000",
"enabled": true,
"id": 3,
"name": "United States Webstore",
"type": "web",
"updated_at": "2014-12-03T09:58:29+0000"
},
"checkout_state": "payment",
"comments": [],
"confirmed": true,
"created_at": "2014-12-15T13:15:22+0000",
"currency": "USD",
"email": "xschaefer@example.com",
"expires_at": "2014-12-15T16:15:22+0000",
"id": 52,
"items": [
{
"_links": {
"product": {
"href": "/app_dev.php/api/products/101"
},
"variant": {
"href": "/app_dev.php/api/products/101/variants/779"
}
},
"adjustments": [],
"adjustments_total": 0,
"id": 277,
"immutable": false,
"inventory_units": [
{
"_links": {
"order": {
"href": "/app_dev.php/api/orders/52"
}
},
"created_at": "2014-12-15T13:18:48+0000",
"id": 828,
"inventory_state": "checkout",
"updated_at": "2014-12-15T14:30:41+0000"
},
{
"_links": {
"order": {
"href": "/app_dev.php/api/orders/52"
}
},
"created_at": "2014-12-15T13:18:48+0000",
"id": 829,
"inventory_state": "checkout",
"updated_at": "2014-12-15T14:30:41+0000"
},
{
"_links": {
"order": {
57
Sylius, Release
"href": "/app_dev.php/api/orders/52"
}
},
"created_at": "2014-12-15T13:18:48+0000",
"id": 830,
"inventory_state": "checkout",
"updated_at": "2014-12-15T14:30:41+0000"
}
],
"quantity": 3,
"total": 1500000,
"unit_price": 500000,
"variant": {
"available_on": "2014-04-01T06:43:02+0000",
"created_at": "2014-12-03T09:54:35+0000",
"id": 779,
"master": true,
"object": {
"attributes": [
{
"id": 238,
"name": "Book author",
"presentation": "Author",
"value": "Marlen Yost"
},
{
"id": 239,
"name": "Book ISBN",
"presentation": "ISBN",
"value": "326ccbc7-92d1-3aec-b3af-df8afdc5651d"
},
{
"id": 240,
"name": "Book pages",
"presentation": "Number of pages",
"value": "149"
}
],
"created_at": "2014-12-03T09:54:35+0000",
"description": "Et eveniet voluptas ut magni vero temporibus nihil. Omnis possimu
"id": 101,
"name": "Book \"Quidem\" by \"Marlen Yost\"",
"options": [],
"short_description": "Distinctio quos est eaque fugit totam repellendus.",
"updated_at": "2014-12-03T09:54:35+0000"
},
"options": [],
"sku": "326ccbc7-92d1-3aec-b3af-df8afdc5651d",
"updated_at": "2014-12-03T09:54:35+0000"
}
}
],
"items_total": 1500000,
"payments": [
{
"_links": {
"order": {
"href": "/app_dev.php/api/orders/52"
58
Sylius, Release
},
"payment-method": {
"href": "/app_dev.php/api/payment-methods/1"
},
"self": {
"href": "/app_dev.php/api/payments/51"
}
},
"amount": 1504750,
"created_at": "2014-12-15T15:02:54+0000",
"currency": "USD",
"id": 51,
"method": {
"_links": {
"self": {
"href": "/app_dev.php/api/payment-methods/1"
}
},
"created_at": "2014-12-03T09:54:28+0000",
"id": 1,
"name": "Dummy",
"updated_at": "2014-12-03T09:54:28+0000"
},
"state": "new",
"updated_at": "2014-12-15T15:02:55+0000"
}
],
"shipments": [
{
"_links": {
"method": {
"href": "/app_dev.php/api/shipping-methods/4"
},
"order": {
"href": "/app_dev.php/api/orders/52"
},
"self": {
"href": "/app_dev.php/api/shipments/51"
}
},
"created_at": "2014-12-15T14:30:40+0000",
"id": 51,
"method": {
"_links": {
"self": {
"href": "/app_dev.php/api/shipping-methods/4"
},
"zone": {
"href": "/app_dev.php/api/zones/4"
}
},
"calculator": "flexible_rate",
"category_requirement": 1,
"configuration": {
"additional_item_cost": 500,
"additional_item_limit": 10,
"first_item_cost": 4000
},
59
Sylius, Release
"created_at": "2014-12-03T09:54:28+0000",
"enabled": true,
"id": 4,
"name": "FedEx World Shipping",
"updated_at": "2014-12-03T09:54:28+0000"
},
"state": "checkout",
"updated_at": "2014-12-15T14:30:41+0000"
}
],
"shipping_address": {
"_links": {
"country": {
"href": "/app_dev.php/api/countries/9"
}
},
"city": "New York",
"created_at": "2014-12-15T13:37:28+0000",
"first_name": "John",
"id": 105,
"last_name": "Doe",
"postcode": "12435",
"street": "Test",
"updated_at": "2014-12-15T13:37:29+0000"
},
"state": "cart",
"total": 1504750,
"updated_at": "2014-12-15T15:02:55+0000",
"user": {
"credentials_expired": false,
"email": "xschaefer@example.com",
"email_canonical": "xschaefer@example.com",
"enabled": true,
"expired": false,
"groups": [],
"id": 5,
"locked": false,
"roles": [],
"username": "xschaefer@example.com",
"username_canonical": "xschaefer@example.com"
}
}
This is how your final order looks, if you are happy with that response, simply call another PUT to confirm the
checkout, which will became a real order and appear in the backend.
PUT /api/checkouts/44
Response
Final response contains the full order information, now you can call the purchase action to actually pay for the order.
STATUS: 200 OK
{"to": "do"}
60
Sylius, Release
Purchase step
TODO.
PUT /api/checkouts/44
Parameters
You can check the payment status in the payment lists on order response.
STATUS: 200 OK
{"to": "do"}
Parameters
61
Sylius, Release
Response
"page":1,
"limit":10,
"pages":12,
"total":120,
"_links":{
"self":{
"href":"\/api\/products\/?page=1"
},
"first":{
"href":"\/api\/products\/?page=1"
},
"last":{
"href":"\/api\/products\/?page=12"
},
"next":{
"href":"\/api\/products\/?page=2"
}
},
"_embedded":{
"items":[
{
"created_at": "2014-11-26T23:00:20+0000",
"description": "Facere ipsum id eveniet rem omnis et. Totam vero eos eveniet nihil si
"id": 2173,
"masterVariant": {
"available_on": "2014-03-29T01:30:04+0000",
"created_at": "2014-11-26T23:00:20+0000",
"id": 13403,
"master": true,
"options": [],
"sku": "68051",
"updated_at": "2014-11-26T23:00:20+0000"
},
"name": "T-Shirt \"ipsam\"",
"short_description": "Aut rerum quasi neque.",
"updated_at": "2014-11-26T23:00:20+0000"
}
]
}
}
62
Sylius, Release
Response
STATUS: 200 OK
{
"created_at": "2014-11-26T23:00:20+0000",
"description": "Facere ipsum id eveniet rem omnis et. Totam vero eos eveniet nihil sint. Labore o
"id": 2173,
"masterVariant": {
"available_on": "2014-03-29T01:30:04+0000",
"created_at": "2014-11-26T23:00:20+0000",
"id": 13403,
"master": true,
"options": [],
"sku": "68051",
"updated_at": "2014-11-26T23:00:20+0000"
},
"name": "T-Shirt \"ipsam\"",
"short_description": "Aut rerum quasi neque.",
"updated_at": "2014-11-26T23:00:20+0000"
}
Create an product
To create a new product, you can execute the following request:
POST /api/products/
Parameters
63
Sylius, Release
"updated_at": "2014-11-29T14:23:58+0000"
}
Updating a product
You can update an existing product using PUT or PATCH method:
PUT /api/products/2181
PATCH /api/products/2181
Parameters
Deleting a product
You can delete (soft) a product from the catalog by making the following DELETE call:
DELETE /api/products/24
Response
STATUS: 204 NO CONTENT
64
Sylius, Release
Parameters
"page":1,
"limit":10,
"pages":10,
"total":100,
"_links":{
"self":{
"href":"\/api\/users\/?page=1"
},
"first":{
"href":"\/api\/users\/?page=1"
},
"last":{
"href":"\/api\/users\/?page=12"
},
"next":{
"href":"\/api\/users\/?page=2"
}
},
"_embedded":{
"items":[
{
"credentials_expired": false,
"email": "chelsie.witting@example.com",
"email_canonical": "chelsie.witting@example.com",
"enabled": true,
"expired": false,
"groups": [],
"id": 481,
"locked": false,
"password": "EbOLtGHYxJKotA+bdb9BElhXPd8qZsnlo8CjDdCk+qFR22EEZJoOTntBX/M5GUXw2vnEqOKI
"roles": [],
"salt": "h9ltmmawvdsk08oocogkws4sg040k04",
"username": "chelsie.witting@example.com",
"username_canonical": "chelsie.witting@example.com"
}
]
}
}
65
Sylius, Release
GET /api/users/481
Response
STATUS: 200 OK
{
"credentials_expired": false,
"email": "chelsie.witting@example.com",
"email_canonical": "chelsie.witting@example.com",
"enabled": true,
"expired": false,
"groups": [],
"id": 481,
"locked": false,
"password": "EbOLtGHYxJKotA+bdb9BElhXPd8qZsnlo8CjDdCk+qFR22EEZJoOTntBX/M5GUXw2vnEqOKIEVPaJr66yxXq
"roles": [],
"salt": "h9ltmmawvdsk08oocogkws4sg040k04",
"username": "chelsie.witting@example.com",
"username_canonical": "chelsie.witting@example.com"
}
Create an user
To create a new user, you can execute the following request:
POST /api/users/
Parameters
"credentials_expired": false,
"email": "chelsie.witting@example.com",
"email_canonical": "chelsie.witting@example.com",
"enabled": true,
"expired": false,
"groups": [],
"id": 481,
"locked": false,
"password": "EbOLtGHYxJKotA+bdb9BElhXPd8qZsnlo8CjDdCk+qFR22EEZJoOTntBX/M5GUXw2vnEqOKIEVPaJr66yxXq
66
Sylius, Release
"roles": [],
"salt": "h9ltmmawvdsk08oocogkws4sg040k04",
"username": "chelsie.witting@example.com",
"username_canonical": "chelsie.witting@example.com"
}
Updating a user
You can update an existing user using PUT or PATCH method:
PUT /api/users/481
PATCH /api/users/481
Parameters
Deleting a user
You can delete (soft) a user from the system by making the following DELETE call:
DELETE /api/users/24
Response
STATUS: 204 NO CONTENT
Parameters
67
Sylius, Release
Response
The successful response will contain the user object with a confirmation token and date of password request.
STATUS: 200 OK
{
"confirmation_token": "dzOeNrmdnn20IVHBW2Uaq-yAYsO2sY2hCXhfKdYl_xM",
"credentials_expired": false,
"email": "sylius@example.com",
"email_canonical": "sylius@example.com",
"enabled": true,
"expired": false,
"groups": [],
"id": 1,
"last_login": "2014-12-08T13:08:02+0000",
"locked": false,
"password_requested_at": "2014-12-08T14:19:26+0000",
"roles": [
"ROLE_SYLIUS_ADMIN"
],
"username": "sylius@example.com",
"username_canonical": "sylius@example.com"
}
Parameters
Parameters
68
Sylius, Release
69
Sylius, Release
},
"calculator": "flexible_rate",
"category_requirement": 1,
"configuration": {
"additional_item_cost": 500,
"additional_item_limit": 10,
"first_item_cost": 4000
},
"created_at": "2014-11-26T23:00:15+0000",
"enabled": true,
"id": 120,
"name": "FedEx World Shipping",
"updated_at": "2014-11-26T23:00:15+0000"
},
"state": "backordered",
"updated_at": "2014-11-26T23:00:34+0000"
}
]
}
}
Response
STATUS: 200 OK
{
"_links": {
"method": {
"href": "/api/shipping-methods/120"
},
"order": {
"href": "/api/orders/302"
},
"self": {
"href": "/api/shipments/251"
}
},
"created_at": "2014-11-26T23:00:34+0000",
"id": 251,
"method": {
"_links": {
"self": {
"href": "/api/shipping-methods/120"
},
"zone": {
"href": "/api/zones/120"
}
},
"calculator": "flexible_rate",
70
Sylius, Release
"category_requirement": 1,
"configuration": {
"additional_item_cost": 500,
"additional_item_limit": 10,
"first_item_cost": 4000
},
"created_at": "2014-11-26T23:00:15+0000",
"enabled": true,
"id": 120,
"name": "FedEx World Shipping",
"updated_at": "2014-11-26T23:00:15+0000"
},
"state": "backordered",
"updated_at": "2014-11-26T23:00:34+0000"
}
Deleting a shipment
You can delete a shipment from the system by making the following DELETE call:
DELETE /api/shipments/24
Response
STATUS: 204 NO CONTENT
Parameters
71
Sylius, Release
Response
STATUS: 200 OK
{
"page":1,
"limit":10,
"pages":8,
"total":80,
"_links":{
"self":{
"href":"\/api\/payments\/?page=1"
},
"first":{
"href":"\/api\/payments\/?page=1"
},
"last":{
"href":"\/api\/payments\/?page=12"
},
"next":{
"href":"\/api\/payments\/?page=2"
}
},
"_embedded":{
"items":[
{"to": "do"}
]
}
}
Response
STATUS: 200 OK
{"to": "do"}
Deleting a payment
You can delete a payment from the system by making the following DELETE call:
DELETE /api/payments/99
Response
STATUS: 204 NO CONTENT
72
Sylius, Release
Parameters
73
Sylius, Release
"id": 1,
"type": "fixed_discount"
}
],
"coupon_based": false,
"created_at": "2014-12-03T09:54:28+0000",
"exclusive": false,
"id": 1,
"name": "New Year",
"priority": 0,
"rules": [
{
"configuration": {
"count": 3,
"equal": true
},
"id": 1,
"type": "item_count"
}
],
"updated_at": "2014-12-03T09:54:28+0000",
"used": 0
}
]
}
}
Response
STATUS: 200 OK
{
"_links": {
"coupons": {
"href": "/app_dev.php/api/promotions/1/coupons/"
},
"self": {
"href": "/app_dev.php/api/promotions/1"
}
},
"actions": [
{
"configuration": {
"amount": 500
},
"id": 1,
"type": "fixed_discount"
}
],
74
Sylius, Release
"coupon_based": false,
"created_at": "2014-12-03T09:54:28+0000",
"exclusive": false,
"id": 1,
"name": "New Year",
"priority": 0,
"rules": [
{
"configuration": {
"count": 3,
"equal": true
},
"id": 1,
"type": "item_count"
}
],
"updated_at": "2014-12-03T09:54:28+0000",
"used": 0
}
Deleting a promotion
You can delete a promotion from the system by making the following DELETE call:
DELETE /api/promotions/1
Response
STATUS: 204 NO CONTENT
Parameters
75
Sylius, Release
"promotion": {
"href": "/api/promotions/1"
},
"self": {
"href": "/api/promotions/1/coupons/1"
}
},
"code": "XAETWESF",
"id": 1,
"usage_limit": 1,
"used": 0
}
]
},
"_links": {
"first": {
"href": "/api/promotions/1/coupons/?page=1&limit=10"
},
"last": {
"href": "/api/promotions/1/coupons/?page=1&limit=10"
},
"self": {
"href": "/api/promotions/1/coupons/?page=1&limit=10"
}
},
"limit": 10,
"page": 1,
"pages": 1,
"total": 1
}
Parameters
76
Sylius, Release
}
},
"code": "SUPER-AWESOME-SALE",
"id": 1,
"usage_limit": 3,
"used": 0
}
Parameters
77
Sylius, Release
},
"code": "LONDON-1",
"created_at": "2014-11-26T23:00:21+0000",
"enabled": true,
"id": 57,
"name": "London Werehouse",
"updated_at": "2014-11-26T23:00:21+0000"
}
]
},
"_links": {
"first": {
"href": "/api/stock-locations/?page=1&limit=10"
},
"last": {
"href": "/api/stock-locations/?page=1&limit=10"
},
"self": {
"href": "/api/stock-locations/?page=1&limit=10"
}
},
"limit": 10,
"page": 1,
"pages": 1,
"total": 4
}
Response
STATUS: 200 OK
{
"_links": {
"self": {
"href": "/api/stock-locations/57"
}
},
"address": {
"_links": {
"country": {
"href": "/api/countries/7517"
}
},
"city": "Naderton",
"created_at": "2014-11-26T23:00:21+0000",
"first_name": "Sabrina",
"id": 519,
"last_name": "Roberts",
"postcode": "45449-6358",
78
Sylius, Release
Parameters
79
Sylius, Release
Parameters
Response
STATUS: 204 NO CONTENT
80
Sylius, Release
Promotions API
StockLocation API
81
Sylius, Release
82
CHAPTER 3
Using Composer
We assume youre familiar with Composer, a dependency manager for PHP. Otherwise, check how to install Composer.
$ composer create-project -s dev sylius/sylius # or sylius/sylius-standard
$ cd sylius # or sylius-standard
$ php app/console sylius:install
Using Git
$
$
$
$
Installation
Installation
83
Sylius, Release
84
CHAPTER 4
Cookbook
4.1 Cookbook
4.1.1 Using the Installer commands
Sylius platform ships with the sylius:install command, which takes care of creating the database, schema,
dumping the assets and basic store configuration.
This command actually uses several other commands behind the scenes and each of those is available for you:
Checking system requirements
You can quickly check all your system requirements and possible recommendations by calling the following command:
$ php app/console sylius:install:check-requirements
Database configuration
Sylius can create or even reset the database/schema for you, simply call:
$ php app/console sylius:install:database
The command will check if your database schema exists. If yes, you may decide to recreate it from scratch, otherwise
Sylius will take care of this automatically. It also allows you to load sample data.
Loading sample data
You can load sample data by calling the following command:
$ php app/console sylius:install:sample-data
85
Sylius, Release
You
get
passed
a
FactoryInterface
and
Available for the backend and frontend menus, by listening/subscribing to any of the event constants defined in
Sylius\Bundle\WebBundle\Event\MenuBuilderEvent.
Example Usage
// src/Acme/ReportsBundle/EventListener/MenuBuilderListener.php
namespace Acme\ReportsBundle\EventListener;
use Sylius\Bundle\WebBundle\Event\MenuBuilderEvent;
class MenuBuilderListener
{
public function addBackendMenuItems(MenuBuilderEvent $event)
{
$menu = $event->getMenu();
$menu['sales']->addChild('reports', array(
'route' => 'acme_reports_index',
'labelAttributes' => array('icon' => 'glyphicon glyphicon-stats'),
))->setLabel('Daily and monthly reports');
}
}
YAML
services:
acme_reports.menu_builder:
class: Acme\ReportsBundle\EventListener\MenuBuilderListener
tags:
- { name: kernel.event_listener, event: sylius.menu_builder.backend.main, method: ad
- { name: kernel.event_listener, event: sylius.menu_builder.backend.sidebar, method:
XML
<!-- src/Acme/ReportsBundle/Resources/config/services.xml -->
<?xml version="1.0" encoding="UTF-8" ?>
<container xmlns="http://symfony.com/schema/dic/services"
86
Chapter 4. Cookbook
Sylius, Release
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://symfony.com/schema/dic/services http://symfony.com/schema/dic/ser
<services>
<service id="acme_reports.menu_builder" class="Acme\ReportsBundle\EventListener\MenuBuil
<tag name="kernel.event_listener" event="sylius.menu_builder.backend.main" method="a
<tag name="kernel.event_listener" event="sylius.menu_builder.backend.sidebar" method
</service>
</services>
</container>
PHP
// src/Acme/ReportsBundle/Resources/config/services.php
use Symfony\Component\DependencyInjection\Definition;
<container xmlns="http://symfony.com/schema/dic/services"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://symfony.com/schema/dic/services http://symfony.com/schema/dic/services
<parameters>
<parameter key="app.price.calculator.registry.class">App\Component\Registry\ServiceRegistry</
<parameter key="app.price.calculator.interface">App\Bundle\MyBundle\PriceCalculatorInterface<
</parameters>
<services>
<!-- You need to declare the registry as a service, it expect as argument the type of object
<service id="app.price.calculator.registry" class="%app.price.calculator.registry.class%">
<argument>%app.price.calculator.interface%</argument>
</service>
<!-- Don't forget that a registry don't create object. You need to create them before and reg
<service id="app.price.calculator.default" class="...">
<service id="app.price.calculator.custom" class="...">
</services>
</container>
namespace App\Bundle\MyBundle\DependencyInjection\Compiler;
class RegisterCalculatorServicePass implements CompilerPassInterface
{
public function process(ContainerBuilder $container)
{
// You can check if your registry is defined
4.1. Cookbook
87
Sylius, Release
if (!$container->hasDefinition('app.price.calculator.registry')) {
return;
}
$registryDefinition = $container->getDefinition('app.price.calculator.registry');
// You can register your services like this
$registryDefinition->addMethodCall(
'register',
array(
'default',
new Reference('app.price.calculator.default'),
)
);
$registryDefinition->addMethodCall(
'register',
array(
'custom',
new Reference('app.price.calculator.default'),
)
);
}
}
Finally, you need to register your custom pass with the container
namespace App\Bundle\MyBundle;
use App\Bundle\MyBundle\DependencyInjection\Compiler\RegisterCalculatorServicePass;
class AppMyBundleBundle extends Bundle
{
public function build(ContainerBuilder $container)
{
parent::build($container);
$container->addCompilerPass(new RegisterCalculatorServicePass());
}
}
88
Chapter 4. Cookbook
CHAPTER 5
Integrations
5.1 Integrations
Welcome to Sylius Integrations, where you can learn about all available connectors, bridges and integrations with
other applications.
89
Sylius, Release
90
Chapter 5. Integrations
CHAPTER 6
Migration Guide
91
Sylius, Release
92
CHAPTER 7
Bundles
Retrieving any resource from database always happens via the repository, which implements
Sylius\Bundle\ResourceBundle\Model\RepositoryInterface. If you have been using Doctrine, you should already be familiar with this concept, as it extends the default Doctrine ObjectRepository
interface.
Lets assume you want to load a product from database. Your product repository is always accessible via the
sylius.repository.product service.
<?php
public function myAction()
{
$repository = $this->container->get('sylius.repository.product');
}
Retrieving many resources is as simple as calling the proper methods on the repository.
93
Sylius, Release
<?php
public function myAction()
{
$repository = $this->container->get('sylius.repository.product');
Every Sylius repository supports paginating products. To create a Pagerfanta instance use the createPaginator
method.
<?php
public function myAction(Request $request)
{
$repository = $this->container->get('sylius.repository.product');
$products = $repository->createPaginator();
$products->setMaxPerPage(3);
$products->setCurrentPage($request->query->get('page', 1));
// Now you can returns products to template and iterate over it to get products from current page
}
Paginator can be created for a specific criteria and with desired sorting.
<?php
public function myAction(Request $request)
{
$repository = $this->container->get('sylius.repository.product');
$products = $repository->createPaginator(array('foo' => true), array('createdAt' => 'desc'));
$products->setMaxPerPage(3);
$products->setCurrentPage($request->query->get('page', 1));
}
To create a new resource instance, you can simply call the createNew() method on the repository.
Now lets try something else than product, well create a new TaxRate model.
<?php
public function myAction()
{
$repository = $this->container->get('sylius.repository.tax_rate');
$taxRate = $repository->createNew();
}
Note: Creating resources via this factory method makes the code more testable, and allows you to change the model
class easily.
94
Chapter 7. Bundles
Sylius, Release
To save or remove a resource, you can use any ObjectManager which is capable of managing the class. Every
model has its own manager alias, for example the sylius.manager.address is an alias to the ORM EntityManager.
Of course, it is also perfectly fine if you use the doctrine.orm.entity_manager service name or any other
appropriate manager service.
<?php
public function myAction()
{
$repository = $this->container->get('sylius.repository.address');
$manager = $this->container->get('sylius.manager.address'); // Alias to the appropriate doctrine
$address = $repository->createNew();
$address
->setFirstname('John')
->setLastname('Doe')
;
$manager->persist($address);
$manager->flush(); // Save changes in database.
}
Overriding Models
...
Extending base Models
All Sylius models live in Sylius\Component\Xyz\Model namespace together with the interfaces. As an example, for Sylius Taxation Component its TaxCategory and TaxRate.
Lets assume you want to add zone field to the Sylius tax rates.
Firstly, you need to create your own TaxRate class, which will extend the base model.
95
Sylius, Release
namespace Acme\Bundle\ShopBundle\Entity;
use Sylius\Component\Addressing\Model\ZoneInterface;
use Sylius\Component\Taxation\Model\TaxRate as BaseTaxRate;
class TaxRate extends BaseTaxRate
{
private $zone;
public function getZone()
{
return $this->zone;
}
public function setZone(ZoneInterface $zone)
{
$this->zone = $zone;
return $this;
}
}
96
Chapter 7. Bundles
Sylius, Release
All Doctrine relations to Sylius\\Component\\Taxation\\Model\\TaxRateInterface are using your new class as target-entity, you do not need to update any mappings.
TaxRateType form type is using your model as data_class.
Sylius\\Component\\Taxation\\Model\\TaxRate is automatically turned into Doctrine Mapped
Superclass.
Overriding Controllers
All Sylius bundles are using SyliusResourceBundle as a foundation for database storage.
Extending base Controller
If you want to modify the controller or add your custom actions, you can do so by defining a new controller class. By
extending resource controller, you also get access to several handy methods. Lets add to our custom controller a new
method to recommend a product:
<?php
// src/Acme/ShopBundle/Controller/ProductController.php
namespace Acme\ShopBundle\Controller;
use Sylius\Bundle\ResourceBundle\Controller\ResourceController;
use Symfony\Component\HttpFoundation\Request;
97
Sylius, Release
defaults:
_controller: sylius.controller.product:recommendAction
Sylius is using both custom and default Doctrine repositories and often youll need to add your own methods. Lets
assume you want to find all orders for a given customer.
Firstly, you need to create your own repository class
<?php
// src/Acme/ShopBundle/Repository/OrderRepository.php
namespace Acme\ShopBundle\Repository;
use Sylius\Bundle\ResourceBundle\Doctrine\ORM\EntityRepository;
class OrderRepository extends EntityRepository
{
public function findByCustomer(Customer $customer)
{
return $this
->createQueryBuilder('o')
->join('o.billingAddress', 'billingAddress')
->join('o.shippingAddress', 'shippingAddress')
->join('o.customer', 'customer')
->where('o.customer = :customer')
->setParameter('customer', $customer)
->getQuery()
->getResult()
;
}
}
98
Chapter 7. Bundles
Sylius, Release
<?php
public function ordersAction()
{
$customer = // Obtain customer instance.
$repository = $this->container->get('sylius.repository.order');
$orders = $repository->findByCustomer($customer);
}
<constraint-mapping xmlns="http://symfony.com/schema/dic/constraint-mapping"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://symfony.com/schema/dic/constraint-mapping
http://symfony.com/schema/dic/services/constraint-mapping-1.0
<class name="Sylius\Bundle\TaxationBundle\Model\TaxCategory">
<property name="name">
<constraint name="NotBlank">
<option name="message">Fill me in!</option>
<option name="groups">acme</option>
</constraint>
<constraint name="Length">
<option name="min">5</option>
<option name="max">255</option>
<option name="minMessage">Looonger!</option>
<option name="maxMessage">Shooorter!</option>
<option name="groups">acme</option>
</constraint>
</property>
</class>
</constraint-mapping>
99
Sylius, Release
Done! Now all Sylius forms will use acme validation group on all forms of tax category.
Overriding Forms
Every form type in Sylius holds its class name in a specific parameter. This allows you to easily add or remove fields
by extending the base form class.
Extending base Forms
Done! Sylius will now use your custom address form everywhere!
What has happened?
100
Chapter 7. Bundles
Sylius, Release
Configuration
In your AppKernel class, please register Sylius bundles before DoctrineBundle. This is important as we use listeners
which have to be processed first.
If you do not register bundles in this order, Doctrine will throw Doctrine\Common\Persistence\Mapping\MappingExcepti
exceptions about missing classes.
Using interfaces
When defining relation to Sylius model, use the interface name instead of concrete class. It will be automatically
replaced with the configured model, enabling much greater flexibility.
<?xml version="1.0" encoding="UTF-8"?>
<doctrine-mapping xmlns="http://doctrine-project.org/schemas/orm/doctrine-mapping"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://doctrine-project.org/schemas/orm/doctrine-mapping
http://doctrine-project.org/schemas/orm/doctrine-mapping.xsd">
Thanks to this approach, if the TaxCategory model has changed, you do not need to worry about remapping other
entities.
Events
All Sylius bundles are using SyliusResourceBundle, which has some built-in events.
Events reference
Event
sylius.<resource>.pre_create
sylius.<resource>.create
sylius.<resource>.post_create
sylius.<resource>.pre_update
sylius.<resource>.update
sylius.<resource>.post_update
sylius.<resource>.pre_delete
sylius.<resource>.delete
sylius.<resource>.post_delete
Description
Before persist
After persist
After flush
Before persist
After persist
After flush
Before remove
After remove
After flush
Lets take the Product model as an example. As you should already know, the product controller is represented by the
sylius.controller.product service. Several useful events are dispatched during execution of every default
7.1. Symfony2 Ecommerce Bundles
101
Sylius, Release
action of this controller. When creating a new resource via the createAction method, 3 events occur.
First, before the persist() is called on the product, the sylius.product.pre_create event is dispatched.
Secondly, just before the database flush is performed, Sylius dispatches the sylius.product.create event.
Finally, after the data storage is updated, sylius.product.post_create is triggered.
The same set of events is available for the update and delete operations. All the dispatches are using the
GenericEvent class and return the Product object by the getSubject method.
Registering a listener
Well stay with the Product model and create a listener which updates Solr (search engine) document every time a
product is updated.
namespace Acme\ShopBundle\EventListener;
use Symfony\Component\EventDispatcher\GenericEvent;
class SolrListener
{
// ... Constructor with indexer injection code.
public function onProductUpdate(GenericEvent $event)
{
$this->indexer->updateProductDocument($event->getSubject());
}
}
<services>
<service id="acme.listener.solr" class="Acme\ShopBundle\EventListener\SolrListener">
<tag name="kernel.event_listener" event="sylius.product.post_update" method="onProductUpd
</service>
</services>
</container>
Done! Every time a product is edited and the database updated, this listener will also use the indexer to update Solr
index accordingly.
7.1.2 SyliusAddressingBundle
This bundle integrates the Addressing into Symfony2 and Doctrine.
With minimal configuration you can introduce addresses, countries, provinces and zones management into your
project. Its fully customizable, but the default setup should be optimal for most use cases.
It also contains zone matching mechanisms, which allow you to match customer addresses to appropriate tax/shipping
(or any other) zones. There are several models inside the bundle, Address, Country, Province, Zone and ZoneMember.
102
Chapter 7. Bundles
Sylius, Release
There is also a ZoneMatcher service. Youll get familiar with it in later parts of this documentation.
Installation
We assume youre familiar with Composer, a dependency manager for PHP. Use following command to add the bundle
to your composer.json and download package.
If you have Composer installed globally.
$ composer require sylius/addressing-bundle:*
Note: Please register the bundle before DoctrineBundle. This is important as we use listeners which have to be
processed first.
Container configuration
103
Sylius, Release
sylius_translation:
driver: doctrine/orm
default_locale: en
Routing configuration
Warning: This should be done only in dev environment! We recommend using Doctrine migrations, to safely
update your schema.
Templates
ZoneMatcher
This bundle exposes the ZoneMatcher as sylius.zone_matcher service.
<?php
$zoneMatcher = $this->get('sylius.zone_matcher');
$zone = $zoneMatcher->match($user->getBillingAddress());
Forms
The bundle ships with a set of useful form types for all models. You can use the defaults or override them with your
own types.
104
Chapter 7. Bundles
Sylius, Release
Address form
The address form type is named sylius_address and you can create it whenever you need, using the form factory.
<?php
// src/Acme/ShopBundle/Controller/AddressController.php
namespace Acme\ShopBundle\Controller;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Symfony\Component\HttpFoundation\Request;
class DemoController extends Controller
{
public function fooAction(Request $request)
{
$form = $this->get('form.factory')->create('sylius_address');
}
}
7.1.3 SyliusAttributeBundle
This bundle provides easy integration of the Sylius Attribute component with any Symfony full-stack application.
Sylius uses this bundle internally for its product catalog to manage the different attributes that are specific to each
product.
Installation
We assume youre familiar with Composer, a dependency manager for PHP. Use the following command to add the
bundle to your composer.json and download the package.
105
Sylius, Release
Note: Please register the bundle before DoctrineBundle. This is important as we use listeners which have to be
processed first.
Container configuration
Chapter 7. Bundles
Sylius, Release
Warning: This should be done only in dev environment! We recommend using Doctrine migrations, to safely
update your schema.
Congratulations! The bundle is now installed and ready to use.
Configuration reference
sylius_attribute:
driver: ~ # The driver used for persistence layer. Currently only `doctrine/orm` is supported.
classes:
# `subject_name` can be any name, for example `product`, `ad`, or `blog_post`
subject_name:
subject: ~ # Required: The subject class implementing `AttributeSubjectInterface`.
attribute:
model:
~ # Required: The attribute model class implementing `AttributeInterfac
repository: ~ # Required: The repository class for the attribute.
controller: Sylius\Bundle\ResourceBundle\Controller\ResourceController
form:
Sylius\Bundle\AttributeBundle\Form\Type\AttributeType
attribute_value:
model:
~ # Required: The attribute value model class implementing `AttributeVa
repository: ~ # Required: The repository class for the attribute value.
controller: Sylius\Bundle\ResourceBundle\Controller\ResourceController
form:
Sylius\Bundle\AttributeBundle\Form\Type\AttributeValueType
validation_groups:
# `subject_name` should be same name as the name key defined for the classes section above.
subject_name:
attribute:
[ sylius ]
attribute_value: [ sylius ]
7.1.4 SyliusCartBundle
A generic solution for a cart system inside a Symfony2 application.
It doesnt matter if you are starting a new project or you need to implement this feature for an existing system - this
bundle should be helpful. Currently only the Doctrine ORM driver is implemented, so well use it here as an example.
There are two main models inside the bundle, Cart and CartItem.
There are also 2 main services, Provider and ItemResolver. Youll get familiar with them in further parts of the
documentation.
Installation
We assume youre familiar with Composer, a dependency manager for PHP. Use the following command to add the
bundle to your composer.json and download package.
If you have Composer installed globally.
$ composer require "sylius/cart-bundle"
107
Sylius, Release
First, you need to enable the bundle inside the kernel. If youre not using any other Sylius bundles, you will also need
to add the following bundles and their dependencies to the kernel:
SyliusResourceBundle
SyliusMoneyBundle
SyliusOrderBundle
Dont worry, everything was automatically installed via Composer.
Note: Please register the bundle before DoctrineBundle. This is important as we use listeners which have to be
processed first. It is generally a good idea to place all of the Sylius bundles at the beginning of the bundles list, as it is
done in the Sylius-Standard project.
<?php
// app/AppKernel.php
public function registerBundles()
{
$bundles = array(
new Sylius\Bundle\ResourceBundle\SyliusResourceBundle(),
new Sylius\Bundle\MoneyBundle\SyliusMoneyBundle(),
new Sylius\Bundle\OrderBundle\SyliusOrderBundle(),
new Sylius\Bundle\CartBundle\SyliusCartBundle(),
// Other bundles...
new Doctrine\Bundle\DoctrineBundle\DoctrineBundle(),
new FOS\RestBundle\FOSRestBundle(),
new JMS\SerializerBundle\JMSSerializerBundle($this),
);
}
This is no longer a required step in the latest version of the SyliusCartBundle, and if you are happy with the default
implementation (which is Sylius\Bundle\CartBundle\Model\CartItem), you can just skip to the next
section.
You can create your CartItem entity, living inside your application code. We think that keeping the applicationspecific and simple bundle structure is a good practice, so lets assume you have your AppBundle registered under
App\AppBundle namespace.
<?php
// src/App/AppBundle/Entity/CartItem.php
namespace App\AppBundle\Entity;
use Sylius\Component\Cart\Model\CartItem as BaseCartItem;
108
Chapter 7. Bundles
Sylius, Release
Now we need to define a simple mapping for this entity to map its fields.
You should
create a mapping file in your AppBundle, put it inside the doctrine mapping directory
src/App/AppBundle/Resources/config/doctrine/CartItem.orm.xml.
<?xml version="1.0" encoding="UTF-8"?>
<doctrine-mapping xmlns="http://doctrine-project.org/schemas/orm/doctrine-mapping"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://doctrine-project.org/schemas/orm/doctrine-mapping
http://doctrine-project.org/schemas/orm/doctrine-mapping
<entity name="App\AppBundle\Entity\CartItem" table="app_cart_item">
</entity>
</doctrine-mapping>
You do not have to map the ID field because it is already mapped in the
Sylius\Component\Cart\Model\CartItem class, together with the relation between Cart and CartItem.
Lets assume you have a Product entity, which represents your main merchandise within your webshop.
Note: Please remember that you can use anything else, Product here is just an obvious example, but it will work in a
similar way with other entities.
We need to modify the CartItem entity and its mapping a bit, so it allows us to put a product inside the cart item.
<?php
// src/App/AppBundle/Entity/CartItem.php
namespace App\AppBundle\Entity;
use Sylius\Component\Cart\Model\CartItem as BaseCartItem;
class CartItem extends BaseCartItem
{
private $product;
public function getProduct()
{
return $this->product;
}
public function setProduct(Product $product)
{
$this->product = $product;
}
}
We added a product property, and a simple getter and setter. We have to also map the Product to CartItem, lets
create this relation in mapping files.
<?xml version="1.0" encoding="UTF-8"?>
<doctrine-mapping xmlns="http://doctrine-project.org/schemas/orm/doctrine-mapping"
109
Sylius, Release
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://doctrine-project.org/schemas/orm/doctrine-mapping
http://doctrine-project.org/schemas/orm/doctrine-mapping
<entity name="App\AppBundle\Entity\CartItem" table="app_cart_item">
<many-to-one field="product" target-entity="App\AppBundle\Entity\Product">
<join-column name="product_id" referenced-column-name="id" />
</many-to-one>
</entity>
</doctrine-mapping>
The ItemResolver will be used by the controller to resolve the new cart item - based on a user request information.
Its only requirement is to implement Sylius\Component\Cart\Resolver\ItemResolverInterface.
<?php
// src/App/AppBundle/Cart/ItemResolver.php
namespace App\AppBundle\Cart;
use Sylius\Component\Cart\Model\CartItemInterface;
use Sylius\Component\Cart\Resolver\ItemResolverInterface;
class ItemResolver implements ItemResolverInterface
{
public function resolve(CartItemInterface $item, $request)
{
}
}
110
Chapter 7. Bundles
Sylius, Release
$this->entityManager = $entityManager;
}
public function resolve(CartItemInterface $item, $request)
{
}
private function getProductRepository()
{
return $this->entityManager->getRepository('AppBundle:Product');
}
}
We also added a simple method getProductRepository() to keep the resolving code cleaner.
We must use this repository to find a product with id, given by the user via the request. This can be done in various
ways, but to keep the example simple - well use a query parameter.
<?php
// src/App/AppBundle/Cart/ItemResolver.php
namespace App\AppBundle\Cart;
use
use
use
use
Sylius\Component\Cart\Model\CartItemInterface;
Sylius\Component\Cart\Resolver\ItemResolverInterface;
Sylius\Component\Cart\Resolver\ItemResolvingException;
Doctrine\ORM\EntityManager;
111
Sylius, Release
Note: Please remember that item accepts only integers as price and quantity.
Register our brand new service in the container. Well use XML as an example, but you are free to pick any other
format.
<?xml version="1.0" encoding="UTF-8"?>
<container xmlns="http://symfony.com/schema/dic/services"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://symfony.com/schema/dic/services
http://symfony.com/schema/dic/services/services-1.0.xsd">
<services>
<service id="app.cart_item_resolver" class="App\AppBundle\Cart\ItemResolver">
<argument type="service" id="doctrine.orm.entity_manager" />
</service>
</services>
</container>
112
Chapter 7. Bundles
Sylius, Release
sylius_cart:
resource: @SyliusCartBundle/Resources/config/routing.yml
prefix: /cart
Warning: This should be done only in dev environment! We recommend using Doctrine migrations, to safely
update your schema.
Templates
We think that providing a sensible default template is really difficult, especially when a cart summary is not the simplest
page. This is the reason why we do not currently include any, but if you have an idea for a good starter template, let
us know!
The bundle requires only the summary.html.twig template for cart summary page. The easiest way to override the
view is by placing it here app/Resources/SyliusCartBundle/views/Cart/summary.html.twig.
Note: You can use the templates from our Sylius app as inspiration.
You can access the cart total value using the ->getTotal() method.
The denormalized number of cart items is available via ->getTotalItems() method.
Recalculation of totals can happen by calling ->calculateTotal() method, using the simplest possible math.
It will also update the item totals. The carts have their expiration time - ->getExpiresAt() returns that time and
->incrementExpiresAt() sets it to +3 hours from now by default. The collection of items (Implementing
the Doctrine\Common\Collections\Collection interface) can be obtained using the ->getItems().
CartItem
Just like for the cart, the total is available via the same method (->getTotal()), but the unit price is accessible using
the ->getUnitPrice() Each item also can calculate its total, using the quantity (->getQuantity()) and the
unit price. It also has a very important method called ->equals(CartItemInterface $item), which decides
whether the items are same or not. If they are, it should return true, false otherwise. This is taken into account when
adding an item to the cart. If the added item is equal to an existing one, their quantities are summed, but no new
item is added to the cart. By default, it compares the ids, but for our example we would prefer to check the products.
We can easily modify our CartItem entity to do that correctly.
113
Sylius, Release
<?php
// src/App/AppBundle/Entity/CartItem.php
namespace App/AppBundle/Entity;
use Sylius\Bundle\Component\Cart\CartItem as BaseCartItem;
use Sylius\Bundle\Component\Cart\CartItemInterface;
class CartItem extends BaseCartItem
{
private $product;
public function getProduct()
{
return $this->product;
}
public function setProduct(Product $product)
{
$this->product = $product;
}
public function equals(CartItemInterface $item)
{
return $this->product === $item->getProduct();
}
}
If the user tries to add the same product twice or more, it will just sum the quantities, instead of adding duplicates to
the cart.
Routing and default actions
This bundle provides a quite simple default routing with several handy and common actions. You can see the usage
guide below.
Cart summary page
To point user to the cart summary page, you can use the sylius_cart_summary route. It will render the page
with the cart and form variables by default.
The cart is the current cart and form is the view of the cart form.
Adding cart item
In our simple example, we only need to add the following link in the places where we need the add to cart button.
<a href="{{ path('sylius_cart_item_add', {'productId': product.id}) }}">Add product to cart</a>
Clicking this link will add the selected product to the cart.
114
Chapter 7. Bundles
Sylius, Release
Removing item
On the cart summary page you have access to all the cart items, so another simple link will allow a user to remove
items from the cart.
<a href="{{ path('sylius_cart_item_remove', {'id': item.id}) }}">Remove from cart</a>
On the cart summary page, you have access to the cart form, if you want to save it, simply submit the form with the
following action.
<form action="{{ path('sylius_cart_save') }}" method="post">Save cart</a>
115
Sylius, Release
$this->get('sylius.repository.cart_item');
// Those repositories have some handy default methods, for example...
$item = $this->get('sylius.repository.cart')->createNew();
}
The resolver is used to create a new item based on the user request.
<?php
// ...
public function addItemAction(Request $request)
{
$resolver = $this->get('sylius.cart_resolver');
$item = $resolver->resolve($this->createNew(), $request);
}
Note: A more advanced example of a resolver implementation is available in Sylius Sandbox application on GitHub.
In templates
When using Twig as your template engine, you have access to 2 handy functions.
The sylius_cart_get function uses the provider to get the current cart.
{% set cart = sylius_cart_get() %}
Current cart totals: {{ cart.total }} for {{ cart.totalItems }} items!
The sylius_cart_form returns the form view for the CartItem form. It allows you to easily build more complex
actions for adding items to cart. In this simple example we allow to provide the quantity of item. Youll need to
process this form in your resolver.
116
Chapter 7. Bundles
Sylius, Release
Note: An example with multiple variants of this form can be found in Sylius Sandbox app. It allows for selecting a
variation/options/quantity of the product. It also adapts to the product type.
Summary
Configuration reference
sylius_cart:
# The driver used for persistence layer.
driver: ~
# Service id of cart item resolver.
resolver: ~
# Cart provider service id.
provider: sylius.cart_provider.default
# The id of cart storage for default provider.
storage: sylius.cart_storage.session
classes:
cart:
controller: Sylius\Bundle\CartBundle\Controller\CartController
form: Sylius\Bundle\CartBundle\Form\Type\CartType
item:
controller: Sylius\Bundle\CartBundle\Controller\CartItemController
form: Sylius\Bundle\CartBundle\Form\Type\CartItemType
validation_groups:
cart: [sylius]
item: [sylius]
phpspec2 examples
$ composer install --dev --prefer-dist
$ bin/phpspec run -f pretty
Bug tracking
This bundle uses GitHub issues. If you have found bug, please create an issue.
7.1.5 SyliusFlowBundle
Wizards with reusable steps for Symfony2 applications. Suitable for building checkouts or installations.
117
Sylius, Release
Installation
We assume youre familiar with Composer, a dependency manager for PHP. Use the following command to add the
bundle to your composer.json and download package.
If you have Composer installed globally.
$ composer require "sylius/flow-bundle"
First, you need to enable the bundle inside the kernel. If youre not using any other Sylius bundles, you will also need
to add SyliusResourceBundle and its dependencies to the kernel. Dont worry, everything was automatically installed
via Composer.
<?php
// app/AppKernel.php
public function registerBundles()
{
$bundles = array(
new Sylius\Bundle\FlowBundle\SyliusFlowBundle(),
// Other bundles...
);
}
We will create a very simple wizard now, without forms, storage, to keep things simple and get started fast.
Lets create a few simple steps:
<?php
namespace Acme\DemoBundle\Process\Step;
use Sylius\Bundle\FlowBundle\Process\Context\ProcessContextInterface;
use Sylius\Bundle\FlowBundle\Process\Step\AbstractControllerStep;
class FirstStep extends AbstractControllerStep
{
public function displayAction(ProcessContextInterface $context)
{
return $this->render('AcmeDemoBundle:Process/Step:first.html.twig');
}
public function forwardAction(ProcessContextInterface $context)
{
return $this->complete();
118
Chapter 7. Bundles
Sylius, Release
}
}
<?php
namespace Acme\DemoBundle\Process\Step;
use Sylius\Bundle\FlowBundle\Process\Context\ProcessContextInterface;
use Sylius\Bundle\FlowBundle\Process\Step\AbstractControllerStep;
class SecondStep extends AbstractControllerStep
{
public function displayAction(ProcessContextInterface $context)
{
return $this->render('AcmeDemoBundle:Process/Step:second.html.twig');
}
public function forwardAction(ProcessContextInterface $context)
{
return $this->complete();
}
}
Sylius\Bundle\FlowBundle\Process\Builder\ProcessBuilderInterface;
Sylius\Bundle\FlowBundle\Process\Scenario\ProcessScenarioInterface;
Symfony\Component\DependencyInjection\ContainerAware;
Acme\DemoBundle\Process\Step;
As you can see, we just add each step to process builder with a desired name. The name will be used in the routes to
navigate to particular step.
119
Sylius, Release
Registering scenario
In order for this to work, we need to register SyliusScenario and tag it as sylius.process.scenario:
<service id="sylius.scenario.flow" class="Acme\DemoBundle\Process\SyliusScenario">
<call method="setContainer">
<argument type="service" id="service_container" />
</call>
<tag name="sylius.process.scenario" alias="acme_flow" />
</service>
The configured alias will be used later in the route parameters to identify the scenario as you can have more then one.
Routing configuration
If you take a look into imported routing configuration, you will see that sylius_flow_start is a wizard entry
point. sylius_flow_display displays the step with the given name, sylius_flow_forward forwards to
the next step from the step with the given name. All routes have an scenarioAlias as a required parameter to identify
the scenario.
Templates
Step templates are like any other action template, usually due to the nature of multi-step wizards, they have back and
forward buttons:
Using storage
Storing data with default storage
By default, flow bundle will use session for data storage. Here is simple example how to use it in your steps:
<?php
namespace Acme\DemoBundle\Process\Step;
use Sylius\Bundle\FlowBundle\Process\Context\ProcessContextInterface;
use Sylius\Bundle\FlowBundle\Process\Step\ControllerStep;
class FirstStep extends ControllerStep
{
// ...
public function forwardAction(ProcessContextInterface $context)
{
120
Chapter 7. Bundles
Sylius, Release
$request = $this->getRequest();
$form = $this->createForm('my_form');
if ($request->isMethod('POST') && $form->bind($request)->isValid()) {
$context->getStorage()->set('my_data', $form->getData());
return $this->complete();
}
return $this->render('AcmeDemoBundle:Process/Step:first.html.twig', array(
'form' => $form->createView(),
));
}
}
Tests
$ composer install --dev --prefer-dist
$ phpunit
Working examples
If you want to see working implementation, try out the Sylius application.
There is also an example that shows how to integrate this bundle into Symfony Standard Edition.
Bug tracking
This bundle uses GitHub issues. If you have found bug, please create an issue.
7.1.6 SyliusGridBundle
Displaying a grid with sorting and filtering options is a common task for many web applications. This bundle integrates
the Sylius Grid component with Symfony2 framework and allows you to display grids really easily.
Some of the features worth mentioning:
Uses YAML to define the grid structure
Supports different data sources: Doctrine ORM/ODM, native SQL query.
Rich filter functionality, easy to define your own filter type with flexible form
7.1. Symfony2 Ecommerce Bundles
121
Sylius, Release
Each column type is configurable and you can create your own
Bulk actions
Automatic sorting
Installation
We assume youre familiar with Composer, a dependency manager for PHP. Use the following command to add the
bundle to your composer.json and download the package.
If you have Composer installed globally.
$ composer require sylius/grid-bundle:v0.15.0
Congratulations! The bundle is now installed and ready to use. You need to define your first resource and grid!
Your First Grid
In order to use grids, we need to register your entity as a Sylius resource. Let us assume you have Tournament model in
your application, which represents a sport tournament and has several fields, including name, date, status and category.
In order to make it a Sylius resource, you need to configure it under sylius_resource node:
# app/config/config.yml
sylius_resource:
resources:
app.tournament:
122
Chapter 7. Bundles
Sylius, Release
Thats it! Your class is now a resource. In order to learn what does it mean, please refer to SyliusResourceBundle
documentation.
Columns Definition
Thats it. SyliusResourceBundle allows to generate a default CRUD interface including the grid we have just defined.
Just put this in your routing configuration!
# app/config/routing.yml
app_tournament:
resource: app.tournament
type: sylius.crud
123
Sylius, Release
# app/config/config.yml
sylius_grids:
grids:
app_tournament:
driver: doctrine/orm # Use appropriate driver.
resource: app.tournament
columns:
name:
type: string
date:
type: datetime
status:
type: boolean
category:
type: string
options:
path: category.name
filters:
name:
type: string
date:
type: datetime
status:
type: boolean
category:
type: entity
options:
entity: AppBundle:TournamentCategory
Default Sorting
We want to have our tournaments sorted by name, by default, right? That is easy!
# app/config/config.yml
sylius_grids:
grids:
app_tournament:
driver: doctrine/orm # Use appropriate driver.
resource: app.tournament
sorting:
name: asc
columns:
name:
type: string
date:
type: datetime
status:
type: boolean
category:
type: string
options:
path: category.name
filters:
name:
type: string
124
Chapter 7. Bundles
Sylius, Release
date:
type: datetime
status:
type: boolean
category:
type: entity
options:
entity: AppBundle:TournamentCategory
Actions Configuration
Next step is adding some actions to the grid. We start with the basic ones, edit and delete. We can also add a simple
custom action with external link.
# app/config/config.yml
sylius_grids:
grids:
app_tournament:
driver: doctrine/orm # Use appropriate driver.
resource: app.tournament
sorting:
name: asc
columns:
name:
type: string
date:
type: datetime
status:
type: boolean
category:
type: string
options:
path: category.name
filters:
name:
type: string
date:
type: datetime
status:
type: boolean
category:
type: entity
options:
entity: AppBundle:TournamentCategory
actions:
edit:
type: link
options:
route: app_tournament_update
delete:
type: submit
options:
route: app_tournament_delete
method: DELETE
125
Sylius, Release
Column Types
This is the list of built-in column types.
String (string)
Simplest column type, which basically renders the value at given path as a string.
path Path to the value
By default is uses the name of the column, but your can specify the path in options. For example:
sylius_grid:
grids:
app_user:
columns:
email:
type: string
options:
path: contactDetails.email
This column type works exactly the same way as string, but expects DateTime instance and outputs a formatted date
and time string.
Date (date)
This column type works exactly the same way as string, but expects DateTime instance and outputs a formatted date
string.
Twig (twig)
Twig column type is the most flexible from all of them, because it delegates the logic of rendering the value to Twig
templating engine. You just have to specify the template and it will be rendered with the data variable available to
you.
sylius_grid:
grids:
app_user:
columns:
name:
type: twig
options:
template: :Grid/Column:_prettyName.html.twig
In the :Grid/Column:_prettyName.html.twig template, you just need to render the value as you see fit:
<strong>{{ data.name }}</strong>
<p>{{ data.description|markdown }}</p>
126
Chapter 7. Bundles
Sylius, Release
Boolean (boolean)
Boolean column type expects the value to be boolean and renders a default or custom Twig template.
sylius_grid:
grids:
app_user:
columns:
status:
type: boolean
options:
path: accountDetails.enabled # Optional!
template: :Grid/Column:_userStatus.html.twig # Optional!
Array (array)
This column type is a list of values. If you do not specify the Twig template, it will simply display the values as comma
separated list. Otherwise it will render the value using Twig.
sylius_grid:
grids:
app_user:
columns:
groups:
type: array
options:
template: :Grid/Column:_userGroups.html.twig # Optional!
Column configuration
Each column can be configured with several configuration fields, to make it more suitable to your grid requirements.
Name
type
label
sortable
options
Type
string
string
bool
array
Description
Type of column. Default column types are described here.
Label displayed in column header. By default, it is column name.
Whether column should be sortable or not. True by default.
Array of column options (see below).
Description
Available (and required) for twig column type. Path to template that is used to
render column value.
Path to property displayed in column (can be property of resource or one of its
referenced object).
string|arrayOne or more properties that will be used to column sorting (can be property of
resource or one of its referenced object).
Default
column
name
column
name
Filters
Here you can find the list of all supported filters. Keep in mind you can very easily define your own!
127
Sylius, Release
String (string)
Simplest filter type. It can filter in one or multiple columns, by default it uses the filter name as field, but you can
specify different set of fields.
fields Array of fields to filter
sylius_grid:
grids:
app_user:
filters:
search:
type: string
options:
fields: [username, e-mail, firstName, lastName]
This filter type works exactly the same way as datetime, but does not include the time.
The filter has the following search options:
between
not between
more than
less than
128
Chapter 7. Bundles
Sylius, Release
Boolean (boolean)
This is entity filter and allows you to select appropriate entity from list and filter using this value.
class Entity name (full or short)
multiple (Default: false) Allow to select multiple values?
sylius_grid:
grids:
app_user:
filters:
brand:
type: entity
options:
class: AppBundle:Brand
multiple: true
Choice (choice)
This filter allows the user to select one or multiple values and filter the result set.
choices Array of choices
multiple (Default: false) Allow to select multiple values?
sylius_grid:
grids:
app_user:
filters:
gender:
type: choice
options:
choices:
male: Boys
female: Girls
Country (country)
129
Sylius, Release
Currency (currency)
130
Chapter 7. Bundles
Sylius, Release
That is all. Now let register your new column type as service.
# app/config/services.yml
services:
app.grid.column_type.tournament_monitor:
class: App\Grid\ColumnType\TournamentMonitorType
tags:
- { name: sylius.grid_column_type type: tournament_monitor }
Now you can use your new column type in the grid configuration!
sylius_grid:
grids:
app_tournament:
driver: doctrine/orm
resource: app.tournament
columns:
monitor:
type: tournament_monitor
options:
dynamic: %kernel.debug%
Custom Filter
Sylius grids come with a lot of built-in filters, but there are use-cases where you need something more than basic filter.
Grids allow you to define your own filter types!
To add a new filter, we need to create appropriate class and form type.
<?php
namespace App\Grid\Filter;
use Sylius\Component\Grid\Data\DataSourceInterface;
use Sylius\Component\Grid\Filter\FilterInterface;
use Symfony\Component\OptionsResolver\OptionsResolverInterface;
class TournamentStatisticsFilter implements FilterInterface
{
public function apply(DataSourceInterface $dataSource, $data, array $options = array())
{
// Your filtering logic. DataSource is kind of query builder.
// $data['stats'] contains the submitted value!
}
public function setOptions(OptionsResolverInterface $resolver)
{
$resolver
->setDefaults(array(
'range' => array(0, 10)
))
->setAllowedTypes(array(
'range' => array('array')
))
;
}
131
Sylius, Release
That is all. Now let register your new filter type as service.
# app/config/services.yml
services:
app.grid.filter.tournament_statistics:
class: App\Grid\Filter\TournamentStatisticsFilter
tags:
- { name: sylius.grid_filter, type: tournament_statistics }
app.form.type.filter.tournament_statistics:
class: AppBundle\Form\Type\Filter\TournamentStatisticsFilterType
tags:
- { name: form.type, alias: sylius_filter_tournament_statistics }
Now you can use your new filter type in the grid configuration!
sylius_grid:
grids:
132
Chapter 7. Bundles
Sylius, Release
app_tournament:
driver: doctrine/orm
resource: app.tournament
filters:
stats:
type: tournament_statistics
options:
range: [0, 100]
Configuration Reference
sylius_grid:
grids:
app_user: # Your grid name.
driver: doctrine/orm # Data source driver.
resource: app.user # Resource name.
sorting:
name: asc
columns:
name:
type: twig # Type of column.
label: Name # Label.
sortable: true
options:
template: :Grid/Column:_name.html.twig # Only twig column
path: name
sort: name
filters:
group:
type: entity
label: Group
options:
entity: AppBundle:Group
actions:
edit:
type: link
options:
route: app_user_update
bulk_actions:
delete:
type: delete
copy:
type: copy
7.1.7 SyliusInventoryBundle
Flexible inventory management for Symfony2 applications.
With minimal configuration you can implement inventory tracking in your project.
Its fully customizable, but the default setup should be optimal for most use cases.
There is StockableInterface and InventoryUnit model inside the bundle.
There are services AvailabilityChecker, InventoryOperator and InventoryChangeListener.
Youll get familiar with them in later parts of this documentation.
133
Sylius, Release
Installation
We assume youre familiar with Composer, a dependency manager for PHP. Use the following command to add the
bundle to your composer.json and download package.
If you have Composer installed globally.
$ composer require "sylius/inventory-bundle"
First, you need to enable the bundle inside the kernel. If youre not using any other Sylius bundles, you will also need
to add SyliusResourceBundle and its dependencies to the kernel. Dont worry, everything was automatically installed
via Composer.
<?php
// app/AppKernel.php
public function registerBundles()
{
$bundles = array(
// ...
new FOS\RestBundle\FOSRestBundle(),
new Sylius\Bundle\ResourceBundle\SyliusResourceBundle(),
new Sylius\Bundle\InventoryBundle\SyliusInventoryBundle(),
);
}
Lets assume we want to implement a book store application and track the books inventory.
You have to create a Book and an InventoryUnit entity, living inside your application code. We think that keeping
the app-specific bundle structure simple is a good practice, so lets assume you have your AppBundle registered
under App\Bundle\AppBundle namespace.
We will create Book entity.
<?php
// src/App/AppBundle/Entity/Book.php
namespace App\AppBundle\Entity;
use Sylius\Bundle\InventoryBundle\Model\StockableInterface;
use Doctrine\ORM\Mapping as ORM;
/**
* @ORM\Entity
* @ORM\Table(name="app_book")
*/
class Book implements StockableInterface
134
Chapter 7. Bundles
Sylius, Release
{
/**
* @ORM\Id
* @ORM\Column(type="integer")
* @ORM\GeneratedValue(strategy="AUTO")
*/
protected $id;
/**
* @ORM\Column(type="string")
*/
protected $isbn;
/**
* @ORM\Column(type="string")
*/
protected $title;
/**
* @ORM\Column(type="integer")
*/
protected $onHand;
/**
* @ORM\Column(type="boolean")
*/
protected $availableOnDemand;
public function __construct()
{
$this->onHand = 1;
$this->availableOnDemand = true;
}
public function getId()
{
return $this->id;
}
public function getIsbn()
{
return $this->isbn;
}
public function setIsbn($isbn)
{
$this->isbn = $isbn;
}
public function getSku()
{
return $this->getIsbn();
}
public function getTitle()
{
return $this->title;
}
135
Sylius, Release
Note: This example shows the full power of StockableInterface. The bundle also provides an Stockable entity which
implements StockableInterface for you. By extending the Stockable entity, the example above can be dramatically
simplified.
In order to track the books inventory our Book entity must implement StockableInterface. Note that we added
->getSku() method which is alias to ->getIsbn(), this is the power of the interface, we now have full control over the entity mapping. In the same way ->getInventoryName() exposes the book title as the displayed
name for our stockable entity.
The next step requires the creating of the InventoryUnit entity, lets do this now.
<?php
// src/App/AppBundle/Entity/InventoryUnit.php
namespace App\AppBundle\Entity;
use Sylius\Bundle\InventoryBundle\Entity\InventoryUnit as BaseInventoryUnit;
use Doctrine\ORM\Mapping as ORM;
/**
* @ORM\Entity
136
Chapter 7. Bundles
Sylius, Release
* @ORM\Table(name="app_inventory_unit")
*/
class InventoryUnit extends BaseInventoryUnit
{
/**
* @ORM\Id
* @ORM\Column(type="integer")
* @ORM\GeneratedValue(strategy="AUTO")
*/
protected $id;
}
Note that we are using base entity from Sylius bundle, which means inheriting some functionality inventory bundle provides. InventoryUnit holds the reference to stockable object, which is Book in our case. So, if we use the
InventoryOperator to create inventory units, they will reference the given book entity.
Container configuration
Routing configuration
Warning: This should be done only in dev environment! We recommend using Doctrine migrations, to safely
update your schema.
Templates
137
Sylius, Release
Models
Here is a quick reference for the default models.
InventoryUnit
Each unit holds a reference to a stockable object and its state, which can be sold or backordered. It also provides
some handy shortcut methods like isSold, isBackordered and getSku.
Stockable
In order to be able to track stock levels in your application, you must implement StockableInterface or use the Stockable
model. It uses the SKU to identify stockable, need to provide display name and to check if stockable is available on
demand. It can get/set current stock level with getOnHand and setOnHand methods.
Using the services
When using the bundle, you have access to several handy services.
AvailabilityChecker
The name speaks for itself, this service checks availability for given stockable object. It takes backorders setting into
account, so if backorders are enabled, stockable will always be available. Backorders can be enabled per stockable if
it is available on demand. If none of this is the case, it means that backorders are not enabled for the given stockable
and AvailabilityChecker will rely on the current stock level.
There are two methods for checking availability. ->isStockAvailable() just checks whether stockable object
is available in stock and doesnt care about quantity. ->isStockSufficient() checks if there is enough units in
the stock for given quantity.
InventoryOperator
Inventory operator is the heart of this bundle. It can be used to manage stock levels and inventory units. It can also
fill backorders for the given stockable, this is a very powerful feature in combination with InventoryChangeListener.
Creating/destroying inventory units with a given state is also the operators job.
InventoryChangeListener
It simply triggers InventoryOperatorInterface::fillBackorders(). This can be extended by implementing InventoryChangeListenerInterface. Events can be configured like explained later on the documentation
Summary.
Twig Extension
There are two handy twig functions bundled in: sylius_inventory_is_available and sylius_inventory_is_sufficient.
They are simple proxies to the availability checker, and can be used to show if the stockable object is available/sufficient.
138
Chapter 7. Bundles
Sylius, Release
Here is a simple example, note that product variable has to be an instance of StockableInterface.
{% if not sylius_inventory_is_available(product) %}
<span class="label label-important">out of stock</span>
{% endif %}
Summary
Configuration reference
sylius_inventory:
# The driver used for persistence layer.
driver: ~
# Enable/disable backorders.
backorders: true
# Array of events for InventoryChangeListener
events: ~
# Enable or disbale tracking inventory
track_inventory: true
# The availability checker service id.
checker: sylius.availability_checker.default
# The inventory operator service id.
operator: sylius.inventory_operator.default
classes:
inventory_unit:
model: Sylius\Component\Inventory\Model\InventoryUnit
controller: Sylius\Bundle\InventoryBundle\Controller\InventoryUnitController
repository: ~ # You can override the repository class here.
stockable:
model: ~ # The stockable model class.
controller: Sylius\Bundle\ResourceBundle\Controller\ResourceController
phpspec2 examples
$ composer install --dev --prefer-dist
$ bin/phpspec run -f pretty
Bug tracking
This bundle uses GitHub issues. If you have found bug, please create an issue.
7.1.8 SyliusMailerBundle
Sending customizable e-mails has never been easier in Symfony.
You can configure different e-mail types in the YAML or in database. (and use YAML as fallback) This allows you to
send out e-mails with one simple method call, providing an unique code and data.
The bundle supports adapters, by default e-mails are rendered using Twig and sent via Swiftmailer, but you can easily
implement your own adapter and delegate the whole operation to external API.
This bundle provides easy integration of the Sylius Mailer component with any Symfony full-stack application.
139
Sylius, Release
Installation
We assume youre familiar with Composer, a dependency manager for PHP. Use the following command to add the
bundle to your composer.json and download the package.
If you have Composer installed globally.
$ composer require sylius/mailer-bundle:0.14.*@dev
Note: Please register the bundle before DoctrineBundle. This is important as we use listeners which have to be
processed first.
Container configuration
140
Chapter 7. Bundles
Sylius, Release
stof_doctrine_extensions:
orm:
default:
timestampable: true
Warning: This should be done only in dev environment! We recommend using Doctrine migrations, to safely
update your schema.
Congratulations! The bundle is now installed and ready to use.
Your First Email
Lets say you want to send a notification to the website team when someone submits a new position to your movie
catalog website!
You can do it in few simple steps:
Configure Your E-Mail
Thats it! Your unique code is movie_added_notification. Now, lets create the template.
Creating Your Template
141
Sylius, Release
The service responsible for sending an e-mail has id sylius.email_sender. All you need to do is retrieve it
from the container or inject to a listener:
<?php
namespace App\AppBundle\Controller;
use Symfony\Component\HttpFoundation\Request;
class MovieController
{
public function submitAction(Request $request)
{
// Your code.
$this->get('sylius.email_sender')->send('movie_added_notification', array('team@website.com')
}
}
Listener example:
<?php
namespace App\AppBundle\Controller;
use App\Event\MovieCreatedEvent;
use Sylius\Component\Mailer\Sender\SenderInterface;
class MovieNotificationListener
{
private $sender;
public function __construct(SenderInterface $sender)
{
$this->sender = $sender;
}
public function onMovieCreation(MovieCreatedEvent $event)
{
$movie = $event->getMovie();
$user = $event->getUser();
142
Chapter 7. Bundles
Sylius, Release
We recommend using events approach, but you can send e-mails from anywhere in your application. Enjoy!
Using Custom Adapter
There are certain use cases, where you do not want to send the e-mail from your app, but delegate the task to an
external API.
It is really simple with Adapters system!
Implement Your Adapter
Create your adapter class and add your custom logic for sending:
<?php
namespace App\Mailer\Adapter;
use Sylius\Component\Mailer\Sender\AdapterInterface;
use Sylius\Component\Mailer\Model\EmailInterface
class CustomAdapter implements AdapterInterface
{
public function send(EmailInterface $email, array $recipients, array $data = array())
{
// Your custom logic.
}
}
Now you just need to put service name under sylius_mailer configuration in app/config/config.yml.
sylius_mailer:
adapter: app.email_sender.adapter.custom
Thats it! Your new adapter will be used to send out e-mails. You can do whatever you want there!
Configuration reference
sylius_mailer:
driver: ~ # The driver used for persistence layer. Currently only `doctrine/orm` is supported.
sender_adapter: sylius.email_sender.adapter.swiftmailer # Adapter for sending e-mails.
renderer_adapter: sylius.email_renderer.adapter.twig # Adapter for rendering e-mails.
classes:
email:
143
Sylius, Release
model:
Sylius\Component\Mailer\Model\Email # The email model class implementing `E
repository: ~ # Is set automatically if empty.
controller: Sylius\Bundle\ResourceBundle\Controller\ResourceController
form:
Sylius\Bundle\MailerBundle\Form\Type\EmailType
validation_groups:
email: [sylius]
sender:
name: # Required - default sender name.
address: # Required - default sender e-mail address.
templates: # Your templates available for selection in backend!
label: Template path
label: Template path
label: Template path
emails:
your_email:
subject: Subject of your email
template: AppBundle:Email:yourEmail.html.twig
enabled: true/false
sender:
name: Custom name
address: Custom sender address for this e-mail
your_another_email:
subject: Subject of your another email
template: AppBundle:Email:yourAnotherEmail.html.twig
enabled: true/false
sender:
name: Custom name
address: Custom sender address for this e-mail
7.1.9 SyliusOmnipayBundle
Symfony2 integration for Omnipay library, PHP abstraction for payment gateways.
Installation
We assume youre familiar with Composer, a dependency manager for PHP. Use the following command to add the
bundle to your composer.json and download package.
If you have Composer installed globally.
$ composer require "sylius/omnipay-bundle"
144
Chapter 7. Bundles
Sylius, Release
Configuration
Implemented gateways
145
Sylius, Release
Payflow Pro
PaymentExpress (DPS) PxPay
PaymentExpress (DPS) PxPost
PayPal Express Checkout
PayPal Payments Pro
Pin Payments
Sage Pay Direct
Sage Pay Server
Stripe
WorldPay
The list above is always growing. The full list of supported gateways can be found at the Omnipay github repository.
How to manage gateways
The bundle provide handy services, which help to manage the activated gateways and options.
Services
Here are a couple of services which are available to use out of the box.
sylius.omnipay.gateway_factory - implement Omnipay\Common\GatewayFactory to manipulate with gateway
and options
sylius.form.type.omnipay.gateway_choice - quick proxy service to list defined in configuration gateways
Controller
To be written.
7.1.10 SyliusOrderBundle
This bundle is a foundation for sales order handling for Symfony2 projects. It allows you to use any model as the
merchandise.
It also includes a super flexible adjustments feature, which serves as a basis for any taxation, shipping charges or
discounts system.
Installation
We assume youre familiar with Composer, a dependency manager for PHP. Use the following command to add the
bundle to your composer.json and download package.
If you have Composer installed globally.
$ composer require sylius/order-bundle:*
146
Chapter 7. Bundles
Sylius, Release
Note: Please register the bundle before DoctrineBundle. This is important as we use listeners which have to be
processed first.
You have to create your own Order entity, living inside your application code. We think that keeping the appspecific bundle structure simple is a good practice, so lets assume you have your AppBundle registered under
App\Bundle\AppBundle namespace.
<?php
// src/App/AppBundle/Entity/Order.php
namespace App\AppBundle\Entity;
use Sylius\Component\Order\Model\Order as BaseOrder;
class Order extends BaseOrder
{
}
Now we need to define simple mapping for this entity, because it only extends the Doctrine mapped superclass. You should create a mapping file in your AppBundle, put it inside the doctrine mapping directory
src/App/AppBundle/Resources/config/doctrine/Order.orm.xml.
147
Sylius, Release
<doctrine-mapping xmlns="http://doctrine-project.org/schemas/orm/doctrine-mapping"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://doctrine-project.org/schemas/orm/doctrine-mapping
http://doctrine-project.org/schemas/orm/doctrine-mapping
Note: You might wonder why are we putting interface inside mapping, you can read about this Doctrine feature here.
Now lets assume you have a Product entity, which represents your main merchandise in your webshop.
Note: Please remember that you can use anything else, Product here is just an obvious example, but it will work in
similar way with other entities.
All you need to do is making your Product entity to implement ProductInterface and configure it inside Symfony settings.
<?php
// src/App/AppBundle/Entity/Product.php
namespace App\AppBundle\Entity;
use Sylius\Component\Product\Model\ProductInterface;
class Product implements ProductInterface
{
// Your code...
public function getName()
{
// Here you just have to return the nice display name of your merchandise.
return $this->name;
}
}
Now, you do not even have to map your Product model to the order items. It is all done automatically. And that would
be all about entities.
148
Chapter 7. Bundles
Sylius, Release
Container configuration
sylius_order:
driver: doctrine/orm # Configure the doctrine orm driver used in documentation.
classes:
order:
model: App\AppBundle\Entity\Order # The order entity.
order_item:
model: App\AppBundle\Entity\OrderItem # Your order item entity, if you need to override i
sylius_product:
driver: doctrine/orm # Configure the doctrine orm driver used in documentation.
classes:
product:
model: App\AppBundle\Entity\Product
Warning: This should be done only in dev environment! We recommend using Doctrine migrations, to safely
update your schema.
Each order has 2 main identifiers, an ID and a human-friendly number. You can access those by calling
->getId() and ->getNumber() respectively. The number is mutable, so you can change it by calling
->setNumber(E001) on the order instance.
<?php
$order->getId();
$order->getNumber();
$order->setNumber('E001');
Confirmation status
To check whether the order is confirmed or not, you can use the isConfirmed() method, which returns a true/false
value. To change that status, you can use the confirmation setter, setConfirmed(false). All orders are confirmed by default, unless you enabled the e-mail confirmation feature. Order also can contain a confirmation token,
accessible by the appropriate getter and setter.
149
Sylius, Release
<?php
if ($order->isConfirmed()) {
echo 'This one is confirmed, great!';
}
Order totals
The main order total is a sum of the previously mentioned values. You can access the order total value using the
->getTotal() method. Recalculation of totals can happen by calling ->calculateTotal() method, using
the simplest possible math. It will also update the item totals.
Items management
OrderItem basics
An order item model has only the id as identifier, also it has the order to which it belongs, accessible via
->getOrder() method.
The sellable object can be retrieved and set, using the following setter and getter - ->getProduct() &
->setVariant(ProductVariantInterface $variant).
<?php
$item->setVariant($book);
150
Chapter 7. Bundles
Sylius, Release
Note: In most cases youll use the OrderBuilder service to create your orders.
Just like for the order, the total is available via the same method, but the unit price is accessible using the
->getUnitPrice() Each item also can calculate its total, using the quantity (->getQuantity()) and the
unit price.
<?php
$item = $itemRepository->createNew();
$item
->setVariant($book)
->setUnitPrice(2000)
->setQuantity(4)
->calculateTotal()
;
echo $item->getTotal(); // 8000.
Note: To be written.
151
Sylius, Release
<?php
// ObjectManager which is capable of managing the resources.
// For *doctrine/orm* driver it will be EntityManager.
$this->get('sylius.manager.order');
$this->get('sylius.manager.order_item');
$this->get('sylius.manager.adjustment');
// ObjectRepository for the Order resource, it extends the base EntityRepository.
// You can use it like usual entity repository in project.
$this->get('sylius.repository.order');
$this->get('sylius.repository.order_item');
$this->get('sylius.repository.adjustment');
Summary
Note: To be written.
Configuration reference
sylius_order:
# The driver used for persistence layer.
driver: ~
classes:
sellable:
# The class name of the entity you want to put inside orders.
model: ~
order:
model: Sylius\Component\Order\Model\Order
controller: Sylius\Bundle\ResourceBundle\Controller\ResourceController
repository: ~
form: Sylius\Bundle\OrderBundle\Form\Type\OrderType
order_item:
model: Sylius\Component\Order\Model\OrderItem
controller: Sylius\Bundle\ResourceBundle\Controller\ResourceController
repository: ~
form: Sylius\Bundle\OrderBundle\Form\Type\OrderItemType
adjustment:
model: Sylius\Component\Order\Model\Adjustment
controller: Sylius\Bundle\ResourceBundle\Controller\ResourceController
repository: ~
form: Sylius\Bundle\OrderBundle\Form\Type\AdjustmentType
validation_groups:
order: [sylius] # Order validation groups.
order_item: [sylius]
adjustment: [sylius]
152
Chapter 7. Bundles
Sylius, Release
phpspec2 examples
$ composer install --dev --prefer-dist
$ bin/phpspec run -fpretty --verbose
Bug tracking
This bundle uses GitHub issues. If you have found bug, please create an issue.
7.1.11 SyliusProductBundle
The Sylius product catalog is made available as set of 2 standalone bundles. This component contains the most basic
product model with properties (attributes) support. It also includes the product prototyping system, which serves as a
template for creating similar products.
If you need product options support, please see SyliusVariationBundle which allows to manage product variations with
a very flexible architecture.
Installation
We assume youre familiar with Composer, a dependency manager for PHP. Use the following command to add the
bundle to your composer.json and download the package.
If you have Composer installed globally.
$ composer require "sylius/product-bundle"
153
Sylius, Release
new Sylius\Bundle\VariationBundle\SyliusVariationBundle(),
new Sylius\Bundle\TranslationBundle\SyliusTranslationBundle(),
// Other bundles...
new Doctrine\Bundle\DoctrineBundle\DoctrineBundle(),
);
}
Note: Please register the bundle before DoctrineBundle. This is important as we use listeners which have to be
processed first.
Container configuration
Routing configuration
Warning: This should be done only in dev environment! We recommend using Doctrine migrations, to safely
update your schema.
Congratulations! The bundle is now installed and ready to use.
The Product
Retrieving products
Retrieving a product from the database should always happen via repository, which always implements
Sylius\Bundle\ResourceBundle\Model\RepositoryInterface. If you are using Doctrine, youre
already familiar with this concept, as it extends the native Doctrine ObjectRepository interface.
154
Chapter 7. Bundles
Sylius, Release
Product repository also supports paginating products. To create a Pagerfanta instance use the createPaginator
method.
<?php
public function myAction(Request $request)
{
$repository = $this->container->get('sylius.repository.product');
$products = $repository->createPaginator();
$products->setMaxPerPage(3);
$products->setCurrentPage($request->query->get('page', 1));
// Now you can return products to the template and iterate over it to get products from the curren
}
The paginator also can be created for specific criteria and with desired sorting.
<?php
public function myAction(Request $request)
{
$repository = $this->container->get('sylius.repository.product');
$products = $repository->createPaginator(array('foo' => true), array('createdAt' => 'desc'));
$products->setMaxPerPage(3);
$products->setCurrentPage($request->query->get('page', 1));
}
To create new product instance, you can simply call createNew() method on the repository.
155
Sylius, Release
<?php
public function myAction(Request $request)
{
$repository = $this->container->get('sylius.repository.product');
$product = $repository->createNew();
}
Note: Creating a product via this factory method makes the code more testable, and allows you to change the product
class easily.
To save or remove a product, you can use any ObjectManager which manages Product. You can always access it via
alias sylius.manager.product. But its also perfectly fine if you use doctrine.orm.entity_manager
or other appropriate manager service.
<?php
Properties
A product can also have a set of defined Properties (think Attributes), youll learn about them in next chapter of this
documentation.
156
Chapter 7. Bundles
Sylius, Release
Product Properties
Managing Properties
Managing properties happens exactly the same way like products, you have sylius.repository.property
and sylius.manager.property at your disposal.
Assigning properties to product
Value of specific Property for one of Products, happens through ProductProperty model, which holds the references to
Product, Property pair and the value. If you want to programatically set a property value on product, use the following
code.
<?php
public function myAction(Request $request)
{
$propertyRepository = $this->container->get('sylius.repository.property');
$productPropertyRepository = $this->container->get('sylius.repository.product_property');
$property = $propertyRepository->findOneBy(array('name' => 'T-Shirt Collection'));
$productProperty = $productPropertyRepository->createNew();
$productProperty
->setProperty($property)
->setValue('Summer 2013')
;
$product->addProperty($productProperty);
$manager = $this->container->get('sylius.manager.product');
$manager->persist($product);
$manager->flush(); // Save changes in database.
}
This looks a bit tedious, doesnt it? There is a ProductBuilder service which simplifies the creation of products
dramatically, you can learn about it in appropriate chapter.
Forms
The bundle ships with a set of useful form types for all models. You can use the defaults or override them with
your own forms.
Product form
The product form type is named sylius_product and you can create it whenever you need, using the form factory.
<?php
// src/Acme/ShopBundle/Controller/ProductController.php
namespace Acme\ShopBundle\Controller;
157
Sylius, Release
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Symfony\Component\HttpFoundation\Request;
class DemoController extends Controller
{
public function fooAction(Request $request)
{
$form = $this->get('form.factory')->create('sylius_product');
}
}
Type
text
textarea
datetime
text
text
You can render each of these using the usual Symfony way {{ form_row(form.description) }}.
Property form
Default form for the Property model has name sylius_property and contains several basic fields.
Field
name
presentation
type
Type
text
text
choice
Prototype form
The default form for the Prototype model has name sylius_prototype and is built from the following fields.
Field
name
properties
Type
text
sylius_property_choice
Miscellaneous fields
There are a few more form types, which can become useful when integrating the bundle into your app.
sylius_product_property is a form which is used to set the product properties (and their values). It has 2
fields, the property choice field and a value input.
sylius_property_choice is a ready-to-use select field, with a list of all Properties from database.
sylius_product_to_identifier can be used to render a text field, which will transform the value into a
product.
If you need to customize existing fields or add your own, please read the overriding forms chapter.
158
Chapter 7. Bundles
Sylius, Release
Prototypes
...
Prototype Builder
It will add appropriate options and variants to given product based on prototype.
Product Builder
This service provides a fluent interface for easy product creation.
The example shown below is self explanatory:
<?php
$product = $this->get('sylius.builder.product')
->create('Github mug')
->setDescription("Coffee. Let's face it -- humans need to drink liquids!")
->addAttribute('collection', 2013)
->addAttribute('color', 'Red')
->addAttribute('material', 'Stone')
->save()
;
Summary
Configuration reference
sylius_product:
driver: ~ # The driver used for persistence layer.
engine: twig # Templating engine to use by default.
classes:
product:
model: Sylius\Component\Product\Model\Product
controller: Sylius\Bundle\ResourceBundle\Controller\ResourceController
repository: ~
form: Sylius\Bundle\AssortmentBundle\Form\Type\ProductType
product_prototype:
model: Sylius\Component\Product\Model\Prototype
controller: Sylius\Bundle\ProductBundle\Controller\PrototypeController
159
Sylius, Release
repository: ~
form: Sylius\Bundle\AssortmentBundle\Form\Type\PrototypeType
validation_groups:
product: [sylius] # Product validation groups.
product_prototype: [sylius] # Product prototype validation groups.
Tests
$ composer install --dev --prefer-dist
$ bin/phpspec run -fpretty --verbose
Bug tracking
This bundle uses GitHub issues. If you have found bug, please create an issue.
7.1.12 SyliusPromotionBundle
Promotions system for Symfony2 applications.
With minimal configuration you can introduce promotions and coupons into your project. The following types of
promotions are available and totally mixable:
percentage discounts
fixed amount discounts
promotions limited by time
promotions limited by a maximum number of usages
promotions based on coupons
This means you can for instance create the following promotions :
20$ discount for New Year orders having more than 3 items
8% discount for Christmas orders over 100 EUR
first 3 orders have 100% discount
5% discount this week with the coupon code WEEK5
40 C discount with the code you have received by mail
Installation
We assume youre familiar with Composer, a dependency manager for PHP. Use the following command to add the
bundle to your composer.json and download the package.
If you have Composer installed globally.
$ composer require "sylius/promotion-bundle"
160
Chapter 7. Bundles
Sylius, Release
Note: Please register the bundle before DoctrineBundle. This is important as we use listeners which have to be
processed first.
Container configuration
Routing configuration
161
Sylius, Release
Warning: This should be done only in dev environment! We recommend using Doctrine migrations, to safely
update your schema.
Congratulations! The bundle is now installed and ready to use.
Models
All the models of this bundle are defined in Sylius\Bundle\PromotionBundle\Model.
Rule
A Rule is used to check if your order is eligible to the promotion. A promotion can have none, one or several rules.
SyliusPromotionBundle comes with 2 types of rules :
item count rule : the number of items of the order is checked
item total rule : the amount of the order is checked
A rule is configured via the configuration attribute which is an array serialized into database. For item count
rules, you have to configure the count key, whereas the amount key is used for item total rules. For both types of
rules, you can configure the equal key to false or true depending is you want the rule to be strict or not. For
instance, for an item count rule configured with equal to false and count to 4, orders with only more than 4
items will be eligible.
Action
An Action defines the the nature of the discount. Common actions are :
percentage discount
fixed amount discount
An action is configured via the configuration attribute which is an array serialized into database. For percentage
discount actions, you have to configure the percentage key, whereas the amount key is used for fixed discount
rules.
Coupon
A Coupon is a ticket having a code that can be exchanged for a financial discount. A promotion can have none, one
or several coupons.
A coupon is considered as valid if the method isValid() returns true. This method checks the number of times
this coupon can be used (attribute usageLimit), the number of times this has already been used (attribute used)
and the coupon expiration date (attribute expiresAt). If usageLimit is not set, the coupon will be usable an
unlimited times.
PromotionSubjectInterface
A PromotionSubjectInterface is the object you want to apply the promotion on. For instance, in Sylius
Standard, a Sylius\Bundle\CoreBundle\Model\Order can be subject to promotions.
162
Chapter 7. Bundles
Sylius, Release
By implementing PromotionSubjectInterface, your object will have to define the following methods :
- getPromotionSubjectItemTotal() should return the amount of your order - getPromotionSubjectItemCount() should return the number of items of your order getPromotionCoupon() should return the coupon linked to your order. If you do not want to use coupon, simply
return null.
Promotion
The Promotion is the main model of this bundle. A promotion has a name, a description and :
can have none, one or several rules
should have at least one action to be effective
can be based on coupons
can have a limited number of usages by using the attributes usageLimit and used. When used reaches
usageLimit the promotion is no longer valid. If usageLimit is not set, the promotion will be usable an
unlimited times.
can be limited by time by using the attributes startsAt and endsAt
How rules are checked ?
Everything related to this subject is located in Sylius\Bundle\PromotionBundle\Checker.
Rule checkers
New rules can be created by implementing RuleCheckerInterface. This interface provides the method
isEligible which aims to determine if the promotion subject respects the current rule or not.
I told you before that SyliusPromotionBundle ships with 2 types of rules : item count rule and item total rule.
Item count rule is defined via the service sylius.promotion_rule_checker.item_count which uses the
class ItemCountRuleChecker. The method isEligible checks here if the promotion subject has the minimum number of items (method getPromotionSubjectItemCount() of PromotionSubjectInterface)
required by the rule.
Item total rule is defined via the service sylius.promotion_rule_checker.item_total which uses
the class ItemTotalRuleChecker. The method isEligible checks here if the promotion subject has the
minimum amount (method getPromotionSubjectItemTotal() of PromotionSubjectInterface) required by the rule.
The promotion eligibility checker service
163
Sylius, Release
to
We have seen above how actions can be created. Now lets see how they are applied to their subject.
The PromotionApplicator is responsible of this via its method apply. This method will execute all the
registered actions of a promotion on a subject.
How promotions are applied ?
By using the promotion eligibility checker and the promotion applicator checker services, the promotion processor
applies all the possible promotions on a subject.
The promotion processor is defined via the service sylius.promotion_processor which uses the class
Sylius\Bundle\PromotionBundle\Processor\PromotionProcessor. Basically, it calls the method
apply of the promotion applicator for all the active promotions that are eligible to the given subject.
Coupon based promotions
Coupon based promotions require special needs that are covered by this documentation.
164
Chapter 7. Bundles
Sylius, Release
Coupon generator
SyliusPromotionBundle
provides
a
way
to
transform
a
simple
string
code
to
a
real
Coupon
object
(and
vice
versa).
This
is
done
via
the
Sylius\Bundle\PromotionBundle\Form\DataTransformer\CouponToCodeTransformer
class.
This data transformer is used by default with the Sylius\Bundle\PromotionBundle\Form\Type\CouponToCodeType
form, provided as the service sylius.form.type.promotion_coupon_to_code.
Note:
An
example
of
integration
of
this
form
can
be
found
in
Sylius\Bundle\CoreBundle\Form\Type\CartType class of Sylius/Standard-Edition.
the
Coupon controller
165
Sylius, Release
controller: Sylius\Bundle\ResourceBundle\Controller\ResourceController
validation_groups:
promotion: [sylius]
promotion_rule: [sylius]
promotion_coupon: [sylius]
promotion_action: [sylius]
promotion_rule_item_total_configuration: [sylius]
promotion_rule_item_count_configuration: [sylius]
promotion_rule_user_loyality_configuration: [sylius]
promotion_rule_shipping_country_configuration: [sylius]
promotion_rule_taxonomy_configuration: [sylius]
promotion_rule_nth_order_configuration: [sylius]
promotion_action_fixed_discount_configuration: [sylius]
promotion_action_percentage_discount_configuration: [sylius]
promotion_action_add_product_configuration: [sylius]
promotion_coupon_generate_instruction: [sylius]
promotion_action_shipping_discount_configuration: [sylius]
phpspec2 examples
$ composer install --dev --prefer-dist
$ bin/phpspec run -fpretty --verbose
Bug tracking
This bundle uses GitHub issues. If you have found bug, please create an issue.
7.1.13 SyliusRbacBundle
Role-Based-Access-Control for Symfony2 applications, integrated with Doctrine ORM. Managable via UI.
Installation
We assume youre familiar with Composer, a dependency manager for PHP. Use the following command to add the
bundle to your composer.json and download the package.
If you have Composer installed globally.
$ composer require sylius/rbac-bundle:0.15.0
166
Chapter 7. Bundles
Sylius, Release
<?php
// app/AppKernel.php
public function registerBundles()
{
$bundles = array(
new FOS\RestBundle\FOSRestBundle(),
new JMS\SerializerBundle\JMSSerializerBundle($this),
new Stof\DoctrineExtensionsBundle\StofDoctrineExtensionsBundle(),
new WhiteOctober\PagerfantaBundle\WhiteOctoberPagerfantaBundle(),
new Doctrine\Bundle\DoctrineCacheBundle\DoctrineCacheBundle(),
new Sylius\Bundle\RbacBundle\SyliusRbacBundle(),
new Sylius\Bundle\ResourceBundle\SyliusResourceBundle(),
// Other bundles...
new Doctrine\Bundle\DoctrineBundle\DoctrineBundle(),
);
}
Note: Please register the bundle before DoctrineBundle. This is important as we use listeners which have to be
processed first.
Container configuration
Implement IdentityInterface
167
Sylius, Release
Warning: This should be done only in dev environment! We recommend using Doctrine migrations, to safely
update your schema.
Congratulations! The bundle is now installed and ready to configure your first roles and permissions.
Setup
...
Define Permissions
168
Chapter 7. Bundles
Sylius, Release
Thats it! Now you have to initialize the roles and permission in the database.
Setup Roles and Permissions in the Database
In Templates
{% if sylius_is_granted('your.permission.code') %}
{{ product.price }}
{% endif %}
Configuration reference
sylius_rbac:
driver: ~ # The driver used for persistence layer. Currently only `doctrine/orm` is supported.
authorization_checker: sylius.authorization_checker.default
identity_provider: sylius.authorization_identity_provider.security
permission_map: sylius.permission_map.cached
security_roles:
ROLE_ADMINISTRATION_ACCESS: Can access backend
roles:
app.admin:
name: Administrator
app.cash_manager:
169
Sylius, Release
classes:
role:
model:
Sylius\Component\Rbac\Model\Role # The role model class implementing `RoleI
repository: ~ # Is set automatically if empty.
controller: Sylius\Bundle\ResourceBundle\Controller\ResourceController
form:
default: Sylius\Bundle\RbacBundle\Form\Type\RoleType
permission:
model:
Sylius\Component\Rbac\Model\Permission # The permission model class impleme
repository: ~ # Is set automatically if empty.
controller: Sylius\Bundle\ResourceBundle\Controller\ResourceController
form:
default: Sylius\Bundle\RbacBundle\Form\Type\PermissionType
validation_groups:
role: [sylius]
permission: [sylius]
7.1.14 SyliusReportBundle
SyliusReportBundle is a flexible reports management system for Symfony2 applications.
Using this bundle, you can generate various and complex reports for your system, starting from user registrations
report or total sales report. Implemented renderers allows you to display data in many different ways - from simple
but clear table, to impressive and colorful charts.
Installation
We assume youre familiar with Composer, a dependency manager for PHP. Use the following command to add the
bundle to your composer.json and download the package.
If you have Composer installed globally.
$ composer require "sylius/report-bundle"
170
Chapter 7. Bundles
Sylius, Release
Note: Please register the bundle before DoctrineBundle. This is important as we use listeners which have to be
processed first.
Container configuration
Routing configuration
Warning: This should be done only in dev environment! We recommend using Doctrine migrations, to safely
update your schema.
Congratulations! The bundle is now installed and ready to use.
7.1. Symfony2 Ecommerce Bundles
171
Sylius, Release
Forms
The bundle ships with a useful form types for report model, but also for default renderers and data fetchers.
Report form
The report form type is named sylius_report and you can create it whenever you need, using the form factory.
<?php
// src/Acme/DemoBundle/Controller/DemoController.php
namespace Acme\DemoBundle\Controller;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Symfony\Component\HttpFoundation\Request;
class DemoController extends Controller
{
public function fooAction(Request $request)
{
$form = $this->get('form.factory')->create('sylius_report');
}
}
Type
text
text
textarea
choice
choice
You can render each of these using the usual Symfony way {{ form_row(form.description) }}.
SyliusReportBundle provides some default data fetchers and renderers. Each of them have custom configuration and adds diffrent part to report form.
Data fetchers Basic data fetcher extend same time provider. This implementation results in same configuration
fields for three different data fetchers.
Caution:
database.
Default data fetchers are part of SyliusCoreBundle, cause they are strictly connected with Sylius
172
Type
datetime
datetime
choice
checkbox
Chapter 7. Bundles
Sylius, Release
Table Renderer
Field
template
Type
choice
Chart Renderer
Field
type
template
Type
choice
choice
173
Sylius, Release
First step is creation of our new data fetcher class. It should provide proper logic and has to implement Sylius\Component\
fetch(array $configuration), which fetches data
getType, which returns unique name of data fetcher
Note: It is highly recommended to place all data fetchers types as constants. Default data fetchers have their types
included in Sylius\Component\Report\Renderer\DefaultDataFetchers
Caution: Data fetcher has to return Data class(Sylius\Component\Report\DataFetcher\Data),
which is part of Report component
<?php
namespace Acme\DemoBundle\DataFetchers\CustomDataFetcher;
use Sylius\Component\Report\DataFetcher\DataFetcherInterface;
use Sylius\Component\Report\DataFetcher\Data;
use Acme\Component\DataFetcher\DefaultRenderers;
class CustomDataFetcher implements DataFetcherInterface
{
/**
* {@inheritdoc}
*/
public function fetch(array $configuration)
{
$data = new Data();
//Some operations, that will provide data for your renderer
return $data;
}
/**
* {@inheritdoc}
*/
public function getType()
{
return DefaultDataFetchers::CUSTOM;
}
}
Each data fetcher has its own, specific cofiguration form, which is added to main report form. It has to extend
Symfony\Component\Form\AbstractType. To be able to configure our data fetcher in form, this class should
override buildForm(FormBuilderInterface $builder, array $options) method. It should also
have getName method, that returns data fetcher string identifier.
174
Chapter 7. Bundles
Sylius, Release
<?php
namespace Acme\DemoBundle\Form\Type\DataFetcher;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
class CustomConfigurationType extends AbstractType
{
/**
* {@inheritdoc}
*/
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add(
//custom options you want to provide in your custom data fetcher
))
;
}
/**
* {@inheritdoc}
*/
public function getName()
{
return 'acme_data_fetcher_custom';
}
}
To be able to use our new data fetcher, it must be registered as service in our services file. We should take care of
two classes we just created, means CustomDataFetcher and CustomConfigurationType. They have to be
tagged with proper tags, to be visible for CompilerPass.
<parameters>
//other parameters
<parameter key="acme.report.data_fetcher.custom.class">Acme\DemoBundle\DataFetchers\CustomDataFet
<parameter key="acme.form.type.data_fetcher.custom.class">Acme\DemoBundle\Form\Type\DataFetcher\C
</parameters>
<services>
//other services
<service id="acme.report.data_fetcher.custom" class="%acme.report.data_fetcher.custom.class%">
<argument type="service" id="acme.repository.order" />
<tag name="sylius.report.data_fetcher" fetcher="custom" label="Custom data fetcher" />
</service>
<service id="acme.form.type.data_fetcher.custom" class="%acme.form.type.data_fetcher.custom.class
<tag name="form.type" alias="acme_data_fetcher_custom" />
</service>
</services>
175
Sylius, Release
Summary
With this three simple steps, you can create your own, great data fetcher. Renderers can not wait for it.
Adding custom renderer
SyliusReportBundle has some default renderers implemented, however, obviously they can be insufficient for some
e-commerce systems. This chapter shows step-by-step way, how to add new renderer to make reports customization
easier and more corresponding to our needs.
Create custom renderer class
First step is creation of our new renderer class. It must implement Sylius\Component\Report\Renderer\RendererIn
render(ReportInterface $report, Data $data), which generates response based on
given report and data fetcher data
getType, which returns unique name of renderer
Note: It is highly recommended to place all renderers types as constants. Default renderers have their types included
in Sylius\Component\Report\Renderer\DefaultRenderers
<?php
namespace Acme\DemoBundle\Renderer\CustomRenderer;
use Sylius\Component\Report\Model\ReportInterface;
use Sylius\Component\Report\Renderer\RendererInterface;
use Acme\Component\Renderer\DefaultRenderers;
class CustomRenderer implements RendererInterface
{
public function render(ReportInterface $report, Data $data)
{
//Some operations on given data, that returns Response, which
//is next catched by controller and used to display view
}
public function getType()
{
return DefaultRenderers::CUSTOM;
}
}
Each renderer has its own, specific cofiguration form, which is added to main report form. It has to extend
Symfony\Component\Form\AbstractType. To be able to configure our renderer in form, this class should
override buildForm(FormBuilderInterface $builder, array $options) method. It should also
have getName method, that returns renderer string identifier.
176
Chapter 7. Bundles
Sylius, Release
<?php
namespace Acme\DemoBundle\Form\Type\Renderer;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
/**
* Custom renderer configuration form type
*/
class CustomConfigurationType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('template', 'choice', array(
'label' => 'acme.form.report.renderer.template', //Default template label - "templat
'choices' => array(
'AcmeDemoBundle:Custom:default.html.twig' => 'Default',
),
))
;
}
public function getName()
{
return 'acme_renderer_custom';
}
}
To be able to display your renderer, you should create its template or templates. Luckily, your renderer templates dont
have to provide all layout of report display page, only simple renderer view, which will be injected in report details
template. Thanks to that, all reports have systematized display, however each renderer move us to completely different
level of data perception.
Default renderers templates are placed in Sylius\Bundle\ReportBundle\Resources\views\ catalogue.
Register custom rednerer class as service
To be able to use our new renderer, it must be registered as service in our services file. We should take care of two
classes we just created, means CustomRenderer and CustomConfigurationType. They have to be tagged
with proper tags, to be visible for CompilerPass.
<parameters>
//other parameters
<parameter key="acme.renderer.custom.class">Acme\DemoBundle\Renderer\CustomRenderer</parameter>
<parameter key="acme.form.type.renderer.custom_configuration.class">Acme\DemoBundle\Form\Type\Ren
</parameters>
<services>
//other services
<service id="acme.renderer.custom" class="%acme.renderer.custom.class%">
<tag name="sylius.report.renderer" renderer="custom" label="Custom renderer" />
177
Sylius, Release
</service>
<service id="acme.form.type.report.renderer.custom_configuration" class="%acme.form.type.report.r
<tag name="form.type" alias="sylius_renderer_custom" />
</service>
</services>
Summary
With this three simple steps, you can create your own, great renderer, which allows you to display fetched data however
you want.
Summary
Configuration reference
sylius_report:
driver: ~
classes:
report:
model: Sylius\Component\Report\Model\Report
costroller: Sylius\Bundle\ReportBundle\Controller\ReportController
repository: ~
form: Sylius\Bundle\ReportBundle\Form\Type\ReportType
Tests
$ composer install --dev --prefer-dist
$ phpunit
Working examples
If you want to see working implementation, try out the Sylius application.
Bug tracking
This bundle uses GitHub issues. If you have found bug, please create an issue.
7.1.15 SyliusResourceBundle
Easy CRUD and persistence for Symfony2 apps.
During our work on Sylius, we noticed a lot of duplicated code across all controllers. We started looking for a good
solution to the problem. Were not big fans of administration generators (theyre cool, but not for our use case!) - we
wanted something simpler and more flexible.
Another idea was to not limit ourselves to one persistence backend. Initial implementation included custom manager
classes, which was quite of an overhead, so we decided to simply stick with Doctrine Common Persistence interfaces.
If you are using Doctrine ORM or any of the ODMs, youre already familiar with those concepts. Resource bundle
relies mainly on the ObjectManager and ObjectRepository interfaces.
178
Chapter 7. Bundles
Sylius, Release
The last annoying problem this bundle tries to solve, is having separate backend and frontend controllers, or any
other duplication for displaying the same resource, with different presentation (view). We also wanted an easy way to
filter some resources from list, sort them or display them by id, slug or any other criteria - without having to define
another super simple action for that purpose.
If these are issues youre struggling with, this bundle may be helpful!
Please note that this bundle is not an admin generator. It wont create forms, filters and grids for you. It only
provides format agnostic controllers as foundation to build on, with some basic sorting and filter mechanisms.
Installation
We assume youre familiar with Composer, a dependency manager for PHP. Use the following command to add the
bundle to your composer.json and download the package.
If you have Composer installed globally.
$ composer require "sylius/resource-bundle"
To benefit from bundle services, you have to first register your bundle class as a resource.
You also need to enable HTTP method parameter override, by calling the following method on the Request object.
<?php
// web/app{_dev|_test}.php
use Symfony\Component\HttpFoundation\Request;
Request::enableHttpMethodParameterOverride();
179
Sylius, Release
In your app/config.yml (or in an imported configuration file), you need to define which resources you want to
use :
sylius_resource:
resources:
my_app.entity_name:
driver: doctrine/orm
object_manager: default
templates: App:User
classes:
model: MyApp\Entity\EntityName
interface: MyApp\Entity\EntityNameInterface
controller: Sylius\Bundle\ResourceBundle\Controller\ResourceController
repository: Sylius\Bundle\ResourceBundle\Doctrine\ORM\EntityRepository
my_app.document_name:
driver: doctrine/mongodb-odm
object_manager: default
templates: App:User
classes:
model: MyApp\Document\DocumentName
interface: MyApp\Document\DocumentNameInterface
controller: Sylius\Bundle\ResourceBundle\Controller\ResourceController
repository: Sylius\Bundle\ResourceBundle\Doctrine\ODM\DocumentRepository
First you must list the supported doctrine driver by your bundle, the available drivers are:
SyliusResourceBundle::DRIVER_DOCTRINE_ORM
SyliusResourceBundle::DRIVER_DOCTRINE_MONGODB_ODM
SyliusResourceBundle::DRIVER_DOCTRINE_PHPCR_ODM
class MyBundle extends AbstractResourceBundle
{
public static function getSupportedDrivers()
{
return array(
SyliusResourceBundle::DRIVER_DOCTRINE_ORM
);
}
}
180
Chapter 7. Bundles
Sylius, Release
Note: Since the 0.11 your bundle class must implement ResourceBundleInterface. You can extends the
AbstractResourceBundle which already implements this interface, it will bring you extra functionalities too.
You need to expose a semantic configuration for your bundle.
Configuration that the resource bundle needs to work.
// The resources
->arrayNode('classes')
->addDefaultsIfNotSet()
->children()
->arrayNode('my_entity')
->addDefaultsIfNotSet()
->children()
->scalarNode('model')->defaultValue('MyApp\MyCustomBundle\Model\MyEnt
->scalarNode('controller')->defaultValue('Sylius\Bundle\ResourceBundl
->scalarNode('repository')->end()
->scalarNode('form')->defaultValue('MyApp\MyCustomBundle\Form\Type\My
->end()
->end()
->arrayNode('my_other_entity')
->addDefaultsIfNotSet()
181
Sylius, Release
->children()
->scalarNode('model')->defaultValue('MyApp\MyCustomBundle\Model\MyOth
->scalarNode('controller')->defaultValue('Sylius\Bundle\ResourceBundl
->scalarNode('form')->defaultValue('MyApp\MyCustomBundle\Form\Type\My
// you can use an array, useful when you want to register the choice
->arrayNode('form')
->addDefaultsIfNotSet()
->children()
->scalarNode('default')->defaultValue('MyApp\MyCustomBundle\F
->scalarNode('choice')->defaultValue('MyApp\MyCustomBundle\Fo
->end()
->end()
->end()
->end()
->end()
->end()
->end()
;
return $treeBuilder;
}
}
The resource bundle provide you AbstractResourceExtension, your bundle extension have to extends it.
use Sylius\Bundle\ResourceBundle\DependencyInjection\AbstractResourceExtension;
The last parameter of the AbstractResourceExtension::configure() allows you to define what functionalities you want to use :
CONFIGURE_LOADER : load yours service definitions located in $applicationName
182
Chapter 7. Bundles
Sylius, Release
CONFIGURE_FORMS : Register the form as a service (you must register the form as array)
At this step:
For now, with the advanced configuration you can not use several drivers but they can be overwritten. Example,
you want to use doctrine/odm for my_other_entity (see previous chapter), you just need to add this extra
configuration to the app/config.yml.
183
Sylius, Release
sylius_resource:
resources:
my_app.other_entity_key:
driver: doctrine/odm
object_manager: my_custom_manager
classes:
model: %my_app.model.my_entity.class%
Done! Now when you go to /users/3, ResourceController will use the repository (app.repository.user) to
find user with given id. If the requested user resource does not exist, it will throw a 404 exception.
When a user is found, the default template will be rendered - App:User:show.html.twig (like you configured
it in config.yml) with the User result as the user variable. Thats the most basic usage of the simple showAction
action.
Using a custom template
Okay, but what if you want now to display same User resource, but with a different representation?
# routing.yml
app_backend_user_show:
path: /backend/users/{id}
methods: [GET]
defaults:
_controller: app.controller.user:showAction
_sylius:
template: App:Backend/User:show.html.twig
184
Chapter 7. Bundles
Sylius, Release
Nothing more to do here, when you go to /backend/users/3, the controller will try to find the user and render it
using the custom template you specified under the route configuration. Simple, isnt it?
Overriding default criteria
Displaying the user by id can be boring... and lets say we do not want to allow viewing disabled users? There is a
solution for that!
# routing.yml
app_user_show:
path: /users/{username}
methods: [GET]
defaults:
_controller: app.controller.user:showAction
_sylius:
criteria:
username: $username
enabled: true
With this configuration, the controller will look for a user with the given username and exclude disabled users. Internally, it simply uses the $repository->findOneBy(array $criteria) method to look for the resource.
Using custom repository methods
By default, resource repository uses findOneBy(array $criteria), but in some cases its not enough - for example you want to do proper joins or use a custom query. Creating yet another action to change the method called could be
a solution but there is a better way. The configuration below will use a custom repository method to get the resource.
# routing.yml
app_user_show:
path: /users/{username}
methods: [GET]
defaults:
_controller: app.controller.user:showAction
_sylius:
repository:
method: findOneWithFriends
arguments: [$username]
185
Sylius, Release
defaults:
_controller: app.controller.user:indexAction
When you go to /users, ResourceController will use the repository (app.repository.user) to create a
paginator. The default template will be rendered - App:User:index.html.twig with the paginator as the
users variable. A paginator can be a simple array if you disable the pagination otherwise it is a instance of
Pagerfanta\Pagerfanta which is the library used to manage the pagination.
Overriding the template and criteria
Just like for the showAction, you can override the default template and criteria.
# routing.yml
app_user_index_inactive:
path: /users/inactive
methods: [GET]
defaults:
_controller: app.controller.user:indexAction
_sylius:
criteria:
enabled: false
template: App:User:inactive.html.twig
This action will render a custom template with a paginator only for disabled users.
Sorting collection or paginator
Under that route, you can paginate over the users by their score.
Using a custom repository method
You can define your own repository method too, you can use the same way explained in show_resource.
Note:
If
you
want
to
paginate
your
resources
you
need
to
use
EntityRepository::getPaginator($queryBuilder). It will transform your doctrine query builder into
Pagerfanta\Pagerfanta object.
186
Chapter 7. Bundles
Sylius, Release
You can also control the max per page for paginator, using paginate parameter.
# routing.yml
app_user_index_top:
path: /users/top
methods: [GET]
defaults:
_controller: app.controller.user:indexAction
_sylius:
paginate: 5
sortable: true
sorting:
score: desc
template: App:User:top.html.twig
Pagination is handy, but you do not always want to do it, you can disable pagination and simply request a collection
of resources.
# routing.yml
app_user_index_top3:
path: /users/top
methods: [GET]
defaults:
_controller: app.controller.user:indexAction
_sylius:
paginate: false
limit: 3
sortable: true
sorting:
score: desc
template: App:User:top3.html.twig
That action will return the top 3 users by score, as the users variable.
Updating the position of your resource
You need to define two routes, they will use to update the position of the resource.
# routing.yml
my_route_move_up:
pattern: /{id}/move-up
methods: [PUT]
defaults:
_controller: sylius.controller.resource:moveUpAction
_sylius:
redirect: referer
sortable_position: priority # the default value is position
187
Sylius, Release
my_route_move_down:
pattern: /{id}/move-down
methods: [PUT]
defaults:
_controller: sylius.controller.resource:moveDownAction
_sylius:
redirect: referer
sortable_position: priority # the default value is position
In your template, you can use the macro move to print the move up and move down buttons:
{# index.html.twig #}
{% import 'SyliusResourceBundle:Macros:buttons.html.twig' as buttons %}
Listing tools
Sorting your resources (sylius_resource_sort) This TWIG extension renders the title of your columns (in your
table), it created the link used to sort your resources. You will need to enable it per route
# routing.yml
app_user_index:
path: /users
methods: [GET]
defaults:
_controller: app.controller.user:indexAction
sortable: true
or globally
# config.yml
sylius_resource:
settings:
sortable: true
188
Chapter 7. Bundles
Sylius, Release
Parameters
Parameter
property
label
order
options
NO
NO
NO
string
string
array
This extension renders the following template : SyliusResourceBundle:Twig:sorting.html.twig. You will need to
enable it per route
# routing.yml
app_user_index:
path: /users
methods: [GET]
defaults:
_controller: app.controller.user:indexAction
paginate: $paginate
or globally
# config.yml
sylius_resource:
settings:
paginate: $paginate
Example
<table>
<tr>
<td>
{{ sylius_resource_sort('productId', 'product.id'|trans) }}
</td>
<td>
{{ sylius_resource_sort('productName', 'product.name'|trans, 'desc', {'route': 'my_custom
</td>
</tr>
<table>
Number of item by page (sylius_resource_paginate) This TWIG extension renders a HTML select which allows
the user to choose how many items he wants to display in the page.
Parameters
Parameter
paginator
limits
options
YES
NO
189
Sylius, Release
Example
{{ sylius_resource_paginate(paginator, [10, 30, 50]) }}
<table>
<!-- ... -->
</table>
{{ sylius_resource_paginate(paginator, [10, 30, 50]) }}
Rendering pagination For now, you need to create your own macro, it could look like :
{% macro pagination(paginator, options) %}
{% if paginator.haveToPaginate()|default(false) %}
{{ pagerfanta(paginator, 'twitter_bootstrap3_translated', options|default({})) }}
{% endif %}
{% endmacro %}
Done! Now when you go to /users/new, ResourceController will use the repository (app.repository.user)
to create new user instance. Then it will try to create an app_user form, and set the newly created user as data.
Note: Currently, this bundle does not generate a form for you, the right form type has to be created and registered in
the container manually.
As a response, it will render the App:User:create.html.twig template with form view as the form variable.
Declaring your form as a service
As said previously, you need to declare your form as a service. Its name must be contructed with the following pattern
application_resource (Example: sylius_product). (see the Configuration chapter to see how configure
your resources and your application name)
<parameters>
<!-- If you use the basic configuration this paramter is not available in the container. You need
<parameter key="app.form.type.user.class">App\Bundle\Form\UserType</parameter>
</parameters>
<services>
<service id="app.form.type.user" class="%app.form.type.user.class%">
<tag name="form.type" alias="app_user" />
</service>
</services>
190
Chapter 7. Bundles
Sylius, Release
You can use exactly the same route to handle the submit of the form and create the user.
<form method="post" action="{{ path('app_user_create') }}">
On submit, the create action with method POST, will bind the request on the form, and if it is valid it will use the right
manager to persist the resource. Then, by default it redirects to app_user_show to display the created user, but you
can easily change that behavior - youll see this in later sections.
When validation fails, it will render the form just like previously with the errors to display.
Changing the template
Just like for the show and index actions, you can customize the template per route.
# routing.yml
app_user_create:
path: /users/new
methods: [GET, POST]
defaults:
_controller: app.controller.user:createAction
_sylius:
template: App:Backend/User:create.html.twig
You can also use custom form type on per route basis. By default it generates the form type name following the simple
convention bundle prefix + _ + resource logical name. Below you can see the usage for specifying
a custom form.
# routing.yml
app_user_create:
path: /users/new
methods: [GET, POST]
defaults:
_controller: app.controller.user:createAction
_sylius:
template: App:Backend/User:create.html.twig
form: app_user_custom
191
Sylius, Release
By default, ResourceController will use the createNew method with no arguments to create a new instance
of your object. However, this behavior can be modified. To use different method of your repository, you can simply
configure the factory option.
# routing.yml
app_user_create:
path: /users/new
methods: [GET, POST]
defaults:
_controller: app.controller.user:createAction
_sylius:
factory: createNewWithGroups
Additionally, if you want to provide your custom method with arguments from the request, you can do so by adding
more parameters.
# routing.yml
app_user_create:
path: /users/{groupId}/new
methods: [GET, POST]
defaults:
_controller: app.controller.user:createAction
_sylius:
factory:
method: createNewWithGroups
arguments: [$groupId]
By default the controller will try to get the id of the newly created resource and redirect to the show route. You can
easily change that. For example, to redirect user to list after successfully creating a new resource - you can use the
following configuration.
# routing.yml
app_user_create:
path: /users/new
methods: [GET, POST]
defaults:
_controller: app.controller.user:createAction
_sylius:
redirect: app_user_index
You can also perform more complex redirects, with parameters. For example...
# routing.yml
app_user_create:
path: /competition/{competitionId}/users/new
methods: [GET, POST]
192
Chapter 7. Bundles
Sylius, Release
defaults:
_controller: app.controller.user:createAction
_sylius:
redirect:
route: app_competition_show
parameters: { id: $competitionId }
In addition to the request parameters, you can access some of the newly created objects properties, using the
resource. prefix.
# routing.yml
app_user_create:
path: /users/new
methods: [GET, POST]
defaults:
_controller: app.controller.user:createAction
_sylius:
redirect:
route: app_user_show
parameters: { email: resource.email }
With this configuration, the email parameter for route app_user_show will be obtained from your newly created
user.
Updating existing resource
To display an edit form of a particular resource, change it or update it via API, you should use the updateAction
action of your app.controller.user service.
# routing.yml
app_user_update:
path: /users/{id}/edit
methods: [GET, PUT]
defaults:
_controller: app.controller.user:updateAction
Done!
Now when you go to /users/5/edit, ResourceController will use the repository
(app.repository.user) to find the user with ID === 5. If found it will create the app_user form,
and set the existing user as data.
Note: Currently, this bundle does not generate a form for you, the right form type has to be updated and registered in
the container manually.
As a response, it will render the App:User:update.html.twig template with form view as the form variable
and the existing User as the user variable.
Submitting the form
You can use exactly the same route to handle the submit of the form and update the user.
<form method="post" action="{{ path('app_user_update', {'id': user.id}) }}">
<input type="hidden" name="_method" value="PUT" />
193
Sylius, Release
On submit, the update action with method PUT, will bind the request on the form, and if it is valid it will use the right
manager to persist the resource. Then, by default it redirects to app_user_show to display the updated user, but
like for creation of the resource - its customizable.
When validation fails, it will simply render the form again.
Changing the template
Just like for other actions, you can customize the template.
# routing.yml
app_user_update:
path: /users/{id}/edit
methods: [GET, PUT]
defaults:
_controller: app.controller.user:updateAction
_sylius:
template: App:Backend/User:update.html.twig
Same way like for createAction you can override the default form.
# routing.yml
app_user_update:
path: /users/{id}/edit
methods: [GET, PUT]
defaults:
_controller: app.controller.user:updateAction
_sylius:
template: App:Backend/User:update.html.twig
form: app_user_custom
By default, the updateAction will look for the resource by id. You can easily change that criteria.
# routing.yml
app_user_update:
path: /users/{username}/edit
methods: [GET, PUT]
defaults:
_controller: app.controller.user:updateAction
_sylius:
criteria: { username: $username }
By default the controller will try to get the id of resource and redirect to the show route. To change that, use the
following configuration.
194
Chapter 7. Bundles
Sylius, Release
# routing.yml
app_user_update:
path: /users/{id}/edit
methods: [GET, PUT]
defaults:
_controller: app.controller.user:updateAction
_sylius:
redirect: app_user_index
You can also perform more complex redirects, with parameters. For example...
# routing.yml
app_user_update:
path: /competition/{competitionId}/users/{id}/edit
methods: [GET, PUT]
defaults:
_controller: app.controller.user:updateAction
_sylius:
redirect:
route: app_competition_show
parameters: { id: $competitionId }
Deleting resource
Deleting a resource is simple.
# routing.yml
app_user_delete:
path: /users/{id}
methods: [DELETE]
defaults:
_controller: app.controller.user:deleteAction
Currently browsers do not support the DELETE http method. Fortunately, Symfony has a very useful feature. You
can make a POST call with override parameter, which will force the framework to treat the request as specified method.
<form method="post" action="{{ path('app_user_delete', {'id': user.id}) }}">
<input type="hidden" name="_method" value="DELETE" />
<button type="submit">
Delete
</button>
</form>
On submit, the delete action with the method DELETE, will remove and flush the resource. Then, by default it redirects
to app_user_index to display the users index, but like for other actions - its customizable.
Overriding the criteria
By default, the deleteAction will look for the resource by id. However, you can easily change that. For example, you
want to delete the user who belongs to particular company, not only by his id.
7.1. Symfony2 Ecommerce Bundles
195
Sylius, Release
# routing.yml
app_user_delete:
path: /companies/{companyId}/users/{id}
methods: [DELETE]
defaults:
_controller: app.controller.user:deleteAction
_sylius:
criteria:
id:
$id
company: $companyId
There are no magic hacks behind that, it simply takes parameters from request and builds the criteria array for the
findOneBy repository method.
Custom redirect after success
By default the controller will try to get the id of the resource and redirect to the index route. To change that, use the
following configuration.
# routing.yml
app_user_delete:
path: /competition/{competitionId}/users/{id}
methods: [DELETE]
defaults:
_controller: app.controller.user:deleteAction
_sylius:
redirect:
route: app_competition_show
parameters: { id: $competitionId }
196
Chapter 7. Bundles
Sylius, Release
For the current this resource, you can use my_app.entity_key.create, my_app.entity_key.update
and my_app.entity_key.delete in your translation files.
Note:
Caution: The domain used for translating flash messages is flashes.
flashes.locale.yml (Exemple: flashes.en.yml).
Doctrine tools
This bundle allow you easy usage of two extra doctrine tools: MappingDriver and ResolveDoctrineTargetEntitiesPass.
The first one allow you to put your models (entities, document, etc) and their mappings in specific directories. The
second one define relationships between different entities without making them hard dependencies. We will explain
how you can enable them in the next chapters.
Note: Caution : these tools are facultatives!
Creating a MappingDriver
class MyBundle extends AbstractResourceBundle
{
// You can specify your mapping format (xml, yaml, annotation), by defaut xml is used.
protected $mappingFormat = ResourceBundleInterface::MAPPING_XML;
// You need to specify a prefix for your bundle
protected function getBundlePrefix()
{
return 'app_bundle_name';
}
// You need specify the namespace where are stored your models
protected function getModelNamespace()
{
return 'MyApp\MyBundle\Model';
}
// You can specify the path where are stored the doctrine mapping, by default this method will re
// model. This path is relative to the Resources/config/doctrine/.
protected function getDoctrineMappingDirectory()
{
return 'model';
}
}
197
Sylius, Release
// You need to specify the mapping between your interfaces and your models. Like the following ex
// get the classname of your model in the container (See the following chapter for more informati
protected function getModelInterfaces()
{
return array(
'MyApp\MyBundle\ModelInterface' => 'sylius.model.resource.class',
);
}
}
Doctrine mapping
This bundle use the loadClassMetadata doctrine event which occurs after the mapping metadata for a class has
been loaded from a mapping source (annotations/xml/yaml). Every models can be declared as mapped superclass,
this listener will transform them in an entity or document if they have not child.
With this following mapping, Doctrine will create the table my_table with the column name.
<!-- Resource/config/Model.orm.xml-->
<doctrine-mapping xmlns="http://doctrine-project.org/schemas/orm/doctrine-mapping"
xmlns:gedmo="http://gediminasm.org/schemas/orm/doctrine-extensions-mapping">
<mapped-superclass name="My/Bundle/Model" table="my_table">
<id name="id" column="id" type="integer">
<generator strategy="AUTO" />
</id>
<field name="name" column="name" type="string" />
</mapped-superclass>
</doctrine-mapping>
If you want to add an extra field, you can create a new model which extends My/Bundle/Model and its doctrine
mapping like that :
<!-- Resource/config/NewModel.orm.xml-->
<doctrine-mapping xmlns="http://doctrine-project.org/schemas/orm/doctrine-mapping"
xmlns:gedmo="http://gediminasm.org/schemas/orm/doctrine-extensions-mapping">
<entity name="My/OtherBundle/NewModel" table="my_new_table">
<field name="description" column="name" type="string" />
</entity>
</doctrine-mapping>
Extra tools
Parameters parser
For each route defined the parameter parser allow you to find extra data in the current request, in the resource previously
created by using the PropertyAccess component or by using the Expression Language component
198
Chapter 7. Bundles
Sylius, Release
Request You need use the following syntax $var_name. It will try to find in the request the key named var_name
$request->get(var_name).
# routing.yml
app_user_index:
path: /products
methods: [GET]
defaults:
_controller: app.controller.user:indexAction
_sylius:
criteria: {name: $name}
Resource previously created You need use the following syntax resource.attribute_name. It will try to find the
value of the attribute name named attribute_name $accessor->getValue($resource, attribute_name)).
# routing.yml
app_user_index:
path: /products
methods: [POST]
defaults:
_controller: app.controller.user:indexAction
_sylius:
redirect:
route: my_route
parameters: {name: resource.name}
Expression Language component You need use the following syntax expr:resource.my_expression.
# routing.yml
app_user_index:
path: /customer/orders
methods: [POST]
defaults:
_controller: app.controller.user:indexAction
_sylius:
repository:
method: findOrderByCustomer
arguments: ['expr:service("security.context").getToken().getUser()']
Note:
service: returns a given service (see the example above);
parameter: returns a specific parameter value, aka: expr:parameter("sylius.locale")
Event Dispatcher
199
Sylius, Release
First, you need to register event listeners, the following example show you how you can do that.
# services.xml
<service id="my_listener" class="MyBundle\MyEventListener">
<tag name="kernel.event_listener" event="sylius.order.pre_create" method="onOrderPreCreate"/>
</service>
# services.yml
services:
my_listener:
class: MyBundle\MyEventListener
tags:
- { name: kernel.event_listener, event: sylius.order.pre_create, method: onOrderPreCreate
Note: Caution: you can use subscribers too, you can get more informations there.
Custom actions
Note: To be written.
Building a API
Header parameter parser
The header parameter parser will find the version and the validation group in the HTTP headers to give them to the
JmsSerializerBundle
Accept: application/json; version=1.0.1; groups=Sylius,Details
In serializer configuration files, you can filter the data that you want to send by using the field called
since_version, until_version and group. The following example show you how it works. The lastname
wont be return after the version 0.3 and the firstname will be returned after the version 0.2. You can play with
groups to return a part of data depending on specifics cases like the symfony form.
200
Chapter 7. Bundles
Sylius, Release
# src/App/Bundle/YourBundle/Resources/serializer/Entity.User.yml
App\Bundle\YourBundle\Entity\User:
exclusion_policy: ALL
properties:
id:
expose: true
type: integer
groups: [Sylius, Details]
firstName:
expose: true
type: string
since_version: 0.2
groups: [Sylius]
lastName:
expose: true
type: string
until_version: 0.3
groups: [Details]
Routes for your API will be automatically generated by ApiLoader class. The resource is the concatenation of the
application and resource name.
api_resource:
resource: my_api.resource
type: sylius.api
GET
GET
POST
PUT|PATCH
DELETE
ANY
ANY
ANY
ANY
ANY
ANY
ANY
ANY
ANY
ANY
/resources/
/resources/{id}
/resources/
/resources/{id}
/resources/{id}
201
Sylius, Release
In this example, the value of the select and the position will be sent to the server.
Another way exists, hidden inputs can be used too if you dont want to generate the prototype by the server. You
need to insert as many hidden inputs as select options in the page. They need to have attribute like data-formprototype=prototypeName. prototypeName needs to match to one of all the select options.
202
Chapter 7. Bundles
Sylius, Release
In this example, when you select Rule, the plugin will replace the current form prototype by the value of the hidden
input which has data-form-prototype=rule.
Activation You need to use the jquery plugin and the form theme provided by this bundle.
{% javascripts
'bundles/syliusresource/js/form-collection.js'
%}
<script type="text/javascript" src="{{ asset(asset_url) }}"></script>
{% endjavascripts %}
twig:
form:
resources:
- SyliusResourceBundle::form-collection.html.twig
It creates a input type hidden, its value will be the identifier of the resource. you need to specify the class (data_class)
will be used and the property (identifier) that you want to get.
In the following example, we will add the sku of the product in the form.
ProductType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('product', 'entity_hidden', array(
'data_class' => 'App\Bundle\Product\Model\Product'
'identifier' => 'sku'
))
;
}
}
It creates a document or entity or phpcr_document form type depending on the driver used by the resource. You need
to register it as a service, its contructor requires three paramters, the first one is the FQDN of the resource, the second
203
Sylius, Release
one is the driver used by it and the last on is the name of the form type.
services:
app.form.type.entity:
class:
argument:
- App/Bundle/Model/Product
- doctrine/orm
- product_choice
Note: Caution : If you use the advanced configuration, the resource extension will register it automatically.
Summary
Configuration reference
sylius_resource:
settings:
# Enable pagination
paginate: true
# If the pagination is disabled, you can specify a limit
limit: false
# If the pagination is enabled, you can specify the allowed page size
allowed_paginate: [10, 20, 30]
# Default page size
default_page_size: 10
# Enable sorting
sortable: false
# Default sorting parameters
sorting: []
# Enable filtering
filterable: false
# Default filtering parameters
criteria: []
resources:
app.user:
driver: doctrine/orm # Also supported - doctrine/mongodb-odm.
templates: AppBundle:User
classes:
model: App\Entity\User
controller: Sylius\Bundle\ResourceBundle\Controller\ResourceController
repository: Sylius\Bundle\ResourceBundle\Doctrine\ORM\EntityRepository
204
Chapter 7. Bundles
Sylius, Release
parameters: [] # array
# Number of item in the list (should be set to false if you want to disable it)
limit: 10 # integer or boolean
# Number of item by page (should be set to false if you want to disable it)
paginate: 10 # integer or boolean
# Enabling the filter
filterable: true # boolean
# Parameter used for filtering resources when filterable is enabled, using a $ to find th
criteria: $paginate # string or array
# Enabling the sorting
sortable: false # boolean
# Parameter used for sorting resources when sortable is enabled, using a $ to find the pa
sorting: $sorting # string or array
repository:
# The method of the repository used to retrieve resources
method: findActiveProduct # string
# Arguments gave to the 'method'
arguments: [] # array
factory:
# The method of the repository used to create the new resource
method: createNew # string
# Arguments gave to the 'method'
arguments: [] # array
# Key used by the translator for managing flash messages, by default it is built with the
flash: sylius.product.create # string
# Name of the property used to manage the position of the resource
sortable_position: position # string
# API request, version used by the serializer
serialization_version: null
# API request, groups used by the serializer
serialization_groups: []
phpspec2 examples
$ composer install --dev --prefer-dist
$ bin/phpspec run -fpretty --verbose
Bug tracking
This bundle uses GitHub issues. If you have found bug, please create an issue.
7.1.16 SyliusSettingsBundle
Settings system with web editing interface for Symfony2 applications.
Allowing application users to edit some global configuration and storing it in database is a common need in a variety
of projects. This bundle provides exactly this feature - you only need to define the configuration.
Installation
We assume youre familiar with Composer, a dependency manager for PHP. Use the following command to add the
bundle to your composer.json and download the package.
205
Sylius, Release
First, you need to enable the bundle inside the kernel. If youre not using any other Sylius bundles, you will also need
to add SyliusResourceBundle and its dependencies to the kernel. This bundle also uses DoctrineCacheBundle. Dont
worry, everything was automatically installed via Composer.
<?php
// app/AppKernel.php
public function registerBundles()
{
$bundles = array(
new FOS\RestBundle\FOSRestBundle(),
new JMS\SerializerBundle\JMSSerializerBundle($this),
new Stof\DoctrineExtensionsBundle\StofDoctrineExtensionsBundle(),
new Doctrine\Bundle\DoctrineCacheBundle\DoctrineCacheBundle(),
new WhiteOctober\PagerfantaBundle\WhiteOctoberPagerfantaBundle(),
new Sylius\Bundle\SettingsBundle\SyliusSettingsBundle(),
new Sylius\Bundle\ResourceBundle\SyliusResourceBundle(),
// Other bundles...
new Doctrine\Bundle\DoctrineBundle\DoctrineBundle(),
);
}
Note: Please register the bundle before DoctrineBundle. This is important as we use listeners which have to be
processed first.
Container configuration
206
Chapter 7. Bundles
Sylius, Release
sylius_settings:
resource: @SyliusSettingsBundle/Resources/config/routing.yml
prefix: /settings
Note: We used default namespace in this example. If you want to use other namespaces for saving your settings,
routing config should be updated as it contains the namespace parameter.
Warning: This should be done only in dev environment! We recommend using Doctrine migrations, to safely
update your schema.
207
Sylius, Release
->add('meta_description', 'textarea')
;
}
}
A proper form will be generated, with a submit action, which updates the settings in database.
Using in templates
Bundle provides handy SyliusSettingsExtension which you can use in your templates.
In our example, it can be something like:
{% set meta = sylius_settings_all('meta') %}
<head>
<title>{{ meta.title }}</title>
<meta name="keywords" content="{{ meta.meta_keywords }}">
<meta name="description" content="{{ meta.meta_description }}">
</head>
Chapter 7. Bundles
Sylius, Release
Note: To be written.
Summary
Configuration Reference
sylius_settings:
# The driver used for persistence layer.
driver: ~
classes:
parameter:
model: Sylius\Bundle\SettingsBundle\Model\Parameter
controller: Sylius\Bundle\ResourceBundle\Controller\ResourceController
repository: ~
form: Sylius\Bundle\SettingsBundle\Form\Type\ParameterType
209
Sylius, Release
Tests
$ composer install --dev --prefer-dist
$ bin/phpspec run -fpretty --verbose
Bug tracking
This bundle uses GitHub issues. If you have found bug, please create an issue.
7.1.17 SyliusShippingBundle
SyliusShippingBundle is the shipment management component for Symfony2 e-commerce applications.
If you need to manage shipments, shipping methods and deal with complex cost calculation, this bundle can help you
a lot!
Your products or whatever you need to deliver, can be categorized under unlimited set of categories. You can display
appropriate shipping methods available to the user, based on object category, weight, dimensions and anything you
can imagine.
Flexible shipping cost calculation system allows you to create your own calculator services.
Installation
We assume youre familiar with Composer, a dependency manager for PHP. Use the following command to add the
bundle to your composer.json and download package.
If you have Composer installed globally.
$ composer require "sylius/shipping-bundle"
210
Chapter 7. Bundles
Sylius, Release
new Sylius\Bundle\ShippingBundle\SyliusShippingBundle(),
new Sylius\Bundle\ResourceBundle\SyliusResourceBundle(),
// Other bundles...
new Doctrine\Bundle\DoctrineBundle\DoctrineBundle(),
);
}
Note: Please register the bundle before DoctrineBundle. This is important as we use listeners which have to be
processed first.
Container configuration
Routing configuration
Warning: This should be done only in dev environment! We recommend using Doctrine migrations, to safely
update your schema.
The ShippableInterface
In order to handle your merchandise through the Sylius shipping engine, your models need to implement ShippableInterface.
Implementing the interface
211
Sylius, Release
First step is to implement the simple interface, which contains few simple methods.
namespace Acme\Bundle\ShopBundle\Entity;
use Sylius\Component\Shipping\Model\ShippableInterface;
use Sylius\Component\Shipping\Model\ShippingCategoryInterface;
class Book implements ShippableInterface
{
private $shippingCategory;
public function getShippingCategory()
{
return $this->shippingCategory;
}
Second and last task is to define the relation inside Resources/config/doctrine/Book.orm.xml of your
bundle.
<?xml version="1.0" encoding="UTF-8"?>
<doctrine-mapping xmlns="http://doctrine-project.org/schemas/orm/doctrine-mapping"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://doctrine-project.org/schemas/orm/doctrine-mapping
http://doctrine-project.org/schemas/orm/doctrine-mapping.xsd">
<entity name="Acme\ShopBundle\Entity\Book" table="acme_book">
<!-- your mappings... -->
212
Chapter 7. Bundles
Sylius, Release
</many-to-one>
</entity>
</doctrine-mapping>
Done! Now your Book model can be used in Sylius shippingation engine.
Forms
If you want to add a shipping category selection field to your model form,
sylius_shipping_category_choice type.
namespace Acme\ShopBundle\Form\Type;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\Form\AbstractType;
class BookType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('title', 'text')
->add('shippingCategory', 'sylius_shipping_category_choice')
;
}
}
The ShippingSubjectInterface
The find available shipping methods or calculate shipping cost you need to use object implementing
ShippingSubjectInterface.
The default Shipment model is already implementing ShippingSubjectInterface.
Interface methods
213
Sylius, Release
Attribute
id
name
description
createdAt
updatedAt
Description
Unique id of the shipping category
Name of the shipping category
Human friendly description of the classification
Date when the category was created
Date of the last shipping category update
The flexible_rate calculator, charges one price for the first item, and another price for every other item.
Weight rate
The weight_rate calculator, charges one price for certain weight of shipment. So if the shipment weights 5 kg,
and calculator is configured to charge $4 per kg, the final price is $20.
214
Chapter 7. Bundles
Sylius, Release
More calculators
Depending on community contributions and Sylius resources, more default calculators can be implemented, for example weight_range_rate.
Custom calculators
Sylius ships with several default calculators, but you can easily register your own.
Simple calculators
All shipping cost calculators implement CalculatorInterface. In our example well create a calculator which
calls an external API to obtain the shipping cost.
<?php
// src/Acme/ShopBundle\Shipping/DHLCalculator.php
namespace Acme\ShopBundle\Shipping;
use Acme\ShopBundle\Shipping\DHLService;
use Sylius\Bundle\ShippingBundle\Calculator\Calculator;
use Sylius\Bundle\ShippingBundle\Model\ShippingSubjectInterface;
class DHLCalculator extends Calculator
{
private $dhlService;
public function __construct(DHLService $dhlService)
{
$this->dhlService = $dhlService;
}
public function calculate(ShippingSubjectInterface $subject, array $configuration)
{
return $this->dhlService->getShippingCostForWeight($subject->getShippingWeight());
}
}
Now, you need to register your new service in container and tag it with sylius.shipping_calculator.
<?xml version="1.0" encoding="UTF-8"?>
<container xmlns="http://symfony.com/schema/dic/services"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://symfony.com/schema/dic/services
http://symfony.com/schema/dic/services/services-1.0.xsd">
<services>
<service id="acme.shipping_calculator.dhl" class="Acme\ShopBundle\Shipping\DHLCalculator">
<argument type="service" id="acme.dhl_service" />
<tag name="sylius.shipping_calculator" calculator="dhl" label="DHL" />
</service>
</services>
</container>
215
Sylius, Release
That would be all. This new option (DHL) will appear on the ShippingMethod creation form, in the calculator
field.
Configurable calculators
You can also create configurable calculators, meaning that you can have several ShippingMethods using same type
of calculator, with different settings.
Lets modify the DHLCalculator, so that it charges 0 if shipping more than X items. First step is to define the
configuration options, using the Symfony OptionsResolver component.
<?php
// src/Acme/ShopBundle\Shipping/DHLCalculator.php
namespace Acme\ShopBundle\Shipping;
use
use
use
use
Acme\ShopBundle\Shipping\DHLService;
Sylius\Bundle\ShippingBundle\Calculator\Calculator;
Sylius\Bundle\ShippingBundle\Model\ShippingSubjectInterface;
Symfony\Component\OptionsResolver\OptionsResolverInterface;
Done, weve set the default item limit to 10. Now we have to create a form type which will be displayed if our
216
Chapter 7. Bundles
Sylius, Release
calculator is selected.
<?php
// src/Acme/ShopBundle/Form/Type/Shipping/DHLConfigurationType.php
namespace Acme\ShopBundle\Form\Type\Shipping;
use
use
use
use
use
Symfony\Component\Form\AbstractType;
Symfony\Component\Form\FormBuilderInterface;
Symfony\Component\OptionsResolver\OptionsResolverInterface;
Symfony\Component\Validator\Constraints\NotBlank;
Symfony\Component\Validator\Constraints\Type;
We also need to register the form type and the calculator in the container.
<?xml version="1.0" encoding="UTF-8"?>
<container xmlns="http://symfony.com/schema/dic/services"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://symfony.com/schema/dic/services
http://symfony.com/schema/dic/services/services-1.0.xsd">
<services>
<service id="acme.shipping_calculator.dhl" class="Acme\ShopBundle\Shipping\DHLCalculator">
<argument type="service" id="acme.dhl_service" />
<tag name="sylius.shipping_calculator" calculator="dhl" label="DHL" />
</service>
<service id="acme.form.type.shipping_calculator.dhl" class="Acme\ShopBundle\Form\Type\Shippin
217
Sylius, Release
Finally, configure the calculator to use the form, by implementing simple getConfigurationFormType method.
<?php
// src/Acme/ShopBundle\Shipping/DHLCalculator.php
namespace Acme\ShopBundle\Shipping;
use
use
use
use
Acme\ShopBundle\Shipping\DHLService;
Sylius\Bundle\ShippingBundle\Calculator\Calculator;
Sylius\Bundle\ShippingBundle\Model\ShippingSubjectInterface;
Symfony\Component\OptionsResolver\OptionsResolverInterface;
Perfect, now were able to use the configuration inside the calculate method.
218
Chapter 7. Bundles
Sylius, Release
<?php
// src/Acme/ShopBundle\Shipping/DHLCalculator.php
namespace Acme\ShopBundle\Shipping;
use
use
use
use
Acme\ShopBundle\Shipping\DHLService;
Sylius\Bundle\ShippingBundle\Calculator\Calculator;
Sylius\Bundle\ShippingBundle\Model\ShippingSubjectInterface;
Symfony\Component\OptionsResolver\OptionsResolverInterface;
Your new configurable calculator is ready to use. When you select the DHL calculator in ShippingMethod form,
configuration fields will appear automatically.
219
Sylius, Release
Every ShippableInterface can hold a reference to ShippingCategory. The ShippingSubjectInterface (or ShipmentInterface) returns a collection of shippables.
ShippingMethod has an optional shipping category setting as well as categoryRequirement which has 3 options. If
this setting is set to null, categories system is ignored.
Match any requirement With this requirement, the shipping method will support any shipment (or shipping
subject) which contains at least one shippable with the same category.
Match all requirement All shippables have to reference the same category as the ShippingMethod.
Match none requirement None of the shippables can have the same shipping category.
Shipping rules
The categories system is sufficient for basic use cases, for more advanced requirements, Sylius has the shipping rules
system.
Every ShippingMethod can have a collection of ShippingRule instances. Each shipping rule, has a checker and
configuration assigned. The ShippingRule.checker attribute holds the alias name of appropriate service implementing RuleCheckerInterface. Just like with cost calculators, Sylius ships with default checkers, but you can easily
implement your own.
The ShippingMethodEligibilityChecker service can check if given subject, satisfies the category and shipping rules.
Default rule checkers
Sylius ships with several shipping rule checker types, so you can easily decide whether the shipping method is applicable to given shipment.
Item count
The item_count checker, accepts the subject only if the items count fits into min and max range.
You can configure a method, which will be available only if the shipment contains more than 5 items, but less than 20.
Item total
The item_total checker, is testing if the shipping subject total value is more than configured minimum, or eventually, less than maximum.
220
Chapter 7. Bundles
Sylius, Release
Weight
The weight checker, allows to ship the shipment using the particular method, only if the shipment weight falls into
the configure min and max range.
More checkers
Depending on community contributions and Sylius resources, more default checkers can be implemented.
Custom rule checkers
Implementing a custom rule checker is really simple, just like calculators, you can use simple services, or more
complex - configurable checkers.
Simple checkers
Note: To be written.
Configurable calculators
Note: To be written.
Summary
Configuration Reference
sylius_shipping:
# The driver used for persistence layer.
driver: ~
classes:
shipment:
model: Sylius\Component\Shipping\Model\Shipment
controller: Sylius\Bundle\ResourceBundle\Controller\ResourceController
repository: ~
form: Sylius\Bundle\ShippingBundle\Form\Type\ShipmentType
shipment_item:
model: Sylius\Component\Shipping\Model\ShipmentItem
controller: Sylius\Bundle\ResourceBundle\Controller\ResourceController
repository: ~
form: Sylius\Bundle\ShippingBundle\Form\Type\ShipmentItemType
shipping_method:
model: Sylius\Component\Shipping\Model\ShippingMethod
controller: Sylius\Bundle\ResourceBundle\Controller\ResourceController
repository: ~
form: Sylius\Bundle\ShippingBundle\Form\Type\ShippingMethodType
shipping_method_rule:
model: Sylius\Component\Shipping\Model\ShippingMethodRule
controller: Sylius\Bundle\ResourceBundle\Controller\ResourceController
221
Sylius, Release
repository: ~
form: Sylius\Bundle\ShippingBundle\Form\Type\ShippingMethodRuleType
shipping_method_rule:
model: Sylius\Component\Shipping\Model\Rule
controller: Sylius\Bundle\ResourceBundle\Controller\ResourceController
repository: ~
form: Sylius\Bundle\ShippingBundle\Form\Type\RuleType
validation_groups:
shipping_category: [sylius]
shipping_method: [sylius]
shipping_rule_item_count_configuration: [sylius]
shipping_calculator_flat_rate_configuration: [sylius]
shipping_calculator_per_item_rate_configuration: [sylius]
shipping_calculator_flexible_rate_configuration: [sylius]
shipping_calculator_weight_rate_configuration: [sylius]
Tests
$ composer install --dev --prefer-dist
$ bin/phpspec run -fpretty --verbose
Bug tracking
This bundle uses GitHub issues. If you have found bug, please create an issue.
7.1.18 SyliusTaxationBundle
Calculating and applying taxes is a common task for most of ecommerce applications. SyliusTaxationBundle is a
reusable taxation component for Symfony2. You can integrate it into your existing application and enable the tax
calculation logic for any model implementing the TaxableInterface.
It supports different tax categories and customizable tax calculators - youre able to easily implement your own calculator services. The default implementation handles tax included in and excluded from the price.
As with any Sylius bundle, you can override all the models, controllers, repositories, forms and services.
Installation
We assume youre familiar with Composer, a dependency manager for PHP. Use the following command to add the
bundle to your composer.json and download package.
If you have Composer installed globally.
$ composer require "sylius/taxation-bundle"
222
Chapter 7. Bundles
Sylius, Release
Note: Please register the bundle before DoctrineBundle. This is important as we use listeners which have to be
processed first.
Container configuration
Routing configuration
223
Sylius, Release
Warning: This should be done only in dev environment! We recommend using Doctrine migrations, to safely
update your schema.
The TaxableInterface
In order to calculate the taxes for a model in your application, it needs to implement the TaxableInterface It is a
very simple interface, with only one method - the getTaxCategory(), as every taxable has to belong to a specific
tax category.
Implementing the interface
Lets assume that you have a Server entity in your application. Every server has its price and other parameters, but
you would like to calculate the tax included in price. You could calculate the math in a simple method, but its not
enough when you have to handle multiple tax rates, categories and zones.
First step is to implement the simple interface.
namespace AcmeBundle\Entity;
use Sylius\Component\Taxation\Model\TaxCategoryInterface;
use Sylius\Component\Taxation\Model\TaxableInterface;
class Server implements TaxableInterface
{
private $name;
private $taxCategory;
public function getName()
{
return $this->name;
}
public function setName($name)
{
$this->name = $name;
}
public function getTaxCategory()
{
return $this->taxCategory;
}
224
Chapter 7. Bundles
Sylius, Release
<doctrine-mapping xmlns="http://doctrine-project.org/schemas/orm/doctrine-mapping"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://doctrine-project.org/schemas/orm/doctrine-mapping
http://doctrine-project.org/schemas/orm/doctrine-mapping.xsd">
<entity name="AcmeBundle\Entity\Server" table="acme_server">
<!-- your mappings... -->
Done! Now your Server model can be used in Sylius taxation engine.
Forms
selection
field
to
your
model
form,
simply
use
the
namespace AcmeBundle\Form\Type;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\Form\AbstractType;
class ServerType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('name', 'text')
->add('taxCategory', 'sylius_tax_category_choice')
;
}
public function getName()
{
return 'acme_server';
}
}
Configuring taxation
To start calculating taxes, we need to configure the system. In most cases, the configuration process is done via web
interface, but you can also do it programatically.
Creating the tax categories
225
Sylius, Release
Second thing to do is to classify the taxables, in our example well get two products and assign the proper categories
to them.
<?php
public function configureAction()
{
$tshirt = // ...
$banana = // ... Some logic behind loading entities.
$repository = $this->container->get('sylius.repository.tax_category');
$clothing = $repository->findOneBy(array('name' => 'Clothing'));
$food = $repository->findOneBy(array('name' => 'Food'));
$tshirt->setTaxCategory($clothing);
$food->setTaxCategory($food);
// Save the product entities.
}
Finally, you have to create appropriate tax rates for each of categories.
<?php
public function configureAction()
{
$taxCategoryRepository = $this->container->get('sylius.repository.tax_category');
226
Chapter 7. Bundles
Sylius, Release
Done! See the Calculating Taxes chapter to see how to apply these rates.
Calculating taxes
Warning: When using the CoreBundle (i.e: full stack Sylius framework), the taxes are already calculated at each
cart change. It is implemented by the TaxationProcessor class, which is called by the OrderTaxationListener.
In order to calculate tax amount for given taxable, we need to find out the applicable tax rate. The tax rate resolver
service is available under sylius.tax_rate_resolver id, while the delegating tax calculator is accessible via
sylius.tax_calculator name.
Resolving rate and using calculator
<?php
namespace Acme\ShopBundle\Taxation
use Acme\ShopBundle\Entity\Order;
use Sylius\Bundle\TaxationBundle\Calculator\CalculatorInterface;
use Sylius\Bundle\TaxationBundle\Resolver\TaxRateResolverInterface;
class TaxApplicator
{
private $calculator;
private $taxRateResolver;
public function __construct(
CalculatorInterface $calculator,
TaxRateResolverInterface $taxRateResolver,
)
227
Sylius, Release
{
$this->calculator = $calculator;
$this->taxRateResolver = $taxRateResolver;
}
public function applyTaxes(Order $order)
{
$tax = 0;
foreach ($order->getItems() as $item) {
$taxable = $item->getProduct();
$rate = $this->taxRateResolver->resolve($taxable);
if (null === $rate) {
continue; // Skip this item, there is no matching tax rate.
}
$tax += $this->calculator->calculate($item->getTotal(), $rate);
}
$order->setTaxTotal($tax); // Set the calculated taxes.
}
}
All calculators implement the TaxCalculatorInterface. First, you need to create a new class.
namespace Acme\Bundle\ShopBundle\TaxCalculator;
use Sylius\Bundle\TaxationBundle\Calculator\TaxCalculatorInterface;
use Sylius\Bundle\TaxationBundle\Model\TaxRateInterface;
class FeeCalculator implements TaxCalculatorInterface
{
public function calculate($amount, TaxRate $rate)
{
return $amount * ($rate->getAmount() + 0,15 * 0,30);
}
}
228
Chapter 7. Bundles
Sylius, Release
Summary
Configuration Reference
sylius_taxation:
# The driver used for persistence layer.
driver: ~
classes:
tax_category:
model: Sylius\Component\Taxation\Model\TaxCategory
controller: Sylius\Bundle\ResourceBundle\Controller\ResourceController
repository: ~
form:
default: Sylius\Bundle\TaxationBundle\Form\Type\TaxCategoryType
choice: Sylius\Bundle\ResourceBundle\Form\Type\ResourceChoiceType
tax_rate:
model: Sylius\Component\Taxation\Model\TaxRate
controller: Sylius\Bundle\ResourceBundle\Controller\ResourceController
repository: ~
form:
default: Sylius\Bundle\TaxationBundle\Form\Type\TaxRateType
validation_groups:
tax_category: [sylius]
tax_rate: [sylius]
Tests
$ composer install --dev --prefer-dist
$ bin/phpspec run -fpretty --verbose
Bug tracking
This bundle uses GitHub issues. If you have found bug, please create an issue.
7.1.19 SyliusTaxonomiesBundle
Flexible categorization system for Symfony2 applications.
Installation
We assume youre familiar with Composer, a dependency manager for PHP. Use the following command to add the
bundle to your composer.json and download the package.
If you have Composer installed globally.
$ composer require "sylius/taxonomy-bundle"
229
Sylius, Release
Note: This version is compatible only with Symfony 2.3 or newer. Please see the CHANGELOG file in the repository,
to find version to use with older vendors.
First, you need to enable the bundle inside the kernel. If youre not using any other Sylius bundles, you will also need
to add SyliusResourceBundle and its dependencies to the kernel. Dont worry, everything was automatically installed
via Composer.
<?php
// app/AppKernel.php
public function registerBundles()
{
$bundles = array(
new FOS\RestBundle\FOSRestBundle(),
new JMS\SerializerBundle\JMSSerializerBundle($this),
new Stof\DoctrineExtensionsBundle\StofDoctrineExtensionsBundle(),
new WhiteOctober\PagerfantaBundle\WhiteOctoberPagerfantaBundle(),
new Sylius\Bundle\TaxonomyBundle\SyliusTaxonomyBundle(),
new Sylius\Bundle\ResourceBundle\SyliusResourceBundle(),
// Other bundles...
new Doctrine\Bundle\DoctrineBundle\DoctrineBundle(),
);
}
Note: Please register the bundle before DoctrineBundle. This is important as we use listeners which have to be
processed first.
Container configuration
And configure doctrine extensions which are used in the taxonomy bundle:
stof_doctrine_extensions:
orm:
default:
tree: true
sluggable: true
Routing configuration
230
Chapter 7. Bundles
Sylius, Release
sylius_taxonomy:
resource: @SyliusTaxonomyBundle/Resources/config/routing.yml
prefix: /taxonomy
Warning: This should be done only in dev environment! We recommend using Doctrine migrations, to safely
update your schema.
Retrieving taxonomy from database should always happen via repository, which implements
Sylius\Bundle\ResourceBundle\Model\RepositoryInterface.
If you are using Doctrine,
youre already familiar with this concept, as it extends the native Doctrine ObjectRepository interface.
Your taxonomy repository is always accessible via sylius.repository.taxonomy service. Of course,
sylius.repository.taxon is also available for use, but usually you obtains taxons directly from Taxonomy
model. Youll see that in further parts of this document.
<?php
public function myAction(Request $request)
{
$repository = $this->container->get('sylius.repository.taxonomy');
}
<?php
public function myAction(Request $request)
{
$repository = $this->container->get('sylius.repository.taxonomy');
231
Sylius, Release
$taxonomies = $repository->createPaginator();
$taxonomies->setMaxPerPage(5);
$taxonomies->setCurrentPage($request->query->get('page', 1));
// Now you can return taxonomies to template and iterate over it to get taxonomies from current pa
}
Paginator also can be created for specific criteria and with desired sorting.
<?php
public function myAction(Request $request)
{
$repository = $this->container->get('sylius.repository.taxonomy');
$taxonomies = $repository->createPaginator(array('foo' => true), array('createdAt' => 'desc'));
$taxonomies->setMaxPerPage(3);
$taxonomies->setCurrentPage($request->query->get('page', 1));
}
To create new taxonomy instance, you can simply call createNew() method on the repository.
<?php
public function myAction(Request $request)
{
$repository = $this->container->get('sylius.repository.taxonomy');
$taxonomy = $repository->createNew();
}
Note: Creating taxonomy via this factory method makes the code more testable, and allows you to change taxonomy
class easily.
To save or remove a taxonomy, you can use any ObjectManager which manages Taxonomy.
You
can always access it via alias sylius.manager.taxonomy. But its also perfectly fine if you use
doctrine.orm.entity_manager or other appropriate manager service.
<?php
232
Chapter 7. Bundles
Sylius, Release
$manager->persist($taxonomy);
$manager->flush(); // Save changes in database.
}
Taxons
Taxons can be handled exactly the same way, but with usage of sylius.repository.taxon.
Taxonomy contains methods which allow you to retrieve the child taxons. Lets look again at our example tree.
| Categories
|-- T-Shirts
|
|-- Men
|
`-- Women
|-- Stickers
|-- Mugs
`-- Books
To get a flat list of taxons under taxonomy, use the getTaxonsAsList method.
<?php
public function myAction(Request $request)
{
// Find the taxonomy
$taxonomyRepository = $this->container->get('sylius.repository.taxonomy');
$taxonomy = $taxonomyRepository->findOneByName('Categories');
// Get the taxons as a list
$taxonRepository = $this->container->get('sylius.repository.taxon');
$taxons = $taxonRepository->getTaxonsAsList($taxonomy);
}
$taxons variable will now contain flat list (ArrayCollection) of taxons in following order: T-Shirts, Men, Women,
Stickers, Mugs, Books.
If, for example, you want to render them as tree.
<?php
public function myAction(Request $request)
{
$repository = $this->container->get('sylius.repository.taxonomy');
233
Sylius, Release
$taxonomy = $repository->findOneByName('Categories');
$taxons = $taxonomy->getTaxons();
}
Summary
Configuration Reference
sylius_taxonomies:
# The driver used for persistence layer.
driver: ~
classes:
taxonomy:
model: Sylius\Component\Taxonomy\Model\Taxonomy
controller: Sylius\Bundle\ResourceBundle\Controller\ResourceController
repository: ~
form: Sylius\Bundle\TaxonomiesBundle\Form\Type\TaxonomyType
taxon:
model: Sylius\Component\Taxonomy\Model\Taxon
controller: Sylius\Bundle\ResourceBundle\Controller\ResourceController
repository: ~
form: Sylius\Bundle\TaxonomiesBundle\Form\Type\TaxonType
validation_groups:
taxonomy: [sylius]
taxon: [sylius]
Tests
$ composer install --dev --prefer-dist
$ bin/phpspec run -fpretty --verbose
Bug tracking
This bundle uses GitHub issues. If you have found bug, please create an issue.
7.1.20 SyliusVariationBundle
This bundle allows you to manage and generate variations of any compatible object with a very flexible architecture.
Sylius uses this bundle internally for its product catalog to manage variations of the same product based on its options
and their values, but can be used with almost any object.
Installation
We assume youre familiar with Composer, a dependency manager for PHP. Use the following command to add the
bundle to your composer.json and download the package.
234
Chapter 7. Bundles
Sylius, Release
Note: Please register the bundle before DoctrineBundle. This is important as we use listeners which have to be
processed first.
Container configuration
235
Sylius, Release
Warning: This should be done only in dev environment! We recommend using Doctrine migrations, to safely
update your schema.
Congratulations! The bundle is now installed and ready to use.
Configuration reference
sylius_variation:
driver: ~ # The driver used for persistence layer. Currently only `doctrine/orm` is supported.
classes:
# `variation_name` can be any name, for example `product`, `ad`, or `blog_post`
variation_name:
variable: ~ # Required: The variable model class implementing `VariableInterface`
# of which variants can be created from
variant:
model:
~ # Required: The variant model class implementing `VariantInterface`
repository: ~ # Required: The repository class for the variant
controller: Sylius\Bundle\ResourceBundle\Controller\ResourceController
form:
Sylius\Bundle\VariationBundle\Form\Type\VariantType
option:
model:
~ # Required: The option model class implementing `OptionInterface`
repository: ~ # Required: The repository class for the option
controller: Sylius\Bundle\ResourceBundle\Controller\ResourceController
form:
Sylius\Bundle\VariationBundle\Form\Type\OptionType
option_value:
model:
~ # Required: The option value model class implementing `OptionValueInt
repository: ~ # Required: The repository class for the option value
controller: Sylius\Bundle\ResourceBundle\Controller\ResourceController
form:
Sylius\Bundle\VariationBundle\Form\Type\OptionValueType
validation_groups:
# `variation_name` should be same name as the name key defined for the classes section abov
variation_name:
variant:
[ sylius ]
option:
[ sylius ]
option_value: [ sylius ]
236
Chapter 7. Bundles
Sylius, Release
SyliusMailerBundle
SyliusOmnipayBundle
SyliusOrderBundle
SyliusProductBundle
SyliusPromotionBundle
SyliusRbacBundle
SyliusReportBundle
SyliusResourceBundle
SyliusSettingsBundle
SyliusShippingBundle
SyliusTaxationBundle
SyliusTaxonomiesBundle
SyliusVariationBundle
Bundles General Guide
SyliusAddressingBundle
/bundles/SyliusArchetypeBundle/index
SyliusAttributeBundle
SyliusCartBundle
/bundles/SyliusContactBundle/index
SyliusFlowBundle
SyliusGridBundle
SyliusInventoryBundle
SyliusMailerBundle
SyliusOmnipayBundle
SyliusOrderBundle
SyliusProductBundle
SyliusPromotionBundle
SyliusRbacBundle
SyliusReportBundle
SyliusResourceBundle
SyliusSettingsBundle
SyliusShippingBundle
SyliusTaxationBundle
SyliusTaxonomiesBundle
SyliusVariationBundle
237
Sylius, Release
238
Chapter 7. Bundles
CHAPTER 8
Components
The name sylius/taxation is written at the top of the documentation for whatever component you want.
Tip: Install composer if you dont have it already present on your system. Depending on how you install, you may
end up with a composer.phar file in your directory. In that case, no worries! Just run php composer.phar
require sylius/taxation.
3. Write your code!
Once Composer has downloaded the component(s), all you need to do is include the vendor/autoload.php file
that was generated by Composer. This file takes care of autoloading all of the libraries so that you can use them
immediately:
239
Sylius, Release
Now what?
Now that the component is installed and autoloaded, read the specific components documentation to find out more
about how to use it.
And have fun!
8.1.2 Addressing
Sylius Addressing component for PHP E-Commerce applications which provides you with basic Address, Country,
Province and Zone models.
Installation
You can install the component in 2 different ways:
Install it via Composer (sylius\addressing on Packagist);
Use the official Git repository (https://github.com/Sylius/Addressing).
Then, require the vendor/autoload.php file to enable the autoloading mechanism provided by Composer. Otherwise, your application wont be able to find the classes of this Sylius component.
240
Chapter 8. Components
Sylius, Release
Basic Usage
ZoneMatcher
Zones are not very useful by themselves, but they can take part in e.g. a complex taxation/shipping system. This
service is capable of getting a Zone specific for given Address.
It uses a collaborator implementing Doctrines ObjectRepository interface to obtain all available zones, compare them
with given Address and return best fitted Zone.
First lets make some preparations.
<?php
use
use
use
use
Sylius\Component\Addressing\Model\Address;
Sylius\Component\Addressing\Model\Country;
Sylius\Component\Addressing\Model\Zone;
Sylius\Component\Addressing\Model\ZoneMemberCountry;
Now that we have all the needed parts lets match something.
<?php
use Sylius\Component\Addressing\Matcher\ZoneMatcher;
$zoneRepository = // get the zone repository
$zoneMatcher = new ZoneMatcher($zoneRepository);
$zoneMatcher->match($address); // returns the best matching zone
// for the address given, in this case $zone
To be more specific you can provide a scope which will narrow the search only to zones with same corresponding
property.
<?php
$zone->setScope('earth');
$zoneMatcher->match($address, 'earth'); // returns $zone
241
Sylius, Release
Models
Address
The customers address is represented by an Address model. It should contain all data concerning customers address
and as default has the following properties:
Property
id
firstName
lastName
phoneNumber
company
country
province
street
city
postcode
createdAt
updatedAt
Description
Unique id of the address
Customers first name
Customers last name
Customers phone number
Company name
Reference to a Country object
Reference to a Province object
Address street
Address city
Address postcode
Date when address was created
Date of last address update
Note: This model implements the AddressInterface. For more detailed information go to Sylius API Address.
Country
The geographical area of a country is represented by a Country model. It should contain all data concerning a country
and as default has the following properties:
Property
id
isoName
provinces
enabled
Description
Unique id of the country
Countrys ISO code
Collection of Province objects
Indicates whether country is enabled
Note: This model implements the CountryInterface. For more detailed information go to Sylius API Country.
Province
Smaller area inside a country is represented by a Province model. You can use it to manage provinces or states and
assign it to an address as well. It should contain all data concerning a province and as default has the following
properties:
242
Chapter 8. Components
Sylius, Release
Property
id
name
isoName
country
Description
Unique id of the province
Provinces name
Provinces ISO code
The Country this province is assigned to
Note: This model implements the ProvinceInterface. For more detailed information go to Sylius API Province.
Zone
The geographical area is represented by a Zone model. It should contain all data concerning a zone and as default has
the following properties:
Property
id
name
type
scope
members
Description
Unique id of the zone
Zones name
Zones type
Zones scope
All of the ZoneMember objects assigned to this zone
Note: This model implements the ZoneInterface. For more detailed information go to Sylius API Zone.
ZoneMember
In order to add a member to a zone, a class must extend abstract ZoneMember. On default this model has the
following properties:
Property
id
belongsTo
Description
Unique id of the zone member
The Zone this member is assigned to
Note: This model implements ZoneMemberInterface For more detailed information go to Sylius API ZoneMember.
Note: Each ZoneMember instance holds a reference to the Zone object and an appropriate area entity, for example
a Country.
There are three default zone member models:
ZoneMemberCountry
ZoneMemberProvince
ZoneMemberZone
Tip: Feel free to implement your own custom zone members!
ZoneMemberCountry
Country member of a zone is represented by a ZoneMemberCountry model. It has all the properties of ZoneMember
and one additional:
Property
country
Description
The Country associated with this zone member
243
Sylius, Release
ZoneMemberProvince
Province member of a zone is represented by a ZoneMemberProvince model. It has all the properties of ZoneMember
and one additional:
Property
province
Description
The Province associated with this zone member
ZoneMemberZone
Zone member of a zone is represented by a ZoneMemberZone model. It has all the properties of ZoneMember and
one additional:
Property
zone
Description
The Zone associated with this zone member
Interfaces
Model Interfaces
AddressInterface This interface should be implemented by models representing the customers address.
Note: This interface extends TimestampableInterface. For more detailed information go to Sylius API AddressInterface.
ZoneInterface This interface should be implemented by models representing a single zone. It also holds all the
Zone Types.
Note: For more detailed information go to Sylius API ZoneInterface.
244
Chapter 8. Components
Sylius, Release
ZoneMemberInterface This interface should be implemented by models that represent an area a specific zone
contains, e.g. all countries in the European Union.
Note: For more detailed information go to Sylius API ZoneMemberInterface.
Service Interfaces
RestrictedZoneCheckerInterface A service implementing this interface should be able to check if given Address
is in a restricted zone.
Note: For more detailed information go to Sylius API RestrictedZoneCheckerInterface.
ZoneMatcherInterface This interface should be implemented by a service responsible of finding the best matching
zone, and all zones containing the provided Address.
Note: For more detailed information go to Sylius API ZoneMatcherInterface.
Zone Types
There are three zone types available by default:
Related constant
TYPE_COUNTRY
TYPE_PROVINCE
TYPE_ZONE
Type
country
province
zone
Note: All of the above types are constant fields in the ZoneInterface.
8.1.3 Archetype
Handling of dynamic attributes and options on PHP models is a common task for most of modern business applications.
Additionally when an object has certain attributes and options, similar objects are likely to be built from the same set
of attributes and/or options.
This Sylius Archetype component makes it easier to define types of objects that have these attributes and options and
attach them when creating a new object. This is called an _archetype_ and a model can be defined as an archetype by
implementing a simple interface.
Installation
You can install the component in 2 different ways:
Install it via Composer (sylius\archetype on Packagist);
Use the official Git repository (https://github.com/Sylius/Archetype).
Then, require the vendor/autoload.php file to enable the autoloading mechanism provided by Composer. Otherwise, your application wont be able to find the classes of this Sylius component.
245
Sylius, Release
Basic Usage
The usage of this component bases on a few classes cooperation. Create an Archetype with given Attributes as an
ArrayCollection. To create an Archetype we can use its Builder class, which will use your AttributeValues repository.
Archetype
<?php
use
use
use
use
Doctrine\Common\Collections\ArrayCollection;
Sylius\Component\Attribute\Model\Attribute;
Sylius\Component\Archetype\Model\Archetype;
Sylius\Component\Archetype\Builder\ArchetypeBuilder;
ArchetypeBuilder
/**
* @param RepositoryInterface $attributeValueRepository
*/
$builder = new ArchetypeBuilder($attributeValueRepository);
/**
* @var ArchetypeSubjectInterface $subject
*/
$subject = /* ... */;
$builder->build($subject);
Note: You can find more information about this class in Sylius API ArchetypeBuilder.
246
Chapter 8. Components
Sylius, Release
Models
Archetype
Every archetype is represented by the Archetype instance and has the following properties:
Property
id
code
attributes
options
parent
createdAt
updatedAt
Description
Unique id of the archetype
Machine-friendly name of the archetype (car, shoe, bean_bag)
Attributes to add when building new objects based on the archetype
Options to add when building new objects based on the archetype
The parent archetype to inherit from (examples might be Vehicle for Car or Footwear for
Shoe)
Date when attribute was created
Date of last attribute update
Note: This model implements the ArchetypeInterface. You can find more information about this class in Sylius API
Archetype.
ArchetypeTranslation
Description
Unique id of the archetypes translation
Name of the archetype s translation
Note: This model implements the ArchetypeTranslationInterface. You can find more information about this class in
Sylius API ArchetypeTranslation.
Interfaces
Model Interfaces
ArchetypeSubjectInterface To characterize an object with attributes and options from a common archetype, the
object class needs to implement the ArchetypeSubjectInterface.
Note: This interface extends the AttributeSubjectInterface and the VariableInterface. You will find more information
about this interface in Sylius Api ArchetypeSubjectInterface.
8.1. PHP E-Commerce Components
247
Sylius, Release
Services Interfaces
ArchetypeBuilderInterface This interface should be implemented by services that will build the archetypes of
products.
Note: You will find more information about this interface in Sylius Api ArchetypeBuilderInterface.
8.1.4 Attribute
Handling of dynamic attributes on PHP models is a common task for most of modern business applications. Sylius
component makes it easier to handle different types of attributes and attach them to any object by implementing a
simple interface.
Installation
You can install the component in 2 different ways:
Install it via Composer (sylius/attribute on Packagist).
Use the official Git repository (https://github.com/Sylius/Attribute).
Then, require the vendor/autoload.php file to enable the autoloading mechanism provided by Composer. Otherwise, your application wont be able to find the classes of this Sylius component.
Basic Usage
Creating an attributable class
In the following example you will see a minimalistic implementation of the AttributeSubjectInterface.
<?php
namespace Example\Model;
use Sylius\Component\Attribute\Model\AttributeSubjectInterface;
use Sylius\Component\Attribute\Model\AttributeValueInterface;
class Shirt implements AttributeSubjectInterface
{
/**
* @var AttributeValueInterface[]
*/
private $attributes;
/**
* {@inheritdoc}
*/
public function getAttributes()
{
return $this->attributes;
}
248
Chapter 8. Components
Sylius, Release
/**
* {@inheritdoc}
*/
public function setAttributes(array $attributes)
{
foreach ($attributes as $attribute) {
$this->addAttribute($attribute);
}
}
/**
* {@inheritdoc}
*/
public function addAttribute(AttributeValueInterface $attribute)
{
if (!$this->hasAttribute($attribute)) {
$attribute->setSubject($this);
$this->attributes[] = $attribute;
}
}
/**
* {@inheritdoc}
*/
public function removeAttribute(AttributeValueInterface $attribute)
{
if ($this->hasAttribute($attribute)){
$attribute->setSubject(null);
$key = array_search($attribute, $this->attributes);
unset($this->attributes[$key]);
}
}
/**
* {@inheritdoc}
*/
public function hasAttribute(AttributeValueInterface $attribute)
{
return in_array($attribute, $this->attributes);
}
/**
* {@inheritdoc}
*/
public function hasAttributeByName($attributeName)
{
foreach ($this->attributes as $attribute) {
if ($attribute->getName() === $attributeName) {
return true;
}
}
return false;
}
/**
* {@inheritdoc}
*/
249
Sylius, Release
Note: An implementation similar to the one above has been done in the component_product_model_product model.
Or you can just add all attributes needed using a class implementing Doctrines Collection interface, e.g. the ArrayCollection class.
<?php
use Doctrine\Common\Collections\ArrayCollection;
$attributes = new ArrayCollection();
$attributes->add($smallSize);
$attributes->add($mediumSize);
$shirt->setAttributes($attributes);
Note: Notice that you dont actually add an Attribute to the subject, instead you need to add every AttributeValue
250
Chapter 8. Components
Sylius, Release
Accessing attributes
<?php
$shirt->getAttributes(); // returns an array containing all set attributes
$shirt->hasAttribute($smallSize); // returns true
$shirt->hasAttribute($hugeSize); // returns false
Removing an attribute
<?php
$shirt->hasAttribute($smallSize); // returns true
$shirt->removeAttribute($smallSize);
$shirt->hasAttribute($smallSize); // now returns false
Models
Attribute
Every attribute is represented by the Attribute model which by default has the following properties:
Property
id
type
name
configuration
values
createdAt
updatedAt
Description
Unique id of the attribute
Attributes type (text by default)
Attributes name
Attributes configuration
Collection of attribute values
Date when attribute was created
Date of last attribute update
Note: This model extends the AbstractTranslatable class and implements the AttributeInterface. For more detailed
information go to Sylius API Attribute.
Hint: Default attribute types are stored in the AttributeTypes class.
251
Sylius, Release
AttributeValue
This model binds the subject and the attribute, it is used to store the value of the attribute for the subject. It has the
following properties:
Property
id
subject
attribute
value
Description
Unique id of the attribute value
Reference to attributes subject
Reference to an attribute
Attributes value
Note: This model implements the AttributeValueInterface. For more detailed information go to Sylius API AttributeValue.
AttributeTranslation
The attributes presentation for different locales is represented by the AttributeTranslation model which has the
following properties:
Property
id
presentation
Description
Unique id of the attribute translation
Attributes name for given locale
Note: This model extends the AbstractTranslation class and implements the AttributeTranslationInterface. For more
detailed information go to Sylius API AttributeTranslation.
Interfaces
Model Interfaces
AttributeInterface This interface should be implemented by models used for describing a products attribute.
Note: This interface extends the TimestampableInterface and the AttributeTranslationInterface. For more detailed
information go to Sylius API AttributeInterface.
AttributeValueInterface This interface should be implemented by models used for binding an Attribute with a
model implementing the AttributeSubjectInterface e.g. the component_product_model_product.
Note: For more detailed information go to Sylius API AttributeValueInterface.
AttributeSubjectInterface This interface should be implemented by models you want to characterize with various
AttributeValue objects.
It will ask you to implement the management of AttributeValue models.
252
Chapter 8. Components
Sylius, Release
AttributeTypes
The following attribute types are available by default in the AttributeTypes class:
Related constant
TEXT
NUMBER
PERCENTAGE
CHECKBOX
CHOICE
MONEY
Type
text
number
percentage
checkbox
choice
money
Hint: Use the static method AttributeTypes::getChoices() to get an array containing all types.
Note: For more detailed information go to Sylius API AttributeTypes.
8.1.5 Cart
Common models, services and interface to handle a shopping cart in PHP e-commerce application. It is strictly related
to Order model.
Installation
You can install the component in 2 different ways:
Install it via Composer (sylius/cart on Packagist);
Use the official Git repository (https://github.com/Sylius/Cart).
Then, require the vendor/autoload.php file to enable the autoloading mechanism provided by Composer. Otherwise, your application wont be able to find the classes of this Sylius component.
Basic Usage
Note: The cart is basically an order with an appropriate state. Check Orders State Machine.
Hint: For more examples go to Order Basic Usage.
CartContext
The CartContext provides you with useful tools to set and retrieve current cart identifier based on storage.
<?php
use Sylius\Component\Cart\Context\CartContext;
use Sylius\Component\Cart;
253
Sylius, Release
Models
Cart
The cart is represented by Cart instance. It inherits all the properties from component_order_model_order and add
one property:
Method
expiresAt
Description
Expiration time
Type
DateTime
CartItem
The items of the cart are represented by the CartItem instances. CartItem has no properties but it inherits from
OrderItem.
Note: This model implements the CartItemInterface
Interfaces
Model Interfaces
CartProviderInterface A cart provider retrieves existing cart or create new one based on the storage. To characterize an object which is a Provider, it needs to implement the CartProviderInterface.
Note: For more detailed information go to Sylius Api CartProviderInterface.
254
Chapter 8. Components
Sylius, Release
PurgerInterface A cart purger purges all expired carts. To characterize an object which is a Purger, it needs to
implement the PurgerInterface.
Note: For more detailed information go to Sylius Api PurgerInterface.
ItemResolverInterface A cart resolver returns cart item that needs to be added based on given data. To characterize
an object which is a Resolver, it needs to implement the ItemResolverInterface.
Note: For more detailed information go to Sylius Api ItemResolverInterface.
Caution: This method throws ItemResolvingException if an error occurs.
CartRepositoryInterface In order to decouple from storage that provides expired carts, you should create repository
class which implements this interface.
Note: This interface extends the OrderRepositoryInterface For more detailed information go to Sylius API
CartRepositoryInterface_.
CartContextInterface This interface is implemented by the services responsible for setting and retrieving current cart identifier based on storage. To characterize an object which is a CartContext it needs to implement the
CartContextInterface
Note: For more detailed information go to Sylius API CartContextInterface.
8.1.6 Channel
Sale channels management implementation in PHP.
Installation
You can install the component in 2 different ways:
Install it via Composer (sylius/channel on Packagist);
Use the official Git repository (https://github.com/Sylius/Channel).
Then, require the vendor/autoload.php file to enable the autoloading mechanism provided by Composer. Otherwise, your application wont be able to find the classes of this Sylius component.
Basic Usage
ChannelContext
The ChannelContext allows you to manage the currently used sale channel.
255
Sylius, Release
<?php
use Sylius\Component\Channel\Context\ChannelContext;
use Sylius\Component\Channel\Model\Channel;
$channel = new Channel();
$channelContext = new ChannelContext();
$channelContext->setChannel($channel);
$channelContext->getChannel(); // will return the $channel object
Models
Channel
Sale channel is represented by a Channel model. It should have everything concerning channels data and as default
has the following properties:
Property
id
code
name
description
url
color
enabled
createdAt
updatedAt
Description
Unique id of the channel
Channels code
Channels name
Channels description
Channels URL
Channels color
Indicates whether channel is available
Date of creation
Date of update
Note: This model implements ChannelInterface. For more detailed information go to Sylius API Channel.
Interfaces
Model Interfaces
ChannelInterface This interface should be implemented by every custom sale channel model.
Note: This interface extends TimestampableInterface. For more detailed information go to Sylius API ChannelInterface.
ChannelAwareInterface This interface should be implemented by models associated with a specific sale channel.
Note: For more detailed information go to Sylius API ChannelAwareInterface.
ChannelsAwareInterface This interface should be implemented by models associated with multiple channels.
256
Chapter 8. Components
Sylius, Release
Service Interfaces
ChannelContextInterface This interface should be implemented by a service responsible for managing the currently used Channel.
Note: For more detailed information go to Sylius API ChannelContextInterface.
ChannelRepositoryInterface This interface should be implemented by repositories responsible for storing the
Channel objects.
Note: For more detailed information go to Sylius API ChannelRepositoryInterface.
8.1.7 Contact
Managing contact form for PHP apps.
Installation
We assume youre familiar with Composer, a dependency manager for PHP. Use following command to add the
component to your composer.json and download package.
If you have Composer installed globally.
$ composer require sylius/contact:*
Models
ContactTopic
ContactRequest
Summary
phpspec2 examples
$ composer install --dev --prefer-dist
$ bin/phpspec run -fpretty --verbose
Bug tracking
This component uses GitHub issues. If you have found bug, please create an issue.
8.1. PHP E-Commerce Components
257
Sylius, Release
8.1.8 Currency
Managing different currencies, exchange rates and converting cash amounts for PHP apps.
Installation
We assume youre familiar with Composer, a dependency manager for PHP. Use following command to add the
component to your composer.json and download package.
If you have Composer installed globally.
$ composer require sylius/currency:*
Models
Currency
Description
Code of the currency
Exchange rate
Date of creation
Date of last update
Type
string
float
boolean
DateTime
DateTime
CurrencyInterface
Note: This interface asks you to implement a extra method named CurrencyInterface::getName() which
will return the human-friendly name of the currency
Currency provider
The CurrencyProvider allows you
CurrencyProviderInterface.
to
get
the
available
currencies,
it
implements
the
258
Chapter 8. Components
Sylius, Release
Summary
phpspec2 examples
$ composer install --dev --prefer-dist
$ bin/phpspec run -fpretty --verbose
Bug tracking
This component uses GitHub issues. If you have found bug, please create an issue.
8.1.9 Grid
Sylius component used for describing data grids. Decoupled from Symfony and useful for any kind of system, which
needs to provide user with grid functionality.
Installation
We assume youre familiar with Composer, a dependency manager for PHP. Use following command to add the
component to your composer.json and download package.
If you have Composer installed globally.
$ composer require sylius/grid:0.15.0
Summary
phpspec2 examples
$ composer install --dev --prefer-dist
$ bin/phpspec run -fpretty --verbose
Bug tracking
This component uses GitHub issues. If you have found bug, please create an issue.
8.1.10 Inventory
Inventory management for PHP applications.
259
Sylius, Release
Installation
You can install the component in 2 different ways:
Install it via Composer (sylius\inventory on Packagist);
Use the official Git repository (https://github.com/Sylius/Inventory).
Then, require the vendor/autoload.php file to enable the autoloading mechanism provided by Composer. Otherwise, your application wont be able to find the classes of this Sylius component.
Basic Usage
Stockable Object
The first thing you should do it is implementing stockable object. Example implementation:
<?php
class Product implements StockableInterface
{
/**
* Get stock keeping unit.
*
* @return mixed
*/
public function getSku()
{
// TODO: Implement getSku() method.
}
/**
* Get inventory displayed name.
*
* @return string
*/
public function getInventoryName()
{
// TODO: Implement getInventoryName() method.
}
/**
* Simply checks if there any stock available.
* It should also return true for items available on demand.
*
* @return Boolean
*/
public function isInStock()
{
// TODO: Implement isInStock() method.
}
/**
* Is stockable available on demand?
*
* @return Boolean
*/
public function isAvailableOnDemand()
260
Chapter 8. Components
Sylius, Release
{
// TODO: Implement isAvailableOnDemand() method.
}
/**
* Get stock on hold.
*
* @return integer
*/
public function getOnHold()
{
// TODO: Implement getOnHold() method.
}
/**
* Set stock on hold.
*
* @param integer
*/
public function setOnHold($onHold)
{
// TODO: Implement setOnHold() method.
}
/**
* Get stock on hand.
*
* @return integer
*/
public function getOnHand()
{
// TODO: Implement getOnHand() method.
}
/**
* Set stock on hand.
*
* @param integer $onHand
*/
public function setOnHand($onHand)
{
// TODO: Implement setOnHand() method.
}
}
InventoryOperator
Sylius\Component\Inventory\Operator\InventoryOperator;
Sylius\Component\Inventory\Checker\AvailabilityChecker;
Sylius\Component\Inventory\Operator\BackordersHandler;
Sylius\Component\Resource\Repository\InMemoryRepository;
261
Sylius, Release
Decrease This specific case will be more complicated. It uses backordersHandler to :ref:process-backorders_.
<?php
use
use
use
use
use
use
Sylius\Component\Inventory\Operator\InventoryOperator;
Sylius\Component\Inventory\Checker\AvailabilityChecker;
Sylius\Component\Inventory\Operator\BackordersHandler;
Doctrine\Common\Collections\ArrayCollection;
Sylius\Component\Inventory\Model\InventoryUnit;
Sylius\Component\Inventory\Model\InventoryUnitInterface;
262
Chapter 8. Components
Sylius, Release
NoopInventoryOperator
In some cases, you may want to have unlimited inventory, this operator will allow you to do that.
Hint: This operator is based on the null object pattern. For more detailed information go to Null Object pattern.
Note: For more detailed information go to Sylius API NoopInventoryOperator.
BackordersHandler
Sylius\Component\Inventory\Operator\BackordersHandler;
Doctrine\Common\Collections\ArrayCollection;
Sylius\Component\Inventory\Model\InventoryUnit;
Sylius\Component\Inventory\Model\InventoryUnitInterface;
263
Sylius, Release
Fill backorders This method will change inventory unit state to sold.
<?php
use Sylius\Component\Inventory\Operator\BackordersHandler;
$inventoryUnitRepository; // Repository model.
$product = new Product(); // Stockable model.
$backordersHandler = new BackordersHandler($inventoryUnitRepository);
$product->getOnHand(); // Output will be 6.
// Let's assume that we have 9 inventory units with a 'backordered' state.
// This method will find all inventory units for that specific stockable with 'backordered' state.
$backordersHandler->fillBackorders($product);
// Now 6 of them will have 'sold' state.
$product->getOnHand(); // Output will be 0.
AvailabilityChecker
The AvailabilityChecker checks availability of a given stockable object. To charactrize an object which is an AvailabilityChecker, it needs to implement the :ref:component_inventory_checker_availability_checker_interface_.
Second parameter of the ->isStockSufficient() method gives a possibility to check for a given quantity of a
stockable.
<?php
use Sylius\Component\Inventory\Checker\AvailabilityChecker;
$product = new Product(); // Stockable model.
$product->isAvailableOnDemand(); // Output will be false.
$product->getOnHand(); // Output will be 5
$product->getOnHold(); // Output will be 4
$availabilityChecker = new AvailabilityChecker(false); // backorders = false;
$availabilityChecker->isStockAvailable($product); // Output will be true.
$availabilityChecker->isStockSufficient($product, 5); // Output will be false.
Backorders The backorder property generally indicates that the customers demand for a product or service exceeds
a stockables capacity to supply it.
<?php
use Sylius\Component\Inventory\Checker\AvailabilityChecker;
$product = new Product(); // Stockable model.
$availabilityChecker = new AvailabilityChecker(true); // backorders = true;
264
Chapter 8. Components
Sylius, Release
Available On Demand
<?php
use Sylius\Component\Inventory\Checker\AvailabilityChecker;
$product = new Product(); // Stockable model.
$product->isAvailableOnDemand(); // Output will be true.
$availabilityChecker = new AvailabilityChecker(false); // backorders = false;
$availabilityChecker->isStockAvailable($product); // Output will be true.
$availabilityChecker->isStockSufficient($product, 5); // Output will be true.
Hint: In the above cases results of ->getOnHand() and ->getOnHold() will be irrelevant.
Note: For more detailed information go to Sylius API AvailabilityChecker.
InventoryUnitFactory
Models
InventoryUnit
InventoryUnit object represents an inventory unit. InventoryUnits have the following properties:
265
Sylius, Release
Property
id
stockable
invantoryState
createdAt
updatedAt
Description
Unique id of the inventory unit
Reference to any stockable unit. (Implements LocalesAwareInterface)
State of the inventory unit (e.g. checkout, sold)
Date when inventory unit was created
Date of last change
Note: This model implements the InventoryUnitInterface For more detailed information go to Sylius API InventoryUnit.
Interfaces
Model Interfaces
StockableInterface This interface provides basic operations for any model that can be stored.
Note: For more detailed information go to Sylius API StockableInterface.
Service Interfaces
AvailabilityCheckerInterface This interface provides methods for checking availability of stockable objects.
Note: For more detailed information go to Sylius API AvailabilityCheckerInterface.
BackordersHandlerInterface This interface is implemented by services responsible for changing inventory states.
Note: For more detailed information go to Sylius API BackordersHandlerInterface.
InventoryOperatorInterface This interface is implemented by services responsible for managing inventory units.
Note: For more detailed information go to Sylius API InventoryOperatorInterface.
266
Chapter 8. Components
Sylius, Release
State Machine
Inventory Unit States
Sylius itself uses a complex state machine system to manage all states of the business domain. This component has
some sensible default states defined in the InventoryUnitInterface.
All new InventoryUnit instances have the state checkout by default, which means they are in the cart and wait for
verification. The following states are defined:
Related constant
STATE_CHECKOUT
STATE_ONHOLD
STATE_SOLD
STATE_BACKORDERED
STATE_RETURNED
State
checkout
onhold
sold
backordered
returned
Description
Item is in the cart
Item is hold (e.g. waiting for the payment)
Item has been sold and is no longer in the warehouse
Item has been sold, but is not in stock and waiting for supply
Item has been sold, but returned and is in stock
Tip: Please keep in mind that these states are just default, you can define and use your own. If you use this component
with SyliusInventoryBundle and Symfony2, you will have full state machine configuration at your disposal.
Transition
hold
backorder
sell
release
return
Name
sylius_inventory_unit
Note: All of above transitions and the graph are constant fields in the InventoryUnitTransitions class.
8.1.11 Locales
Managing different locales for PHP apps.
Installation
You can install the component in 2 different ways:
Install it via Composer (sylius\locale on Packagist);
Use the official Git repository (https://github.com/Sylius/Locale).
Then, require the vendor/autoload.php file to enable the autoloading mechanism provided by Composer. Otherwise, your application wont be able to find the classes of this Sylius component.
267
Sylius, Release
Basic Usage
LocaleContext
268
Chapter 8. Components
Sylius, Release
LocaleProvider
Models
Locale
Locale represents one locale available in the application. It uses Symfony Intl component to return locale name.
Locale has the following properties:
Property
id
code
enabled
createdAt
updatedAt
Description
Unique id of the locale
Locales code
Indicates whether locale is available
Date when locale was created
Date of last change
Hint: This model has one const STORAGE_KEY it is key used to store the locale in storage.
Note:
This model implements the LocaleInterface
For more detailed information go to Sylius API Locale.
Interfaces
Model Interfaces
269
Sylius, Release
LocalesAwareInterface This interface provides basic operations for locale management. If you want to have locales
in your model just implement this interface.
Note: For more detailed information go to Sylius API LocalesAwareInterface.
Service Interfaces
LocaleContextInterface This interface is implemented by the service responsible for managing the current locale.
Note: For more detailed information go to Sylius API LocaleContextInterface.
LocaleProviderInterface This interface is implemented by the service responsible for providing you with a list of
available locales.
Note: For more detailed information go to Sylius API LocaleProviderInterface.
8.1.12 Mailer
Sylius Mailer component abstracts the process of sending e-mails. It also provides interface to configure various
parameters for unique e-mails.
Installation
You can install the component in 2 different ways:
Install it via Composer (sylius\mailer on Packagist);
Use the official Git repository (https://github.com/Sylius/Mailer).
Then, require the vendor/autoload.php file to enable the autoloading mechanism provided by Composer. Otherwise, your application wont be able to find the classes of this Sylius component.
Basic usage
Sender
SenderAdapter This is an abstraction layer that allows you to create your own logic of sending an email.
<?php
use Sylius\Component\Mailer\Sender\Adapter\AbstractAdapter as BaseSenderAdapter;
use Sylius\Component\Mailer\Model\EmailInterface;
use Sylius\Component\Mailer\Model\Email;
class SenderAdapter extends BaseSenderAdapter
{
/**
* Send an e-mail.
*
* @param array $recipients
* @param string $senderAddress
270
Chapter 8. Components
Sylius, Release
Sender This service collects those two adapters SenderAdapter, RendererAdapter and deals with process of sending an email.
<?php
use Sylius\Component\Mailer\Provider\DefaultSettingsProvider;
use Sylius\Component\Mailer\Provider\EmailProvider;
use Sylius\Component\Mailer\Sender\Sender;
$sender = new Sender($rendererAdapter, $senderAdapter, $emailProvider, $defaultSettingsProvider);
$sender->send('christmas_party_invitiation', array('mike.ehrmantraut@gmail.com'));
Renderer
RendererAdapter This is an abstraction layer that allows you to create your own logic of rendering an email object.
<?php
use Sylius\Component\Mailer\Renderer\Adapter\AbstractAdapter as BaseRendererAdapter;
use Sylius\Component\Mailer\Model\EmailInterface;
use Sylius\Component\Mailer\Model\Email;
class RendererAdapter extends BaseRendererAdapter
{
/**
* Render an e-mail.
*
* @param EmailInterface $email
* @param array $data
*
271
Sylius, Release
* @return RenderedEmail
*/
public function render(EmailInterface $email, array $data = array())
{
// TODO: Implement render() method.
return new RenderedEmail($subject, $body);
}
}
$email = new Email();
$email->setCode('christmas_party_invitiation');
$email->setContent('Hi, we would like to invite you to christmas party');
$email->setSubject('Christmas party');
$email->setSenderAddress('mike.ehrmantraut@gmail.com');
$email->setSenderName('Mike Ehrmantraut');
$rendererAdapter = new RendererAdapter();
$renderedEmail = $rendererAdapter->render($email, $data); // It will render an email object based on
$renderedEmail->getBody(); // Output will be Hi, we would .....
$renderedEmail->getSubject(); // Output will be Christmas party.
DefaultSettingsProvider
The DefaultSettingsProvider is service which provides you with default sender address and sender name.
<?php
use Sylius\Component\Mailer\Provider\DefaultSettingsProvider;
EmailProvider
272
Chapter 8. Components
Sylius, Release
Models
Email
Description
Unique id of the email
Code of the email
Indicates whether email is available
Subject of the email message
Content of the email message
Template of the email
Name of a sender
Address of a sender
Date when the email was created
Date of last change
Note: This model implements the EmailInterface For more detailed information go to Sylius API Email.
Interfaces
Model Interfaces
EmailInterface This interface should be implemented by model representing a single type of Email.
Note: This interface extends TimestampableInterface. For more detailed information go to Sylius API EmailInterface.
Service Interfaces
DefaultSettingsProviderInterface This interface provides methods for retrieving default sender name nad address.
Note: For more detailed information go to Sylius API DefaultSettingsProviderInterface.
273
Sylius, Release
EmailProviderInterface This interface provides methods for retrieving an email from storage.
Note: For more detailed information go to Sylius API EmailProviderInterface.
8.1.13 Order
E-Commerce PHP library for creating and managing sales orders.
Installation
You can install the component in 2 different ways:
Install it via Composer (sylius\order on Packagist);
Use the official Git repository (https://github.com/Sylius/Order).
Then, require the vendor/autoload.php file to enable the autoloading mechanism provided by Composer. Otherwise, your application wont be able to find the classes of this Sylius component.
Basic Usage
Order
Every order has 2 main identifiers, an ID and a human-friendly number. You can access those by calling
->getId() and ->getNumber() respectively. The number is mutable, so you can change it by calling
->setNumber(E001) on the order instance.
Order Totals
Note: All money amounts in Sylius are represented as cents - integers. An order has 3 basic totals, which are all
persisted together with the order. The first total is the items total, it is calculated as the sum of all item totals. The
second total is the adjustments total, you can read more about this in next chapter.
274
Chapter 8. Components
Sylius, Release
<?php
echo $order->getItemsTotal(); //Output will be 1900.
echo $order->getAdjustmentsTotal(); //Output will be -250.
$order->calculateTotal();
echo $order->getTotal(); //Output will be 1650.
The main order total is a sum of the previously mentioned values. You can access the order total value using the
->getTotal() method.
Recalculation of totals can happen by calling ->calculateTotal() method, using the simplest math. It will also
update the item totals.
Items Management The collection of items (Implementing the Doctrine\Common\Collections\Collection
interface) can be obtained using the ->getItems(). To add or remove items, you can simply use the addItem
and removeItem methods.
<?php
use Sylius\Component\Order\Model\Order;
use Sylius\Component\Order\Model\OrderItem;
$order = new Order();
$item1 = new OrderItem();
$item1->setName('Super cool product');
$item1->setUnitPrice(1999); // 19.99!
$item1->setQuantity(2);
$item2 = new OrderItem();
$item2->setName('Interesting t-shirt');
$item2->setUnitPrice(2549); // 25.49!
$order->addItem($item1);
$order->addItem($item2);
$order->removeItem($item1);
Order Item
An order item model has only the id property as identifier and it has the order reference, accessible via
->getOrder() method.
Order Item totals Just like for the order, the total is available via the same method, but the unit price is accessible
using the ->getUnitPrice() Each item also can calculate its total, using the quantity (->getQuantity())
and the unit price.
<?php
use Sylius\Component\Order\Model\OrderItem;
$item = new OrderItem();
$item->setUnitPrice(2000);
$item->setQuantity(4);
$item->calculateTotal();
275
Sylius, Release
Adjustments
Neutral Adjustments In some cases, you may want to use Adjustment just for displaying purposes. For example,
when your order items have the tax already included in the price.
Every Adjustment instance has the neutral property, which indicates if it should be counted against object total.
<?php
use Sylius\Component\Order\Order;
use Sylius\Component\Order\OrderItem;
use Sylius\Component\Order\Adjustment;
$order = new Order();
$tshirt = new OrderItem();
$tshirt->setUnitPrice(4999);
$shippingFees = new Adjustment();
$shippingFees->setAmount(1000);
$tax = new Adjustment();
$tax->setAmount(1150);
$tax->setNeutral(true);
$order->addItem($tshirt);
$order->addAdjustment($shippingFees);
$order->addAdjustment($tax);
$order->calculateTotal();
$order->getTotal(); // Output will be 5999.
Negative Adjustments Adjustments can also have negative amounts, which means that they will decrease the order
total by certain amount. Lets add a 5$ discount to the previous example.
276
Chapter 8. Components
Sylius, Release
<?php
use Sylius\Component\Order\Order;
use Sylius\Component\Order\OrderItem;
use Sylius\Component\Order\Adjustment;
$order = new Order();
$tshirt = new OrderItem();
$tshirt->setUnitPrice(4999);
$shippingFees = new Adjustment();
$shippingFees->setAmount(1000);
$tax = new Adjustment();
$tax->setAmount(1150);
$tax->setNeutral(true);
$discount = new Adjustment();
$discount->setAmount(-500);
$order->addItem($tshirt);
$order->addAdjustment($shippingFees);
$order->addAdjustment($tax);
$order->addAdjustment($discount);
$order->calculateTotal();
$order->getTotal(); // Output will be 5499.
Locked Adjustments You can also lock an adjustment, this will ensure that it wont be deleted from order or order
item.
<?php
use Sylius\Component\Order\Order;
use Sylius\Component\Order\OrderItem;
use Sylius\Component\Order\Adjustment;
$order = new Order();
$tshirt = new OrderItem();
$tshirt->setUnitPrice(4999);
$shippingFees = new Adjustment();
$shippingFees->setAmount(1000);
$shippingFees->lock();
$discount = new Adjustment();
$discount->setAmount(-500);
$order->addItem($tshirt);
$order->addAdjustment($shippingFees);
$order->addAdjustment($discount);
$order->removeAdjustment($shippingFees);
$order->calculateTotal();
$order->getTotal(); // Output will be 5499.
277
Sylius, Release
Models
Order
Description
Unique id of the order
Completion time of the order
Number is human-friendly identifier
Total value of items in order
Total value of adjustments
Calculated total (items + adjustments)
Collection of items
Collection of adjustments
Collection of comments
Collection of identities
Date when order was created
Date of last change
Date when order was deleted
State of the order (e.g. cart, pending)
Note: This model implements the OrderInterface For more detailed information go to Sylius API Order.
OrderItem
OrderItem object represents items in order. OrderItems have the following properties:
Property
id
order
quantity
unitPrice
adjustments
adjustmentsTotal
total
immutable
Description
Unique id of the orderItem
Reference to Order
Items quantity
The price of a single unit
Collection of adjustments
Total of the adjustments in orderItem
Total of the orderItem (unitPrice * quantity)
Boolean flag of immutability
Note: This model implements the OrderItemInterface For more detailed information go to Sylius API OrderItem.
Adjustment
Adjustment object represents an adjustment to the orders or order items total. Their amount can be positive (charges
- taxes, shipping fees etc.) or negative (discounts etc.). Adjustments have the following properties:
278
Chapter 8. Components
Sylius, Release
Property
id
order
orderItem
type
description
amount
neutral
locked
originId
originType
createdAt
updatedAt
Description
Unique id of the adjustment
Reference to Order
Reference to OrderItem
Type of the adjustment (e.g. tax)
e.g. Clothing Tax 9%
Adjustment amount
Boolean flag of neutrality
Adjustment lock (prevent from deletion)
Origin id of the adjustment
Origin type of the adjustment
Date when adjustment was created
Date of last change
Note: This model implements the AdjustmentInterface For more detailed information go to Sylius API Adjustment.
Comment
Comment object represents a comment assigned to the order. Comments have the following properties:
Property
id
order
notifyCustomer
comment
state
author
createdAt
updatedAt
Description
Unique id of the comment
Reference to Order
Boolean flag of notification
Comment content
State of order
Comment author
Date when comment was created
Date of last change
Note: This model implements the CommentInterface For more detailed information go to Sylius API Comment.
Identity
Identity object is used for storing external identifications, such as referring order id in some external system (e.g.
ERP). Identities have the following properties:
Property
id
order
name
value
Description
Unique id of the identity
Reference to Order
Identity name (e.g. ebay id)
Identity value (e.g. 24312332)
Note: This model implements the IdentityInterface For more detailed information go to Sylius API Identity.
Interfaces
Model Interfaces
279
Sylius, Release
OrderAwareInterface This interface provides basic operations for order management. If you want to have orders
in your model just implement this interface.
Note: For more detailed information go to Sylius API OrderAwareInterface.
AdjustableInterface This interface provides basic operations for adjustment management. Use this interface if you
want to make a model adjustable.
For example following models implement this interface:
component_resource_model_order
component_resource_model_order-item
Note: For more detailed information go to Sylius API AdjustableInterface.
CommentAwareInterface This interface provides basic operations for comments management. If you want to have
comments in your model just implement this interface.
Note: For more detailed information go to Sylius API CommentAwareInterface_.
IdentityInterface This interface should be implemented by model representing a single Identity. It can be used for
storing external identifications.
Note: For more detailed information go to Sylius API IdentityInterface_.
280
Chapter 8. Components
Sylius, Release
Services Interfaces
OrderRepositoryInterface In order to decouple from storage that provides recently completed orders or check if
given orders number is already used, you should create repository class which implements this interface.
Note: This interface extends the RepositoryInterface and the HashSubjectRepositoryInterface. For more detailed
information about the interface go to Sylius API OrderRepositoryInterface.
State Machine
Order States
Sylius itself uses a complex state machine system to manage all states of the business domain. This component has
some sensible default states defined in the OrderInterface.
All new Order instances have the state cart by default, which means they are unconfirmed. The following states are
defined:
Related constant
STATE_CART
STATE_CART_LOCKED
STATE_PENDING
STATE_CONFIRMED
STATE_SHIPPED
STATE_ABANDONED
STATE_CANCELLED
STATE_RETURNED
State
cart
cart_locked
pending
confirmed
shipped
abandoned
cancelled
returned
Description
Unconfirmed order, ready to add/remove items
Cart which should not be removed when expired
Order waiting for confirmation
Confirmed and completed order
Order has been shipped to the customer
Been waiting too long for confirmation
Cancelled by customer or manager
Order has been returned and refunded
Tip: Please keep in mind that these states are just default, you can define and use your own. If you use this component
with SyliusOrderBundle and Symfony2, you will have full state machine configuration at your disposal.
Order Transitions
Transition
create
release
confirm
ship
abandon
cancel
return
Name
sylius_order
Note: All of above transitions and the graph are constant fields in the OrderTransitions class.
281
Sylius, Release
8.1.14 Originator
Installation
You can install the component in 2 different ways:
Install it via Composer (sylius/originator on Packagist);
Use the official Git repository (https://github.com/Sylius/Originator).
Then, require the vendor/autoload.php file to enable the autoloading mechanism provided by Composer. Otherwise, your application wont be able to find the classes of this Sylius component.
Basic Usage
Originator
This service searches a repository for the origin object of given object implementing the OriginAwareInterface and
returns it.
Lets say we have class:
<?php
namespace Example\Model;
class Ancestor
{
/**
* @var int
*/
$identifier;
/**
* @param int $id
*/
public function __construct($id = null)
{
$this->identifier = $id;
}
/**
* @return int
*/
public function getIdentifier()
{
return $this->identifier;
}
}
Note: Any class used as an origin needs to have a getter for its identifier.
and:
<?php
namespace Example\Model;
282
Chapter 8. Components
Sylius, Release
use Sylius\Component\Originator\Model\OriginAwareInterface;
class OriginAware implements OriginAwareInterface
{
/**
* @var int
*/
$originId;
/**
* @var string
*/
$originType;
// all of the interface's methods
}
Now, to create a new Originator you will need a service which implements the Doctrines ManagerRegistry and the
requested objects identifier property name (the default setting is id):
<?php
use Sylius\Component\Originator\Originator\Originator;
use //the ManagerRegistry service, here: $registry
$originator = new Originator($registry); //using the default field name
//or
$originator = new Originator($registry, 'identifier');
Sylius\Component\Originator\Originator\Originator;
Example\Model\Ancestor;
Example\Model\OriginAware;
//the ManagerRegistry service, here: $registry
Now, with origin set in $aware object and if we have our $ancestor in a repository we can:
283
Sylius, Release
Interfaces
Model Interface
OriginAwareInterface This interface should be implemented by any model which you want to characterize with an
origin.
Note: For more detailed information go to Sylius API OriginAwareInterface.
Service Interfaces
OriginatorInterface A service implementing this interface should be capable of getting any object via an implementation of OriginAwareInterface and setting an origin object.
Note: For more detailed information go to Sylius API OriginatorInterface.
8.1.15 Payment
PHP library which provides abstraction of payments management. It ships with default Payment, PaymentMethod
and CreditCard models.
Note: This component does not provide any payment gateway. Integrate it with Payum.
Installation
You can install the component in 2 different ways:
Install it via Composer (sylius\payment on Packagist);
Use the official Git repository (https://github.com/Sylius/Payment).
Then, require the vendor/autoload.php file to enable the autoloading mechanism provided by Composer. Otherwise, your application wont be able to find the classes of this Sylius component.
Basic Usage
FixedFeeCalculator
This calculator is used to get the amount of fee set at the amount key in the configuration array.
284
Chapter 8. Components
Sylius, Release
<?php
use Sylius\Component\Payment\Calculator\FixedFeeCalculator;
use Sylius\Component\Payment\Model\Payment;
$fixedFeeCalculator = new FixedFeeCalculator();
$payment = new Payment();
$payment->setAmount(500);
$configuration = array('amount' => 10);
$fixedFeeCalculator->calculate($payment, $configuration); // returns value of the 'amount' key
// so in this case 10
PercentFeeCalculator
This calculator uses the percent keys value of the configuration array in order to calculate a payments fee.
<?php
use Sylius\Component\Payment\Calculator\PercentFeeCalculator;
use Sylius\Component\Payment\Model\Payment;
$percentFeeCalculator = new PercentFeeCalculator();
$payment = new Payment();
$payment->setAmount(200);
$configuration = array('percent' => 10);
$percentFeeCalculator->calculate($payment, $configuration); // returns 20
DelegatingFeeCalculator
This calculator doesnt do any calculations itself, instead it uses a specified calculator to do the work and just returns
the result.
<?php
use
use
use
use
Sylius\Component\Payment\Model\Payment;
Sylius\Component\Payment\Model\PaymentMethod;
Sylius\Component\Payment\Calculator\DelegatingFeeCalculator;
Sylius\Component\Registry\ServiceRegistry;
285
Sylius, Release
$calculator = DelegatingFeeCalculator($registry);
$configurations = array('amount' => 14, 'percent' => 23);
$paymentMethod = new PaymentMethod();
$paymentMethod->setFeeCalculatorConfiguration($configurations);
$payment = new Payment();
$payment->setAmount(200);
$payment->setMethod($paymentMethod);
$calculator->calculate($payment); // returns 14 as the FixedFeeCalculator
// is set by default
$paymentMethod->setFeeCalculator(DefaultFeeCalculators::PERCENT);
$calculator->calculate($payment); // now it returns 46
// because we changed to the PercentFeeCalculator
Hint: All the default calculator types are available via the DefaultFeeCalculators class.
Note: This service implements the DelegatingFeeCalculatorInterface.
Models
Payment
Every payment is represented by a Payment instance and has the following properties:
Property
id
method
currency
amount
state
creditCard
details
createdAt
updatedAt
deletedAt
Description
Unique id of the payment
Payment method associated with this payment
Payments currency
Payments amount
Payments state
Credit card as a source
Payments details
Date of creation
Date of the last update
Date of deletion
Note: This model implements the PaymentInterface and the PaymentSubjectInterface. For more detailed information
go to Sylius API Payment.
Hint: All default payment states are available in Payment States.
CreditCard
Every credit card is represented by a CreditCard instance and has the following properties:
286
Chapter 8. Components
Sylius, Release
Property
id
token
type
cardholderName
number
securityCode
expiryMonth
expiryYear
createdAt
updatedAt
Description
Unique id of the credit card
Payment gateway token
Type of credit card (VISA, MasterCard...)
Cardholders name
Card number
Security code
Expiry month
Expiry year
Date of creation
Date of the last update
Note: This model implements the CreditCardInterface. For more detailed information go to Sylius API CreditCard.
PaymentMethod
Every method of payment is represented by a PaymentMethod instance and has the following properties:
Property
id
name
enabled
description
gateway
environment
feeCalculator
feeCalculatorConfiguration
createdAt
updatedAt
Description
Unique id of the payment method
Payment methods name
Indicate whether the payment method is enabled
Payment methods description
Payment methods gateway to use
Required app environment
Calculator for additional fee costs (by default set to fixed)
Fee calculators configuration
Date of creation
Date of the last update
Note: This model implements the PaymentMethodInterface. For more detailed information go to Sylius API PaymentMethod.
PaymentMethodTranslation
This model is used to ensure that different locales have the correct representation of the following payment properties:
Property
id
name
description
Description
Unique id of the payment method
Payment methods name
Payment methods description
Note: This model extends the component_resource_model_abstract-translation and implements the PaymentMethodTranslationInterface. For more detailed information go to Sylius API PaymentMethodTranslation.
Interfaces
Model Interfaces
CreditCardInterface This interface should be implemented by any custom model representing a credit card. It also
contains all the default Credit Card Types.
287
Sylius, Release
Note: This interface extends the PaymentSourceInterface and the TimestampableInterface. For more detailed information go to Sylius API CreditCardInterface.
PaymentInterface This interface should be implemented by any custom model representing a payment. Also it
keeps all of the default /components/Payment/payment_states.
Note: This interface extends the TimestampableInterface and the SoftDeletableInterface. For more detailed information go to Sylius API PaymentInterface.
PaymentMethodInterface In order to create a custom payment method class, which could be used by other models
or services from this component, it needs to implement this interface.
Note: This interface extends the TimestampableInterface and the PaymentMethodTranslationInterface. For more
detailed information go to Sylius API PaymentMethodInterface.
PaymentMethodsAwareInterface This interface should be implemented by any custom storage used to store representations of the payment method.
Note: For more detailed information go to Sylius API PaymentMethodsAwareInterface.
PaymentSourceInterface This interface needs to be implemented by any custom payment source. The default
payment source is CreditCard.
Note: For more detailed information go to Sylius API PaymentSourceInterface.
PaymentSubjectInterface Only a class implementing this interface can be a used for fee calculation.
Note: For more detailed information go to Sylius API PaymentSubjectInterface.
PaymentsSubjectInterface Any container which manages multiple payments should implement this interface.
Note: For more detailed information go to Sylius API PaymentsSubjectInterface.
Service Interfaces
FeeCalculatorInterface This interface should be implemented by any service designed to calculate the fee of a
payment.
288
Chapter 8. Components
Sylius, Release
DelegatingFeeCalculatorInterface This interface should be implemented by any service which doesnt calculate
the fee by itself, but instead chooses another calculator (from a registry etc.) to do the calculation, and then returns the
result.
Note: For more detailed information go to Sylius API DelegatingFeeCalculatorInterface.
Type
visa
mastercard
discover
amex
diners_club
jcb
switch
solo
dankort
maestro
forbrugsforeningen
laser
DefaultFeeCalculators
The following calculator types are available by default:
Related constant
FIXED
PERCENT
Type
fixed
percent
289
Sylius, Release
State Machine
Payment States
State
new
pending
processing
completed
authorized
failed
cancelled
void
refunded
unknown
Description
The newly created payment
Payment waiting to be processed
Payment which is in process of verification
Completed payment
Payment which has been authorized
Payment has failed
Cancelled by a customer or manager
Payment timed out or an order with it has been canceled
A completed payment which has been refunded
Payment is in an unknown state
Payment Transitions
Transition
create
process
complete
fail
cancel
refund
void
Name
sylius_payment
Note: All of above transitions and the graph are constant fields in the PaymentTransitions class.
8.1.16 Pricing
Calculating prices is a common task for most PHP E-Commerce applications. This library provides multiple strategies
and flexible calculators system.
Installation
We assume youre familiar with Composer, a dependency manager for PHP. Use following command to add the
component to your composer.json and download package.
If you have Composer installed globally.
290
Chapter 8. Components
Sylius, Release
Summary
phpspec2 examples
$ composer install --dev --prefer-dist
$ bin/phpspec run -fpretty --verbose
Bug tracking
This component uses GitHub issues. If you have found bug, please create an issue.
8.1.17 Product
Powerful products catalog for PHP applications.
Installation
We assume youre familiar with Composer, a dependency manager for PHP. Use following command to add the
component to your composer.json and download package.
If you have Composer installed globally.
$ composer require sylius/product:*
Models
The Product
Product is the main model in SyliusProductComponent. This simple class represents every unique product in the
catalog. The default interface contains the following attributes with appropriate setters and getters.
291
Sylius, Release
Attribute
id
name
slug
description
availableOn
metaDescription
metaKeywords
createdAt
updatedAt
deletedAt
Description
Unique id of the product
Name of the product
SEO slug, by default created from the name
Description of your great product
Date when product becomes available in catalog
Description for search engines
Comma separated list of keywords for product (SEO)
Date when product was created
Date of last product update
Date of deletion from catalog
Product Properties
Except products, you can also define Properties (think Attributes) and define their values on each product. Default
property model has following structure.
Attribute
id
name
presentation
type
createdAt
updatedAt
Description
Unique id of the property
Name of the property (T-Shirt Material)
Pretty name visible for user (Material)
Property type
Date when property was created
Date of last property update
Currently there are several different property types are available, a proper form widget (Symfony Form type) will be
rendered on product form for entering the value.
Type
text
number
percentage
checkbox
choice
Summary
phpspec2 examples
$ composer install --dev --prefer-dist
$ bin/phpspec run -fpretty --verbose
Bug tracking
This component uses GitHub issues. If you have found bug, please create an issue.
8.1.18 Promotion
Super-flexible promotions system with support of complex rules and actions. Coupon codes included!
292
Chapter 8. Components
Sylius, Release
Installation
We assume youre familiar with Composer, a dependency manager for PHP. Use following command to add the
component to your composer.json and download package.
If you have Composer installed globally.
$ composer require sylius/promotion:*
Summary
phpspec2 examples
$ composer install --dev --prefer-dist
$ bin/phpspec run -fpretty --verbose
Bug tracking
This component uses GitHub issues. If you have found bug, please create an issue.
8.1.19 RBAC
Sylius Rbac component implements a hierarchical variant of RBAC, which means that we have separate concept of
Users (Identity), Roles and Permissions. Every Identity can have multiple roles, which inherit all permissions from
their child roles. Permissions are defined as tree as well, top level tree has all the permissions defined in the lower
nodes.
Installation
You can install the component in 2 different ways:
Install it via Composer (sylius\rbac on Packagist);
Use the official Git repository (https://github.com/Sylius/Rbac).
Then, require the vendor/autoload.php file to enable the autoloading mechanism provided by Composer. Otherwise, your application wont be able to find the classes of this Sylius component.
Basic Usage
To use RBAC without Symfony2, you need to implement your own services.
293
Sylius, Release
Permissions are connected to Roles, rather than concrete users. Every Identity can have multiple roles, which inherits
all permissions from their child roles.
<?php
use Sylius\Component\Rbac\Model\Role;
use Sylius\Component\Rbac\Model\Permission;
// Assume that in your application you want to have two roles and some permissions to manage customer
// Let's start with creating root permission.
$manageCustomer = new Permission();
$manageCustomer->setCode('sylius.manage.customer');
$manageCustomer->setDescription('Manage customers');
// Next create more specific permissions.
$deleteCustomer = new Permission();
$deleteCustomer->setCode('sylius.delete.customer');
$deleteCustomer->setDescription('Delete customer');
$createCustomer = new Permission();
$createCustomer->setCode('sylius.create.customer');
$createCustomer->setDescription('Create customer');
// Now take care of permission inheritance.
$manageCustomer->addChild($deleteCustomer);
$manageCustomer->addChild($createCustomer);
//Great! Now we have Customer Manager permission which inherits above permissions.
// Roles are defined as tree structure as well, it is the same rule as with permissions.
// Let's start with our root role.
$administrator = new Role();
$administrator->setCode('administrator');
$administrator->setName('Administrator');
$customerManager = new Role();
$customerManager->setCode('customer_manager');
$customerManager->setName('Customer Manager');
// Take care of role inheritance.
$administrator->addChild($customerManager);
$customerManager->addPermission($manageCustomer);
// Now Administrator and Catalog Manager have permission to manage customer.
AuthorizationChecker
294
Chapter 8. Components
Sylius, Release
use
use
use
use
use
Sylius\Component\Resource\Repository\InMemoryRepository;
Sylius\Component\Rbac\Authorization\PermissionMap;
Sylius\Component\Rbac\Provider\PermissionProvider;
Sylius\Component\Rbac\Resolver\PermissionsResolver;
Sylius\Component\Rbac\Resolver\RolesResolver;
PermissionMap
Sylius\Component\Resource\Repository\InMemoryRepository;
Sylius\Component\Rbac\Authorization\PermissionMap;
Sylius\Component\Rbac\Provider\PermissionProvider;
Sylius\Component\Rbac\Resolver\PermissionsResolver;
Sylius\Component\Rbac\Model\Role;
Sylius\Component\Rbac\Model\Permission;
295
Sylius, Release
CachedPermissionMap
If you need to get faster access to permissions you can use cache system in your application.
PermissionProvider
<?php
use Sylius\Component\Rbac\Provider\PermissionProvider;
use Sylius\Component\Resource\Repository\InMemoryRepository;
$permissions = new InMemoryRepository();
Permissions and roles are in tree model so basically resolvers and iterators have implemented logic to fetch leafs of
given permission or role.
<?php
use
use
use
use
use
use
use
Sylius\Component\Resource\Repository\InMemoryRepository;
Sylius\Component\Rbac\Model\Role;
Sylius\Component\Rbac\Model\Permission;
Sylius\Component\Rbac\Resolver\NestedSetPermissionsResolver;
Sylius\Component\Rbac\Resolver\NestedSetRolesResolver;
Sylius\Component\Rbac\Model\IdentityInterface;
Sylius\Component\Rbac\Model\RoleInterface;
296
Chapter 8. Components
Sylius, Release
Models
Permission
The Permission object represents an permission. Permissions are defined as a tree, top level tree has all the permissions defined in the lower nodes. Permissions have the following properties:
297
Sylius, Release
Property
id
code
description
parent
children
left
right
level
createdAt
updatedAt
Description
Unique id of the Permission
Unique code of Permission (e.g. sylius.customer.manage, sylius.channel.show)
(e.g. Manage customers, Show channel)
Reference to parent Permission
Collection of children Permissions
Reference to left leaf
Reference to right leaf
Tree level
Date when Permission was created
Date of last change
Note: This model implements the PermissionInterface. For more detailed information go to Sylius API Permission.
Role
The Role object represents an role. Every Identity can have multiple roles, which inherit all permissions from their
child roles. If you want to have Roles in your model, just implement IdentityInterface.
Property
id
code
name
description
parent
children
left
right
level
permissions
securityRoles
createdAt
updatedAt
Description
Unique id of the Role
Code of Role
Role name (e.g. Administrator, Catalog Manager, Shipping Manager)
(e.g. Administrator user, Shipping Department)
Reference to parent Role
Collection of children Roles
Reference to left leaf
Reference to right leaf
Tree level
Collection of Permissions
Collection of security roles (e.g. {ROLE_ADMINISTRATION_ACCESS})
Date when Role was created
Date of last change
Note: This model implements the RoleInterface. For more detailed information go to Sylius API Role.
Hint: For example implementation of tree model you can use Doctrine extension.
Interfaces
Model Interfaces
IdentityInterface This interface should be implemented by model representing a single Authorization Identity,
which has certain Roles assigned.
Note: For more detailed information go to Sylius API IdentityInterface.
Chapter 8. Components
Sylius, Release
Service Interfaces
CurrentIdentityProviderInterface Service implementing this interface should return an instance of currently used
identity.
Note: For more detailed information go to Sylius API CurrentIdentityProviderInterface.
PermissionProviderInterface Service implementing this interface should return an instance of permission by given
code.
Note: For more detailed information go to Sylius API PermissionProviderInterface.
AuthorizationCheckerInterface Service implementing this interface should check whether current identity has specific permission.
Note: For more detailed information go to Sylius API AuthorizationCheckerInterface.
PermissionMapInterface Service implementing this interface should return permissions by given code.
Note: For more detailed information go to Sylius API PermissionMapInterface.
PermissionRepositoryInterface In order to decouple from storage that provides permissions, you should create
repository class which implements this interface.
Note: For more detailed information go to Sylius API PermissionRepositoryInterface.
RoleRepositoryInterface In order to decouple from storage that provides roles, you should create repository class
which implements this interface.
Note: For more detailed information go to Sylius API RoleRepositoryInterface.
PermissionsResolverInterface Service implementing this interface should return permissions with all their child
permissions.
Note: For more detailed information go to Sylius API PermissionsResolverInterface.
299
Sylius, Release
RolesResolverInterface Service implementing this interface should return roles with their child roles.
Note: For more detailed information go to Sylius API RolesResolverInterface.
8.1.20 Registry
Simple registry component useful for all types of applications.
Installation
You can install the component in 2 different ways:
Install it via Composer (sylius\registry on Packagist);
Use the official Git repository (https://github.com/Sylius/Registry).
Then, require the vendor/autoload.php file to enable the autoloading mechanism provided by Composer. Otherwise, your application wont be able to find the classes of this Sylius component.
Basic Usage
A registry object acts as a collection of objects. The sylius ServiceRegistry allows you to store objects which implement a specific interface.
ServiceRegistry
To create a new ServiceRegistry you need to determine what kind of interface should be kept inside.
For the sake of examples lets use the FeeCalculatorInterface from the component_payment_index component.
<?php
use Sylius\Component\Registry\ServiceRegistry;
$registry = new ServiceRegistry('Sylius\Component\Payment\Calculator\FeeCalculatorInterface');
Once youve done that you can manage any object with the corresponding interface. So for starters, lets add some
services:
<?php
use Sylius\Component\Payment\Calculator\FixedFeeCalculator;
use Sylius\Component\Payment\Calculator\PercentFeeCalculator;
$registry->register('fixed', new FixedFeeCalculator());
$registry->register('percent', new PercentFeeCalculator());
Hint: The first parameter of register is incredibly important, as we will use it for all further operations. Also its
the key at which our service is stored in the array returned by all method.
After specifying the interface and inserting services, we can manage them:
300
Chapter 8. Components
Sylius, Release
<?php
$registry->has('fixed'); // returns true
$registry->get('fixed'); // returns the FixedFeeCalculator we inserted earlier on
$registry->all(); // returns an array containing both calculators
Interfaces
ServiceRegistryInterface
This interface should be implemented by a service responsible for managing various services.
Note: For more detailed information go to Sylius API ServiceRegistryInterface.
Exceptions
ExistingServiceException
This exception is thrown when you try to register a service that is already in the registry.
Note: This exception extends the \InvalidArgumentException.
NonExistingServiceException
This exception is thrown when you try to unregister a service which is not in the registry.
Note: This exception extends the \InvalidArgumentException.
301
Sylius, Release
8.1.21 Report
Super-flexible report system with posibility of custom report creation, based on already created data fetchers and
renderers.
Installation
You can install the component in 2 different ways:
Install it via Composer (sylius\report on Packagist);
Use the official Git repository (https://github.com/Sylius/Report).
Then, require the vendor/autoload.php file to enable the autoloading mechanism provided by Composer. Otherwise, your application wont be able to find the classes of this Sylius component.
Basic Usage
Note: First of all you need to register your data fetcher and renderer. For more detailed information go to
:ref:Registry_.
DelegatingDataFetcher
This service allows you to delegate fetching to your custom registered service. Your data fetcher class should implement DataFetcherInterface.
<?php
use Sylius\Component\Report\DataFetcher\DataFetcherInterface;
/**
* Sales total data fetcher
*/
class SalesTotalDataFetcher implements DataFetcherInterface
{
const TYPE = 'sales_total';
/**
* {@inheritdoc}
*/
public function fetch(array $configuration)
{
// TODO: Implement fetch() method.
}
/**
* {@inheritdoc}
*/
public function getType()
{
return self::TYPE;
}
}
302
Chapter 8. Components
Sylius, Release
<?php
use
use
use
use
use
use
use
use
Sylius\Component\Report\DataFetcher\Data;
Sylius\Component\Report\DataFetcher\DefaultDataFetchers;
Sylius\Component\Report\Renderer\DefaultRenderers;
Sylius\Component\Report\DataFetcher\DelegatingDataFetcher;
Sylius\Component\Registry\ServiceRegistry;
Sylius\Component\Report\Model\Report;
Sylius\Component\Report\Renderer\RendererInterface;
Sylius\Component\Report\Model\ReportInterface;
DelegatingRenderer
This service allows you to delegate rendering to your custom registered service. Your renderer should implement
RendererInterface.
<?php
use Sylius\Component\Report\Renderer\RendererInterface;
class TableRenderer implements RendererInterface
{
const TYPE = 'table';
/**
* {@inheritdoc}
*/
public function render(ReportInterface $report, Data $data)
{
// TODO: Implement render() method.
}
/**
* {@inheritdoc}
*/
public function getType()
{
return self::TYPE;
}
}
303
Sylius, Release
<?php
use
use
use
use
use
use
use
Sylius\Component\Report\DataFetcher\Data;
Sylius\Component\Report\Renderer\DelegatingRenderer;
Sylius\Component\Report\DataFetcher\DefaultDataFetchers;
Sylius\Component\Report\Renderer\DefaultRenderers;
Sylius\Component\Registry\ServiceRegistry;
Sylius\Component\Report\Model\Report;
Sylius\Component\Report\Model\ReportInterface;
Models
Report
Report is the main model in SyliusReportComponent. This simple class represents every unique report in the system.
The default model contains the following attributes with appropriate setters and getters.
Attribute
id
code
name
description
renderer
rendererConfiguration
dataFetcher
dataFetcherConfiguration
Description
Unique id of the report
Unique code of the report
Name of the report
Description of your report
Name of the renderer that visualize report data
Configuration of used renderer
Name of the dataFetcher that provides report data
Configuration of used data fetcher
Note: This model implements the ReportInterface For more detailed information go to Sylius API Report.
Data
Description
Array of labels that describe data
Array of values with data
304
Chapter 8. Components
Sylius, Release
Interfaces
Model Interfaces
Service Interfaces
DataFetcherInterface This interface should be implemented by service representing data fetcher. Responsible for
providing specific data for a report, based on its configuration.
Note: For more detailed information go to Sylius API DataFetcherInterface.
RendererInterface This interface should be implemented by service representing data renderer, which renders the
data in a specific output format. Examples would be graph, table, csv.
Note: For more detailed information go to Sylius API RendererInterface.
DelegatingDataFetcherInterface This interface should be implemented by service responsible for delegating data
fetching.
Note: For more detailed information go to Sylius API DelegatingDataFetcherInterface.
DelegatingRendererInterface This interface should be implemented by service responsible for delegating data rendering.
Note: For more detailed information go to Sylius API DelegatingRendererInterface.
8.1.22 Resource
Domain management abstraction for PHP. It provides interface for most common operations on the application resources.
Installation
We assume youre familiar with Composer, a dependency manager for PHP. Use following command to add the
component to your composer.json and download package.
If you have Composer installed globally.
$ composer require sylius/resource:*
305
Sylius, Release
Model interfaces
SoftDeletableInterface
This interface will ask you to implement the following methods to your model, they will use by the soft deletable
Doctrine2 extension. :
Method
isDeleted()
getDeletedAt()
setDeletedAt(DateTime $deletedAt)
Description
Check if the resource has been deleted
Get the time of deletion
Cet deletion time.
Returned value
boolean
DateTime
Void
TimestampableInterface
This interface will ask you to implement the following methods to your model, they will use by the timestampable
Doctrine2 extension. :
Method
getCreatedAt()
getUpdatedAt()
setCreatedAt(DateTime $createdAt)
setUpdatedAt(DateTime $updatedAt)
Description
Get creation time
Get the time of last update
Set creation time
Set the time of last update
Returned value
DateTime
DateTime
Void
Void
Repository interfaces
RepositoryInterface
This interface will ask you to implement two methods to your repositories:
Method
Description
createNew()
Returned
value
mixed
mixed
Summary
phpspec2 examples
$ composer install --dev --prefer-dist
$ bin/phpspec run -fpretty --verbose
Bug tracking
This component uses GitHub issues. If you have found bug, please create an issue.
306
Chapter 8. Components
Sylius, Release
8.1.23 Sequence
Component for generating number/hash sequences in PHP.
Installation
You can install the component in 2 different ways:
Install it via Composer (sylius/sequence on Packagist);
Use the official Git repository (https://github.com/Sylius/Sequence).
Then, require the vendor/autoload.php file to enable the autoloading mechanism provided by Composer. Otherwise, your application wont be able to find the classes of this Sylius component.
Basic Usage
In order to benefit from the components features at first you need to create a basic class that will implement the
SequenceSubjectInterface. Lets assume that you would like to generate identifiers for orders in your system. Your
Order class therefore will implement this interface to have and ability to be a subject of sequence automatic generation
by your services.
SequenceSubjectInterface
Lets see how an exemplary class implementing SequenceSubjectInterface should look like.
<?php
namespace AppBundle\Entity\Order;
use Sylius\Component\Sequence\Model\SequenceSubjectInterface;
class Order implements SequenceSubjectInterface
{
const SEQUENCE_TYPE = 'order';
/**
* @var string
*/
private $number;
/**
* {@inheritdoc}
*/
public function getSequenceType()
{
return self::SEQUENCE_TYPE;
}
/**
* {@inheritdoc}
*/
public function getNumber()
{
return $this->number;
}
307
Sylius, Release
/**
* {@inheritdoc}
*/
public function setNumber($number)
{
$this->number = $number;
}
}
Hint: You can read more about each of the available generators in the Generators chapter.
Models
Sequence
Sequence is a generated set of numbers and/or letters stored on a model. They may be useful for example as order or
customer identifiers.
Property
id
index
type
Description
Unique id of the sequence
The sequences index
The sequences type
Note: This model implements the SequenceInterface. For more detailed information go to Sylius API Sequence.
Interfaces
Model Interfaces
308
Chapter 8. Components
Sylius, Release
Note: You will find more information about this interface in Sylius API SequenceInterface.
SequenceSubjectInterface To characterize an object with attributes and options from a sequence, the object class
needs to implement the SequenceSubjectInterface.
Note: You will find more information about this interface in Sylius API SequenceSubjectInterface.
Service Interfaces
GeneratorInterface This interface gives a possibility to generate and apply next available number for a given subject.
Note: You will find more information about this interface in Sylius API GeneratorInterface.
HashSubjectRepositoryInterface Repository interface for model which needs number uniqueness check before
applying. It provides a method isNumberUsed().
Note: You will find more information about this interface in Sylius API HashSubjectRepositoryInterface.
Generators
AbstractGenerator
A custom generator model should extend this class in order to generate sequences on a given object that implements
the SequenceSubjectInterface.
Note: This class implements the GeneratorInterface. For more detailed information go to Sylius API AbstractGenerator.
SequentialGenerator
Description
Order number max length
The sequence start number
309
Sylius, Release
Note: This generator implements the GeneratorInterface and extends the AbstractGenerator. For more detailed
information go to Sylius API SequentialGenerator.
HashGenerator
This class generates hash numbers similar to the Amazon order identifiers (e.g. 105-3958356-3707476) and also
random hashed segments of a given length.
Below you can see a snippet on how to use it:
<?php
$subject = new Order();
$repository = new InMemoryRepository();
// Instantiate the generator that will generate a 3 by 7 by 7 digits number.
$generator = new HashGenerator($repository);
$index = /** index of the sequence **/
$generator->generateNumber($index, $subject);
$subject->getNumber(); // returns randomized sequence of format 'xxx-xxxxxxx-xxxxxxx'
Note: This generator implements the GeneratorInterface and extends the AbstractGenerator. For more detailed
information go to Sylius API HashGenerator.
GeneratorRegistry
NonExistingGeneratorException
This exception is thrown when your are trying to get a generator that does not exist in your system.
Note: This exception extends the \InvalidArgumentException.
8.1.24 Shipping
Shipments and shipping methods management for PHP E-Commerce apps. It contains flexible calculators system for
computing the shipping costs.
310
Chapter 8. Components
Sylius, Release
Installation
We assume youre familiar with Composer, a dependency manager for PHP. Use following command to add the
component to your composer.json and download package.
If you have Composer installed globally.
$ composer require sylius/shipping:*
Summary
phpspec2 examples
$ composer install --dev --prefer-dist
$ bin/phpspec run -fpretty --verbose
Bug tracking
This component uses GitHub issues. If you have found bug, please create an issue.
8.1.25 Taxation
Tax rates and tax classification for PHP apps. You can define different tax categories and match them to objects.
Installation
We assume youre familiar with Composer, a dependency manager for PHP. Use following command to add the
component to your composer.json and download package.
If you have Composer installed globally.
$ composer require sylius/taxation:*
Models
The Tax rate
Tax rate model holds the configuration for particular tax rate.
311
Sylius, Release
Attribute
id
category
name
amount
includedInPrice
calculator
createdAt
updatedAt
Description
Unique id of the tax rate
Tax rate category
Name of the rate
Amount as float (for example 0,23)
Is the tax included in price?
Type of calculator
Date when the rate was created
Date of the last tax rate update
Tax category model holds the configuration for particular tax category.
Attribute
id
name
description
rates
createdAt
updatedAt
Description
Unique id of the tax category
Name of the category
Description of tax category
Collection of tax rates belonging to this tax category
Date when the category was created
Date of the last tax category update
Summary
phpspec2 examples
$ composer install --dev --prefer-dist
$ bin/phpspec run -fpretty --verbose
Bug tracking
This component uses GitHub issues. If you have found bug, please create an issue.
8.1.26 Taxonomy
Basic taxonomies library for any PHP application.
Installation
We assume youre familiar with Composer, a dependency manager for PHP. Use following command to add the
component to your composer.json and download package.
If you have Composer installed globally.
$ composer require sylius/taxonomy:*
312
Chapter 8. Components
Sylius, Release
Models
Taxonomy is a list constructed from individual Taxons. Every taxonomy has one special taxon, which serves as a root
of the tree. All taxons can have many child taxons, you can define as many of them as you need.
A good examples of taxonomies are Categories and Brands. Below you can see an example tree.
| Categories
|-- T-Shirts
|
|-- Men
|
`-- Women
|-- Stickers
|-- Mugs
`-- Books
| Brands
|-- SuperTees
|-- Stickypicky
|-- Mugland
`-- Bookmania
Taxonomy
Attribute
id
name
root
createdAt
updatedAt
Description
Unique id of the taxonomy
Name of the taxonomy
First, root Taxon
Date when taxonomy was created
Date of last update
Type
mixed
string
TaxonInterface
DateTime
DateTime
Description
Get all taxons
Check if the taxonomy has taxon
Add a taxon
Remove a taxon
Returned value
TaxonInterface[]
boolean
Void
Void
313
Sylius, Release
Taxons
Attribute
id
name
slug
permalink
description
taxonomy
parent
children
left
right
level
createdAt
updatedAt
Description
Unique id of the taxon
Name of the taxon
Urlized name
Full permalink for given taxon
Description of taxon
Taxonomy
Parent taxon
Sub taxons
Location within taxonomy
Location within taxonomy
How deep it is in the tree
Date when taxon was created
Date of last update
Type
mixed
string
string
string
string
TaxonomyInterface
TaxonInterface
Collection
mixed
mixed
mixed
DateTime
DateTime
Description
Check whether the taxon has a child
Add child taxon
Remove child taxon.
Returned value
boolean
Void
Void
TaxonsAwareInterface
Description
Get all taxons
Set the taxons
Checks whether object has taxon
Add a taxon
Remove a taxon
Returned value
TaxonInterface[]
Void
Boolean
TaxonomyInterface
TaxonomyInterface
Summary
phpspec2 examples
$ composer install --dev --prefer-dist
$ bin/phpspec run -fpretty --verbose
Bug tracking
This component uses GitHub issues. If you have found bug, please create an issue.
8.1.27 Translation
Translations management for PHP E-Commerce applications.
314
Chapter 8. Components
Sylius, Release
Installation
You can install the component in 2 different ways:
Install it via Composer (sylius/translation on Packagist);
Use the official Git repository (https://github.com/Sylius/Translation).
Then, require the vendor/autoload.php file to enable the autoloading mechanism provided by Composer. Otherwise, your application wont be able to find the classes of this Sylius component.
Basic Usage
Implementing AbstractTranslation
First lets create a class which will keep our translatable properties:
<?php
namespace Example\Model;
use Sylius\Component\Translation\Model\AbstractTranslation;
class BookTranslation extends AbstractTranslation
{
/**
* @var string
*/
private $title;
/**
* @return string
*/
public getTitle()
{
return $this->title;
}
/**
* @param string $title
*/
public setTitle($title)
{
$this->title = $title;
}
}
Implementing AbstractTranslatable
Now the following class will be actually capable of translating the title:
<?php
namespace Example\Model;
use Sylius\Component\Translation\Model\AbstractTranslatable;
315
Sylius, Release
Note: As you could notice, inside both methods we use the translate method. More specified explanation on
what it does is described further on.
Using Translations
Once we have both abstract classes implemented we can start translating. So first we need to create a few instances of
our translation class:
<?php
use Example\Model\Book;
use Example\Model\BookTranslation;
$englishBook = new BookTranslation();
$englishBook->setLocale('en');
$englishBook->setTitle("Harry Potter and the Philosopher's Stone");
// now we have a title set for the english locale
$spanishBook = new BookTranslation();
$spanishBook->setLocale('es');
$spanishBook->setTitle('Harry Potter y la Piedra Filosofal');
// spanish
$germanBook = new BookTranslation();
$germanBook->setLocale('de');
$germanBook->setTitle('Harry Potter und der Stein der Weisen');
// and german
When we already have our translations, we can work with the Book:
<?php
$harryPotter = new Book();
$harryPotter->addTranslation($englishBook);
$harryPotter->addTranslation($spanishBook);
$harryPotter->addTranslation($germanBook);
316
Chapter 8. Components
Sylius, Release
You can always use the translate method by itself, but the same principal is in play:
<?php
$harryPotter->translate('de');
// but
$harryPotter->translate();
// and
$harryPotter->translate('hi');
// both return $englishBook
// returns $germanBook
LocaleProvider
This service provides you with an easy way of managing locales. The first parameter set in its constructor is the
current locale and the second, fallback.
In this example lets use the provider with our Book class which extends the AbstractTranslatable:
<?php
use Example\Model\Book;
use Sylius\Component\Translation\Provider\LocaleProvider;
$provider = new LocaleProvider('de', 'en');
$book = new Book();
$book->setCurrentLocale($provider->getCurrentLocale());
$book->setFallbackLocale($provider->getFallbackLocale());
$book->getCurrentLocale(); // returns 'de'
$book->getFallbackLocale(); // returns 'en'
... and with an AbstractTranslation class such as the exemplary BookTranslation it goes:
<?php
use Example\Model\BookTranslation;
use Sylius\Component\Translation\Provider\LocaleProvider;
317
Sylius, Release
Models
AbstractTranslatable
This class should be extended by any model which needs different presentations of its fields in various locales.
Property
translations
currentLocale
currentTranslation
fallbackLocale
Description
List of objects implementing the AbstractTranslation class
Currently set locale
Translation chosen from translations list accordingly to current locale
Locale used in case no translation is available for the current one
Note: This model implements the TranslatableInterface. For more detailed information go to Sylius API AbstractTranslatable.
AbstractTranslation
This class should be extended by a model responsible of maintaining a single translation for provided locale.
Property
locale
translatable
Description
Translations locale
The translatable model associated with this translation
Note: This model implements the TranslationInterface. For more detailed information go to Sylius API AbstractTranslation.
Interfaces
Model Interfaces
TranslatableInterface This interface should be implemented by a model used in more than one language.
Hint: Although you can implement this interface in your class, its easier to just extend the AbstractTranslatable
class.
Note: For more detailed information go to Sylius API TranslatableInterface.
318
Chapter 8. Components
Sylius, Release
TranslationInterface This interface should be implemented by a model responsible for keeping a single translation.
Hint: And as above, although you are completely free to create your own class implementing this interface, its
already implemented in the AbstractTranslation class.
Note: For more detailed information go to Sylius API TranslationInterface.
Service Interfaces
LocaleProviderInterface This interface should be implemented by a service responsible for managing locales.
Note: For more detailed information go to Sylius API LocaleProviderInterface.
8.1.28 User
Users management implementation in PHP.
Installation
You can install the component in 2 different ways:
Install it via Composer (sylius/user on Packagist);
Use the official Git repository (https://github.com/Sylius/User).
Then, require the vendor/autoload.php file to enable the autoloading mechanism provided by Composer. Otherwise, your application wont be able to find the classes of this Sylius component.
Models
Customer
The customer is represented as a Customer instance. It should have everything concerning personal data and as default
has the following properties:
319
Sylius, Release
Property
id
email
emailCanonical
firstName
lastName
birthday
gender
user
groups
createdAt
updatedAt
deletedAt
Description
Unique id of the customer
Customers email
Normalized representation of an email (lowercase)
Customers first name
Customers last name
Customers birthday
Customers gender
Corresponding user object
Customers groups
Date of creation
Date of update
Date of deletion
Type
integer
string
string
string
string
DateTime
string
UserInterface
Collection
DateTime
DateTime
DateTime
User
The registered user is represented as an User instance. It should have everything concerning application user preferences and a corresponding Customer instance. As default has the following properties:
Property
id
customer
username
usernameCanonical
enabled
salt
password
plainPassword
lastLogin
confirmationToken
passwordRequestedAt
locked
expiresAt
credentialExpiresAt
roles
oauthAccounts
createdAt
updatedAt
deletedAt
Description
Unique id of the user
Customer which is associated to this user (required)
Users username
Normalized representation of a username (lowercase)
Indicates whether user is enabled
Additional input to a function that hashes a password
Encrypted password, must be persisted
Password before encryption, must not be persisted
Last login date
Random string used to verify user
Date of password request
Indicates whether user is locked
Date when user account will expire
Date when user account credentials will expire
Security roles of a user
Associated OAuth accounts
Date of creation
Date of update
Date of deletion
Type
integer
CustomerInterface
string
string
bool
string
string
string
DateTime
string
DateTime
bool
DateTime
DateTime
array
Collection
DateTime
DateTime
DateTime
Group
The customer group is represented as a Group instance. It can be used to classify customers. As default has the
following properties:
Property
id
name
320
Description
Unique id of the group
Group name
Type
integer
string
Chapter 8. Components
Sylius, Release
UserOAuth
The user OAuth account is represented as an UserOAuth instance. It has all data concerning OAuth account and as
default has the following properties:
Property
id
provider
identifier
accessToken
user
Description
Unique id of the customer
OAuth provider name
OAuth identifier
OAuth access token
Corresponding user account
Type
integer
string
string
string
UserInterface
Basic Usage
Canonicalization
In order to be able to query or sort by some string, we should normalize it. The most common use case for that is
canonical email or username. We can then allow for case insensitive users identification by email or username.
Canonicalizer User component offers simple canonicalizer which converts given string to lowercase letters. Example usage:
// File example: src/script.php
<?php
// update this to the path to the "vendor/"
// directory, relative to this file
require_once __DIR__.'/../vendor/autoload.php';
use Sylius\Component\User\Model\Customer;
use Sylius\Component\Canonicalizer\Canonicalizer;
$canonicalizer = new Canonicalizer();
$customer = new Customer();
$customer->setEmail('MyEmail@eXample.Com');
$canonicalEmail = $canonicalizer->canonicalize($customer->getEmail());
$customer->setEmailCanonical($canonicalEmail);
$customer->getEmail() // returns 'MyEmail@eXample.Com'
$customer->getEmailCanonical() // returns 'myemail@example.com'
Updating password
In order to store users password safely you need to encode it and get rid of the plain password.
321
Sylius, Release
PasswordUpdater User component offers simple password updater and encoder. All you need to do is set the plain
password on User entity and use updatePassword method on PasswordUpdater. The plain password will be removed
and the encoded password will be set on User entity. Now you can safely store the encoded password. Example usage:
// File example: src/script.php
<?php
// update this to the path to the "vendor/"
// directory, relative to this file
require_once __DIR__.'/../vendor/autoload.php';
use Sylius\Component\User\Model\User;
use Sylius\Component\User\Security\PasswordUpdater;
use Sylius\Component\User\Security\UserPbkdf2PasswordEncoder;
$user = new User();
$user->setPlainPassword('secretPassword');
$user->getPlainPassword(); // returns 'secretPassword'
$user->getPassword(); // returns null
// after you set user's password you need to encode it and get rid of unsafe plain text
$passwordUpdater = new PasswordUpdater(new UserPbkdf2PasswordEncoder());
$passwordUpdater->updatePassword($user);
// the plain password no longer exist
$user->getPlainPassword(); // returns null
// encoded password can be safely stored
$user->getPassword(); //returns 'notPredictableBecauseOfSaltHashedPassword'
Note: The password encoder takes users salt (random, autogenerated string in the User constructor) as an additional
input to a one-way function that hashes a password. The primary function of salts is to defend against dictionary
attacks versus a list of password hashes and against pre-computed rainbow table attacks.
8.1.29 Variation
Library for managing object variants and options. This functionality can be attached to any object to create different
configurations.
Installation
You can install the component in 2 different ways:
Install it via Composer (sylius\variation on Packagist);
Use the official Git repository (https://github.com/Sylius/Variation).
Then, require the vendor/autoload.php file to enable the autoloading mechanism provided by Composer. Otherwise, your application wont be able to find the classes of this Sylius component.
322
Chapter 8. Components
Sylius, Release
Basic Usage
VariableInterface
Lets see how an exemplary class implementing the VariableInterface should look like.
<?php
use
use
use
use
use
Sylius\Component\Variation\Model\VariableInterface;
Doctrine\Common\Collections\Collection;
Doctrine\Common\Collections\ArrayCollection;
Sylius\Component\Variation\Model\VariantInterface;
Sylius\Component\Variation\Model\OptionInterface;
323
Sylius, Release
{
$this->master = $variant;
}
/**
* {@inheritdoc}
*/
public function hasVariants()
{
if ($this->variants->isEmpty()) {
return false;
}
return true;
}
/**
* {@inheritdoc}
*/
public function getVariants()
{
return $this->variants;
}
/**
* {@inheritdoc}
*/
public function setVariants(Collection $variants)
{
$this->variants = $variants;
}
/**
* {@inheritdoc}
*/
public function addVariant(VariantInterface $variant)
{
$this->variants->add($variant);
}
/**
* {@inheritdoc}
*/
public function removeVariant(VariantInterface $variant)
{
$this->variants->removeElement($variant);
}
/**
* {@inheritdoc}
*/
public function hasVariant(VariantInterface $variant)
{
if ($this->variants->contains($variant)) {
return true;
}
return false;
324
Chapter 8. Components
Sylius, Release
}
/**
* {@inheritdoc}
*/
public function hasOptions()
{
if ($this->options->isEmpty()) {
return false;
}
return true;
}
/**
* {@inheritdoc}
*/
public function getOptions()
{
return $this->options;
}
/**
* {@inheritdoc}
*/
public function setOptions(Collection $options)
{
$this->options = $options;
}
/**
* {@inheritdoc}
*/
public function addOption(OptionInterface $option)
{
$this->options->add($option);
}
/**
* {@inheritdoc}
*/
public function removeOption(OptionInterface $option)
{
$this->options->removeElement($option);
}
/**
* {@inheritdoc}
*/
public function hasOption(OptionInterface $option)
{
if ($this->options->contains($option)) {
return true;
}
return false;
}
}
325
Sylius, Release
VariantGenerator
A VariantGenerator is used to create all possible combinations of an objects options and to create Variant models
from them.
Example:
If an object such as a T-shirt has 2 options - Color and Size - with 3 possible values per option, then the generator will
create 9 variants and assign them to the object.
The generator will ignore invalid variants or variants that already exist.
T-Shirt Options
Colors
Black
White
Red
Size
Small
Medium
Large
Sylius\Component\Variation\Generator\VariantGenerator;
Sylius\Component\Variation\Model\VariableInterface;
Sylius\Component\Variation\SetBuilder\CartesianSetBuilder;
Sylius\Component\Resource\Repository\InMemoryRepository;
326
Chapter 8. Components
Sylius, Release
Models
Variant
Every variant is represented by Variant instance and has the following properties:
Property
id
master
presentation
object
options
createdAt
updatedAt
Description
Unique id of the variant
Defines whether variant is master
Name displayed to user
Related product
Option values
Date of creation
Date of the last update
Note: This model implements the VariantInterface. You will find more information about this interface in Sylius API
Variant.
Option
Every variant option is represented by Option instance and has the following properties:
Property
id
name
presentation
values
createdAt
updatedAt
Description
Unique id of the Option
Internal name
Name displayed to user
Option values
Date of creation
Date of the last update
Note: This model implements the OptionInterface. You will find more information about this interface in Sylius API
Option.
OptionTranslation
Every variant option has a corresponding translation stored as an OptionTranslation instance and has the following
properties:
Property
id
presentation
Description
Unique id of the translation
Translated option name
327
Sylius, Release
Note: This model implements the OptionTranslationInterface. You will find more information about this interface in
Sylius API OptionTranslation.
OptionValue
Every variant option value is represented by OptionValue instance and has the following properties:
Property
id
value
option
Description
Unique id of the OptionValue
Option internal value
An instance of Option
Note: This model implements the OptionValueInterface. You will find more information about this interface in Sylius
API OptionValue.
Interfaces
Model Interfaces
VariableInterface In order for the object class to manage variants and options it has to implement the
VariableInterface.
Note: You will find more information about this interface in Sylius API VariableInterface.
VariantInterface When an object class implements the VariantInterface it has a possibility to manage options.
Note: This interface extends the component_resource_model_softdeletable-interface and the TimestampableInterface. You will find more information about this interface in Sylius API VariantInterface.
OptionInterface In order for an object class to represent the option type it has to implement the
OptionInterface.
Note: This interface extends the TimestampableInterface and the OptionTranslationInterface. You will find more
information about this interface in Sylius API OptionInterface.
OptionTranslationInterface In order to store the translation of an Option an object class needs to imlement this
interface.
Note: You will find more information about this interface in Sylius API OptionTranslationInterface.
OptionValueInterface If you need to store a value of an Option you will have to create an object class that implements this interface.
Note: You will find more information about that interface in Sylius API OptionValueInterface.
328
Chapter 8. Components
Sylius, Release
Services Interfaces
SetBuilderInterface When you want a service to be able to Build a product set from one or more given sets it should
implement the SetBuilderInterface.
Note: You will find more information about that interface in Sylius API SetBuilderInterface.
VariantGeneratorInterface This interface is used to create all possible (non-existing) variations of a given object
based on its options.
Note: You will find more information about that interface in Sylius API VariantGeneratorInterface.
Addressing
Archetype
Attribute
Cart
Channel
Contact
Currency
Grid
Inventory
Locales
Mailer
Order
Originator
Payment
Pricing
Product
Promotion
RBAC
Registry
Report
Resource
Sequence
Shipping
Taxation
Taxonomy
Translation
User
329
Sylius, Release
Variation
Addressing
Archetype
Attribute
Cart
Channel
Contact
Currency
Grid
Inventory
Locales
Mailer
Order
Originator
Payment
Pricing
Product
Promotion
RBAC
Registry
Report
Resource
Sequence
Shipping
Taxation
Taxonomy
Translation
User
Variation
330
Chapter 8. Components
CHAPTER 9
Contributing
9.1 Contributing
Note: This section is based on the great Symfony2 documentation.
331
Sylius, Release
Install the Software Stack Before working on Sylius, setup a Symfony2 friendly environment with the following
software:
Git;
PHP version 5.3.3 or above;
PHPUnit 3.6.4 or above;
MySQL.
Configure Git Set up your user information with your real name and a working email address:
$ git config --global user.name "Your Name"
$ git config --global user.email you@example.com
Tip: If you are new to Git, you are highly recommended to read the excellent and free ProGit book.
Tip: If your IDE creates configuration files inside the projects directory, you can use global .gitignore file (for
all projects) or .git/info/exclude file (per project) to ignore them. See Githubs documentation.
Tip: Windows users: when installing Git, the installer will ask what to do with line endings, and suggests replacing
all LF with CRLF. This is the wrong setting if you wish to contribute to Sylius. Selecting the as-is method is your
best choice, as Git will convert your line feeds to the ones in the repository. If you have already installed Git, you can
check the value of this setting by typing:
$ git config core.autocrlf
This will return either false, input or true; true and false being the wrong values. Change it to input by
typing:
$ git config --global core.autocrlf input
Replace global by local if you want to set it only for the active repository
Get the Sylius Source Code Get the Sylius source code:
Create a GitHub account and sign in;
Fork the Sylius repository (click on the Fork button);
After the forking action has completed, clone your fork locally (this will create a Sylius directory):
$ git clone git@github.com:USERNAME/Sylius.git
The License Before you start, you must know that all the patches you are going to submit must be released under
the MIT license, unless explicitly specified in your commits.
332
Chapter 9. Contributing
Sylius, Release
Create a Topic Branch Each time you want to work on a patch for a bug or on an enhancement, create a topic
branch:
$ git checkout -b BRANCH_NAME master
Tip: Use a descriptive name for your branch (issue_XXX where XXX is the GitHub issue number is a good
convention for bug fixes).
The above checkout commands automatically switch the code to the newly created branch (check the branch you are
working on with git branch).
Work on your Patch Work on the code as much as you want and commit as much as you want; but keep in mind
the following:
Practice BDD, which is the development methodology we use at Sylius;
Read about the Sylius conventions and follow the coding standards (use git diff --check to check for
trailing spaces also read the tip below);
Do atomic and logically separate commits (use the power of git rebase to have a clean and logical history);
Squash irrelevant commits that are just about fixing coding standards or fixing typos in your own code;
Never fix coding standards in some existing code as it makes the code review more difficult (submit CS fixes as
a separate patch);
Write good commit messages (see the tip below).
Tip: A good commit message is composed of a summary (the first line), optionally followed by a blank line and
a more detailed description. The summary should start with the Component you are working on in square brackets
([Cart], [Taxation], ...). Use a verb (fixed ..., added ..., ...) to start the summary and dont add a
period at the end.
Prepare your Patch for Submission When your patch is not about a bug fix (when you add a new feature or change
an existing one for instance), it must also include the following:
An explanation of the changes in the relevant CHANGELOG file(s) (the [BC BREAK] or the [DEPRECATION]
prefix must be used when relevant);
An explanation on how to upgrade an existing application in the relevant UPGRADE file(s) if the changes break
backward compatibility or if you deprecate something that will ultimately break backward compatibility.
Step 3: Submit your Patch
Whenever you feel that your patch is ready for submission, follow the following steps.
Rebase your Patch Before submitting your patch, update your branch (needed if it takes you a while to finish your
changes):
$
$
$
$
$
git
git
git
git
git
checkout master
fetch upstream
merge upstream/master
checkout BRANCH_NAME
rebase master
9.1. Contributing
333
Sylius, Release
When doing the rebase command, you might have to fix merge conflicts. git status will show you the unmerged files. Resolve all the conflicts, then continue the rebase:
$ git add ... # add resolved files
$ git rebase --continue
Make a Pull Request You can now make a pull request on the Sylius/Sylius GitHub repository.
To ease the core team work, always include the modified components in your pull request message, like in:
[Cart] Fixed something
[Taxation] [Addressing] Added something
The pull request description must include the following checklist at the top to ensure that contributions may be reviewed without needless feedback loops and that your contributions can be included into Sylius as quickly as possible:
|
|
|
|
|
|
|
|
|
Q
------------Bug fix?
New feature?
BC breaks?
Deprecations?
Fixed tickets
License
Doc PR
|
|
|
|
|
|
|
|
|
A
--[yes|no]
[yes|no]
[yes|no]
[yes|no]
[comma separated list of tickets fixed by the PR]
MIT
[The reference to the documentation PR if any]
Q
------------Bug fix?
New feature?
BC breaks?
Deprecations?
Fixed tickets
License
Doc PR
|
|
|
|
|
|
|
|
|
A
--no
no
no
no
#12, #43
MIT
Sylius/Sylius-Docs#123
The whole table must be included (do not remove lines that you think are not relevant). For simple typos, minor
changes in the PHPDocs, or changes in translation files, use the shorter version of the check-list:
|
|
|
|
Q
------------Fixed tickets
License
|
|
|
|
A
--[comma separated list of tickets fixed by the PR]
MIT
Chapter 9. Contributing
Sylius, Release
If you answer yes to Deprecations?, the patch must contain updates to the relevant CHANGELOG and
UPGRADE files;
If some of the previous requirements are not met, create a todo-list and add relevant items:
- [ ] Fix the specs as they have not been updated yet
- [ ] Submit changes to the documentation
- [ ] Document the BC breaks
If the code is not finished yet because you dont have time to finish it or because you want early feedback on your
work, add an item to todo-list:
- [ ] Finish the feature
- [ ] Gather feedback for my changes
As long as you have items in the todo-list, please prefix the pull request title with [WIP].
In the pull request description, give as much details as possible about your changes (dont hesitate to give code
examples to illustrate your points). If your pull request is about adding a new feature or modifying an existing one,
explain the rationale for the changes. The pull request description helps the code review.
In addition to this code pull request, you must also send a pull request to the documentation repository to update the
documentation when appropriate.
Rework your Patch Based on the feedback on the pull request, you might need to rework your patch. Before
re-submitting the patch, rebase with upstream/master, dont merge; and force the push to the origin:
$ git rebase -f upstream/master
$ git push --force origin BRANCH_NAME
Note: When doing a push --force, always specify the branch name explicitly to avoid messing other branches
in the repo (--force tells Git that you really want to mess with things so do it carefully).
Often, Sylius team members will ask you to squash your commits. This means you will convert many commits to
one commit. To do this, use the rebase command:
$ git rebase -i upstream/master
$ git push --force origin BRANCH_NAME
After you type this command, an editor will popup showing a list of commits:
pick 1a31be6 first commit
pick 7fc64b4 second commit
pick 7d33018 third commit
To squash all commits into the first one, remove the word pick before the second and the last commits, and replace
it by the word squash or just s. When you save, Git will start rebasing, and if successful, will ask you to edit the
commit message, which by default is a listing of the commit messages of all the commits. When you are finished,
execute the push command.
Security Issues
This document explains how Sylius issues are handled by the Sylius core team.
9.1. Contributing
335
Sylius, Release
If you think that you have found a security issue in Sylius, dont use the bug tracker and do not post it publicly. Instead,
all security issues must be sent to security [at] sylius.org. Emails sent to this address are forwarded to the Sylius core
team members.
Resolving Process
For each report, we first try to confirm the vulnerability. When it is confirmed, the team works on a solution following
these steps:
1. Send an acknowledgement to the reporter;
2. Work on a patch;
3. Write a security announcement for the official Sylius blog about the vulnerability. This post should contain the
following information:
a title that always include the Security release string;
a description of the vulnerability;
the affected versions;
the possible exploits;
how to patch/upgrade/workaround affected applications;
credits.
4. Send the patch and the announcement to the reporter for review;
5. Apply the patch to all maintained versions of Sylius;
6. Publish the post on the official Sylius blog;
7. Update the security advisory list (see below).
Note: Releases that include security issues should not be done on Saturday or Sunday, except if the vulnerability has
been publicly posted.
Note: While we are working on a patch, please do not reveal the issue publicly.
BDD Methodology
Note: This part of documentation is inspired by the official PHPSpec docs.
Sylius adopted the full-stack BDD methodology for its development processes.
According to Wikipedia:
BDD is a software development process based on test-driven development (TDD). Behavior-driven development combines the general techniques and principles of TDD with ideas from domain-driven design
and object-oriented analysis and design to provide software developers and business analysts with shared
tools and a shared process to collaborate on software development, with the aim of delivering software
that matters.
336
Chapter 9. Contributing
Sylius, Release
To run the entire suite of features and specs, including the ones that depend on external dependencies, Sylius needs
to be able to autoload them. By default, they are autoloaded from vendor/ under the main root directory (see
autoload.php.dist).
To install them all, use Composer:
Step 1: Get Composer
$ curl -s http://getcomposer.org/installer | php
Make sure you download composer.phar in the same folder where the composer.json file is located.
Step 2: Install vendors
$ php composer.phar install
Note: Note that the script takes some time (several minutes) to finish.
Note:
If you dont have curl installed, you can also just download the installer file manually at
http://getcomposer.org/installer. Place this file into your project and then run:
$ php installer
$ php composer.phar install
9.1. Contributing
337
Sylius, Release
127.0.0.1
sylius-test.local
Additionally, copy behat.yml.dist to behat.yml, edit base_url parameter to match your host:
default:
...
extensions:
Behat\MinkExtension\Extension:
...
base_url: http://sylius-test.local/app_test.php/
Behat
We use Behat for StoryBDD and you should always write new scenarios when adding a feature, or update existing
stories to adapt Sylius to business requirements changes.
Sylius is an open source project, so the client is not clearly visible at first look. But they are here - the Sylius users.
We have our needs and Behat helps us understand and satisfy these needs.
Note: To be written.
You can launch Selenium by issuing the following command:
$ java -jar selenium-server-standalone-2.38.0.jar
PHPSpec
PHPSpec is a PHP toolset to drive emergent design by specification. It is not really a testing tool, but a design
instrument, which helps structuring the objects and how they work together.
Sylius approach is to always describe the behavior of the next object you are about to implement.
As an example, well write a service, which updates product prices based on an external API. To initialize a new spec,
use the desc command.
We just need to tell PHPSpec we will be working on the PriceUpdater class.
$ bin/phpspec desc "Sylius\Bundle\CoreBundle\Pricing\PriceUpdater"
Specification for PriceUpdater created in spec.
338
Chapter 9. Contributing
Sylius, Release
What have we just done? PHPSpec has created the spec for us. You can navigate to the spec folder and see the spec
there:
<?php
namespace spec\Sylius\Bundle\CoreBundle\Pricing;
use PhpSpec\ObjectBehavior;
use Prophecy\Argument;
class PriceUpdaterSpec extends ObjectBehavior
{
function it_is_initializable()
{
$this->shouldHaveType('Sylius\Bundle\CoreBundle\Pricing\PriceUpdater');
}
}
The object behavior is made of examples. Examples are encased in public methods, started with it_. or its_.
PHPSpec searches for such methods in your specification to run. Why underscores for example names?
just_because_its_much_easier_to_read than someLongCamelCasingLikeThat.
Now, lets write first example which will update the products price:
<?php
namespace spec\Sylius\Bundle\CoreBundle\Pricing;
use
use
use
use
Acme\ApiClient;
PhpSpec\ObjectBehavior;
Prophecy\Argument;
Sylius\Bundle\CoreBundle\Model\ProductInterface;
The example looks clear and simple, the PriceUpdater service should obtain the SKU of the product, call the
external API and update products price accordingly.
Try running the example by using the following command:
$ bin/phpspec run
> spec\Sylius\Bundle\CoreBundle\Pricing\PriceUpdater
9.1. Contributing
339
Sylius, Release
Once the class is created and you run the command again, PHPSpec will ask if it should create the method as well.
Start implementing the very initial version of the price updater.
<?php
namespace Sylius\Bundle\CoreBundle\Pricing;
use Sylius\Bundle\CoreBundle\Model\ProductInterface;
use Acme\ApiClient;
class PriceUpdater
{
private $api;
public function __construct(ApiClient $api)
{
$this->api = $api;
}
public function updatePrice(ProductInterface $product)
{
$price = $this->api->getCurrentProductPrice($product->getSku());
$product->setPrice($price);
}
}
Done! If you run PHPSpec again, you should see the following output:
$ bin/phpspec run
> spec\Sylius\Bundle\CoreBundle\Pricing\PriceUpdater
it updates product price through api
1 examples (1 passed)
223ms
This example is greatly simplified, in order to illustrate how we work. There should be few more examples, which
cover errors, API exceptions and other edge-cases.
Few tips & rules to follow when working with PHPSpec & Sylius:
RED is good, add or fix the code to make it green;
RED-GREEN-REFACTOR is our rule;
All specs must pass;
When writing examples, describe the behavior of the object in present tense;
Omit the public keyword;
Use underscores (_) in the examples;
Use type hinting to mock and stub classes;
If your specification is getting too complex, the design is wrong, try decoupling a bit more;
340
Chapter 9. Contributing
Sylius, Release
If you cannot describe something easily, probably you should not be doing it that way;
shouldBeCalled or willReturn, never together, except for builders;
Use constants in assumptions but strings in expected results;
Happy coding!
Coding Standards
When contributing code to Sylius, you must follow its coding standards.
Sylius follows the standards defined in the PSR-0, PSR-1 and PSR-2 documents.
Here is a short example containing most features described below:
<?php
/*
* This file is part of the Sylius package.
*
edrzejewski
* (c) Pawe J
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Acme;
/**
* Coding standards demonstration.
*/
class FooBar
{
const SOME_CONST = 42;
private $fooBar;
/**
* @param string $dummy Some argument description
*/
public function __construct($dummy)
{
$this->fooBar = $this->transformText($dummy);
}
/**
* @param string $dummy Some argument description
* @param array $options
*
* @return string|null Transformed input
*
* @throws \RuntimeException
*/
private function transformText($dummy, array $options = array())
{
$mergedOptions = array_merge(
array(
'some_default'
=> 'values',
'another_default' => 'more values',
9.1. Contributing
341
Sylius, Release
),
$options
);
if (true === $dummy) {
return;
}
if ('string' === $dummy) {
if ('values' === $mergedOptions['some_default']) {
return substr($dummy, 0, 5);
}
return ucwords($dummy);
}
throw new \RuntimeException(sprintf('Unrecognized dummy option "%s"', $dummy));
}
}
Structure
Use camelCase, not underscores, for variable, function and method names, arguments;
Use underscores for option names and parameter names;
Use namespaces for all classes;
Prefix abstract classes with Abstract.
Suffix interfaces with Interface;
Suffix traits with Trait;
Suffix exceptions with Exception;
Use alphanumeric characters and underscores for file names;
342
Chapter 9. Contributing
Sylius, Release
Dont forget to look at the more verbose Conventions document for more subjective naming considerations.
Service Naming Conventions
A service name contains groups, separated by dots;
All Sylius services use sylius as first group;
Use lowercase letters for service and parameter names;
A group name uses the underscore notation;
Each service has a corresponding parameter containing the class name, following the service_name.class
convention.
Documentation
Sylius is released under the MIT license, and the license block has to be present at the top of every PHP file,
before the namespace.
Conventions
This document describes coding standards and conventions used in the Sylius codebase to make it more consistent and
predictable.
Method Names
When an object has a main many relation with related things (objects, parameters, ...), the method names are
normalized:
get()
set()
has()
all()
replace()
remove()
clear()
isEmpty()
add()
register()
count()
9.1. Contributing
343
Sylius, Release
keys()
The usage of these methods are only allowed when it is clear that there is a main relation:
a CookieJar has many Cookie objects;
a Service Container has many services and many parameters (as services is the main relation, the naming
convention is used for this relation);
a Console Input has many arguments and many options. There is no main relation, and so the naming
convention does not apply.
For many relations where the convention does not apply, the following methods must be used instead (where XXX is
the name of the related thing):
Main Relation
get()
set()
n/a
has()
all()
replace()
remove()
clear()
isEmpty()
add()
register()
count()
keys()
Other Relations
getXXX()
setXXX()
replaceXXX()
hasXXX()
getXXXs()
setXXXs()
removeXXX()
clearXXX()
isEmptyXXX()
addXXX()
registerXXX()
countXXX()
n/a
Note: While setXXX and replaceXXX are very similar, there is one notable difference: setXXX may replace,
or add new elements to the relation. replaceXXX, on the other hand, cannot add new elements. If an unrecognized
key is passed to replaceXXX it must throw an exception.
Deprecations
Warning: Sylius is the pre-alpha development stage. We release minor version before every larger change, but be
prepared for BC breaks to happen until 1.0.0 release.
From time to time, some classes and/or methods are deprecated in the framework; that happens when a feature implementation cannot be changed because of backward compatibility issues, but we still want to propose a better
alternative. In that case, the old implementation can simply be deprecated.
A feature is marked as deprecated by adding a @deprecated phpdoc to relevant classes, methods, properties, ...:
/**
* @deprecated Deprecated since version 1.X, to be removed in 1.Y. Use XXX instead.
*/
The deprecation message should indicate the version when the class/method was deprecated, the version when it will
be removed, and whenever possible, how the feature was replaced.
A PHP E_USER_DEPRECATED error must also be triggered to help people with the migration starting one or two
minor versions before the version where the feature will be removed (depending on the criticality of the removal):
344
Chapter 9. Contributing
Sylius, Release
trigger_error(
'XXX() is deprecated since version 2.X and will be removed in 2.Y. Use XXX instead.',
E_USER_DEPRECATED
);
Git
This document explains some conventions and specificities in the way we manage the Sylius code with Git.
Pull Requests
Whenever a pull request is merged, all the information contained in the pull request is saved in the repository.
You can easily spot pull request merges as the commit message always follows this pattern:
merged branch USER_NAME/BRANCH_NAME (PR #1111)
Sylius License
Sylius is released under the MIT license.
According to Wikipedia:
It is a permissive license, meaning that it permits reuse within proprietary software on the condition that
the license is distributed with that software. The license is also GPL-compatible, meaning that the GPL
permits combination and redistribution with software that uses the MIT License.
The License
9.1. Contributing
345
Sylius, Release
9.1.2 Community
Support
We have very friendly community which provides support for all Sylius users seeking help!
IRC Channels
There are 2 channels available on Freenode IRC network, where you can meet other Sylius developers, ask for help or
discuss ideas.
Users channel Channel #sylius is for Sylius users - a place where you should seek help and advices. Usually you
can meet there several people eager to provide your with community support and answer your questions.
We invite everyone interested in using Sylius to this room, we warmly welcome new people in our growing community!
Developers channel sylius-dev is the channel where youll most likely meet Sylius core team and contributors. It
is the right place to discuss about Pull Requests, ideas and architecture. It will be perfect starting point if you want to
contribute to the project or chat about concept youd like to introduce at Sylius.
Now the best part! You do not need to be a Symfony2 guru to help! There is plenty of work which can be done by
people starting with Symfony, and to us, every contribution is invaluable!
How to connect You should pick a nice username and connect to irc.freenode.org via XChat or any other
IRC client. You can also use web client.
StackOverflow.com
We encourage asking Sylius related questions on the stackoverflow.com platform. Be sure to tag them with sylius tag
- it will make it easier to find for people who can answer it.
To view all Sylius related questions - visit this link. You can also search for phrase.
Statistics
You can always check sylius.org/community to see an overview of our community at work!
Below, you can find more useful links:
Sylius Pull Requests - pull requests
Most recent patches - commits
GitHub issues - issues
Symfony2 bundles index - knpbundles.com
346
Chapter 9. Contributing
Sylius, Release
Before contributing, you need to become familiar with the markup language used by the documentation.
The Sylius documentation is hosted on GitHub:
https://github.com/Sylius/Sylius-Docs
If you want to submit a patch, fork the official repository on GitHub and then clone your fork:
$ git clone git://github.com/YOURUSERNAME/Sylius-Docs.git
The master branch holds the documentation for the development branch of the code.
Create a dedicated branch for your changes (for organization):
$ git checkout -b improving_foo_and_bar
You can now make your changes directly to this branch and commit them. When youre done, push this branch to your
GitHub fork and initiate a pull request.
Creating a Pull Request Following the example, the pull request will default to be between your
improving_foo_and_bar branch and the Sylius-Docs master branch.
GitHub covers the topic of pull requests in detail.
Note: The Sylius documentation is licensed under a Creative Commons Attribution-Share Alike 3.0 Unported License.
You can also prefix the title of your pull request in a few cases:
[WIP] (Work in Progress) is used when you are not yet finished with your pull request, but you would like it to
be reviewed. The pull request wont be merged until you say it is ready.
[WCM] (Waiting Code Merge) is used when youre documenting a new feature or change that hasnt been
accepted yet into the core code. The pull request will not be merged until it is merged in the core code (or closed
if the change is rejected).
Pull Request Format Unless youre fixing some minor typos, the pull request description must include the following checklist to ensure that contributions may be reviewed without needless feedback loops and that your contributions
can be included into the documentation as quickly as possible:
|
|
|
|
|
Q
------------Doc fix?
New docs?
Fixed tickets
9.1. Contributing
|
|
|
|
|
A
--[yes|no]
[yes|no] (PR # on Sylius/Sylius if applicable)
[comma separated list of tickets fixed by the PR]
347
Sylius, Release
Q
------------Doc fix?
New docs?
Fixed tickets
|
|
|
|
|
A
--yes
yes (Sylius/Sylius#1250)
#1075
If youre documenting a brand new feature or a change thats been made in Sylius, you should precede your description
of the change with a .. versionadded:: 1.X tag and a short description:
.. versionadded:: 1.1
The ``getProductDiscount`` method was introduced in Sylius 1.1.
Standards
All documentation in the Sylius Documentation should follow the documentation standards.
Reporting an Issue
The most easy contribution you can make is reporting issues: a typo, a grammar mistake, a bug in a code example, a
missing explanation, and so on.
Steps:
Submit new issue in the GitHub tracker;
(optional) Submit a patch.
Translating
Chapter 9. Contributing
Sylius, Release
Sphinx is a build system that adds some nice tools to create documentation from reStructuredText documents. As
such, it adds new directives and interpreted text roles to standard reST markup.
Syntax Highlighting All code examples uses PHP as the default highlighted language. You can change it with the
code-block directive:
.. code-block:: yaml
{ foo: bar, bar: { foo: bar, bar: baz } }
If your PHP code begins with <?php, then you need to use html+php as the highlighted pseudo-language:
.. code-block:: html+php
<?php echo $this->foobar(); ?>
Configuration Blocks Whenever you show a configuration, you must use the configuration-block directive
to show the configuration in all supported configuration formats (PHP, YAML, and XML)
.. configuration-block::
.. code-block:: yaml
# Configuration in YAML
.. code-block:: xml
<!-- Configuration in XML //-->
.. code-block:: php
// Configuration in PHP
XML
<!-- Configuration in XML //-->
PHP
// Configuration in PHP
9.1. Contributing
349
Sylius, Release
Markup format
html
xml
php
yaml
jinja
html+jinja
html+php
ini
php-annotations
Displayed
HTML
XML
PHP
YAML
Twig
Twig
PHP
INI
Annotations
Adding Links To add links to other pages in the documents use the following syntax:
:doc:`/path/to/page`
Using the path and filename of the page without the extension, for example:
:doc:`/book/architecture`
:doc:`/bundles/SyliusAddressingBundle/installation`
The link text will be the main heading of the document linked to. You can also specify alternative text for the link:
:doc:`Simple CRUD </bundles/SyliusResourceBundle/installation>`
350
Chapter 9. Contributing
Sylius, Release
# ...
sys.path.append(os.path.abspath('_exts'))
# adding PhpLexer
from sphinx.highlighting import lexers
from pygments.lexers.web import PhpLexer
# ...
# add the extensions to the list of extensions
extensions = [..., 'sensio.sphinx.refinclude', 'sensio.sphinx.configurationblock', 'sensio.sphinx.php
# enable highlighting for PHP code not between ``<?php ... ?>`` by default
lexers['php'] = PhpLexer(startinline=True)
lexers['php-annotations'] = PhpLexer(startinline=True)
lexers['php-standalone'] = PhpLexer(startinline=True)
lexers['php-symfony'] = PhpLexer(startinline=True)
# use PHP as the primary domain
primary_domain = 'php'
# set URL for API links
api_url = 'http://api.sylius.org/master/%s'
Documentation Standards
In order to help the reader as much as possible and to create code examples that look and feel familiar, you should
follow these standards.
Sphinx
The following characters are chosen for different heading levels: level 1 is =, level 2 -, level 3 ~, level 4 . and
level 5 ";
Each line should break approximately after the first word that crosses the 72nd character (so most lines end up
being 72-78 characters);
The :: shorthand is preferred over .. code-block::
documentation to see when you should use the shorthand);
Inline hyperlinks are not used. Separate the link and their target definition, which you add on the bottom of the
page;
Inline markup should be closed on the same line as the open-string;
Example
Example
=======
When you are working on the docs, you should follow the
`Sylius Documentation`_ standards.
Level 2
------A PHP example would be::
9.1. Contributing
351
Sylius, Release
Code Examples
The code follows the Sylius Coding Standards as well as the Twig Coding Standards;
To avoid horizontal scrolling on code blocks, we prefer to break a line correctly if it crosses the 85th character;
When you fold one or more lines of code, place ... in a comment at the point of the fold. These comments
are: // ... (php), # ... (yaml/bash), {# ... #} (twig), <!-- ... --> (xml/html), ; ... (ini),
... (text);
When you fold a part of a line, e.g. a variable value, put ... (without comment) at the place of the fold;
Description of the folded code: (optional) If you fold several lines: the description of the fold can be placed
after the ... If you fold only part of a line: the description can be placed before the line;
If useful to the reader, a PHP code example should start with the namespace declaration;
When referencing classes, be sure to show the use statements at the top of your code block. You dont need to
show all use statements in every example, just show what is actually being used in the code block;
If useful, a codeblock should begin with a comment containing the filename of the file in the code block.
Dont place a blank line after this comment, unless the next line is also a comment;
You should put a $ in front of every bash line.
Formats Configuration examples should show recommended formats using configuration blocks. The recommended
formats (and their orders) are:
Configuration (including services and routing): YAML
Validation: XML
Doctrine Mapping: XML
Example
// src/Foo/Bar.php
namespace Foo;
use Acme\Demo\Cat;
// ...
class Bar
{
// ...
public function foo($bar)
352
Chapter 9. Contributing
Sylius, Release
{
// set foo with a value of bar
$foo = ...;
$cat = new Cat($foo);
// ... check if $bar has the correct value
return $cat->baz($bar, ...);
}
}
Caution: In YAML you should put a space after { and before } (e.g. { _controller:
should not be done in Twig (e.g. {hello : value}).
...
Language Standards
For sections, use the following capitalization rules: Capitalization of the first word, and all other words, except
for closed-class words:
The Vitamins are in my Fresh California Raisins
Do not use Serial (Oxford) Commas;
You should use a form of you instead of we (i.e. avoid the first person point of view: use the second instead);
When referencing a hypothetical person, such as a user with a session cookie, gender-neutral pronouns
(they/their/them) should be used. For example, instead of:
he or she, use they
him or her, use them
his or her, use their
his or hers, use theirs
himself or herself, use themselves
Sylius Documentation License
The Sylius documentation is licensed under a Creative Commons Attribution-Share Alike 3.0 Unported License.
You are free:
to Share to copy, distribute and transmit the work;
to Remix to adapt the work.
Under the following conditions:
Attribution You must attribute the work in the manner specified by the author or licensor (but not in any way
that suggests that they endorse you or your use of the work);
Share Alike If you alter, transform, or build upon this work, you may distribute the resulting work only under
the same or similar license to this one.
With the understanding that:
Waiver Any of the above conditions can be waived if you get permission from the copyright holder;
9.1. Contributing
353
Sylius, Release
Public Domain Where the work or any of its elements is in the public domain under applicable law, that
status is in no way affected by the license;
Other Rights In no way are any of the following rights affected by the license:
Your fair dealing or fair use rights, or other applicable copyright exceptions and limitations;
The authors moral rights;
Rights other persons may have either in the work itself or in how the work is used, such as publicity or
privacy rights.
Notice For any reuse or distribution, you must make clear to others the license terms of this work. The best
way to do this is with a link to this web page.
This is a human-readable summary of the Legal Code (the full license).
Code
Bugs
Patches
Security
Behavior Driven Development
Coding Standards
Code Conventions
Git
License
Documentation
Overview
Format
Documentation Standards
License
Community
Support
Statistics
Code
Bugs
Patches
Security
Behavior Driven Development
Coding Standards
Code Conventions
Git
License
Documentation
354
Chapter 9. Contributing
Sylius, Release
Overview
Format
Documentation Standards
License
Community
Support
Statistics
9.1. Contributing
355
Sylius, Release
356
Chapter 9. Contributing
Index
Addresses, 12
Architecture, 6
Authorization, 33
C
Channels, 10
Content, 27
Currencies, 25
E
E-Mails, 28
Environments, 4
I
Installation, 5, 83
Introduction, 3, 91
Introduction to Sylius REST API, 33
Inventory, 14
L
Locales, 26
O
Orders, 15
P
Payments, 18
Pricing, 21
Products, 11
Promotions, 22
S
Settings, 29
Shipments, 17
State Machine, 9
T
Taxation, 20
357