Dashboards
Dashboards¶
Dashboards are the entry point of backends and they link to one or more resources. Dashboards also display a main menu to navigate the resources and the information of the logged in user.
Imagine that you have a simple application with three Doctrine entities: users, blog posts and categories. Your own employees can create and edit any of them but external collaborators can only create blog posts.
You can implement this in EasyAdmin as follows:
- Create three CRUD controllers (e.g.
UserCrudController
,BlogPostCrudController
andCategoryCrudController
); - Create a dashboard for your employees (e.g.
DashboardController
) and link to the three resources; - Create a dashboard for your external collaborators (e.g.
ExternalDashboardController
) and link only to theBlogPostCrudController
resource.
Technically, dashboards are regular Symfony controllers so you can do
anything you usually do in a controller, such as injecting services and using
shortcuts like $this->render()
or $this->isGranted()
.
Dashboard controller classes must implement the
EasyCorp\Bundle\EasyAdminBundle\Contracts\Controller\DashboardControllerInterface
,
which ensures that certain methods are defined in the dashboard. Instead of
implementing the interface, you can also extend from the
AbstractDashboardController
class. Run the following command to quickly
generate a dashboard controller:
1 | $ php bin/console make:admin:dashboard
|
Dashboard Route¶
Each dashboard uses a single Symfony route to serve all its URLs. The needed
information is passed using query string parameters. If you generated the
dashboard with the make:admin:dashboard
command, the route is defined using
Symfony route annotations:
namespace App\Controller\Admin;
use EasyCorp\Bundle\EasyAdminBundle\Config\Dashboard;
use EasyCorp\Bundle\EasyAdminBundle\Controller\AbstractDashboardController;
use Symfony\Component\Routing\Annotation\Route;
class DashboardController extends AbstractDashboardController
{
/**
* @Route("/admin")
*/
public function index(): Response
{
return parent::index();
}
// ...
}
The /admin
URL is only a default value, so you can change it. If you do that,
don’t forget to also update this value in your Symfony security config to
restrict access to the entire backend.
There’s no need to define a explicit name for this route. Symfony autogenerates a route name and EasyAdmin gets that value at runtime to generate all URLs. However, if you generate URLs pointing to the dashboard in other parts of your application, you can define an explicit route name to simplify your code:
/**
* @Route("/admin", name="some_route_name")
*/
public function index(): Response
{
return parent::index();
}
If you don’t use annotations, you must configure the dashboard route using YAML, XML or PHP config in a separate file. For example, when using YAML:
1 2 3 4 5 6 | # config/routes.yaml
dashboard:
path: /admin
controller: App\Controller\Admin\DashboardController::index
# ...
|
In practice you won’t have to deal with this route or the query string parameters in your application because EasyAdmin provides a service to generate admin URLs.
Note
Using a single route to handle all backend URLs means that generated URLs are a bit long and ugly. This is a reasonable trade-off because it makes many other features, such as generating admin URLs, much simpler.
Dashboard Configuration¶
The dashboard configuration is defined in the configureDashboard()
method
(the main menu and the user menu are configured in their own methods, as
explained later):
namespace App\Controller\Admin;
use EasyCorp\Bundle\EasyAdminBundle\Config\Dashboard;
use EasyCorp\Bundle\EasyAdminBundle\Controller\AbstractDashboardController;
class DashboardController extends AbstractDashboardController
{
// ...
public function configureDashboard(): Dashboard
{
return Dashboard::new()
// the name visible to end users
->setTitle('ACME Corp.')
// you can include HTML contents too (e.g. to link to an image)
->setTitle('<img src="..."> ACME <span class="text-small">Corp.</span>')
// the path defined in this method is passed to the Twig asset() function
->setFaviconPath('favicon.svg')
// the domain used by default is 'messages'
->setTranslationDomain('my-custom-domain')
// there's no need to define the "text direction" explicitly because
// its default value is inferred dynamically from the user locale
->setTextDirection('ltr')
// set this option if you prefer the page content to span the entire
// browser width, instead of the default design which sets a max width
->renderContentMaximized()
// set this option if you prefer the sidebar (which contains the main menu)
// to be displayed as a narrow column instead of the default expanded design
->renderSidebarMinimized()
// by default, all backend URLs include a signature hash. If a user changes any
// query parameter (to "hack" the backend) the signature won't match and EasyAdmin
// triggers an error. If this causes any issue in your backend, call this method
// to disable this feature and remove all URL signature checks
->disableUrlSignatures()
;
}
}
Admin Context¶
EasyAdmin initializes a variable of type EasyCorp\Bundle\EasyAdminBundle\Context\AdminContext
automatically on each backend request. This object implements the context object
design pattern and stores all the information commonly needed in different parts
of the backend.
This context object is automatically injected in every template as a variable
called ea
(the initials of “EasyAdmin”):
1 2 3 4 5 | <h1>{{ ea.dashboardTitle }}</h1>
{% for menuItem in ea.mainMenu.items %}
{# ... #}
{% endfor %}
|
The AdminContext
variable is created dynamically on each request, so you
can’t inject it directly in your services. Instead, use the AdminContextProvider
service to get the context variable:
use EasyCorp\Bundle\EasyAdminBundle\Provider\AdminContextProvider;
final class SomeService
{
private $adminContextProvider;
public function __construct(AdminContextProvider $adminContextProvider)
{
$this->adminContextProvider = $adminContextProvider;
}
public function someMethod()
{
$context = $this->adminContextProvider->getContext();
}
// ...
}
In controllers, use the AdminContext
type-hint in any argument where you
want to inject the context object:
use EasyCorp\Bundle\EasyAdminBundle\Context\AdminContext;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
class SomeController extends AbstractController
{
public function someMethod(AdminContext $context)
{
// ...
}
}
Translation¶
The backend interface is fully translated using the Symfony translation
features. EasyAdmin own messages and contents use the EasyAdminBundle
translation domain (thanks to our community for kindly providing translations
for tens of languages).
The rest of the contents (e.g. the label of the menu items, entity and field
names, etc.) use the messages
translation domain by default. You can change
this value with the translationDomain()
method:
class DashboardController extends AbstractDashboardController
{
// ...
public function configureDashboard(): Dashboard
{
return Dashboard::new()
// ...
// the argument is the name of any valid Symfony translation domain
->setTranslationDomain('admin');
}
}
The backend uses the same language configured in the Symfony application.
When the locale is Arabic (ar
), Persian (fa
) or Hebrew (he
), the
HTML text direction is set to rtl
(right-to-left) automatically. Otherwise,
the text is displayed as ltr
(left-to-right), but you can configure this
value explicitly:
class DashboardController extends AbstractDashboardController
{
// ...
public function configureDashboard(): Dashboard
{
return Dashboard::new()
// ...
// most of the times there's no need to configure this explicitly
// (default: 'rtl' or 'ltr' depending on the language)
->setTextDirection('rtl');
}
}
Tip
If you want to make the backend use a different language than the public website, you’ll need to work with the user locale to set the request locale before the translation service retrieves it.
Note
The contents stored in the database (e.g. the content of a blog post or the name of a product) are not translated. EasyAdmin does not support the translation of the entity property contents into different languages.
Page Templates¶
EasyAdmin provides several page templates which are useful when adding custom logic in your dashboards.
Login Form Template¶
Twig Template Path: @EasyAdmin/page/login.html.twig
It displays a simple username + password login form that matches the style of the rest of the backend. The template defines lots of config options, but most applications can rely on its default values:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 | namespace App\Controller;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Annotation\Route;
use Symfony\Component\Security\Http\Authentication\AuthenticationUtils;
class SecurityController extends AbstractController
{
/**
* @Route("/login", name="login")
*/
public function login(AuthenticationUtils $authenticationUtils): Response
{
$error = $authenticationUtils->getLastAuthenticationError();
$lastUsername = $authenticationUtils->getLastUsername();
return $this->render('@EasyAdmin/page/login.html.twig', [
// parameters usually defined in Symfony login forms
'error' => $error,
'last_username' => $lastUsername,
// OPTIONAL parameters to customize the login form:
// the translation_domain to use (define this option only if you are
// rendering the login template in a regular Symfony controller; when
// rendering it from an EasyAdmin Dashboard this is automatically set to
// the same domain as the rest of the Dashboard)
'translation_domain' => 'admin',
// the title visible above the login form (define this option only if you are
// rendering the login template in a regular Symfony controller; when rendering
// it from an EasyAdmin Dashboard this is automatically set as the Dashboard title)
'page_title' => 'ACME login',
// the string used to generate the CSRF token. If you don't define
// this parameter, the login form won't include a CSRF token
'csrf_token_intention' => 'authenticate',
// the URL users are redirected to after the login (default: '/admin')
'target_path' => $this->generateUrl('admin_dashboard'),
// the label displayed for the username form field (the |trans filter is applied to it)
'username_label' => 'Your username',
// the label displayed for the password form field (the |trans filter is applied to it)
'password_label' => 'Your password',
// the label displayed for the Sign In form button (the |trans filter is applied to it)
'sign_in_label' => 'Log in',
// the 'name' HTML attribute of the <input> used for the username field (default: '_username')
'username_parameter' => 'my_custom_username_field',
// the 'name' HTML attribute of the <input> used for the password field (default: '_password')
'password_parameter' => 'my_custom_password_field',
]);
}
}
|
Content Page Template¶
Twig Template Path: @EasyAdmin/page/content.html.twig
It displays a simple page similar to the index/detail/form pages, with the main header, the sidebar menu and the central content section. The only difference is that the content section is completely empty, so it’s useful to display your own text contents, custom forms, etc.
This work, including the code samples, is licensed under a Creative Commons BY-SA 3.0 license.