Как создать виджет на Symfony

Недавно на работе у меня спросили то, как создать систему виджетов на Symfony. Вроде бы, всё очень просто для человека который хоть немного понимает то, как он работает.
Но, как оказалось, вопрос достаточно часто актуальный. Не каждый как оказалось хочет передавать переменные буквально каждый раз. 🙂

Будем создавать виджет, который выводит все категории в сайдбар. Для начала, нам понадобится сам Symfony. 4 или 5 версии, а так же Twig который по умолчанию есть в коробке.

Чтобы было куда складывать виджет-классы, создаём папку src/Widget

Сразу же создаём в этой папке файл Categories.php (это название виджета). Так же допустим, что сущность для категорий у вас уже есть.

<?php

namespace App\Widget; //Здесь нужно оставить так или указать правильный, смотря как вы назвали папку и смотря куда её положили
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;

class Categories  extends AbstractController //Здесь мы наследнем наш "виджет" от контроллера
{
    private $em; //Задаём приватную переменную для менеджера сущностей

    public function __construct() {
        $this->em = $this->getDoctrine()->getManager(); //в конструкте сразу заполняем менеджер сущностей
    }

    public function show() { //Создаём публичную функцию show, она и будет показывать наш виджет
        $categories_rep = $this->em->getRepository(\App\Entity\Categories::class); //получаем репозиторий
        $categories = $categories_rep->findAll(); //и получаем все категории

        return $this->render('widgets/category.html.twig',['categories'=>$categories]); //рендерим шаблон виджета
    }
}

Теперь нам нужно создать папку в которой будут лежать шаблоны для наших виджетов.
Создаём templates/widgets и так же туда же кидаем файл category.html.twig

<aside class="widget widget_categories">
    <h3 class="widget-title">
        <span>Рубрики</span>
    </h3>
    <ul>
        {% for c in categories %}
            <li class="cat-item cat-item-{{ c.id }}">
                <a href="{{ path('category', {slug: c.slug}) }}">{{ c.name }}</a> ({{ c.countPosts }})
            </li>
        {% endfor %}
    </ul>
</aside>

Всё, система считай готова. Нам осталось только вывести нужный виджет в нужном месте. Идём, например, в base.html.twig и создаём там сайдбар, в котором будем рендерить виджеты.

            <div id="secondary" class="sidebar widget-area  widget-white" role="complementary">
                {{ render(controller('App\\Widget\\Categories::show')) }}
            </div>