How to develop a bundle in the Sulu-Admin – #3: REST-API
This part of the tutorial is based on the results of the previous blog-post.
One of Sulu’s core concepts is the separation of data and presentation in the Sulu-Admin. To achieve this the Admin is developed as a single-page application with JavaScript - we talked about the basics in the last part - and a standardized RESTful-API. This enables the developer to link external data-sources into the system or export existing data.
In this part we are going to integrate a “News” endpoint in the API of Sulu. We will develop the following parts:
- RestController - delivers data in a JSON-serialized format.
- NewsManager - encapsulates the CRUD operations to interact with “News” items.
- NewsEntity - a simple Doctrine entity which will be stored in the database.
For the rest of this tutorial we will use this Doctrine mapping file. It contains an id, the content and the title. This example is very basic but it can be extended for your needs.
To generate the PHP class put an empty "NewsItem" class into "Entity/NewsItem.php" file and use the following commands to generate the getters/setters and updating the database schema:
After this step we can define our “NewsManager” class. This class uses the “EntityManager” of Doctrine to find or persist “NewsItem” entities. You can see the complete code of this manager in the related PR of this tutorial here. So I’m only explaining the important parts of the manager class.
Both methods "create" and "update" use the "bind" to map the data between the data-array and the entity. This enables developers to extend it easily with additional features and data-fields.
Experienced users of Symfony and Doctrine will have noticed that the manager only calls "persist" but not "flush" which would save it to the database. This is a one simple aspect of the Hexagonal Architecture which is based on the "single responsibility” principle. The manager class is responsible for News-Item CRUD operations and the controller is responsible for the REST-API. This architecture will enable you to simply create fast batch-processing commands like import which only call the heavy "flush" operation when you want it.
To fully implement the Hexagonal Architecture we would also have to encapsulate the "createNewInstance" - for "create" method -, the "persist" and all the "find" methods into an interface which will be injected by the container. This could then be implemented for Symfony and Doctrine or other frameworks. See a talk about that here. For this simple example we will keep the Doctrine dependency.
This service definition enables you to publish the manager in the container and use it later in the controller class:
For the REST-API we use the well documented FOSRestBundle which automatically creates RESTful routes defined by the name of the action. The complete code for the controller can also be found in the related PR here.
The important parts of the controller are the return statements.
The FOSRestBundle will serialize the given entity with the JMS-serializer and returns it as a JSON-response.
To register this rest-routes we have to import the controller in the routing config. The following file has to be imported in the “app/config/admin/routing.yml” with the type "rest" which uses the FOSRestBundle route-loader to generate RESTful routes.
To check the registration of routes use following command:
After this we have a small working API. Don’t forget that we deliberately ignore validation and exceptions for the sake of a manageable tutorial.
That's it for the third part of the series. Next time we will introduce the form to create and update “news” items.
The code for this part of the tutorial can be found here https://github.com/sulu-io/ExampleNewsBundle/pull/3.