Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Sulu - ein CMS auf Basis von Symfony

Sulu - ein CMS auf Basis von Symfony

Es gibt immer mehr CMS, die Symfony Komponenten einbauen oder gleich auf dem kompletten Stack aufbauen. Sulu gehört zu den letzteren und erfreut sich immer grösserer Beliebtheit. Soweit so gut, nur was sind die Vorteile für die Entwickler? Wie können sie das Potential wirklich nutzen? Genau diese Fragen sollten nach diesem Vortrag beantwortet sein. Anhand von Sulu werden die unterschiedlichen Schnittstellen in das Symfony Ökosystem und deren Verwendung erklärt.

Im Detail werden wir uns dem Thema Routing, Controllers und Events im Umfeld Symfony und Sulu widmen. Des Weiteren spielt der Service Container inklusive Compiler Pass, welches wohl eines der Hidden Features in Symfony ist, eine grosse Rolle, um das Zusammenspiel reibungslos zu ermöglichen.

Thomas Schedler

October 27, 2017
Tweet

More Decks by Thomas Schedler

Other Decks in Programming

Transcript

  1. Sulu CMS
    Batteries included! Thanks to Symfony.

    View Slide

  2. I'm Thomas Schedler
    @chirimoya | https://github.com/chirimoya
    ... head of development and
    technical consultant. Young
    father trying to master Heston
    Blumenthal recipes.

    View Slide

  3. Who knows Sulu?

    View Slide

  4. Sulu
    – Content Management Platform
    – Full-Stack Symfony
    – Made for businesses
    – Simple UI
    – High Performance
    – Open Source

    View Slide

  5. For business
    – Built with the needs of business and
    industry in mind
    – Enterprise features without ridiculous
    license fees
    – Supports multi-language, multi-portal
    and multi-channel
    – Easy to integrate data from external
    resources

    View Slide

  6. For editors
    – Really simple and very fast user interface
    – Web-based, no installation required
    – Edit forms that validate content & ensure
    correct semantics
    – Live preview content as you type it
    – Switch between different devices
    (Smartphone, Tablet or Desktop)

    View Slide

  7. For developers
    – Full-Stack Symfony environment
    – Semantic configuration of templates
    – Easy transition from data to HTML
    – Build applications around content
    management
    – Add/Remove functionality with Symfony
    Bundles

    View Slide

  8. Where we see us
    Bicycles
    Everyone can ride them, many
    can repair it

    (WordPress etc.)
    Cars
    Many can ride them,
    some can repair it

    (TYPO3 etc.)
    Supertanker
    Need highly specialized
    staff, expensive
    and very complex

    (Hybris, OpenText, AEM
    etc.)

    Trucks
    Need a special license,
    must be configured
    to your needs

    (eZ Publish, Pimcore etc.)

    View Slide

  9. When to use Sulu?
    – Complex website scenarios
    – News- and media platforms
    – Brand and corporate presences
    – Social and collaborative sites
    – E-Business projects
    – Handling external data resources
    – Speed is a critical success factor
    – Skilled PHP/Symfony developers
    – Web standards

    View Slide

  10. When not to use Sulu?
    – Sulu is not Wordpress
    – We don’t recommend to use Sulu for:
    – Low budget marketing sites
    – Simple blogs
    – Hobby websites
    – (Very) small business websites

    View Slide

  11. Getting Started
    The basic architecture and concepts of Sulu.

    View Slide

  12. PHPCR DOCTRINE
    MySQL, PostgreSQL, Jackrabbit, ...
    Framework
    Symfony Symfony CMF
    Contact
    Media
    Content ...
    Sulu

    View Slide

  13. REST API
    Single-Page Application
    Your Application
    Website Admin
    Symfony Symfony CMF
    Contact
    Media
    Content ...
    Sulu

    View Slide

  14. Webspaces
    – One single content-structure / page tree
    – The structure represents one or more
    websites
    – Multiple languages implemented as
    dimensions
    – Multiple webspaces support
    Webspace ...

    View Slide

  15. Content Tree …

    View Slide

  16. We XML

    View Slide


  17. example.com
    example






    example.com
    example



    example.com/{localization}




    {host}/{localization}




    View Slide

  18. Templates & Content Types
    – The structure of the page
    – How that structure is rendered
    – Each page template is defined by two files:
    – an XML file that contains the page
    structure
    – a Twig file that contains the HTML code
    – A page structure consists of properties, each
    of which has a content type

    View Slide

  19. Content Types ... Live Preview ...

    View Slide


  20. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://schemas.sulu.io/template/template http://schemas.sulu.io/
    template/template-1.0.xsd">
    default
    templates/default
    SuluWebsiteBundle:Default:index
    2400














    View Slide

  21. {% extends "master.html.twig" %}
    {% block content %}
    {{ content.title }}

    {{ content.article|raw }}

    {% endblock %}

    View Slide

  22. View Slide

  23. Router
    The main entry point to your Symfony application.

    View Slide

  24. /
    /services
    /blog
    Request
    Response
    Kernel Controller
    Router
    Request URI Controller & Action
    Front Controller
    indexAction()
    servicesAction()
    blogAction()
    Response
    Response
    Response
    Model
    View
    Services

    View Slide

  25. Chain Router
    Router
    /
    /services
    /blog
    Request
    Response
    Kernel Controller
    Request URI Controller & Action
    Front Controller
    indexAction()
    servicesAction()
    blogAction()
    Response
    Response
    Response
    Model
    View
    Services
    Dynamic Router

    View Slide

  26. Sulu routing summarized
    – CMF ChainRouter replaces the default
    routing system
    – and works by accepting a set of
    prioritized Routers
    – The Symfony default Router is registered
    with the highest priority
    – DynamicRouters handle all the
    dynamically defined routes (pages,
    redirects, …)

    View Slide

  27. // app/WebsiteKernel.php


    class WebsiteKernel extends AbstractKernel

    {

    /**

    * {@inheritdoc}

    */

    protected $name = 'website';


    /**

    * @param string $environment

    * @param bool $debug

    */

    public function __construct($environment, $debug)

    {

    parent::__construct($environment, $debug);

    $this->setContext(self::CONTEXT_WEBSITE);

    }


    /**

    * {@inheritdoc}

    */

    public function registerBundles()

    {

    $bundles = parent::registerBundles();

    $bundles[] = new Symfony\Cmf\Bundle\RoutingBundle\CmfRoutingBundle();

    return $bundles;

    }

    }
    $bundles[] = new AppBundle\AppBundle();

    View Slide

  28. // app/config/website/routing.yml
    app:

    resource: "@AppBundle/Controller/"

    type: annotation

    prefix: /app
    // src/AppBundle/Controller/DefaultController.php
    namespace AppBundle\Controller;


    use Symfony\Bundle\FrameworkBundle\Controller\Controller;

    use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;


    class DefaultController extends Controller

    {

    /**

    * @Route("/")

    */

    public function indexAction()

    {

    return $this->render('AppBundle:Default:index.html.twig');

    }

    }
    // src/AppBundle/Resources/views/Default/index.html.twig
    Hallo World!

    View Slide

  29. View Slide

  30. Controller & View
    Add your custom logic within your own content Controller.

    View Slide

  31. Controller
    Chain Router
    Router
    /
    /services
    /blog
    Request
    Response
    Kernel
    Request URI Controller & Action
    Front Controller
    indexAction()
    servicesAction()
    blogAction()
    Response
    Response
    Response
    Model
    View
    Services
    Dynamic Router
    Default Controller

    View Slide

  32. // app/Resources/templates/pages/default.xml

    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

    xsi:schemaLocation="http://schemas.sulu.io/template/template http://
    schemas.sulu.io/template/template-1.0.xsd">


    default


    templates/default

    2400



    Default

    Standard



    ...

    AppBundle:Custom:index

    View Slide

  33. // src/AppBundle/Controller/CustomController.php


    namespace AppBundle\Controller;


    use Sulu\Bundle\WebsiteBundle\Controller\WebsiteController;

    use Sulu\Component\Content\Compat\StructureInterface;


    class CustomController extends WebsiteController

    {

    /**

    * My custom controller action.

    *

    * @param StructureInterface $structure

    * @param bool $preview

    * @param bool $partial

    *

    * @return Response

    */

    public function indexAction(StructureInterface $structure, $preview = false, $partial = false)

    {

    $response = $this->renderStructure(

    $structure,

    [

    // here you can add some custom data for your template

    'myData' => $this->get('my_custom_service')->getMyData(),

    ],

    $preview,

    $partial

    );


    return $response;

    }

    }

    View Slide

  34. Response Format
    HTML, XML or JSON

    View Slide

  35. // app/Resources/templates/pages/default.xml

    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

    xsi:schemaLocation="http://schemas.sulu.io/template/template http://schemas.sulu.io/template/template-1.0.xsd">


    default


    AppBundle:Custom:index

    AppBundle:Custom:index

    2400


    ...

    // src/AppBundle/Resources/views/Custom/index.html.twig


    {% extends "master.html.twig" %}


    {% block content %}

    {{ content.title }}



    {{ content.article|raw }}


    {% endblock %}
    // src/AppBundle/Resources/views/Custom/index.json.twig
    {{ content|json_encode|raw }}
    .html.twig

    View Slide

  36. View Slide

  37. HTTP Cache & ESI
    HTTP Standards FTW!

    View Slide

  38. Reverse Proxy Caches
    – A HTTP Cache is a full page cache
    – It bypasses your application entirely, if
    the cache entry is valid
    – HTTP cache headers are used to mark a
    response cacheable and for how long
    – Symfony comes with a reverse proxy
    written in PHP
    – Switch to something more robust like
    Varnish without any problem
    https://tomayko.com/blog/2008/things-caches-do

    View Slide


  39. Caching entire responses isn't always possible for
    highly dynamic sites, or is it?

    View Slide

  40. ESI - Edge Side Includes
    – The ESI specification describes tags to
    communicate with the gateway cache
    – In Symfony the is
    implemented
    – If the response contains ESI tags, the
    cache either requests the page fragment
    from the backend or embeds the fresh
    cache entry

    View Slide

  41. // app/config/config.yml
    framework:

    ...
    esi: { enabled: true }
    // app/Resources/views/Default/index.html.twig


    {# you can use a controller reference #}

    {{ render_esi(controller('AppBundle:News:latest', { 'limit': 5 })) }}


    {# ... or a URL #}

    {{ render_esi(url('latest_news', { 'limit': 5 })) }}

    View Slide

  42. Model
    Customize what you need.

    View Slide

  43. Customizing Models
    – Doctrine doesn't support model
    customization
    – Inheritance leads to multiple tables for the
    same data structure
    – Sulu’s PersistenceBundle allows to replace
    models via configuration
    – Inspired by Sylius ResourceBundle

    View Slide

  44. // src/AppBundle/EntityTag.php
    namespace AppBundle\Entity;
    use Sulu\Bundle\TagBundle\Entity\Tag as SuluTag;
    class Tag extends SuluTag
    {
    public $description;
    }
    // src/AppBundle/Resources/config/doctrine/Tag.orm.xml

    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">




    // app/config/config.yml
    sulu_tag:
    objects:
    tag:
    model: AppBundle\Entity\Tag

    View Slide

  45. Event Dispatcher
    Handle additional business logic within your Event Subscriber.

    View Slide

  46. Symfony Events
    Kernel Events
    – kernel.request
    – kernel.response
    – kernel.controller
    – kernel.view
    – kernel.terminate

    Doctrine Events
    Lifecycle Events
    – [pre|post]Remove
    – [pre|post]Persist
    – [pre|post]Update
    – [pre|on|post]Flush
    – onClear

    View Slide

  47. Sulu Document Manager Events
    +----------------------+
    | Events |
    +----------------------+
    | persist |
    | hydrate |
    | remove |
    | refresh |
    | copy |
    | move |
    | create |
    | clear |
    | find |
    | reorder |
    | publish |
    | unpublish |
    | remove_draft |
    | flush |
    | query.create |
    | query.create_builder |
    | query.execute |
    | configure_options |
    | metadata_load |
    | restore |
    +----------------------+
    bin/adminconsole sulu:document:subscriber:debug

    View Slide

  48. // src/AppBundle/Document/Subscriber/MailSubscriber.php


    namespace AppBundle\Document\Subscriber;


    use Sulu\Component\DocumentManager\Event\PublishEvent;

    use Sulu\Component\DocumentManager\Events;

    use Symfony\Component\EventDispatcher\EventSubscriberInterface;


    class MailSubscriber implements EventSubscriberInterface

    {

    ...


    /**

    * {@inheritdoc}

    */

    public static function getSubscribedEvents()

    {

    return [

    Events::PUBLISH => ['sendNotification', -1000],

    ];

    }


    public function sendNotification(PublishEvent $event)

    {

    $message = new \Swift_Message('Page Published', 'URL: ' . $event->getDocument()->getResourceSegment());


    $this->mailer->send($message);

    }

    }




    View Slide

  49. Service Container
    The control center for all you application.

    View Slide

  50. Service Container
    – Foundation for extensibility &
    customizability
    – Sulu heavily uses service definitions
    – Add new functionality
    (Modulnavigation, Content-Type, ...)
    – Extend existing (Smart-Content,
    Teaser, ...)
    – Overwrite services

    View Slide

  51. // src/AppBundle/Admin/AppAdmin.php

    namespace AppBundle\Admin;


    use Sulu\Bundle\AdminBundle\Admin\Admin;

    use Sulu\Bundle\AdminBundle\Navigation\Navigation;

    use Sulu\Bundle\AdminBundle\Navigation\NavigationItem;


    class AppAdmin extends Admin

    {

    public function __construct($title)

    {

    $rootNavigationItem = new NavigationItem($title);

    $section = new NavigationItem('navigation.modules');


    $myModule = new NavigationItem('app.my_module');

    $myModule->setIcon('custom');


    $item = new NavigationItem('app.my_module.title');

    $item->setAction('my_module/custom');

    $myModule->addChild($item);


    $rootNavigationItem->addChild($section);

    $section->addChild($myModule);


    $this->setNavigation(new Navigation($rootNavigationItem));

    }

    }

    %sulu_admin.name%



    View Slide

  52. // src/AppBundle/DependencyInjection/AppCompilerPass.php


    namespace AppBundle\DependencyInjection;


    use AppBundle\Contact\CustomContactManager;

    use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;

    use Symfony\Component\DependencyInjection\ContainerBuilder;

    use Symfony\Component\DependencyInjection\Reference;


    class AppCompilerPass implements CompilerPassInterface

    {

    public function process(ContainerBuilder $container)

    {

    $definition = $container->getDefinition('sulu_contact.contact_manager');

    $definition->setClass(CustomContactManager::class);

    $definition->addArgument(new Reference('app.my_custom_service'));

    }

    }
    // src/AppBundle/AppBundle.php


    namespace AppBundle;


    use AppBundle\DependencyInjection\AppCompilerPass;

    use Symfony\Component\DependencyInjection\ContainerBuilder;

    use Symfony\Component\HttpKernel\Bundle\Bundle;


    class AppBundle extends Bundle

    {

    public function build(ContainerBuilder $container)

    {

    $container->addCompilerPass(new AppCompilerPass());

    }

    }

    View Slide

  53. Thanks for watching!
    www.sulu.io

    View Slide