0
votes

I am building my own CMS system. And i did a lot of work with symfony in the past, now i wanna do all a bit more pro :) I want to render basic controller for admin dashboard witch contains a menu, systemnotifications on route "/admin" and then i want to set another controller for example "test" on route "/admin/test" and my problem is that all object notifications from controller named AdminController are not available in this second route "/admin/test", only on route "/admin"

Here my adminControler controller:

class AdminController extends Controller
{
    /**
     * @Route("/admin", name="adminDashboard")
     */
    public function adminDashboard()
    { 

        $loggedUser = $this->getUser()->getId();

        $systemnotifications = $this->forward('App\Controller\SystemNotificationController::notif', [
        'loggedUser' => $loggedUser

        ]);
        return $this->render('admin/index.html.twig', [
                'systemnotifications' => $systemnotifications
        ]);

    }

}

Here my test controller:

class TestController extends Controller
{


    /**
     * @Route("/admin/test", name="test")
     */
    public function test()
    {
        return $this->render('admin/dashboard/index.html.twig', [

        ]);

    }
}

In twig is set, that adminController extends base.html.twig, and Test controller extends index.html.twig (this one witch is rendered from adminController.

My question is how to handle it properly with Symfony best practice. How i should set the Admin Controller for get systemnotifications object where is another Test Controller launched ?

Please help :)

2
I need to call systemnotifications repository in each next controller ? - flow

2 Answers

0
votes

There are two ways to do that the first is inyect in the twig the variable. example see this doc.

# config/packages/twig.yaml
twig:
    # ...
    globals:
        # the value is the service's id
        user_management: '@App\DataProvider\UserDataProvider'
# config/services.yaml
services:
   'App\DataProvider\UserDataProvider':
        arguments:
            - '@session'
        autoconfigure: false
0
votes

The other way is more complicate, if you for example wants the responsability to render specific part of the page, like ... the barnav or the messages

Add this piece of code to the default twig:

{% block user_control %}
  {{ render(controller('LayoutCoreBundle:User:index')) }}
{% endblock %}
<?php
namespace App\Controller;

use App\Event\ShowUserEvent;
use App\Event\ThemeEvents;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use \stdClass;

class UserController extends EmitterController
{
    /**
     * @return \Symfony\Component\HttpFoundation\Response
     */
    public function indexAction()
    {
        if (!$this->getDispatcher()->hasListeners(ThemeEvents::THEME_NAVBAR_USER)) {
            return new Response();
        }
        /** @var ShowUserEvent $userEvent */
        $userEvent = $this->triggerMethod(ThemeEvents::THEME_NAVBAR_USER, new ShowUserEvent());
        $userClass = $userEvent->getUser();
        $user                       = new stdClass();
            $user->id               = $userClass->getIdentifier();
            $user->idEmployee       = $userClass->getIdEmployee();
            $user->setCompanyLogo   = $userClass->getCompanyLogo();
            $user->companyName      = $userClass->getCompanyName();
            $user->company          = $userClass->getCompany();
            $user->avatar           = $userClass->getAvatar();
            $user->fullName         = $userClass->getName();
            $user->menu             = $userClass->getMenu();
            $user->role             = $userClass->getRolname();
        return $this->render(
            'header/index.html.twig',
            [
                'userJson' => $user,
            ]
        );
    }

}

<?php
namespace App\Controller;

use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\DependencyInjection\Container;
use Symfony\Component\EventDispatcher\Event;
use Symfony\Component\EventDispatcher\EventDispatcherInterface;

class EmitterController extends AbstractController
{
    /**
     * @var EventDispatcherInterface
     */
    protected $eventDispatcher;

    /**
     * @param EventDispatcherInterface $dispatcher
     */
    public function __construct(EventDispatcherInterface $dispatcher)
    {
        $this->eventDispatcher = $dispatcher;
    }

    /**
     * @return EventDispatcherInterface
     */
    protected function getDispatcher()
    {
        return $this->eventDispatcher;
    }

    /**
     * @param string $eventName
     *
     * @return bool
     */
    protected function hasListener($eventName)
    {
        return $this->getDispatcher()->hasListeners($eventName);
    }

    /**
     * Will look for a method of the format "on<CamelizedEventName>" and call it with the event as argument.
     *
     *
     * Then it will dispatch the event as normal via the event dispatcher.
     *
     * @param $eventName
     * @param Event $event
     *
     * @return Event
     */
    protected function triggerMethod($eventName, Event $event)
    {
        $method = sprintf('on%s', Container::camelize(str_replace('.', '_', $eventName)));

        if (is_callable([$this, $method])) {
            call_user_func_array([$this, $method], [$event]);
        }

        if ($event->isPropagationStopped()) {
            return $event;
        }

        $this->getDispatcher()->dispatch($eventName, $event);

        return $event;
    }
}

interface ThemeEvents
{
    /**
     * Used to receive notification data
     */
    public const THEME_NOTIFICATIONS = 'theme.notifications';
    /**
     * Used to receive message data
     */
    public const THEME_MESSAGES = 'theme.messages';
    /**
     * Used to receive task data
     */
    public const THEME_TASKS = 'theme.tasks';
    /**
     * Used to receive the current user for the navbar
     */
    public const THEME_NAVBAR_USER = 'theme.navbar_user';
    /**
     * Used to receive breadcrumb data
     */
    public const THEME_BREADCRUMB = 'theme.breadcrumb';
    /**
     * Used to receive the current user for the sidebar
     */
    public const THEME_SIDEBAR_USER = 'theme.sidebar_user';
    /**
     * Used to receive the sidebar menu data
     */
    public const THEME_SIDEBAR_SETUP_MENU = 'theme.sidebar_setup_menu';
}
class ShowUserEvent extends ThemeEvent
{
    /**
     * @var UserInterface
     */
    protected $user;

    /**
     * @var bool
     */
    protected $showProfileLink = true;

    /**
     * @var bool
     */
    protected $showLogoutLink = true;

    /**
     * @var NavBarUserLink[]
     */
    protected $links = [];

    /**
     * @param UserInterface $user
     * @return ShowUserEvent
     */
    public function setUser($user)
    {
        $this->user = $user;

        return $this;
    }

    /**
     * @return UserInterface
     */
    public function getUser()
    {
        return $this->user;
    }

    /**
     * @return NavBarUserLink[]
     */
    public function getLinks()
    {
        return $this->links;
    }

    /**
     * @param NavBarUserLink $link
     * @return ShowUserEvent
     */
    public function addLink(NavBarUserLink $link)
    {
        $this->links[] = $link;

        return $this;
    }

    /**
     * @return bool
     */
    public function isShowProfileLink()
    {
        return $this->showProfileLink;
    }

    /**
     * @param bool $showProfileLink
     * @return ShowUserEvent
     */
    public function setShowProfileLink($showProfileLink)
    {
        $this->showProfileLink = $showProfileLink;

        return $this;
    }

    /**
     * @return bool
     */
    public function isShowLogoutLink()
    {
        return $this->showLogoutLink;
    }

    /**
     * @param bool $showLogoutLink
     * @return ShowUserEvent
     */
    public function setShowLogoutLink($showLogoutLink)
    {
        $this->showLogoutLink = $showLogoutLink;

        return $this;
    }
}
class ThemeEvent extends Event
{
}

And then only you need a evensuscriber

class NavbarUserSubscriber implements EventSubscriberInterface
{
    /**
     * @var Security
     */
    protected $security;

    /**
     * @param Security $security
     */
    public function __construct(Security $security)
    {
        $this->security = $security;
    }

    /**
     * @return array
     */
    public static function getSubscribedEvents(): array
    {
        return [
            ThemeEvents::THEME_NAVBAR_USER => ['onShowUser', 100],
            ThemeEvents::THEME_SIDEBAR_USER => ['onShowUser', 100],
        ];
    }
    /**
     * @param ShowUserEvent $event
     * @throws \Exception
     */
    public function onShowUser(ShowUserEvent $event)
    {
        if (null === $this->security->getUser()) {
            return;
        }
        /** @var User $user */
        $user = $this->security->getUser();
        $event->setUser($user);
    }
}

#templates/header/index.html.twig
<script type="text/javascript">
var user = {{ userJson | json_encode() | raw  }};
</script>