Ecosyste.ms: Awesome

An open API service indexing awesome lists of open source software.

Awesome Lists | Featured Topics | Projects

https://github.com/rohan-bhautoo/php-symfony-guide

This guide will help you to learn PHP Symfony 6 Framework basics.
https://github.com/rohan-bhautoo/php-symfony-guide

composer php symfony symfony6

Last synced: 26 days ago
JSON representation

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

Awesome Lists containing this project

README

        





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](https://windows.php.net/download#php-8.1).

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.

```shell
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](https://getcomposer.org/download/).

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](https://getcomposer.org/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](https://getcomposer.org/doc/faqs/how-to-install-composer-programmatically.md).

```sh
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](https://symfony.com/download).

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
```shell
symfony new my_project_directory --version="6.2.*"
```

#### Composer
```shell
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

```shell
# Run server in background with -d
symfony server:start -d
```

### Symfony Check

#### Technical Requirements
```shell
symfony check:requirements
```

#### Security
```shell
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 ```
* ```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.

```shell
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.

```php
#[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.

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

Requirements can be inlined in each parameter using the syntax ```{parameter_name}```.

```php
#[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.

```php
#[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}```.

```php
#[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.

```php
#[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.

```twig


Welcome to Symfony!


{{ page_title }}

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

{# ... #}

```

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.

```php
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 %}```.

```twig
{# Child template #}
{% extends "base.html" %}
{% block body %}


{# ... #}

{% endblock %}
```

```twig
{# 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).

```twig
{% for num in tests %}

{{ num }}

{% endfor %}
```

##### Conditional Statement
```twig
{% for num in tests %}
{% if num <= 2 %}

{{ num }}

{% else %}
Num greater than 2

{% 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](https://twig.symfony.com/doc/3.x/filters/index.html).*

```twig
{{ 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](https://twig.symfony.com/doc/3.x/functions/index.html).*

###### Include Function
The [include](https://twig.symfony.com/doc/3.x/functions/include.html) function returns the rendered content of a template. Included templates have access to the variables of the active context.

```twig
{{ 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.

```twig
{% for num in tests %}
{% if num.test <= 2 %}

{{ num.test }}

{% else %}
Num greater than 2

{% 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.

```twig
{{ num.test }}
```

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

#### Installation
```powershell
composer require --dev symfony/maker-bundle
```

#### Usage
```powershell
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
```yml
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:[email protected]:3306/SymfonyGuide?serverVersion=mariadb-10.8.3&charset=utf8mb4"
```
* Change the ```server_version``` in ```doctrine.yaml``` file.
```yaml
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
```powershell
composer require --dev orm-fixtures
composer require --dev doctrine/doctrine-fixtures-bundle
```

#### Usage
```php
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
```php
$microPostRepository->findAll()
```
* Retrieve data by id
```php
$microPostRepository->findOne(1)
```
* Retrieve one data corresponding to title
```php
$microPostRepository->findOneBy(['title' => 'Welcome to Mauritius'])
```
* Retrieve all data corresponding to title
```php
$microPostRepository->findBy(['title' => 'Welcome to Mauritius'])
```
* Add new data in table
```php
$microPost = new MicroPost();
$microPost->setTitle('Welcome to Germany');
$microPost->setText('Belgium');
$microPost->setCreated(new DateTime());
$microPostRepository->save($microPost, true);
```
* Update existing data in table
```php
$microPost = $microPostRepository->find(2);
$microPost->setTitle('Welcome update');
$microPostRepository->save($microPost, true);
```
* Remove data from table
```php
$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](https://symfony.com/bundles/SensioFrameworkExtraBundle/current/index.html) extends it to add sweet conventions and annotations. It allows for more concise controllers.

```
composer require sensio/framework-extra-bundle
```

```php
/**
* @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](https://symfony.com/bundles/SensioFrameworkExtraBundle/current/annotations/converters.html)).

## 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.

```php
#[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.

```php
$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.

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

// Redirect Page
return $this->redirectToRoute('app_micro_post');
```

```twig
{% block body %}
{% for message in app.flashes('success') %}

{{ message }}

{% 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.

```twig
{{ 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](https://symfony.com/doc/current/form/form_themes.html) 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
```

```php
$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](https://tailwindcss.com/) 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.

```html



tailwind.config = {
darkMode: 'class'
}

```

#### Dark Mode
```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**

* Github: [@rohan-bhautoo](https://github.com/rohan-bhautoo)
* LinkedIn: [@rohan-bhautoo](https://linkedin.com/in/rohan-bhautoo)

## Show your support

Give a ⭐️ if this project helped you!