mirror of
https://github.com/Sylius/Sylius.git
synced 2026-07-14 17:10:53 +00:00
Merge pull request #5214 from TheMadeleine/docs/customization-guide
[Documentation] Customization Guide
This commit is contained in:
commit
d8de7ed240
13 changed files with 741 additions and 73 deletions
|
|
@ -1,71 +0,0 @@
|
|||
Extending the menu
|
||||
==================
|
||||
|
||||
You can add entries to the menu via events easily. You get passed a
|
||||
``Sylius\\Bundle\\WebBundle\\Event\\MenuBuilderEvent`` with ``FactoryInterface`` and ``ItemInterface`` of
|
||||
`KnpMenu`_. So you can manipulate the whole menu.
|
||||
|
||||
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
|
||||
-------------
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
// 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');
|
||||
}
|
||||
}
|
||||
|
||||
.. configuration-block::
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
services:
|
||||
acme_reports.menu_builder:
|
||||
class: Acme\ReportsBundle\EventListener\MenuBuilderListener
|
||||
tags:
|
||||
- { name: kernel.event_listener, event: sylius.menu_builder.backend.main, method: addBackendMenuItems }
|
||||
- { name: kernel.event_listener, event: sylius.menu_builder.backend.sidebar, method: addBackendMenuItems }
|
||||
|
||||
.. code-block:: xml
|
||||
|
||||
<!-- src/Acme/ReportsBundle/Resources/config/services.xml -->
|
||||
<?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_reports.menu_builder" class="Acme\ReportsBundle\EventListener\MenuBuilderListener">
|
||||
<tag name="kernel.event_listener" event="sylius.menu_builder.backend.main" method="addBackendMenuItems" />
|
||||
<tag name="kernel.event_listener" event="sylius.menu_builder.backend.sidebar" method="addBackendMenuItems" />
|
||||
</service>
|
||||
</services>
|
||||
</container>
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
// src/Acme/ReportsBundle/Resources/config/services.php
|
||||
use Symfony\Component\DependencyInjection\Definition;
|
||||
|
||||
$definition = new Definition('Acme\ReportsBundle\EventListener\MenuBuilderListener');
|
||||
$definition->->addTag('kernel.event_listener', array('event' => 'sylius.menu_builder.backend.main', 'method' => 'addBackendMenuItems'));
|
||||
$definition->->addTag('kernel.event_listener', array('event' => 'sylius.menu_builder.backend.sidebar', 'method' => 'addBackendMenuItems'));
|
||||
|
||||
$container->setDefinition('acme_reports.menu_builder', $definition);
|
||||
|
||||
.. _KnpMenu: https://github.com/KnpLabs/KnpMenu
|
||||
|
|
@ -5,7 +5,6 @@ Cookbook
|
|||
:hidden:
|
||||
|
||||
installation-commands
|
||||
extending-menu
|
||||
registry
|
||||
|
||||
.. include:: /cookbook/map.rst.inc
|
||||
|
|
|
|||
|
|
@ -1,3 +1,2 @@
|
|||
* :doc:`/cookbook/installation-commands`
|
||||
* :doc:`/cookbook/extending-menu`
|
||||
* :doc:`/cookbook/registry`
|
||||
|
|
|
|||
166
docs/customization/controller.rst
Normal file
166
docs/customization/controller.rst
Normal file
|
|
@ -0,0 +1,166 @@
|
|||
Customizing Controllers
|
||||
=======================
|
||||
|
||||
All **Sylius** resources are using the `` Sylius\Bundle\ResourceBundle\Controller\ResourceController`` as default, but some of them have been already extended in Bundles.
|
||||
If you want to override some controller action, check which controller you should be extending.
|
||||
|
||||
.. note::
|
||||
There are two types of controllers we can define in Sylius.
|
||||
**Resource Controllers** - are basing only on one Entity, so they return only the resources they have in their name. For instance a ``ProductController`` should return only products.
|
||||
**Standard Controllers** - non-resource; these may use many entities at once, they are useful on more general pages. We are extending these controllers only if the actions we want cannot be done through yaml configuration - like sending emails.
|
||||
|
||||
Why would you customize a Controller?
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
To add your custom actions you need to override controllers. You may bee needing to:
|
||||
|
||||
* add a generic action that will render a list of recommended products with a product on its show page,
|
||||
* render a partial template that cannot be done via yaml resource action.
|
||||
|
||||
How to customize a Resource Controller?
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Imagine that you would want to render a list of best selling products in a partial template that will be reusable anywhere.
|
||||
Assuming that you already have a method on the ``ProductRepository`` - you can see such an example :doc:`here </customization/repository>`.
|
||||
Having this method you may be rendering its result in a new action of the ``ProductController`` using a partial template.
|
||||
|
||||
See example below:
|
||||
|
||||
1. Create a new Controller class under the ``AppBundle/Controller`` namespace.
|
||||
|
||||
Remember that it has to extend a proper base class. How can you check that?
|
||||
|
||||
For the ``ProductController`` run:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
$ php app/console debug:container sylius.controller.product
|
||||
|
||||
As a result you will get the ``Sylius\Bundle\CoreBundle\Controller\ProductController`` - this is the class that you need to be extending.
|
||||
|
||||
Now you have to create the controller that will have a generic action that is basically the ``showAction`` from the ``ResourceController`` extended by
|
||||
getting a list of recommended product from your external api.
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
<?php
|
||||
|
||||
namespace AppBundle\Controller;
|
||||
|
||||
use FOS\RestBundle\View\View;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
use Sylius\Bundle\CoreBundle\Controller\ProductController as BaseProductController;
|
||||
use Sylius\Component\Resource\ResourceActions;
|
||||
|
||||
class ProductController extends BaseProductController
|
||||
{
|
||||
/**
|
||||
* @param Request $request
|
||||
*
|
||||
* @return Response
|
||||
*/
|
||||
public function showAction(Request $request)
|
||||
{
|
||||
$configuration = $this->requestConfigurationFactory->create($this->metadata, $request);
|
||||
|
||||
$this->isGrantedOr403($configuration, ResourceActions::SHOW);
|
||||
$product = $this->findOr404($configuration);
|
||||
|
||||
$recommendationServiceApi = $this->get('app.recommendation_service_api');
|
||||
|
||||
$recommendedProducts = $recommendationServiceApi->getRecommendedProducts($product);
|
||||
|
||||
$this->eventDispatcher->dispatch(ResourceActions::SHOW, $configuration, $product);
|
||||
|
||||
$view = View::create($product);
|
||||
|
||||
if ($configuration->isHtmlRequest()) {
|
||||
$view
|
||||
->setTemplate($configuration->getTemplate(ResourceActions::SHOW . '.html'))
|
||||
->setTemplateVar($this->metadata->getName())
|
||||
->setData([
|
||||
'configuration' => $configuration,
|
||||
'metadata' => $this->metadata,
|
||||
'resource' => $product,
|
||||
'recommendedProducts' => $recommendedProducts,
|
||||
$this->metadata->getName() => $product,
|
||||
])
|
||||
;
|
||||
}
|
||||
|
||||
return $this->viewHandler->handle($configuration, $view);
|
||||
}
|
||||
}
|
||||
|
||||
2. In order to use your controller and its actions you need to configure it in the ``app/config/config.yml``.
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
sylius_product:
|
||||
resources:
|
||||
product:
|
||||
classes:
|
||||
controller: AppBundle\Controller\ProductController
|
||||
|
||||
How to customize a Standard Controller?
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Let's assume that you would like to send some kind of emails (which are not resources) after something has been purchased in your shop - to do this you should modify an ``afterPurchaseAction`` on the ``OrderController``.
|
||||
|
||||
1. Create a new Controller class under the ``AppBundle/Controller/Frontend`` namespace.
|
||||
|
||||
Run ``$ php app/console debug:container sylius.controller.frontend.order``.
|
||||
|
||||
Your class needs to be extending this base class.
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
<?php
|
||||
|
||||
namespace AppBundle\Controller\Frontend;
|
||||
|
||||
use Sylius\Bundle\WebBundle\Controller\Frontend\Account\OrderController as BaseOrderController;
|
||||
use Sylius\Bundle\PayumBundle\Request\GetStatus;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
|
||||
class OrderController extends BaseOrderController
|
||||
{
|
||||
/**
|
||||
* @param Request $request
|
||||
*
|
||||
* @return Response
|
||||
*/
|
||||
public function afterPurchaseAction(Request $request)
|
||||
{
|
||||
$token = $this->getHttpRequestVerifier()->verify($request);
|
||||
$this->getHttpRequestVerifier()->invalidate($token);
|
||||
|
||||
$status = new GetStatus($token);
|
||||
$this->getPayum()->getGateway($token->getGatewayName())->execute($status);
|
||||
$payment = $status->getFirstModel();
|
||||
$order = $payment->getOrder();
|
||||
$this->checkAccessToOrder($order);
|
||||
|
||||
$orderStateResolver = $this->get('sylius.order_processing.state_resolver');
|
||||
$orderStateResolver->resolvePaymentState($order);
|
||||
$orderStateResolver->resolveShippingState($order);
|
||||
|
||||
$this->getOrderManager()->flush();
|
||||
|
||||
$emailManager = $this->get('sylius.email_manager.order');
|
||||
$emailManager->sendConfirmationEmail($order);
|
||||
|
||||
return $this->redirectToRoute('sylius_checkout_thank_you');
|
||||
}
|
||||
}
|
||||
|
||||
2. The next thing you have to do is to override the ``sylius.controller.frontend.order.class`` parameter in ``AppBundle/Resources/config/services.yml``.
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
parameters:
|
||||
sylius.controller.frontend.order.class: AppBundle\Controller\Frontend\OrderController
|
||||
|
||||
From now on your ``afterPurchaseAction`` of the ``OrderController`` will also send emails in addition to its default behaviour.
|
||||
122
docs/customization/form.rst
Normal file
122
docs/customization/form.rst
Normal file
|
|
@ -0,0 +1,122 @@
|
|||
Customizing Forms
|
||||
=================
|
||||
|
||||
The forms in Sylius are placed in the ``Sylius\Bundle\*BundleName*\Form\Type`` namespaces.
|
||||
|
||||
.. warning::
|
||||
Many forms in Sylius are **extended in the CoreBundle**.
|
||||
If the form you are willing to override exists in the ``CoreBundle`` your should be extending the one from Core, not the base form from the bundle.
|
||||
|
||||
Why would you customize a Form?
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
There are plenty of reasons to modify forms that have already been defined in Sylius.
|
||||
Your business needs may sometimes slightly differ from our internal assumptions.
|
||||
|
||||
You can:
|
||||
|
||||
* add completely **new fields**, if you need another phone number for your customers,
|
||||
* **modify** existing fields, make them required, change their HTML class, change labels etc.,
|
||||
* **remove** fields that are not used.
|
||||
|
||||
How to customize a Form?
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
If you want to modify the form for the ``Address`` in your system there are a few steps that you should take.
|
||||
Assuming that you would like to (for example):
|
||||
|
||||
* Add a ``contactHours`` field,
|
||||
* Remove the ``company`` field,
|
||||
* Change the label for the ``lastName`` from ``sylius.form.address.last_name`` to ``app.form.address.surname``
|
||||
|
||||
These will be the steps that you will have to take to achieve that:
|
||||
|
||||
1. If your are planning to add new fields remember that beforehand they need to be added on the model that the form type is based on.
|
||||
|
||||
In case of our example if you need to have the ``contactHours`` on the model and the entity mapping for the ``Address`` resource.
|
||||
To get to know how to prepare that go :doc:`there </customization/model>`.
|
||||
|
||||
2. Write your own form type class that will be extending the default one. Place it in your ``AppBundle\Form\Type`` directory.
|
||||
|
||||
Your new class has to extend a proper base class. How can you check that?
|
||||
|
||||
For the ``AddressType`` run:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
$ php app/console debug:container sylius.form.type.address
|
||||
|
||||
As a result you will get the ``Sylius\Bundle\AddressingBundle\Form\Type\AddressType`` - this is the class that you need to be extending.
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
<?php
|
||||
|
||||
namespace Acme\Bundle\ShopBundle\Form\Type;
|
||||
|
||||
use Sylius\Bundle\AddressingBundle\Form\Type\AddressType as BaseAddressType;
|
||||
use Symfony\Component\Form\FormBuilderInterface;
|
||||
|
||||
class AddressType extends BaseAddressType
|
||||
{
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function buildForm(FormBuilderInterface $builder, array $options)
|
||||
{
|
||||
// Add default fields from the `BaseAddressType` that you are extending.
|
||||
parent::buildForm($builder, $options);
|
||||
|
||||
// Adding new fields works just like in the parent form.
|
||||
$builder->add('contactHours', 'text', [
|
||||
'required' => false,
|
||||
'label' => 'app.form.address.contact_hours',
|
||||
]);
|
||||
|
||||
// To remove a field from a form simply call ->remove(`fieldName`).
|
||||
$builder->remove('company');
|
||||
|
||||
// You can change the label by adding again the same field with a changed `label` parameter.
|
||||
$builder->add('lastName', 'text', [
|
||||
'label' => 'app.form.address.surname',
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
3. Define your newly created class in the ``app/config/config.yml``.
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
sylius_addressing:
|
||||
resources:
|
||||
address:
|
||||
classes:
|
||||
form:
|
||||
default: AppBundle\Form\Type\AddressType
|
||||
|
||||
.. note::
|
||||
Of course remember that you need to render the new fields you have created,
|
||||
and remove the rendering of the fields that you have removed **in your views**.
|
||||
|
||||
In **Twig** for example you can render your modified form in such a way:
|
||||
|
||||
.. code-block:: html
|
||||
|
||||
<div id="addressForm">
|
||||
{{ form_row(form.firstName) }}
|
||||
{{ form_row(form.lastName) }}
|
||||
{{ form_row(form.city) }}
|
||||
{{ form_row(form.street) }}
|
||||
{{ form_row(form.postcode) }}
|
||||
{{ form_row(form.countryCode) }}
|
||||
{{ form_row(form.provinceCode) }}
|
||||
{{ form_row(form.phoneNumber) }}
|
||||
{{ form_row(form.contactHours) }}
|
||||
</div>
|
||||
|
||||
What happens while overriding Forms?
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
* Parameter ``sylius.form.type.address.class`` contains the ``AppBundle\Form\Type\AddressType``.
|
||||
* ``sylius.form.type.address`` form type service uses your custom class.
|
||||
* ``sylius_address`` form type uses your new form everywhere.
|
||||
15
docs/customization/index.rst
Normal file
15
docs/customization/index.rst
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
The Customization Guide
|
||||
=======================
|
||||
|
||||
.. toctree::
|
||||
:hidden:
|
||||
|
||||
model
|
||||
form
|
||||
repository
|
||||
controller
|
||||
validation
|
||||
menu
|
||||
template
|
||||
|
||||
.. include:: /customization/map.rst.inc
|
||||
7
docs/customization/map.rst.inc
Normal file
7
docs/customization/map.rst.inc
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
* :doc:`/customization/model`
|
||||
* :doc:`/customization/form`
|
||||
* :doc:`/customization/repository`
|
||||
* :doc:`/customization/controller`
|
||||
* :doc:`/customization/validation`
|
||||
* :doc:`/customization/menu`
|
||||
* :doc:`/customization/template`
|
||||
72
docs/customization/menu.rst
Normal file
72
docs/customization/menu.rst
Normal file
|
|
@ -0,0 +1,72 @@
|
|||
Customizing Menus
|
||||
=================
|
||||
|
||||
Adding new positions in your menu is done **via events**.
|
||||
|
||||
You have got the ``Sylius\Bundle\WebBundle\Event\MenuBuilderEvent`` with ``FactoryInterface`` and ``ItemInterface`` of `KnpMenu`_. So you can manipulate the whole menu.
|
||||
|
||||
You've got such events that you should be subscribing to:
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
sylius.menu.admin.main # Admin Panel menu
|
||||
sylius.menu_builder.frontend.main # Main Shop menu (top bar)
|
||||
sylius.menu_builder.frontend.currency #
|
||||
sylius.menu_builder.frontend.taxons #
|
||||
sylius.menu_builder.frontend.social #
|
||||
sylius.menu_builder.frontend.account #
|
||||
|
||||
How to customize a Menu?
|
||||
------------------------
|
||||
|
||||
1. In order to add items to any of the Menus in **Sylius** you have to create a ``AppBundle\EventListener\MenuBuilderListener`` class.
|
||||
|
||||
In the example below we are adding a one new item to the Admin panel menu and a one new item to main menu of the shop.
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
<?php
|
||||
|
||||
namespace AppBundle\EventListener;
|
||||
|
||||
use Sylius\Bundle\UiBundle\Menu\Event\MenuBuilderEvent;
|
||||
use Sylius\Bundle\WebBundle\Event\MenuBuilderEvent as FrontendMenuBuilderEvent;
|
||||
|
||||
class MenuBuilderListener
|
||||
{
|
||||
/**
|
||||
* @param MenuBuilderEvent $event
|
||||
*/
|
||||
public function addBackendMenuItems(MenuBuilderEvent $event)
|
||||
{
|
||||
$menu = $event->getMenu();
|
||||
|
||||
$menu->addChild('backend_main')
|
||||
->setLabel('Test Backend Main');
|
||||
}
|
||||
|
||||
/**
|
||||
* @param FrontendMenuBuilderEvent $event
|
||||
*/
|
||||
public function addFrontendMenuItems(FrontendMenuBuilderEvent $event)
|
||||
{
|
||||
$menu = $event->getMenu();
|
||||
|
||||
$menu->addChild('frontend')
|
||||
->setLabel('Frontend Menu Item');
|
||||
}
|
||||
}
|
||||
|
||||
2. After creating your class with proper methods for all the menu customizations you need, subscribe your
|
||||
listener to proper events in the ``AppBundle\Resources\config.services.yml``.
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
services:
|
||||
app.admin.menu_builder_listener:
|
||||
class: AppBundle\EventListener\MenuBuilderListener
|
||||
tags:
|
||||
- { name: kernel.event_listener, event: sylius.menu.admin.main, method: addBackendMenuItems }
|
||||
- { name: kernel.event_listener, event: sylius.menu_builder.frontend.currency, method: addFrontendMenuItems }
|
||||
|
||||
.. _KnpMenu: https://github.com/KnpLabs/KnpMenu
|
||||
109
docs/customization/model.rst
Normal file
109
docs/customization/model.rst
Normal file
|
|
@ -0,0 +1,109 @@
|
|||
Customizing Models
|
||||
==================
|
||||
|
||||
All models in Sylius are placed in the ``Sylius\Component\*ComponentName*\Model`` namespaces alongside with their interfaces.
|
||||
|
||||
.. warning::
|
||||
Many models in Sylius are **extended in the Core component**.
|
||||
If the model you are willing to override exists in the ``Core`` your should be extending the ``Core`` one, not the base model from the component.
|
||||
|
||||
Why would you customize a Model?
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
To give you an idea of some purposes of models customizing have a look at a few examples:
|
||||
|
||||
* Add ``flag`` field to the ``Country``
|
||||
* Add ``secondNumber`` to the ``Customer``
|
||||
* Change the ``reviewSubject`` of a ``Review`` (in Sylius we have ``ProductReviews`` but you can imagine for instance a ``CustomerReview``)
|
||||
* Add ``icon`` to the ``PaymentMethod``
|
||||
|
||||
And of course many similar operations limited only by your imagination.
|
||||
Let's now see how you should perform such customizations.
|
||||
|
||||
How to customize a Model?
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Let's take the ``Sylius\Component\Addressing\Country`` as an example. This one is not extended in Core.
|
||||
How can you check that?
|
||||
|
||||
For the ``Country`` run:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
$ php app/console debug:container --parameter=sylius.model.country.class
|
||||
|
||||
As a result you will get the ``Sylius\Component\Addressing\Model\Country`` - this is the class that you need to be extending.
|
||||
|
||||
Assuming that you would want to add another field on the model - for instance a ``flag``.
|
||||
|
||||
1. The first thing to do is to write your own class which will extend the base `Country`` class.
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
<?php
|
||||
|
||||
namespace AppBundle\Entity;
|
||||
|
||||
use Sylius\Component\Addressing\Model\Country as BaseCountry;
|
||||
|
||||
class Country extends BaseCountry
|
||||
{
|
||||
/**
|
||||
* @var bool
|
||||
*/
|
||||
private $flag;
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
public function getFlag()
|
||||
{
|
||||
return $this->flag;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param bool $flag
|
||||
*/
|
||||
public function setFlag($flag)
|
||||
{
|
||||
$this->flag = $flag;
|
||||
}
|
||||
}
|
||||
|
||||
2. Next define your entity's mapping:
|
||||
|
||||
The file should be placed in ``AppBundle/Resources/config/doctrine/Country.orm.yml``
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
AppBundle\Entity\Country:
|
||||
type: entity
|
||||
table: sylius_country
|
||||
fields:
|
||||
flag:
|
||||
type: boolean
|
||||
nullable: true
|
||||
|
||||
3. Finally you'll need to override the model's class in the ``app/config/config.yml``.
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
sylius_addressing:
|
||||
resources:
|
||||
country:
|
||||
classes:
|
||||
model: AppBundle\Entity\Country
|
||||
|
||||
4. Additionally if you want to give the administrator an ability to add a ``flag`` to any of Countries,
|
||||
you'll need to update its form type. Check how to do it :doc:`here </customization/form>`.
|
||||
|
||||
What happens while overriding Models?
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
* Parameter ``sylius.model.country.class`` contains ``AppBundle\\Entity\\Country``.
|
||||
* ``sylius.repository.country`` represents Doctrine repository for your new class.
|
||||
* ``sylius.manager.country`` represents Doctrine object manager for your new class.
|
||||
* ``sylius.controller.country`` represents the controller for your new class.
|
||||
* All Doctrine relations to ``Sylius\\Component\\Adressing\\Model\\Country`` are using your new class as *target-entity*, you do not need to update any mappings.
|
||||
* ``CountryType`` form type is using your model as ``data_class``.
|
||||
* ``Sylius\\Component\\Addressing\\Model\\Country`` is automatically turned into Doctrine Mapped Superclass.
|
||||
102
docs/customization/repository.rst
Normal file
102
docs/customization/repository.rst
Normal file
|
|
@ -0,0 +1,102 @@
|
|||
Customizing Repositories
|
||||
========================
|
||||
|
||||
.. warning::
|
||||
In **Sylius** we are using both default Doctrine repositories and the custom ones.
|
||||
Often you will be needing to add your very own methods to them. You need to check before which repository is your resource using.
|
||||
|
||||
Why would you customize a Repository?
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Different sets of different resources can be obtained in various scenarios in your application.
|
||||
You may need for instance:
|
||||
|
||||
* finding Orders by a Customer and a chosen Product
|
||||
* finding Products by a Taxon
|
||||
* finding Comments by a Customer
|
||||
|
||||
How to customize a Repository?
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Let's assume that you would want to find products that are the bestsellers in your shop.
|
||||
|
||||
1. Create your own repository class under the ``AppBundle\Repository`` namespace.
|
||||
Remember that it has to extend a proper base class. How can you check that?
|
||||
|
||||
For the ``ProductRepository`` run:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
$ php app/console debug:container sylius.repository.product
|
||||
|
||||
As a result you will get the ``Sylius\Bundle\CoreBundle\Doctrine\ORM\ProductRepository`` - this is the class that you need to be extending.
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
<?php
|
||||
|
||||
namespace AppBundle\Repository;
|
||||
|
||||
use Sylius\Bundle\CoreBundle\Doctrine\ORM\ProductRepository as BaseProductRepository;
|
||||
|
||||
class ProductRepository extends BaseProductRepository
|
||||
{
|
||||
/**
|
||||
* @param int $limit
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function findBySold($limit = 4)
|
||||
{
|
||||
$queryBuilder = $this->createQueryBuilder('o');
|
||||
$queryBuilder
|
||||
->addSelect('variant')
|
||||
->addSelect('translation')
|
||||
->leftJoin('o.variants', 'variant')
|
||||
->leftJoin('o.translations', 'translation')
|
||||
->addOrderBy('variant.sold', 'DESC')
|
||||
->setMaxResults($limit)
|
||||
;
|
||||
|
||||
return $queryBuilder->getQuery()->getResult();
|
||||
}
|
||||
}
|
||||
|
||||
We are using the `Query Builder`_ in the Repositories.
|
||||
As we are selecting Products we need to have a join to translations, because they are a translatable resource. Without it in the query results we wouldn't have a name to be displayed.
|
||||
|
||||
We are sorting the results by the count of how many times the product has been sold, which is being hold on the ``sold`` field on the specific ``variant`` of each product.
|
||||
Then we are limiting the query to 4 by default, to get only 4 bestsellers.
|
||||
|
||||
2. In order to use your repository you need to configure it in the ``app/config/config.yml``.
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
sylius_product:
|
||||
resources:
|
||||
product:
|
||||
classes:
|
||||
repository: AppBundle\Repository\ProductRepository
|
||||
|
||||
3. After configuring the ``sylius.product.repository`` service has your ``findBySold()`` method available.
|
||||
You can form now on use your method in any **Controller**.
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
<?php
|
||||
|
||||
public function bestsellersAction()
|
||||
{
|
||||
$productRepository = $this->container->get('sylius.repository.product');
|
||||
|
||||
$bestsellers = $productRepository->findBySold();
|
||||
}
|
||||
|
||||
What happens while overriding Repositories?
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
* The parameter ``sylius.repository.product.class`` contains ``AppBundle\Repository\ProductRepository``.
|
||||
* The repository service ``sylius.repository.product`` is using your new class.
|
||||
* Under the ``sylius.repository.product`` service you have got all methods from the base repository available plus the one you have added.
|
||||
|
||||
.. _`Query Builder`: http://doctrine-orm.readthedocs.io/projects/doctrine-orm/en/latest/reference/query-builder.html
|
||||
91
docs/customization/template.rst
Normal file
91
docs/customization/template.rst
Normal file
|
|
@ -0,0 +1,91 @@
|
|||
Customizing Templates
|
||||
=====================
|
||||
|
||||
.. note::
|
||||
|
||||
There are two kinds of templates in Sylius. **Shop** and **Admin** ones, plus you can create your own to satisfy your needs.
|
||||
|
||||
Why would you customize a template?
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
The most important case for modifying the existing templates is of course **integrating your own layout of the system**.
|
||||
Sometimes even if you have decided to stay with the default layout provided by Sylius, you need to **slightly modify it to meet your
|
||||
business requirements**.
|
||||
You may just need to **add your logo anywhere**.
|
||||
|
||||
How to customize templates?
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
.. note::
|
||||
|
||||
How do you know which template you should be overriding?
|
||||
Go to the page that you are going to modify, at the bottom in the Symfony toolbar click on the route ,
|
||||
which will redirect you to the profiler. In the Request Attributes section
|
||||
under ``_sylius [ template => ...]`` you can check the path to the current template.
|
||||
|
||||
|
||||
* **Shop** templates: customizing Login Page template:
|
||||
|
||||
The default login template is: ``SyliusShopBundle:Account:login.html.twig``.
|
||||
In order to override it you need to create your own: ``app/Resources/SyliusShopBundle/views/Account/login.html.twig``.
|
||||
|
||||
Copy the contents of the original template to make your work easier. And then modify it to your needs.
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
{% extends 'SyliusShopBundle:Layout:main.html.twig' %}
|
||||
|
||||
{% import 'SyliusUiBundle:Macro:messages.html.twig' as messages %}
|
||||
|
||||
{% block content %}
|
||||
<div class="ui column stackable center page grid">
|
||||
{% if last_error %}
|
||||
{{ messages.error(last_error.messageKey|trans(last_error.messageData, 'security')) }}
|
||||
{% endif %}
|
||||
|
||||
// You can add a headline for instance to see if you are changing things in the correct place.
|
||||
<h1>
|
||||
This Is My Headline
|
||||
</h1>
|
||||
|
||||
<div class="five wide column"></div>
|
||||
<form class="ui six wide column form segment" action="{{ path('sylius_shop_login_check') }}" method="post" novalidate>
|
||||
<div class="one field">
|
||||
{{ form_row(form._username, {'value': last_username|default('')}) }}
|
||||
</div>
|
||||
<div class="one field">
|
||||
{{ form_row(form._password) }}
|
||||
</div>
|
||||
<div class="one field">
|
||||
<button type="submit" class="ui fluid large primary submit button">{{ 'sylius.ui.login_button'|trans }}</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
||||
Done! If you do not see any changes on the ``/shop/login`` url, clear your cache. ``$ php app/console cache:clear``.
|
||||
|
||||
* **Admin** templates: Customization of the Country form view.
|
||||
|
||||
The default template for the Country form is: ``SyliusAdminBundle:Country:_form.html.twig``.
|
||||
In order to override it you need to create your own: ``app/Resources/SyliusAdminBundle/views/Country/_form.html.twig``.
|
||||
|
||||
Copy the contents of the original template to make your work easier. And then modify it to your needs.
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
<div class="ui segment">
|
||||
{{ form_errors(form) }}
|
||||
{{ form_row(form.code) }}
|
||||
{{ form_row(form.enabled) }}
|
||||
</div>
|
||||
<div class="ui segment">
|
||||
|
||||
// You can add a headline for instance to see if you are changing things in the correct place.
|
||||
<h1>My Custom Headline</h1>
|
||||
|
||||
<h4 class="ui dividing header">{{ 'sylius.ui.provinces'|trans }}</h4>
|
||||
{{ form_row(form.provinces, {'label': false}) }}
|
||||
</div>
|
||||
|
||||
Done! If you do not see any changes on the ``/admin/countries/new`` url, clear your cache. ``$ php app/console cache:clear``.
|
||||
47
docs/customization/validation.rst
Normal file
47
docs/customization/validation.rst
Normal file
|
|
@ -0,0 +1,47 @@
|
|||
Customizing Validation
|
||||
======================
|
||||
|
||||
The default validation group for all resources is ``sylius``, but you can configure your own validation.
|
||||
|
||||
How to customize validation?
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Let's take the example of changing the length of ``name`` for the ``Product`` entity - watch out the field ``name`` is hold on the ``ProductTranslation`` model.
|
||||
|
||||
In the ``sylius`` validation group the minimum length is equal to 2.
|
||||
What if you'd want to have at least 10 characters?
|
||||
|
||||
1. Create the ``AppBundle\Resources\config\validation.yml``.
|
||||
|
||||
In this file you need to overwrite the whole validation of your field that you are willing to modify.
|
||||
Take this configuration from the ``Sylius\Bundle\ProductBundle\Resources\config\validation.xml`` - you can choose format ``xml`` or ``yaml``.
|
||||
|
||||
Give it a new, custom validation group - ``[app_product]``.
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
Sylius\Component\Product\Model\ProductTranslation:
|
||||
properties:
|
||||
name:
|
||||
- NotBlank:
|
||||
message: sylius.product.name.not_blank
|
||||
groups: [app_product]
|
||||
- Length:
|
||||
min: 10
|
||||
minMessage: sylius.product.name.min_length
|
||||
max: 255
|
||||
maxMessage: sylius.product.name.max_length
|
||||
groups: [app_product]
|
||||
|
||||
2. Configure the new validation group in the ``app/config/config.yml``.
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
sylius_product:
|
||||
resources:
|
||||
product:
|
||||
validation_groups:
|
||||
default: [app_product]
|
||||
|
||||
Done. Now in all forms where the Product ``name`` is being used your new validation group will be applied,
|
||||
not letting users add products with name shorter than 10 characters.
|
||||
|
|
@ -25,6 +25,16 @@ The Developer's guide to leveraging the flexibility of Sylius.
|
|||
|
||||
.. include:: /book/map.rst.inc
|
||||
|
||||
The Customization Guide
|
||||
-----------------------
|
||||
|
||||
.. toctree::
|
||||
:hidden:
|
||||
|
||||
customization/index
|
||||
|
||||
.. include:: /customization/map.rst.inc
|
||||
|
||||
The API Guide
|
||||
-------------
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue