gstreamer0.10-ffmpeg
gstreamer0.10-plugins-good
packages.
Run:
git status
Installing EasyAdmin didn't do anything fancy: it doesn't have a recipe that adds config files or a button that makes cute kittens appear. Darn. It just added itself and registered its bundle. So simply installing the bundle didn't give us any new routes or pages.
For example, if I try to go to /admin
, we see "Route Not Found." That's because the first step after installing EasyAdmin is to create an admin dashboard: a sort of "landing page" for your admin. You'll typically have only one of these in your app, but you can have multiple, like for different admin user types.
And we don't even need to create this dashboard thingy by hand! Back at your terminal, run:
symfony console make:admin:dashboard
As a reminder, symfony console
is exactly the same as running php bin/console
. The only difference is that running symfony console
allows the Docker environment variables to be injected into this command. It typically makes no difference unless you're running a command that requires database access. So, in this case, php bin/console
would work just fine.
I'll stick with symfony console
throughout this tutorial. So say:
symfony console make:admin:dashboard
We'll call it DashboardController
, generate it into src/Controller/Admin
and... done! This created one new file: src/Controller/Admin/DashboardController.php
. Let's go check it out!
When I open it...
... lines 1 - 2 | |
namespace App\Controller\Admin; | |
use EasyCorp\Bundle\EasyAdminBundle\Config\Dashboard; | |
use EasyCorp\Bundle\EasyAdminBundle\Config\MenuItem; | |
use EasyCorp\Bundle\EasyAdminBundle\Controller\AbstractDashboardController; | |
use Symfony\Component\HttpFoundation\Response; | |
use Symfony\Component\Routing\Annotation\Route; | |
class DashboardController extends AbstractDashboardController | |
{ | |
'/admin', name: 'admin') ( | |
public function index(): Response | |
{ | |
return parent::index(); | |
} | |
public function configureDashboard(): Dashboard | |
{ | |
return Dashboard::new() | |
->setTitle('EasyAdminBundle'); | |
} | |
public function configureMenuItems(): iterable | |
{ | |
yield MenuItem::linkToDashboard('Dashboard', 'fa fa-home'); | |
// yield MenuItem::linkToCrud('The Label', 'fas fa-list', EntityClass::class); | |
} | |
} |
Hmm. There's not much here yet. But one thing you might notice is that it has a route for /admin
:
... lines 1 - 10 | |
class DashboardController extends AbstractDashboardController | |
{ | |
'/admin', name: 'admin') ( | |
public function index(): Response | |
{ | |
... line 16 | |
} | |
... lines 18 - 29 | |
} |
So now, if we find our browser and go to /admin
... we do hit the admin dashboard!
Tip
Since version 4.0.3
of EasyAdmin, this welcome page looks a bit different! For
example, it won't have the side menu that you see in the video. To see the links -
and follow better with the tutorial - create a new dashboard template that will
extend the base layout from EasyAdmin:
{# templates/admin/index.html.twig #}
{% extends '@EasyAdmin/page/content.html.twig' %}
Then, comment out the return parent::index();
line in
DashboardController::index()
and instead render this template:
class DashboardController extends AbstractDashboardController
{
#[Route('/admin', name: 'admin')]
public function index(): Response
{
return $this->render('admin/index.html.twig');
}
}
We'll talk much more later about how to use and design this dashboard page!
I want to point out a few important things. The first is that we do have a /admin
route... and there's nothing fancy or "EasyAdmin" about it. This is just... how we create routes in Symfony. This is a PHP 8 attribute route, which you may or may not be familiar with. I've typically used annotations until now. But because I'm using PHP 8, I'll be using attributes instead of annotations throughout the tutorial. Don't worry though! They work exactly the same. If you're still using PHP 7, you can use annotations just fine.
The second important thing is that DashboardController
is just a normal controller. Though, it does extend AbstractDashboardController
:
... lines 1 - 6 | |
use EasyCorp\Bundle\EasyAdminBundle\Controller\AbstractDashboardController; | |
... lines 8 - 10 | |
class DashboardController extends AbstractDashboardController | |
{ | |
... lines 13 - 29 | |
} |
Hold Cmd
or Ctrl
and click to jump into that class.
This implements DashboardControllerInterface
. So this is a normal controller, but by implementing this interface, EasyAdmin knows that we're inside the admin section... and boots up its engine. We'll learn all about what that means throughout the tutorial.
Most importantly, this class has a number of methods that we can override to configure what our dashboard looks like. We'll also be doing that throughout this tutorial.
And because this is just a normal route and controller, it also follows the normal security rules that we would expect. Right now, this means that no security is being applied. I mean, check it out: I'm not even logged in, but I am successfully on the admin dashboard!
Tip
In Symfony 6.2, you can use the #[IsGranted()]
attribute without installing
SensioFrameworkExtraBundle. It's now part of the core!
So let's secure it! I'll also do this with an attribute. I already have SensioFrameworkExtraBundle installed, so I can say #[IsGranted()]
and hit "tab" to auto-complete that. Let's require any user accessing this controller to have ROLE_ADMIN
... that's kind of a base admin role that all admin users have in my app:
... lines 1 - 7 | |
use Sensio\Bundle\FrameworkExtraBundle\Configuration\IsGranted; | |
... lines 9 - 11 | |
class DashboardController extends AbstractDashboardController | |
{ | |
'ROLE_ADMIN') ( | |
... line 15 | |
public function index(): Response | |
{ | |
... line 18 | |
} | |
... lines 20 - 31 | |
} |
Now when we refresh... beautiful! We bounced back over to the login page!
To log in, open src/DataFixtures/AppFixtures.php
:
... lines 1 - 11 | |
class AppFixtures extends Fixture | |
{ | |
public function load(ObjectManager $manager) | |
{ | |
// Load Users | |
UserFactory::new() | |
->withAttributes([ | |
'email' => 'superadmin@example.com', | |
'plainPassword' => 'adminpass', | |
]) | |
->promoteRole('ROLE_SUPER_ADMIN') | |
->create(); | |
UserFactory::new() | |
->withAttributes([ | |
'email' => 'admin@example.com', | |
'plainPassword' => 'adminpass', | |
]) | |
->promoteRole('ROLE_ADMIN') | |
->create(); | |
UserFactory::new() | |
->withAttributes([ | |
'email' => 'moderatoradmin@example.com', | |
'plainPassword' => 'adminpass', | |
]) | |
->promoteRole('ROLE_MODERATOR') | |
->create(); | |
UserFactory::new() | |
->withAttributes([ | |
'email' => 'tisha@symfonycasts.com', | |
'plainPassword' => 'tishapass', | |
'firstName' => 'Tisha', | |
'lastName' => 'The Cat', | |
'avatar' => 'tisha.png', | |
]) | |
->create(); | |
... lines 50 - 64 | |
} | |
} |
I have a bunch of dummy users in the database: there's a super admin, a normal admin, and then somebody known as a moderator. We'll talk more about these later when we get deeper into how to secure different parts of your admin for different roles.
Anyways, log in with admin@example.com
... password adminpass
, and... beautiful! We're back to our dashboard!
Of course, if you want to, instead of using the IsGranted
PHP attribute, you could also say $this->denyAccessUnlessGranted()
. And you could also go to config/packages/security.yaml
and, down at the bottom, add an access_control
that protects the entire /admin
section:
security: | |
... lines 2 - 36 | |
# Easy way to control access for large sections of your site | |
# Note: Only the *first* access control that matches will be used | |
access_control: | |
- { path: ^/admin, roles: ROLE_ADMIN } | |
- { path: ^/profile, roles: ROLE_USER } | |
... lines 42 - 55 |
Actually, adding this access_control
is basically required: using only the IsGranted
attribute is not enough. We'll learn why a bit later.
So our dashboard is the "jumping off point" for our admin, but there's nothing particularly special here. The page has a title, some menu items, and a nice little user menu over here. Eventually, we'll render something cool on this page - like some stats and graphs - instead of this message from EasyAdmin. Oh, and all of this styling is done with Bootstrap 5 and FontAwesome. More on tweaking the design later.
Before we move on, let's see if we can customize the dashboard a little bit. One of the absolute best things about EasyAdmin is that all the config is done in PHP. Yay! It's usually done via methods in your controller. For example: want to configure the dashboard? There's a configureDashboard()
method for that!
... lines 1 - 11 | |
class DashboardController extends AbstractDashboardController | |
{ | |
... lines 14 - 20 | |
public function configureDashboard(): Dashboard | |
{ | |
return Dashboard::new() | |
->setTitle('EasyAdminBundle'); | |
} | |
... lines 26 - 31 | |
} |
We can change the title of the page to "Cauldron Overflow Admin":
... lines 1 - 11 | |
class DashboardController extends AbstractDashboardController | |
{ | |
... lines 14 - 20 | |
public function configureDashboard(): Dashboard | |
{ | |
return Dashboard::new() | |
->setTitle('Cauldron Overflow Admin'); | |
} | |
... lines 26 - 31 | |
} |
When we refresh... we see "Cauldron Overflow Admin"! And there are a number of other methods... just look at the auto-complete from your editor. There are methods related to the favicon path... and something about the sidebar being minimized. That's referring to a nice feature where you can click on the separator for the sidebar to collapse or expand it.
The main part of the dashboard is really these menu items. And, we only have one right now. This is controlled by configureMenuItems()
:
... lines 1 - 11 | |
class DashboardController extends AbstractDashboardController | |
{ | |
... lines 14 - 26 | |
public function configureMenuItems(): iterable | |
{ | |
yield MenuItem::linkToDashboard('Dashboard', 'fa fa-home'); | |
// yield MenuItem::linkToCrud('The Label', 'fas fa-list', EntityClass::class); | |
} | |
} |
Just to prove that we can, let's change the icon to fa-dashboard
:
... lines 1 - 11 | |
class DashboardController extends AbstractDashboardController | |
{ | |
... lines 14 - 26 | |
public function configureMenuItems(): iterable | |
{ | |
yield MenuItem::linkToDashboard('Dashboard', 'fa fa-dashboard'); | |
... line 30 | |
} | |
} |
This leverages the FontAwesome library. When we refresh, new icon!
So we can definitely do more with our dashboard, but that's enough for now. Because what we're really here for are the "CRUD controllers". These are the sections of our site where we will be able to create, read, update, and delete all of our entities. Let's get those going next!
Hey Kacper G.
Can you double-check that such user exist? I believe you forgot to load the data fixtures
Cheers!
Thanks for reply. Yea. That was it, I forgot to use command "symfony console doctrine:fixtures:load"
Hi guys!
I think I've missed something during the course: after adding #IsGranted attribute to the dashboard route it does not redirect me anywhere, just fails with "Full authentication is required to access this resource" exception.
Could you please point me to the place in the course where that redirect to login page as added.
Thanks
Hey @Vitalii-R
Did you download the course code or did you start from scratch?
Symfony redirects you automatically to the login page when you ask for full authentication, or when you are anonymous and try to visit a secured page
Hello.
With the new version of Symfony 6.2, you can generate a dashboard,
but all the data for Secure #[IsGranted('ROLE_ADMIN')]
Login-Template, src/DataFixtures/AppFixtures.php
are missing, ... ,
and the sensio/framework-extra-bundle
is abandoned
Do you have an update on this or what is the best way to go about it?
Best regards
Tom
Hey Tom,
This is the latest version of the EasyAdmin tutorial. Yeah, in Symfony 6.2 the PHP attributes like #[IsGranted('ROLE_ADMIN')]
you mentioned should work out of the box now, so you don't need to install that extra sensio/framework-extra-bundle
anymore.
We're going to add a note to mention this, thanks for pointing into this!
Also, we do recommend you follow the course by downloading the course code and starting from the start/ folder inside the downloaded archive. This way you will have the exact same versions of dependencies we have in the video. But if you want to follow it on a fresher Symfony version - you might require to do some extra work because of some changes in the dependencies. But don't worry, if you get stuck somewhere following it on Symfony 6.2 - let us know in the comments and we will help!
Cheers!
The workaround for the new welcome page isn't working anymore.
I'm getting 404 errors for fonts used by easyadmin.
It's searching for fonts in the public/bundles/easyadmin/fonts folder for fonts that are actually in the folder but have the wrong hashes
"REQUES Uncaught PHP Exception Symfony\Component\HttpKernel\Exception\NotFoundHttpException: "No route found for "GET https://localhost:8000/bundles/easyadmin/fonts/fa-brands-400.13685372.ttf" (from "https://localhost:8000/bundles/easyadmin/app.css")" at C:\Users\*****\Desktop\code-easyadminbundle\finish\vendor\symfony\http-kernel\EventListener\RouterListener.php line 130"
That's one of the errors in my console.
I'm even trying the "finished" version of the course code, and the admin dashboard looks like its not loading any styles from easyadmin at all, the whole page is smooshed to the left, there are no font awesome icons, the menu is a bunch of blue text floating over a giant picture of a guy and a playing card
Hey Maxim,
I'm not sure you can highlight a specific pattern for this. Well, the EA dashboard is just a Symfony controller first of all. And it implements some interfaces that helps to do this in the standardized (regulated) way, but it's core PHP concepts, not separate patterns.
I hope this helps!
Cheers!
Hey Victor,
Sorry but could you help me
The easy admin assets aren't loading and the none of the javascript is firing. I'm getting 404 errors for woff2 ttf and woff fonts
Hey Nick!
Hm, could you make sure you installed the bundle assets? For it, please, rerun:
$ bin/console assets:install
Then, try to clear the Symfony cache. Also probably do a force reload in your browser just in case or open the website in Incognito.
Cheers!
Hi I have the same problem here. I can't see the "Dashboard" link.
And I'm also stucked on the "Welcome to EasyAdmin 4" pag.
Hi,
I don't see dashboard as yours.
I see "Welcome to EasyAdmin 4" - in the center of page without aside "Dashboard" and user's login (user icon and user name).
Could you check? I have EasyAdmin 4.0.3
Thank you.
I've got something like you if generate url.
public function index(): Response
{
// return parent::index();
$url = $this->adminUrlGenerator
->setController(QuestionCrudController::class)
->generateUrl();
return $this->redirect($url);
}
And one more solution, create own template:
(From docs: https://symfony.com/bundles...
{# templates/admin/my-custom-page.html.twig #}
{% extends '@EasyAdmin/page/content.html.twig' %}
{% block content_title %}The Title of the Page{% endblock %}
{% block page_actions %}
Some Action
{% endblock %}
{% block main %}
<table class="datagrid">
<thead>
<tr>
<td>Some Column</td>
<td>Another Column</td>
</tr>
</thead>
<tbody>
</tbody>
</table>
{% endblock %}
Hey Ruslan
Yeah You are right, there was a change in welcome page, so you need to implement custom dashboard page for dashboard! Checkout my answer below =)
Cheers!
Hello and thanks for this new tutorial!
I'm stucked on the "Welcome to EasyAdmin 4" page. I even can't see the "Dashboard" link.
Any idea?
Hey @Tomas
Yeah that's a weird state, caused by latest EA version, welcome page was changed so to see link you should do some additional work. Create a template inside templates/
directory with name dashboard.html.twig
and put inside following content
{% extends '@EasyAdmin/page/content.html.twig' %}
{% block content_title %}Dashboard{% endblock %}
Now in src/Controller/Admin/DashboardController.php
change index()
this way
public function index(): Response
{
return $this->render('dashboard.html.twig');
}
now you will get an empty page for dashboard
Cheers!
Thomas, sorry for the confusion! Vladimir thanks a lot for helping people and I'm sorry this updated "Welcome Page" was introduced just when you produced the video with the old "Welcome Page".
This past weekend we've tweaked the "Welcome Page" again to hopefully be more clear. It will be part of the next stable release. See https://github.com/EasyCorp...
// composer.json
{
"require": {
"php": ">=8.1.0",
"ext-ctype": "*",
"ext-iconv": "*",
"composer/package-versions-deprecated": "^1.11", // 1.11.99.4
"doctrine/doctrine-bundle": "^2.1", // 2.5.5
"doctrine/doctrine-migrations-bundle": "^3.0", // 3.2.1
"doctrine/orm": "^2.7", // 2.10.4
"easycorp/easyadmin-bundle": "^4.0", // v4.0.2
"handcraftedinthealps/goodby-csv": "^1.4", // 1.4.0
"knplabs/knp-markdown-bundle": "dev-symfony6", // dev-symfony6
"knplabs/knp-time-bundle": "^1.11", // 1.17.0
"sensio/framework-extra-bundle": "^6.0", // v6.2.5
"stof/doctrine-extensions-bundle": "^1.4", // v1.7.0
"symfony/asset": "6.0.*", // v6.0.1
"symfony/console": "6.0.*", // v6.0.2
"symfony/dotenv": "6.0.*", // v6.0.2
"symfony/flex": "^2.0.0", // v2.0.1
"symfony/framework-bundle": "6.0.*", // v6.0.2
"symfony/mime": "6.0.*", // v6.0.2
"symfony/monolog-bundle": "^3.0", // v3.7.1
"symfony/runtime": "6.0.*", // v6.0.0
"symfony/security-bundle": "6.0.*", // v6.0.2
"symfony/stopwatch": "6.0.*", // v6.0.0
"symfony/twig-bundle": "6.0.*", // v6.0.1
"symfony/ux-chartjs": "^2.0", // v2.0.1
"symfony/webpack-encore-bundle": "^1.7", // v1.13.2
"symfony/yaml": "6.0.*", // v6.0.2
"twig/extra-bundle": "^2.12|^3.0", // v3.3.7
"twig/twig": "^2.12|^3.0" // v3.3.7
},
"require-dev": {
"doctrine/doctrine-fixtures-bundle": "^3.3", // 3.4.1
"symfony/debug-bundle": "6.0.*", // v6.0.2
"symfony/maker-bundle": "^1.15", // v1.36.4
"symfony/var-dumper": "6.0.*", // v6.0.2
"symfony/web-profiler-bundle": "6.0.*", // v6.0.2
"zenstruck/foundry": "^1.1" // v1.16.0
}
}
When im trying to log in with email admin@example.com and password adminpass i receive message "Invalid credentials". How to fix it?