We've created a basic front end to display our available Categories, and any Wallpapers that we have added to those categories.

However, up until now, adding a new Wallpaper has only been possible by way of either our console command, or our Doctrine Fixtures.

In this video we are going to get started adding in an Admin area, where we can Create, Read (or List), Update, and Delete (CRUD!) both our wallpapers and our categories.

Back in the olden days, long before modern frameworks appeared, I will confess to avoiding the creation of an Admin area for as long as possible. There's are a bunch of reasons for this:

  • Building an admin area is a lot of work, none of which our end users ever see (we hope!);
  • More code = more potential bugs = more time lost not improving our actual site;
  • Security - if there's no admin area, there's no need to secure it!

To be clear, this was a good few years ago, at least 7 years as best I recall.

My solution to the problem of not having an Admin area was really simple:

I used my database GUI.

For the longest while this was PhpMyAdmin. I often didn't need to bother installing this - in the days when I used cPanel on my servers it was a handy one-click-install option.

When I started managing my own servers I would still install PhpMyAdmin as one of my first tasks. And that was all done manually, no Ansible back then.

My logic was this: PhpMyAdmin gave me full access to everything I needed to do. Sure, relating data together was a bit painful, but here was a tool that had 90% of what I would want in an Admin area, and it was easily secured (with a login screen) to boot.

A little later I moved to using installed database GUI clients, and I found that even more preferable as I didn't have to install PhpMyAdmin.

But when I started venturing out into client work, I couldn't rightly advise end users of my software to "just install SQLYog, or Sequel Pro" and that be a viable solution. If only.

Fast-forwarding this story somewhat, when starting with Symfony 2 we no longer worked so directly with the database. Instead we could create our Entities, and from there we could generated a CRUD boilerplate. Whilst tweaking would inevitably be required, this process alone saved hours of repetitive grunt work in setting up the basics for each entity.

With Symfony's security setup, we could secure off this CRUD section, and within a short amount of time, we had a rudimentary working Admin area.

The code behind this Admin area uses conventional Symfony-style PHP just like the user-visible side of our application / web site. In other words, if you are comfortable with Symfony's forms from working on the front end then you will feel right at home working on the Admin section.

Still, managing our own Admin area is more code for us to maintain. It's very repetitive code at that.

And even though it's an admin area, client expectations are still high. The client might want to use the admin panel on their mobile phone, so you end up spending hours making sure the admin section is responsive. All that effort so one manager can take a 5 second glance once a week... urgh.

Ok, so hopefully at this point you aren't regretting your life choices. I am about to offer a solution :)

Enter EasyAdminBundle

One of the many benefits of using Symfony as your framework of choice is that the code that makes up the framework has been created by some very smart people.

An extra hidden benefit to this is that this code has been reviewed by many more equally smart, or smarter people.

It's a real win-win, and is one of the reasons why I love Symfony - it allows me to stand on the shoulders of giants.

With this in mind, wouldn't it be nice if there was an Admin 'plugin' for any Symfony 2 or Symfony 3 website that had equally been created, and reviewed by smart people from the Symfony community?

Of course it would :)

And so, if you haven't already seen or heard of it, allow me to introduce EasyAdminBundle by Javier Eguiluz (and contributors).

Here we have a bundle that, with very little configuration on our part, gives us a high quality, fast and easy to use Admin panel. Oh, and it's fully responsive so no need to lose a bunch of valuable life on that either.

Enough talking from me, let's add the EasyAdminBundle to our project, and see just how easy it really is:

composer require javiereguiluz/easyadmin-bundle

We need to add the bundle to our project. We do so with composer.

Once that's downloaded, we can enable the Bundle in our project's AppKernel.php:

# /app/AppKernel.php

class AppKernel extends Kernel
{
    public function registerBundles()
    {
        $bundles = [
            // symfony standard bundles here

            new Doctrine\Bundle\MigrationsBundle\DoctrineMigrationsBundle(),
            new Knp\Bundle\PaginatorBundle\KnpPaginatorBundle(),
            new JavierEguiluz\Bundle\EasyAdminBundle\EasyAdminBundle(),

            new AppBundle\AppBundle(),
        ];

        // * snip *

Easy enough so far, right?

We don't need to create any controllers or generate any CRUD here. But we do need to tell our Symfony project that we want to use the controller provided by EasyAdminBundle:

# /app/config/routing.yml

# new
easy_admin_bundle:
    resource: "@EasyAdminBundle/Controller/"
    type:     annotation
    prefix:   /admin

# existing
app:
    resource: '@AppBundle/Controller/'
    type: annotation

Note here the use of the prefix key.

This means that any actions that hit this controller are going to, at the very least, look something like:

http://oursite.whatever/admin

There's a couple of interesting points to make here.

Firstly, as soon as you add this new routing configuration you will get two new entries in your debug:routing output:

 -------------------------- -------- -------- ------ -----------------------------------
  Name                       Method   Scheme   Host   Path
 -------------------------- -------- -------- ------ -----------------------------------
  easyadmin                  ANY      ANY      ANY    /admin/
  admin                      ANY      ANY      ANY    /admin/
 -------------------------- -------- -------- ------ -----------------------------------

I've remove the other output for clarity.

Note though, both easyadmin and admin reference the same controller action.

Secondly, if you read the code from the above link, you will see a completely different method of using Symfony controller actions.

To finish off the installation phase we need to install the bundle's assets:

php bin/console assets:install --symlink

That's the installation part of this done. Now we need to add in our configuration.

Creating A Symfony Admin Panel With EasyAdminBundle

If you have your web server up and running at this point, and you try to hit the /admin route then you will be greeted with the following:

The backend is empty because you haven't configured any Doctrine entity to manage. Solution: open your "app/config/config.yml" file and configure the backend under the "easy_admin" key.

500 Internal Server Error - NoEntitiesConfiguredException

A very helpful error message, as it happens.

One thing I'm going to alter from this suggestion is to separate my configuration out of config.yml. To to this, first I will create a new file:

app/config/config/easy_admin_bundle.yml

And then update config.yml to import this new configuration file:

# /app/config/config.yml

imports:
    - { resource: config/easy_admin_bundle.yml }
    - { resource: parameters.yml }
    - { resource: security.yml }
    - { resource: services.yml }

Before I go on, two things to address:

Yes, I appreciate config/config sucks. But I couldn't think of a better name, and this is accurate enough for me. Feel free to change as needed, or leave your alternatives in the comments below. I'm always happy to rethink my approach.

Secondly, why split out the config?

The reasoning for this is two-fold.

Firstly, I prefer isolating everything if at all possible. If changes are made to config.yml then they very well may break everything. It's easier to spot this if changes happen to this file infrequently.

Secondly, on larger projects I have found the easy_admin config can become quite large. This becomes extra 'noise' to me when working on other parts of the project that still require me to edit config.yml.

It's all personal preference of course, feel free to do all of this inside config.yml.

Anyway, on we go:

# /app/config/config/easy_admin_bundle.yml

easy_admin:
    entities:
        Category:
            class: AppBundle\Entity\Category

The easiest way to get started is to do the very least we can do.

In this case, the Category entity is the most simple of the two entities we have so far.

For each entity we wish to manage in our Admin panel, we need to add an entry under the entities key.

Whatever key we give under entities becomes the 'thing' we are working with. In our case, Category is our entity name, so Category is the key I use.

These two do not need to match up. I could have done:

# /app/config/config/easy_admin_bundle.yml

easy_admin:
    entities:
        Lemonade:
            class: AppBundle\Entity\Category

And this would still work, albeit in a much more confusing fashion :)

That's enough to get us going.

If we now browse to our site:

http://127.0.0.1:8000/admin

We will be redirect to:

http://127.0.0.1:8000/admin/?action=list&entity=Category

And again, I would recommend a perusal of the source code for this controller action as it really is quite an interesting journey.

You should now be able to Create new Category entities, and both edit and delete existing Categories.

Also, you can search and sort, and whilst no immediately obvious, paginate too.

Very, very cool.


Code For This Course

Get the code for this course.

Share This Episode

If you have found this video helpful, please consider sharing. I really appreciate it.


Episodes in this series

# Title Duration
1 Introduction and Site Demo 02:14
2 Setup and a Basic Wallpaper Gallery 08:43
3 Pagination 08:24
4 Adding a Detail View 04:47
5 Creating a Home Page 11:14
6 Creating our Wallpaper Entity 07:50
7 Wallpaper Setup Command - Part 1 - Symfony Commands As a Service 05:56
8 Wallpaper Setup Command - Part 2 - Injection Is Easy 08:53
9 Wallpaper Setup Command - Part 3 - Doing It With Style 05:37
10 Doctrine Fixtures - Part 1 - Setup and Category Entity Creation 08:52
11 Doctrine Fixtures - Part 2 - Relating Wallpapers with Categories 05:56
12 EasyAdminBundle - Setup and Category Configuration 06:02
13 EasyAdminBundle - Wallpaper Setup and List View 07:46
14 EasyAdminBundle - Starting with Wallpaper Uploads 05:57
15 Testing with PhpSpec to Guide Our Implementation 03:39
16 Using PhpSpec to Test our FileMover 05:34
17 Symfony Dependency Testing with PhpSpec 08:47