Get started with Symfony Framework - All you need to know

Symfony is a popular PHP web application framework designed to facilitate the development of web applications by providing reusable components, tools, and a structured environment. It is a set of decoupled and reusable PHP libraries that can be used to build web applications, APIs, and microservices.

Symfony was initially released in 2005 by Fabien Potencier, a French software developer, and the CEO of SensioLabs, a web agency. The framework was created as an answer to the lack of standardization in the PHP community and to provide a structured and maintainable way to develop web applications.

The first stable version, Symfony 1.0, was released in 2007. Symfony 2.0, a major overhaul, was released in 2011. It introduced a new architecture based on the Dependency Injection and Event Dispatcher patterns, leading to increased modularity and extensibility.

Symfony 3.0 was released in 2015, bringing further improvements to the framework. Symfony 4.0, released in 2017, focused on simplifying the developer experience by introducing Flex, a new way to manage project dependencies and configurations. Symfony 5.0, was released in 2019, featuring even more enhancements and updates. The most recent (as of March 2023) major version 6.x was released in November 2022.

How Symfony works

Symfony is built around the Model-View-Controller (MVC) architectural pattern, promoting the separation of concerns within an application. This pattern helps organize the codebase into three main components:

Model

Represents the application's data and business logic.

View

Handles the presentation and display of data.

Controller

Manages user interactions and updates the Model and View accordingly.

Some key features of Symfony include:

Bundles

A modular system that allows for the organization and reuse of code. Each bundle represents a set of features or functionality and can be shared across projects.

Components

Reusable PHP libraries that can be used standalone or within a Symfony project. These components cover a wide range of functionality, from form handling to security and caching.

Dependency Injection

A design pattern that promotes loose coupling between components by managing dependencies externally, making the code more maintainable and testable.

Routing

A powerful system to define and manage application routes, allowing the creation of user-friendly URLs and the mapping of URLs to specific actions within the application.

Templating

Symfony supports the Twig template engine, a fast and flexible way to create templates for the presentation layer of an application.

Security

The framework includes robust security features, such as authentication, authorization, and protection against common web vulnerabilities.

Symfony has a strong community and extensive documentation, which makes it a popular choice among PHP developers. It is widely used for both small projects and large-scale enterprise applications.

Symfony Project Structure

A project built on Symfony should follow a specific structure to take full advantage of the framework's features and conventions. This structure provides a standardized way of organizing your code, making it easier to maintain and scale.

While Symfony allows some flexibility in its structure, it's generally recommended to follow the default directory structure provided when creating a new project using the Symfony CLI or Flex. Here's an overview of the key directories in a typical Symfony project:

bin/

Contains executable files, such as the Symfony console binary.

config/

Holds configuration files for your application, including routing, services, and packages. This directory is organized into subdirectories for different environments (e.g., dev, prod, test).

public/

Serves as the web server document root and includes the main index.php file. This directory also contains assets like JavaScript, CSS, and images.

src/

Contains the main PHP code for your application, organized into bundles or components. Within this directory, you'll typically find subdirectories like Controller, Entity, Repository, Form, and others, depending on your application's needs.

templates/

Holds Twig template files for your application's views.

translations/

Contains translation files if your application supports multiple languages.

var/

Stores generated files, such as cache, logs, and compiled container files. This directory is typically writable by the web server.

vendor/

Contains third-party libraries and dependencies managed by Composer, the PHP dependency manager.

While this structure is recommended for most Symfony projects, you can still make customizations to better suit your application's specific needs. Just keep in mind that deviating from the default structure may require additional configuration and may affect the maintainability and interoperability of your code with other Symfony applications or bundles.

Getting Started with Symfony

To get started with Symfony, you can follow these steps to create a new project using the recommended best practices and default directory structure. Symfony provides a command-line tool called the Symfony CLI, which helps you create and manage your projects.

Install the Symfony CLI:

First, download and install the Symfony CLI following the instructions for your platform from the official documentation: https://symfony.com/download

Create a new Symfony project:

Open a terminal and run the following command to create a new Symfony project. Replace my_project with the desired name for your project directory:

symfony new --full my_project

The --full option creates a new project with the complete default directory structure and configuration, including the recommended bundles for a web application. If you want a minimal installation, you can omit the --full option.

Navigate to the project directory:

cd my_project

Start the local web server:

Run the following command to start the built-in local web server provided by the Symfony CLI:

symfony serve

The server will start, and you'll see the URL to access your new Symfony project, usually http://127.0.0.1:8000.

Access your new Symfony project:

Open your web browser and navigate to the URL provided by the Symfony CLI (http://127.0.0.1:8000 by default). You should see the Symfony welcome page.

Now that you have a new Symfony project set up, you can start building your application by creating controllers, templates, and other required components. The official Symfony documentation is a great resource for learning more about the framework and its components: https://symfony.com/doc/current/

As for boilerplate or starter project code, the new project you just created using the Symfony CLI comes with a basic structure and recommended bundles, which serve as a starting point for building your application. You can customize and build upon this structure to fit the specific requirements of your project.

"Hello World" Tutorial for Symfony

In this tutorial, we'll create a simple "Hello, World!" project in Symfony, using the model, view, controller, route, and Twig template components. We'll assume you already have a Symfony project set up by following the steps in a previous answer.

Create a new controller:

Run the following command in your terminal to create a new controller named HelloController:

php bin/console make:controller HelloController

This will create a new file at src/Controller/HelloController.php with a basic controller structure.

Modify the HelloController:

Open src/Controller/HelloController.php and modify the content to the following:

namespace App\Controller;

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

class HelloController extends AbstractController
{
    /**
     * @Route("/hello/{name}", name="hello")
     */
    public function index(string $name): Response
    {
        return $this->render('hello/index.html.twig', [
            'name' => $name,
        ]);
    }
}

Here, we've defined a route with a path parameter {name}. The name parameter will be passed to the index method, and the method will render a Twig template with the name variable.

Create a new Twig template:

Create a new file at templates/hello/index.html.twig with the following content:

{% extends 'base.html.twig' %}

{% block title %}Hello, {{ name }}!{% endblock %}

{% block body %}
    <h1>Hello, {{ name }}!</h1>
{% endblock %}

This template extends the base layout provided by Symfony and defines a block for the title and body. The name variable is used to display the dynamic content.

Test your new route:

Start the local web server (if it's not already running) using the following command:

symfony serve

Open your web browser and navigate to http://127.0.0.1:8000/hello/World. You should see the message "Hello, World!" displayed on the page.

In this tutorial, we've used the following components of Symfony:

  • Model: Although we didn't use a database or entity in this simple example, the concept of passing the name variable from the controller to the template is similar to passing data from a model to the view.
  • View: The Twig template (templates/hello/index.html.twig) serves as the view, rendering the HTML output.
  • Controller: The HelloController class (src/Controller/HelloController.php) is responsible for handling the request and returning the response.
  • Route: The @Route annotation in the HelloController defines the route path and its name.
  • Twig template: The index.html.twig file is a Twig template used to generate the HTML output.

This simple "Hello, World!" project demonstrates the basic structure and components of a Symfony application. You can build on this foundation to create more complex applications with additional features and functionality.

How to work with databases in Symfony, using Doctrine ORM

Symfony Doctrine ORM (Object-Relational Mapping) is a powerful library for dealing with databases in a Symfony project. Doctrine ORM allows developers to work with databases using an object-oriented approach, abstracting the underlying SQL and providing a more natural way to manage and manipulate data. Doctrine ORM is not a Symfony-specific library, but it is tightly integrated with the framework and is often used in Symfony projects.

Doctrine ORM has several key concepts:

Entities

Entities are PHP classes that represent database tables. Each property of an entity class corresponds to a column in the corresponding database table. Entities define the structure of your data and can include relationships with other entities, like one-to-one, one-to-many, and many-to-many.

Repositories

Repositories are classes responsible for retrieving and storing entity instances. They act as an interface between your application code and the database, encapsulating database-related logic.

Entity Manager

The Entity Manager is the central access point to Doctrine ORM's functionality. It is responsible for managing the persistence and retrieval of entities, transactions, and more. In a Symfony application, you can access the Entity Manager through the Doctrine service.

To work with databases in a Symfony project using Doctrine ORM, follow these general steps:

Install Doctrine

First, you need to install Doctrine ORM and the DoctrineBundle, which provides the integration with Symfony. Use the following command with Composer:

composer require doctrine/orm

Configure the database connection: In the config/packages/doctrine.yaml file, configure the database connection details (such as the database driver, user, password, and host). For example:

doctrine:
    dbal:
        driver: 'pdo_mysql'
        server_version: '5.7'
        charset: utf8mb4
        default_table_options:
            collate: utf8mb4_unicode_ci
        url: '%env(resolve:DATABASE_URL)%'

Then, set the DATABASE_URL environment variable in your .env file with the connection string for your database.

Create entities

Define your data model by creating PHP classes for each table in your database, and annotate the classes and their properties with Doctrine annotations to map them to the corresponding database tables and columns.

Generate database schema

Use the Symfony console command php bin/console doctrine:schema:update --force to create or update the database schema based on your entity classes.

Query and manipulate data

In your application code, use the Entity Manager to query and manipulate data. You can create, update, delete, and fetch entities using the Entity Manager or use custom repository methods for more complex queries.

By using Doctrine ORM in a Symfony project, you can manage databases more effectively, take advantage of object-oriented programming, and keep your application code clean and maintainable.

Doctrine ORM Examples

Let's consider a simple example with a users table and its corresponding User entity. The users table has the following structure:

users
- id (integer, primary key)
- username (varchar)
- email (varchar)
- created_at (datetime)

Here's the corresponding User entity:

namespace App\Entity;

use Doctrine\ORM\Mapping as ORM;

/**
 * @ORM\Entity(repositoryClass="App\Repository\UserRepository")
 * @ORM\Table(name="users")
 */
class User
{
    /**
     * @ORM\Id
     * @ORM\GeneratedValue
     * @ORM\Column(type="integer")
     */
    private $id;

    /**
     * @ORM\Column(type="string", length=255)
     */
    private $username;

    /**
     * @ORM\Column(type="string", length=255)
     */
    private $email;

    /**
     * @ORM\Column(type="datetime")
     */
    private $createdAt;

    // Getters and setters omitted for brevity
}

Now, let's compare a few SQL queries with their equivalent Doctrine ORM operations:

SELECT all users

SQL:

SELECT * FROM users;

Doctrine ORM:

$userRepository = $entityManager->getRepository(User::class);
$users = $userRepository->findAll();

SELECT a user by ID

SQL:

SELECT * FROM users WHERE id = 1;

Doctrine ORM:

$userRepository = $entityManager->getRepository(User::class);
$user = $userRepository->find(1);

INSERT a new user

SQL:

INSERT INTO users (username, email, created_at) VALUES ('john_doe', 'john.doe@example.com', '2023-01-01 00:00:00');

Doctrine ORM:

$user = new User();
$user->setUsername('john_doe');
$user->setEmail('john.doe@example.com');
$user->setCreatedAt(new \DateTime('2023-01-01 00:00:00'));

$entityManager->persist($user);
$entityManager->flush();

UPDATE a user's email

SQL:

UPDATE users SET email = 'new.email@example.com' WHERE id = 1;

Doctrine ORM:

$userRepository = $entityManager->getRepository(User::class);
$user = $userRepository->find(1);

$user->setEmail('new.email@example.com');

$entityManager->flush();

DELETE a user

SQL:

DELETE FROM users WHERE id = 1;

Doctrine ORM:

$userRepository = $entityManager->getRepository(User::class);
$user = $userRepository->find(1);

$entityManager->remove($user);
$entityManager->flush();

As you can see from these examples, Doctrine ORM abstracts the underlying SQL, allowing you to work with objects and methods instead. This leads to more readable and maintainable code, while also making it easier to switch between different database systems.

The downside of using (Doctrine) ORM vs. pure SQL

While Doctrine ORM offers many advantages, such as improved code readability and maintainability, there are also some disadvantages to abstracting SQL. Some of these include:

  • Performance overhead

    Doctrine ORM introduces an additional layer of abstraction, which can lead to a performance overhead compared to writing raw SQL queries. The ORM needs to translate your object operations into SQL and then convert the result sets back into objects. This process can be slower than working directly with SQL, especially for complex queries or large datasets.
  • Complexity

    Doctrine ORM comes with its learning curve, and developers need to understand its concepts and syntax to use it effectively. This can make it more challenging for new developers to get started with a project using Doctrine ORM compared to using plain SQL.
  • Flexibility

    While Doctrine ORM provides a high level of abstraction that works well for most use cases, there may be situations where it doesn't support a specific database feature or query optimization. In these cases, you might need to write custom SQL or use other Doctrine features like native queries or custom hydrators to achieve the desired functionality.
  • Debugging

    When using an ORM, it can sometimes be more difficult to debug performance issues or understand the underlying SQL generated by the ORM. Developers may need to dig deeper into the ORM's internals or use additional tools to profile and optimize their queries.
  • Memory usage

    Doctrine ORM's object-relational mapping can lead to increased memory usage, as it creates and manages object instances for your data. This can be problematic for large datasets, where it might be more efficient to work directly with raw data.

Despite these disadvantages, Doctrine ORM remains a popular choice for many developers due to its benefits in code organization, maintainability, and the ability to work with databases in an object-oriented manner. By understanding these trade-offs, you can make informed decisions about whether or not to use Doctrine ORM in your projects and how to optimize its usage when necessary.

How to make plain MySQL queries in Sympfony without using Doctrine ORM

If you want to use plain MySQL queries in Symfony without using Doctrine ORM, you can use the PDO (PHP Data Objects) extension or the mysqli extension. Here's an example of how to set up and use a plain MySQL query with PDO in Symfony:

First, install the symfony/dotenv component to manage environment variables:

composer require symfony/dotenv

Next, configure your database connection in the .env file:

DATABASE_URL="mysql:host=localhost;dbname=my_database;user=my_user;password=my_password;charset=utf8mb4"

Create a service to manage your PDO connection. You can create a new file called src/Service/PdoConnection.php with the following content:

namespace App\Service;

use PDO;
use Symfony\Component\DependencyInjection\ParameterBag\ParameterBagInterface;

class PdoConnection
{
    private $pdo;

    public function __construct(ParameterBagInterface $params)
    {
        $dsn = $params->get('env(DATABASE_URL)');
        $options = [
            PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
            PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
        ];

        $this->pdo = new PDO($dsn, null, null, $options);
    }

    public function getPdo(): PDO
    {
        return $this->pdo;
    }
}

Register the PdoConnection service in your config/services.yaml file:

services:
    # ...
    App\Service\PdoConnection:
        arguments:
            - '%env()%'

Now, you can use plain MySQL queries in your controller or other services by injecting the PdoConnection service:

namespace App\Controller;

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

class MyController extends AbstractController
{
    /**
     * @Route("/query", name="query_example")
     */
    public function queryExample(PdoConnection $pdoConnection): Response
    {
        $pdo = $pdoConnection->getPdo();

        // Example plain MySQL query
        $sql = "SELECT * FROM users WHERE id = :id";
        $statement = $pdo->prepare($sql);
        $statement->bindValue(':id', 1);
        $statement->execute();
        $user = $statement->fetch();

        // Render result in a template or return JSON response
        return $this->render('query_example.html.twig', [
            'user' => $user,
        ]);
    }
}

By following these steps, you can execute plain MySQL queries in your Symfony application without using Doctrine ORM. This can be useful when you need more control over your SQL queries or when you want to leverage specific features of MySQL that are not supported by Doctrine ORM.

Using Symfony vs no framework - pros and cons

Using Symfony (or any other web framework) has its advantages and disadvantages compared to building a web application without a framework. Here, we'll discuss the pros and cons of using Symfony vs. not using a framework.

Pros of using Symfony (or another web framework):

  1. Structure and organization: Frameworks like Symfony provide a well-defined structure and organization for your project, following best practices and design patterns. This makes it easier to maintain and scale your application over time.
  2. Reusability and modularity: Symfony encourages the use of reusable components and modules, which can help you write more maintainable code and save time when developing new features.
  3. Faster development: A web framework like Symfony provides many built-in tools and libraries that can speed up development by handling common tasks, such as routing, templating, database access, and form handling, so you don't have to reinvent the wheel.
  4. Security: Symfony has built-in security features and follows security best practices, which can help protect your application against common security vulnerabilities like SQL injection, CSRF, and XSS attacks.
  5. Community and resources: Symfony has an active and supportive community, which means you can find plenty of resources, such as documentation, tutorials, and third-party bundles, to help you with your project.
  6. Easier testing and debugging: Symfony provides built-in tools and libraries for testing and debugging your application, making it easier to ensure that your code is reliable and bug-free.

Cons of using Symfony (or another web framework):

  1. Learning curve: If you're not familiar with Symfony or the concepts behind web frameworks, there can be a learning curve involved in understanding how everything fits together and how to use the framework effectively.
  2. Performance overhead: Using a framework like Symfony can introduce some performance overhead compared to a custom-built solution, as the framework provides a lot of features and abstractions that may not be needed in every project. However, this overhead is often negligible, and Symfony is built with performance optimizations in mind.
  3. Flexibility: While Symfony is highly customizable and extensible, there may be cases where the framework's conventions and built-in functionality don't align with your specific project requirements, potentially making it more difficult to implement certain features.
  4. Dependency on the framework: When using a framework, your application becomes dependent on that framework and its updates, which can lead to issues if there are breaking changes in future releases or if the framework becomes obsolete.

Pros of not using a framework:

  1. Complete control: Without a framework, you have complete control over your application's architecture and can build it exactly the way you want, without adhering to any specific conventions or structures.
  2. Potentially better performance: Building a custom solution tailored to your application's specific needs can potentially result in better performance, as you can optimize every aspect of the application without the overhead of a framework.

Cons of not using a framework:

  1. Increased development time: Building an application without a framework often takes longer, as you'll need to handle many tasks that a framework would provide out-of-the-box.
  2. Lack of structure and organization: Without a framework, it's up to you to define the structure and organization of your application, which can lead to inconsistencies and make it more challenging to maintain and scale the project over time.
  3. Reusability and modularity: Without a framework, you might not be encouraged to build reusable components and modules, which can lead to more redundant code and make it harder to add new features.
  4. Security: Building a secure web application without a framework requires a thorough understanding of web security best practices. It can be more challenging to ensure that your application is protected against common vulnerabilities.

Ultimately, whether you should use Symfony or another web framework depends on your specific project requirements, your familiarity with the framework, and your development goals.

If you're building a complex web application that requires a lot of functionality and features, using Symfony or another web framework can save you a significant amount of time and effort by providing a structured, organized foundation and built-in tools to handle common tasks. It's also beneficial if you're working with a team, as the framework's conventions and best practices can make it easier for developers to collaborate and understand each other's code.

However, if you're building a very simple or highly specialized application that doesn't require many of the features provided by a framework, or if you have specific performance requirements that you feel can't be met by using a framework, you might consider building a custom solution without a framework.

In any case, it's essential to carefully evaluate your project requirements and weigh the pros and cons of using a framework like Symfony vs. not using a framework to make an informed decision that best suits your needs.

Updated