rohan-bhautoo / PHP-Symfony-Guide

This guide will help you to learn PHP Symfony 6 Framework basics.

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Version PHP Symfony Composer Docker Tailwind CSS

This guide will help you to learn PHP Symfony 6 Framework basics. The concepts in this course include:

  • Basic of handling requests
  • Twig templates
  • Databases and Doctrine
  • Doctrine Relations
  • Querying the database
  • Authentication (registration, e-mail confirmation, login page, banning users)
  • Authorization of users (roles, voters)
  • User permission system (role-based)
  • File uploads and displaying uploaded images
  • Sending e-mail

You'll learn all this while building a fun and interesting project, a Twitter-like clone, using the most modern CSS framework Tailwind CSS.

Get Started

Setup / Installation

PHP 8.1

PHP will be used to run a built-in server and run console commands. Install PHP 8.1 or higher. Download the Thread safe version here.

Show Steps
  1. Extract the downloaded zip file in C:\Program Files\ directory.

  2. Copy the full directory of the extracted folder.

  3. Now click on Start Menu and search Environment variables and open it.

  4. Under System variables, add a new value inside the Path variable and paste the full directory in step 2.

  5. Save your changes and check the php version in command prompt.

    php --version
    PHP 8.1.13 (cli) (built: Nov 22 2022 15:49:14) (ZTS Visual C++ 2019 x64)
    Copyright (c) The PHP Group
    Zend Engine v4.1.13, Copyright (c) Zend Technologies

Composer

Composer will be used to install PHP packages. Download it here.

Show Installations
  1. Windows Installer - The installer, which requires that you have PHP already installed, will download Composer for you and set up your PATH environment variable so you can simply call composer from any directory. Download and run Composer-Setup.exe - it will install the latest composer version whenever it is executed.

  2. Command-line installation - To quickly install Composer in the current directory, run the following script in your terminal. Use this guide to install Composer programatically.

    php -r "copy('https://getcomposer.org/installer', 'composer-setup.php');"
    php -r "if (hash_file('sha384', 'composer-setup.php') === '55ce33d7678c5a611085589f1f3ddf8b3c52d662cd01d4ba75c0ee0459970c2200a51f492d557530c71c15d8dba01eae') { echo 'Installer verified'; } else { echo 'Installer corrupt'; unlink('composer-setup.php'); } echo PHP_EOL;"
    php composer-setup.php
    php -r "unlink('composer-setup.php');"

Symfony CLI

Download the 386 binaries here.

Show Installations
  1. Extract the ZIP file to C:\symfony-cli.

  2. Add to the Path environment variable under User Variables.

  3. Run symfony in terminal to see the CLI version and commands.

Docker

Docker will be used to run a database server and db admin panel.

Symfony 101

Creating Project

Open your console terminal and run any of these commands to create a new Symfony application:

Symfony-cli

symfony new my_project_directory --version="6.2.*"

Composer

composer create-project symfony/skeleton:"6.2.*" my_project_directory
cd my_project_directory
composer require webapp

Running Symfony Applications

For local development, the most convenient way of running Symfony is by using the local web server provided by the symfony binary.

Using Symfony CLI to run Local Web Server
# Run server in background with -d
symfony server:start -d

Symfony Check

Technical Requirements

symfony check:requirements

Security

symfony check:security

Project Structure

  • config/ - Contains all configuration files such as routes, services and packages.
  • migrations/ - Contains all doctrine migration class files.
  • src/ - Contains all PHP code.
  • templates/ - Contains all Twig templates.
  • bin/ - Contains files for the bin/console command. Ex: php bin/console <command>
  • var/ - Contains all automatically-created files like cache files and logs.
  • vendor/ - Contains all third-party libraries. These are downloaded via the Composer package manager.
  • public/ - It is the document root of the project where any publicly accessible files are contained.

Controllers - Returning a Response

A Controller is the PHP function you write that builds the page. You take the incoming request information and use it to create a Symfony Response object, which can hold HTML content, a JSON string or even a binary file like an image or PDF.

Creating new controllers

After running the command, a new controller and its twig file is created in their respective directory.

symfony console make:controller HelloController

Routing PHP 8 Attributes

A Route is the URL (e.g. /about) to your page and points to a controller.

PHP attributes allow to define routes next to the code of the controllers associated to those routes. Attributes are native in PHP 8 and higher versions.

#[Route('/hello', name: 'app_hello')]

Route Parameter Requirements

In order to differentiate between two routes, ex: /hello/{id} & /hello/{personId}, the requirements option will be used.

The requirements option defines the PHP regular expressions that route parameters must match for the entire route to match.

#[Route('/hello/{id}', name: 'app_hello', requirements: ['id' => '\d+'])]

Requirements can be inlined in each parameter using the syntax {parameter_name<requirements>}.

#[Route('/hello/{id<\d+>}', name: 'app_hello')]
Optional Parameters

Optional Parameters are added if a parameter value is null. For example, if a user visits /hello/1, it will match. But if they visit /hello, it will not match. A default value can be added when visiting the /hello page for the {id} parameter.

#[Route('/hello/{id}', name: 'app_hello', requirements: ['id' => '\d+'])]
public function index(int $id = 1): Response
{
    // ...
}

Default values can also be inlined in each parameter using the syntax {parameter_name?default_value}.

#[Route('/hello/{id<\d+>?1}', name: 'app_hello')]
Priority Parameter

Symfony evaluates routes in the order they are defined. If the path of a route matches many different patterns, it might prevent other routes from being matched. The optional parameter priority can be set to control the routes priority.

#[Route('/hello/{id<\d+>?1}', name: 'app_hello', priority: 2)]

Twig Templates

A template is the best way to organize and render HTML from inside your application, whether you need to render HTML from a controller or generate the contents of an email. Templates in Symfony are created with Twig: a flexible, fast, and secure template engine.

The Twig templating language allows you to write concise, readable templates that are more friendly to web designers and, in several ways, more powerful than PHP templates.

<!DOCTYPE html>
<html>
    <head>
        <title>Welcome to Symfony!</title>
    </head>
    <body>
        <h1>{{ page_title }}</h1>

        {% if user.isLoggedIn %}
            Hello {{ user.name }}!
        {% endif %}

        {# ... #}
    </body>
</html>

Twig syntax is based on these three constructs:

  • {{ ... }}, used to display the content of a variable or the result of evaluating an expression.
  • {% ... %}, used to run some logic, such as a conditional or a loop.
  • {# ... #}, used to add comments to the template (unlike HTML comments, these comments are not included in the rendered page).

Using the AbstractController in the Controller class to render the Twig template.

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

Twig Template Inheritance

The extends tag can be used to extend a template from another one. We also need to surround all of our content with a {% block body %} tag and a closing {% endblock %}.

{# Child template #}
{% extends "base.html" %}
{% block body %}
    <div class="row">
        {# ... #}
    </div>
{% endblock %}
{# Parent template #}
{% block body %}{% endblock %}

Twig Control Structures

For Loop

A for loop can be used inside a twig template to display all the values from an array (from controller).

{% for num in tests %}
  <div>{{ num }}</div>
{% endfor %}
Conditional Statement
{% for num in tests %}
    {% if num <= 2 %}
        <div>{{ num }}</div>
    {% else %}
        <div>Num greater than 2</div>
    {% endif %}
{% endfor %}

Twig Filters & Functions

Filters

Filters in Twig can be used to modify variables. Filters are separated from the variable by a pipe symbol. They may have optional arguments in parentheses.

A list of filters can be find here.

{{ content|safe_join(", ")|lower }} 
Functions - Partial Templates

Twig provides a number of handy functions that can be used directly within Templates.

A list of functions can be find here.

Include Function

The include function returns the rendered content of a template. Included templates have access to the variables of the active context.

{{ include('template.html') }}
Partial Templates

Partial Twig templates help you reduce code duplication by adding code in a template and including it in multiple other templates. Partial templates starts with an _. The _ prefix is optional, but it's a convention used to better differentiate between full templates and template fragments.

{% for num in tests %}
    {% if num.test <= 2 %}
        <div>{{ num.test }}</div>
    {% else %}
        <div>Num greater than 2</div>
    {% endif %}
    {{ include('hello/_test.html.twig', {date: num.created}) }}
{% endfor %}

Generating Links to Routes

Use the path() Twig function to link pages and pass the route name as the first argument and the route parameters as the optional second argument.

<a href={{ path('app_id', {id: num.test}) }}>{{ num.test }}</a>

Symfony Maker

Symfony Maker helps you create empty commands, controllers, form classes, tests and more so you can forget about writing boilerplate code.

Installation

composer require --dev symfony/maker-bundle

Usage

symfony console list make

Symfony Profiler

The profiler is a powerful development tool that gives detailed information about the execution of any request.

Databases and Doctrine ORM

Symfony provides all the tools you need to use databases in your applications thanks to Doctrine, the best set of PHP libraries to work with databases. These tools support relational databases like MySQL and PostgreSQL and also NoSQL databases like MongoDB.

Docker

Docker is a software platform that allows you to build, test, and deploy applications quickly. Docker packages software into standardized units called containers that have everything the software needs to run including libraries, system tools, code, and runtime.

MySQL Server and Connection

version: "3.8"
services:
  mysql:
    image: mariadb:10.8.3
    command: --default-authentication-plugin=mysql_native_password
    restart: always
    environment:
      MYSQL_ROOT_PASSWORD: root
    ports:
      - 3306:3306

  adminer:
    image: adminer
    restart: always
    ports:
      - 8080:8080
  • Configure the database connection by changing the DATABASE_URL in .env file.
    DATABASE_URL="mysql://root:root@127.0.0.1:3306/SymfonyGuide?serverVersion=mariadb-10.8.3&charset=utf8mb4"
    
  • Change the server_version in doctrine.yaml file.
    doctrine:
        dbal:
            url: '%env(resolve:DATABASE_URL)%'
            server_version: '10.8.3'
  • Create database with Symfony command.
    symfony console doctrine:database:create
    
  • If you obtain error could not find driver in ExceptionConverter.php, then enable the extension pdo_mysql in php.ini file.

Entities

Entities are PHP Objects that can be identified over many requests by a unique identifier or primary key. They represent the tables in a database with the columns as variables.

symfony console make:entity

Migrations

Database migrations are a way to safely update your database schema both locally and on production. Instead of running the doctrine:schema:update command or applying the database changes manually with SQL statements, migrations allow to replicate the changes in your database schema in a safe manner.

  • Create migration file in the migrations folder with the SQL query and with the up() and down() functions.
    symfony console make:migration
    
  • Verify the status of the migration.
    symfony console doctrine:migrations:status
    
  • Execute the migration.
    symfony console doctrine:migrations:migrate 
    
  • Reverse a migration.
    symfony console doctrine:migrations:migrate prev
    
  • Execute migration on server without the need to interact with the warning message.
    symfony console doctrine:migrations:migrate --no-interaction
    

Doctrine Fixtures

Fixtures are used to load a "fake" set of data into a database that can then be used for testing or to help give you some interesting data while you're developing your application.

Installation

composer require --dev orm-fixtures
composer require --dev doctrine/doctrine-fixtures-bundle

Usage

public function load(ObjectManager $manager): void
    {
        $microPost1 = new MicroPost();
        $microPost1->setTitle('Welcome to Mauritius');
        $microPost1->setText('Port-Louis');
        $microPost1->setCreated(new DateTime());
        $manager->persist($microPost1);
        $manager->flush();
    }
symfony console doctrine:fixtures:load

Repositories

A repository is a term used by many ORMs. It means the place where our data can be accessed from, a repository of data. This is to distinguish it from a database as a repository does not care how its data is stored.

  • Retrieve all data
    $microPostRepository->findAll()
  • Retrieve data by id
    $microPostRepository->findOne(1)
  • Retrieve one data corresponding to title
    $microPostRepository->findOneBy(['title' => 'Welcome to Mauritius'])
  • Retrieve all data corresponding to title
    $microPostRepository->findBy(['title' => 'Welcome to Mauritius'])
  • Add new data in table
    $microPost = new MicroPost();
    $microPost->setTitle('Welcome to Germany');
    $microPost->setText('Belgium');
    $microPost->setCreated(new DateTime());
    $microPostRepository->save($microPost, true);
  • Update existing data in table
    $microPost = $microPostRepository->find(2);
    $microPost->setTitle('Welcome update');
    $microPostRepository->save($microPost, true);
  • Remove data from table
    $microPost = $microPostRepository->find(2);
    $microPostRepository->remove($microPost, true);

The function flush() flushes all changes to objects that have been queued up to now to the database. This effectively synchronizes the in-memory state of managed objects with the database.

Param Converter

The default Symfony FrameworkBundle implements a basic but robust and flexible MVC framework. SensioFrameworkExtraBundle extends it to add sweet conventions and annotations. It allows for more concise controllers.

composer require sensio/framework-extra-bundle
/**
 * @Route("micro-post/{microPost}", name="app_micro_post_show")
 */
public function showOne(MicroPost $microPost): Response
{
    dd($microPost);
    return $this->render('micro_post/index.html.twig', [
        'controller_name' => 'MicroPostController',
    ]);
}

The {microPost} variable in the URL will be equal to the id of the MicroPost object in the database. By default, it is fetching by the primary key but this can be configurable (Documentation).

Forms

Creating and processing HTML forms is hard and repetitive. You need to deal with rendering HTML form fields, validating submitted data, mapping the form data into objects and a lot more. Symfony includes a powerful form feature that provides all these features and many more for truly complex scenarios.

composer require symfony/form

The recommended workflow when working with Symfony forms is the following:

  • Build the form in a Symfony controller or using a dedicated form class.
  • Render the form in a template so the user can edit and submit it.
  • Process the form to validate the submitted data, transform it into PHP data and do something with it.
#[Route('/micro-post/add', name: 'app_micro_post_add', priority: 2)]
public function add(): Response
{
    $microPost = new MicroPost();
    $form = $this->createFormBuilder($microPost)
    ->add('title')
    ->add('text')
    ->add('submit', SubmitType::class, ['label' => 'Save'])
    ->getForm();

    return $this->render('micro_post/_add.html.twig', [
        'form' => $form,
    ]);
}

Handling Form Submission

The recommended way of processing forms is to use a single action for both rendering the form and handling the form submit.

$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
    $microPost = $form->getData();
    $microPost->setCreated(new DateTime());
    $microPostRepository->save($microPost, true);
}

Flash Messages & Redirects

Flash messages are temporary messages used for user notifications. They are stored in a session and vanish as soon as they are retrieved.

// Flash Message
$this->addFlash('success', 'Your micro post has been added!');

// Redirect Page
return $this->redirectToRoute('app_micro_post');
{% block body %}
    {% for message in app.flashes('success') %}
        <div style='color: green'>{{ message }}<div>
    {% endfor %}
{% endblock %}

Customizing Form Rendering

A single call to the form() Twig function is enough to render an entire form, including all its fields and error messages.

{{ form(form) }}

There are different twig functions that will enable you to customize different parts of the form by adding HTML elements and attributes.

  • form_start() - Renders the start tag of a form.
  • form_end() - Renders the end tag of a form.
  • form_label() - Renders the label for the given field.
  • form_help() - Renders the help text for the given field.
  • form_errors() - Renders any errors for the given field.
  • form_widget() - Renders the HTML widget of a given field.
  • form_row() - Renders the "row" of a given field, which is the combination of the field's label, errors, help and widget.
  • form_rest() - Renders all fields that have not yet been rendered for the given form.
  • form_parent() - Returns the parent form view or null if the form view already is the root form.

Form Themes

Symfony comes with several built-in form themes that make your forms look great when using some of the most popular CSS frameworks.

Form Classes

Symfony recommends putting as little logic as possible in controllers. That's why it's better to move complex forms to dedicated classes instead of defining them in controller actions. Besides, forms defined in classes can be reused in multiple actions and services.

Form classes are form types that implement FormTypeInterface.

symfony console make:form
$form = $this->createForm(MicroPostType::class, new MicroPost());

Styling Application

Nowadays, frameworks, like Bootstrap and Tailwind, are used to design a website more easily and rapidly. They offer some pre-defined styles and also several components.

Tailwind CSS

Tailwind CSS works by scanning all of your HTML files, JavaScript components, and any other templates for class names, generating the corresponding styles and then writing them to a static CSS file.

<head>
  <script src="https://cdn.tailwindcss.com"></script>
  <script>
      tailwind.config = {
          darkMode: 'class'
      }
  </script>
</head>

Dark Mode

<html class="dark">
  <body class="bg-gray-100 text-gray-800 m-10 dark:bg-gray-800 dark:text-white">
  </body>
</html>

Adding Breadcrumbs

Custom Form Theme

Form Validation

Database Relations in Doctrine

Relations

One to One Relation

One to Many Relation

Many to Many Relation

Comments Feature

Adding Comments

Solving N+1 Problem

Display Comments

Authentication & Authorization

Hashing Passwords

Creating Users - Fixtures & Custom Console Command

Authenticating

Logging Out Feature

Relate Posts & Comments to User

Unrun Migration Problem

Get Current User

User Roles

Logout Button and Missing Features

Voters

User Registration & Verification

Registration Controller

Mail Catcher

Testing Registration

User Checkers

Banning Users Functionality

User Profiles, Likes & Following Features

User Profile Form

Embedding Forms

Following Feature

Data Model

Functionality

Tab Navigation

More Features & Complex Database Queries

Reusable Queries

File Uploads

Image Uploading Controller

File Upload Form

Image Upload

Image Avatar

Privacy Feature

Services, Service Container & Dependency Injection

Debug Command

Services & Service Container

Dependency Injection

Author

👤 Rohan Bhautoo

Show your support

Give a ⭐️ if this project helped you!

About

This guide will help you to learn PHP Symfony 6 Framework basics.


Languages

Language:PHP 69.9%Language:Twig 30.1%