Routing, Controllers & Services
Routes & Controllers
<?php
namespace App\Controller;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Attribute\Route;
class ArticleController extends AbstractController
{
#[Route('/articles/{id}', name: 'article_show', methods: ['GET'])]
public function show(int $id, ArticleRepository $repo): Response
{
$article = $repo->find($id) ?? throw $this->createNotFoundException();
return $this->render('article/show.html.twig', [
'article' => $article,
]);
}
#[Route('/articles', name: 'article_create', methods: ['POST'])]
public function create(Request $request): Response
{
return $this->json(['status' => 'created'], Response::HTTP_CREATED);
}
}
// Generate a URL from a route name elsewhere in code:
// $this->generateUrl('article_show', ['id' => $article->getId()]);Services & Autowiring
<?php
namespace App\Service;
class NewsletterSender
{
// Type-hinted constructor args — Symfony's DI container autowires them
public function __construct(
private MailerInterface $mailer,
private LoggerInterface $logger,
) {}
public function send(string $to): void
{
$this->mailer->send((new Email())->to($to)->subject('Weekly digest'));
$this->logger->info('Newsletter sent', ['to' => $to]);
}
}
// Any controller/service just type-hints it — no manual wiring needed:
class NewsletterController extends AbstractController
{
public function trigger(NewsletterSender $sender): Response
{
$sender->send('user@example.com');
return new Response('ok');
}
}
// Scalar args (strings, ints) can't be autowired by type — bind them explicitly:
// services.yaml:
// App\Service\ApiClient:
// arguments:
// $apiKey: '%env(API_KEY)%'Forms & Validation
<?php
class RegistrationFormType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options): void
{
$builder
->add('email', EmailType::class)
->add('plainPassword', PasswordType::class);
}
}
// Constraint attributes on the entity/DTO itself
class RegistrationDto
{
#[Assert\NotBlank]
#[Assert\Email]
public string $email = '';
#[Assert\Length(min: 8)]
public string $plainPassword = '';
}
// In the controller
$form = $this->createForm(RegistrationFormType::class, $dto);
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
// $dto now holds validated, mapped data
}Keep your own version of these notes — editable, searchable, and organised by your stack.
Start free