Johannes Wachter
Johannes Wachter
Core Developer – Sulu GmbH
Sulu Core Developer and Open-Source Enthusiast.

How to develop a bundle in the Sulu-Admin – #1: Introduction

Sulu’s main purpose is to manage content in an easy to use interface based on solid, extendable state of the art technology. Besides the core bundles it is relatively easy to develop custom bundles that use the Sulu-Admin for data manipulation.

In this tutorial we’d like to show you how to implement a very simple “News” bundle which enables you to manage news articles in a dedicated area and display them on a website. Additionally the tutorial will give you a deeper look inside the JavaScript and PHP code.

The example codes can be found in this GitHub repository which also contains Pull-Requests with each single step. This Pull-Requests also contain comments with additional explanations.

Is the data you need to work with best managed with the page-oriented CMS standard or does it feel like everything is squeezed into the content-tree? If the answer is the latter, consider building your own bundle!

Why would you like to manage news articles in a dedicated area?

Why would someone want to manage news articles in a separated area and not simply create them with standard pages in a webspace? This is a good question and the answer can be quite complex. 

The easiest answer is that a standard content management application is not the best way to manage masses of data. One reason is that loading a large amount of pages can take a long time (e.g. on a news-overview page). 

To avoid this the data can be extracted into a faster storage such as in our example. Here we use a MySQL database which is a fast way to aggregate content based on a relational structure. You could of course use any other database that suits your needs as Sulu won’t give you any restrictions using e.g. MongoDB or whatever you like.

Creating a custom “News” bundle could be a little over-the-top if you have only a few news per month. But keep in mind that this is also a great way to extend limited features of the basic system functionalities. For instance, there is currently no way to auto archive pages. This feature can easily be implemented in your own bundle.

As you can see creating a custom bundle is mostly optional. If you are not sure what is best for your project try to answer yourself this question: Is the data you need to work with best managed with the page-oriented CMS standard or does it feel like everything is squeezed into the content-tree? If the answer is the latter, consider building your own bundle!

Requirements

This tutorial requires a complete installation of Sulu-Standard. 

You should have basic knowledge of Symfony, JavaScript, jQuery (e.g. Deferred), RequireJS and Underscore (e.g. templates). Everything else will be created from scratch.

Initialize the bundle

The first step is to initialize a simple Symfony bundle. You can do that on your own or simply run the following command:

app/console generate:bundle --namespace Example/NewsBundle --bundle-name ExampleNewsBundle

We are following the Sulu conventions here using the xml configuration format.

As Sulu doesn’t use the "default" kernel the “auto” kernel and routing registration does not work properly. Therefor you should answer that questions with no and register them by your own.

At this point Sulu doesn't recognize your bundle. To make it visible in the Sulu-Admin we simply add the "Admin" class which provides all information to display it in the navigation. We also use this class to define the entry-point of the JavaScript.

“Admin” is a simple PHP class which will be published as a symfony service.

// file: Admin/NewsAdmin.php

namespace Example\NewsBundle\Admin;

use Sulu\Bundle\AdminBundle\Admin\Admin;
use Sulu\Bundle\AdminBundle\Navigation\Navigation;
use Sulu\Bundle\AdminBundle\Navigation\NavigationItem;

class NewsAdmin extends Admin
{
    public function __construct($title)
    {
        $rootNavigationItem = new NavigationItem($title);

        $this->setNavigation(new Navigation($rootNavigationItem));
    }
}
<!-- file: Resources/config/services.xml -->

<service id="example_news.admin" class="Example\NewsBundle\Admin\NewsAdmin">
    <argument>%sulu_admin.name%</argument>

    <tag name="sulu.admin"/>
</service>

This initializes an empty navigation. Here we will add the navigation link for our “News” overview list. The link should be placed below the "Snippet" link which is placed inside the "Global Content" area. To achieve this you have to create the complete structure of the navigation you want to extend.

// file: Admin/NewsAdmin.php

public function __construct($title)
{
    $rootNavigationItem = new NavigationItem($title);

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

    $global = new NavigationItem('navigation.global-content');
    $section->addChild($global);

    $news = new NavigationItem('navigation.news');
    $news->setAction('example/news');
    $global->addChild($news);

    $rootNavigationItem->addChild($section);

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

In this example the structure is "root" > "navigation.webspaces" > "navigation.global-content" > "navigation.news". These are the translation-keys for the link which will be used by the Sulu-Admin to display it in the system language chosen by the user. The action set to the "NavigationItem" will be later used by the JavaScript application to determine which component should be loaded to display the content for that page.

Now, when you reload the Sulu-Admin you will see the newly created navigation link "navigation.news".

That's it for the first part of the series. Next time we will introduce the entry point of the JavaScript and give you a deeper look into the frontend architecture of Sulu.


The code for this part of the tutorial can be found here github.com/sulu-io/ExampleNewsBundle/pull/1.