2022
Symfony

Symfony

Translated from German using DeepL.

Date: April 2022
Reading time: 5 minutes


Symfony (opens in a new tab) is a PHP framework that was released in 2005. Many content management systems, such as Drupal (opens in a new tab), rely on Symfony, as it also offers reusable components.

Here you can find all the components of Symfony: https://symfony.com/components (opens in a new tab) On this page you can see which components are used in Drupal: https://symfony.com/projects/drupal (opens in a new tab)

The advantages are that you can work faster and more structured with such a framework. It also provides you with many functionalities. If you need something new, such as a form, you can install this feature. If you want to protect the application with a login, simply install the corresponding feature. This allows you to quickly create secure websites.
The Symfony project has over 3'000 contributors, 600'000 developers and 200 million monthly downloads. It is therefore a recognized and stable environment.

Setup

Requirements

To use Symfony, you must have PHP installed. It is also recommended to install the CLI.

brew install symfony-cli/tap/symfony-cli

You can also use Composer to execute certain commands later. However, this is much easier with the Symfony command.
To check whether all the prerequisites have been met, you can execute the following command.

symfony check:requirements

Create application

Symfony Documentation: https://symfony.com/doc/current/setup.html (opens in a new tab)

You can create a project like this:

symfony new my_project_directory --webapp

If you want to program a microservice, a console application or an API, you can omit the --webapp.

symfony new my_project_directory

The project can be started with the Symfony command. However, you must first switch to the created project.

symfony server:start

After these few steps you will now see the Welcome page.

welcome

Hello World

Symfony Documentation: https://symfony.com/doc/current/page_creation.html (opens in a new tab)

Controller

To create a first page, you must create a controller under src/Controller.

HelloController.php
...
public function index(): Response {
    return new Response(
        '<html><body>Hello</body></html>'
    );
}
...

Route

To make this page accessible, a route must be defined.
There are two variants for this.

YAML

The path can be associated with the controller in the configurations.

config/routes.yaml
app_hello:
    path: /
    controller: App\Controller\HelloController::index

hello

Annotation

However, I prefer the annotation. It's a bit faster with this. In addition, you can already see in the controller which route it is listening to.
First you have to install the annotations package.

composer require annotations

You can then use the route annotation.

HelloController.php
...
 
use Symfony\Component\Routing\Annotation\Route;
 
...
 
/**
* @Route("/")
*/
public function index(): Response {
	return new Response(
		'<html><body>Hello</body></html>'
	);
}
 
...

Template

To display the data via a template, you must first install Twig.

composer require twig

You can then render the message in the controller using a template.

HelloController.php
return $this->render('hello/hello.html.twig', [
    'message' => 'Hello',
]);

This template can then use the message.

templates/hello/hello.html.twig
<h1>{{ message }} World</h1>

Twig Doku: https://twig.symfony.com (opens in a new tab)

ORM

Symfony Dock: https://symfony.com/doc/current/doctrine.html (opens in a new tab)

graph

With object-relational mapping, data is converted in order to exchange it between different systems.
ORM allows you to work with objects in the code. However, these exist in the database as a table.

In order to work in Symfony according to the ORM principle, two packages must first be installed.

composer require symfony/orm-pack
composer require --dev symfony/maker-bundle

The database must then be connected in the configuration file.

.env
DATABASE_URL="mysql://user:pw@127.0.0.1:8889/symfony"

You can create the database manually or in the console.

php bin/console doctrine:database:create

The database has now been created and connected. To create a class, the corresponding command is recommended again.

php bin/console make:entity

Now you can add the attributes very easily.

php bin/console make:entity
 
Class name of the entity to create or update:
> Sneaker
 
New property name (press <return> to stop adding fields):
> name
 
Field type (enter ? to see all types) [string]:
> string
 
Field length [255]:
> 255
 
Can this field be null in the database (nullable) (yes/no) [no]:
> no
 
New property name (press <return> to stop adding fields):
>
(press enter again to finish)

After this step, a class is created. You can see from the ORM mapping remarks that this is such a class.

<?php
 
namespace App\Entity;
 
use App\Repository\SneakerRepository;
use Doctrine\ORM\Mapping as ORM;
 
#[ORM\Entity(repositoryClass: SneakerRepository::class)]
class Sneaker
{
    #[ORM\Id]
    #[ORM\GeneratedValue]
    #[ORM\Column(type: 'integer')]
    private $id;
 
    #[ORM\Column(type: 'string', length: 255)]
    private $name;
 
    public function getId(): ?int
    {
        return $this->id;
    }
 
    public function getName(): ?string
    {
        return $this->name;
    }
 
    public function setName(string $name): self
    {
        $this->name = $name;
        return $this;
    }
}

This class can now handle the data locally. However, this information is not yet stored as a table in the database. To do this, the entity must be migrated.

php bin/console make:migration

The SQL required for the migration has now been created. To execute this, the following command must be executed.

php bin/console doctrine:migrations:migrate

Add field

Additional fields can also be added later without any problems.

php bin/console make:entity

You then have to generate a migration again and then synchronize.

php bin/console make:migration
php bin/console doctrine:migrations:migrate

Services

Services can also be implemented in Symfony. This allows you to see which services already exist.

php bin/console debug:autowiring

Create service

src/Lucky/LuckyNumberHandler.php
<?php
namespace App\Lucky;
 
class LuckyNumberHandler {
    public function getLuckyNumber(int $max): int {
        return random_int(0, $max);;
    }
}

Such a service can now be used in a method in the controller.

src/Controller/LuckyController.php
...
use App\Lucky\LuckyNumberHandler;
...
class LuckyController extends AbstractController {
    /**
    * @Route("/lucky/number/{max}")
    */
    public function number(int $max, LuckyNumberHandler $luckyNumberHandler): Response
    {
        return $this->render('lucky/number.html.twig', [
            'number' => $luckyNumberHandler->getLuckyNumber($max),
        ]);
    }
}

If you use the service multiple times, it is better to define it in the constructor. This way, you have to define the handler once and can then use it in the entire class.

src/Controller/LuckyController.php
...
use App\Lucky\LuckyNumberHandler;
...
class LuckyController extends AbstractController {
    private $luckyNumberHandler;
 
    public function __construct(LuckyNumberHandler $luckyNumberHandler) {
        $this->$luckyNumberHandler = $luckyNumberHandler;
    }
 
    /**
    * @Route("/lucky/number/{max}")
    */
    public function number(int $max): Response
    {
        return $this->render('lucky/number.html.twig', [
            'number' => $this->luckyNumberHandler->getLuckyNumber($max),
        ]);
    }
}

Thanks to autowiring, all classes in the src/ folder can be used. No further configuration is required.

config/services.yaml
App\:
    resource: '../src/'
    exclude:
        - '../src/DependencyInjection/'
        - '../src/Entity/'
        - '../src/Kernel.php'

However, you can also configure a service explicitly.

config/services.yaml
App\Service\SiteUpdateManager:
    arguments:
        $adminEmail: 'manager@example.com'

Conclusion

Working with Symfony is very pleasant, as you can progress quickly. The documentation (opens in a new tab) is also, in my opinion, detailed and easy to understand.