Symfony 3: Controllers, Routing, Views

This example demonstrates routing using annotation as well as different ways to pass arguments to the controller.

<?php
// src/Service/TestService.php

namespace App\Service;

class TestService
{
    public function message($name)
    {
        return "Hello $name";
    }
}
<?php

// src/Controller/TestController

namespace App\Controller;

use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Annotation\Route;
use App\Service\TestService;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;

class TestController extends AbstractController
{
    /**
     * @var TestService
     */
    private $testService;


    /**
     * TestController constructor.
     */
    public function __construct(TestService $testService)
    {
        $this->testService = $testService;
    }


    /**
     * @Route("/test1", name="test1")
     * @param Request $request
     * @return Response
     */
    public function test1(Request $request)
    {
        return new Response($this->testService->message(
            $request->get('name')
        ));
    }


    /**
     * @Route("/test2/{name}", name="test2")
     * @param $name
     * @return Response
     */
    public function test2($name)
    {
        return new Response($this->testService->message($name));
    }
}

Annotation configuration can be done from:

# config/routes/annotations.yaml
controllers:
resource: ../../src/Controller/
type: annotation

Route annotation set on the class level. Applies defined annotation as prefix to all inner class annotations.

<?php

namespace App\Controller;

use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\Routing\Annotation\Route;

/**
 * @Route("/blog")
 * Class BlogController
 * @package App\Controller
 */
class BlogController extends AbstractController
{
    public function __construct()
    {
    }

    /**
     * @Route("/", name="blog_index")
     * @param Request $request
     * @return \Symfony\Component\HttpFoundation\Response
     */
    public function index(Request $request)
    {
        return $this->render('base.html.twig', ['message' => 'index page']);
    }


    /**
     * @Route("/hello", name="blog_hello")
     * @param Request $request
     * @return \Symfony\Component\HttpFoundation\Response
     */
    public function hello(Request $request)
    {
        return $this->render('base.html.twig', ['message' => 'hello page']);
    }
}

The index action in example above will be accessible using /blog/ url, while hello action will require /blog/hello.

This example shows the crud for the posts which uses session to store data.

 * @Route("/blog")
 * Class BlogController
 * @package App\Controller
 */
class BlogController extends AbstractController
{


    /**
     * @var \Twig_Environment
     */
    private $twig;
    /**
     * @var SessionInterface
     */
    private $session;
    /**
     * @var RouterInterface
     */
    private $router;

    public function __construct(\Twig_Environment $twig, SessionInterface $session, RouterInterface $router)
    {
        $this->twig = $twig;
        $this->session = $session;
        $this->router = $router;
    }

    /**
     * @Route("/", name="blog_index")
     */
    public function index()
    {
        $html = $this->twig->render('blog/index.html.twig', [
            'posts' => $this->session->get('posts')
        ]);
        return new Response($html);
    }


    /**
     * @Route("/add", name="blog_add")
     */
    public function add()
    {
        $posts = $this->session->get('posts');
        $posts[uniqid()] = [
            'title' => 'Random title' . rand(0, 1000),
            'text' => 'Random text' . rand(0, 1000),
        ];

        $this->session->set('posts', $posts);

        return new RedirectResponse($this->router->generate('blog_index'));
    }


    /**
     * @Route("/show", name="blog_show")
     */
    public function show($id)
    {
        $posts = $this->session->get('posts');
        if (!$posts || !isset($posts['id'])) {
            throw new NotFoundHttpException('Post not found');
        }

        $html = $this->twig->render('blog/post.html.twig', [
            'id' => $id,
            'post' => $posts[$id]
        ]);

        return new Response($html);
    }
}

Template Inheritance:

Twig parent template can be inherited and reused.

base.html.twig

<!DOCTYPE html>
<html>
    <head>
        <meta charset="UTF-8">
        <title>{% block title %}Welcome!{% endblock %}</title>
        {% block stylesheets %}{% endblock %}
    </head>
    <body>
        {% block body %}
            {{ message }}
        {% endblock %}
        {% block javascripts %}{% endblock %}
    </body>
</html>
# child.html.twig
{% extends 'base.html.twig' %}

{% block stylesheets %}
    {{ parent() }}
    <link type="text/css" href="{{ asset('css/child.css') }}" rel="stylesheet"/>
{% endblock %}

{% block title %}{{ page_title }}{% endblock %}
{% block body %} here we go {% block body %}