├── .env
├── .gitignore
├── .idea
├── codeStyles
│ └── codeStyleConfig.xml
├── modules.xml
├── php.xml
├── symfony-6-course.iml
├── vcs.xml
└── workspace.xml
├── README.md
├── assets
├── app.js
├── bootstrap.js
├── controllers.json
├── controllers
│ └── hello_controller.js
├── javascript
│ ├── js.js
│ └── js1.js
└── styles
│ └── app.css
├── bin
└── console
├── composer.json
├── composer.lock
├── config
├── bundles.php
├── packages
│ ├── assets.yaml
│ ├── cache.yaml
│ ├── doctrine.yaml
│ ├── doctrine_migrations.yaml
│ ├── framework.yaml
│ ├── prod
│ │ ├── doctrine.yaml
│ │ └── webpack_encore.yaml
│ ├── routing.yaml
│ ├── security.yaml
│ ├── test
│ │ ├── doctrine.yaml
│ │ ├── validator.yaml
│ │ └── webpack_encore.yaml
│ ├── twig.yaml
│ ├── validator.yaml
│ └── webpack_encore.yaml
├── preload.php
├── routes.yaml
├── routes
│ ├── annotations.yaml
│ └── framework.yaml
└── services.yaml
├── migrations
├── .gitignore
├── Version20220212160836.php
└── Version20220212182633.php
├── package-lock.json
├── package.json
├── public
└── index.php
├── src
├── Controller
│ ├── .gitignore
│ ├── MoviesController.php
│ ├── RegistrationController.php
│ └── SecurityController.php
├── DataFixtures
│ └── AppFixtures.php
├── Entity
│ ├── .gitignore
│ ├── Actor.php
│ ├── Admin.php
│ └── Movie.php
├── Form
│ ├── MovieFormType.php
│ └── RegistrationFormType.php
├── Kernel.php
├── Repository
│ ├── .gitignore
│ ├── ActorRepository.php
│ ├── AdminRepository.php
│ └── MovieRepository.php
└── Security
│ └── LoginFormAuthenticator.php
├── symfony.lock
└── templates
├── base.html.twig
├── index.html.twig
├── login.html.twig
├── movies
├── create.html.twig
├── edit.html.twig
├── index.html.twig
└── show.html.twig
├── register.html.twig
├── registration
└── register.html.twig
└── security
└── login.html.twig
/.env:
--------------------------------------------------------------------------------
1 | # In all environments, the following files are loaded if they exist,
2 | # the latter taking precedence over the former:
3 | #
4 | # * .env contains default values for the environment variables needed by the app
5 | # * .env.local uncommitted file with local overrides
6 | # * .env.$APP_ENV committed environment-specific defaults
7 | # * .env.$APP_ENV.local uncommitted environment-specific overrides
8 | #
9 | # Real environment variables win over .env files.
10 | #
11 | # DO NOT DEFINE PRODUCTION SECRETS IN THIS FILE NOR IN ANY OTHER COMMITTED FILES.
12 | #
13 | # Run "composer dump-env prod" to compile .env files for production use (requires symfony/flex >=1.2).
14 | # https://symfony.com/doc/current/best_practices.html#use-environment-variables-for-infrastructure-configuration
15 |
16 | ###> symfony/framework-bundle ###
17 | APP_ENV=dev
18 | APP_SECRET=63a09515f621d17cec11540238397071
19 | ###< symfony/framework-bundle ###
20 |
21 | ###> doctrine/doctrine-bundle ###
22 | # Format described at https://www.doctrine-project.org/projects/doctrine-dbal/en/latest/reference/configuration.html#connecting-using-a-url
23 | # IMPORTANT: You MUST configure your server version, either here or in config/packages/doctrine.yaml
24 | #
25 | # DATABASE_URL="sqlite:///%kernel.project_dir%/var/data.db"
26 | # DATABASE_URL="mysql://db_user:db_password@127.0.0.1:3306/db_name?serverVersion=5.7"
27 | DATABASE_URL="mysql://root:@127.0.0.1:3306/movies?serverVersion=5.7"
28 | ###< doctrine/doctrine-bundle ###
29 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | ###> symfony/framework-bundle ###
2 | /.env.local
3 | /.env.local.php
4 | /.env.*.local
5 | /config/secrets/prod/prod.decrypt.private.php
6 | /public/bundles/
7 | /var/
8 | /vendor/
9 | ###< symfony/framework-bundle ###
10 |
11 | ###> symfony/webpack-encore-bundle ###
12 | /node_modules/
13 | /public/build/
14 | npm-debug.log
15 | yarn-error.log
16 | ###< symfony/webpack-encore-bundle ###
17 |
--------------------------------------------------------------------------------
/.idea/codeStyles/codeStyleConfig.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/.idea/modules.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/.idea/php.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
--------------------------------------------------------------------------------
/.idea/symfony-6-course.iml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
--------------------------------------------------------------------------------
/.idea/vcs.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/.idea/workspace.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 | $PROJECT_DIR$/composer.json
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 |
107 |
108 |
109 |
110 |
111 |
112 |
113 |
114 |
115 |
116 |
117 |
118 |
119 |
120 |
121 |
122 |
123 |
124 |
125 |
126 |
127 |
128 |
129 |
130 |
131 |
132 |
133 |
134 |
135 |
136 | 1641501433492
137 |
138 |
139 | 1641501433492
140 |
141 |
142 |
143 |
144 |
145 |
146 |
147 |
148 |
149 |
150 |
159 |
160 |
161 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Symfony Course
2 |
3 | Every chapter has its own associated repository. The repository will start with the episode number followed by the name. Example: ```4-setting-up-our-project```.
4 |
5 | This repository is linked to [this YouTube video](https://www.youtube.com/playlist?list=PLFHz2csJcgk-t8ErN1BHUUxTNj45dkSqS) where we will be covering all topics that are needed to become a Symfony developer.
6 |
7 | • Author: [Code With Dary](https://github.com/codewithdary/)
8 | • Twitter: [@codewithdary](https://twitter.com/codewithdary)
9 | • Instagram: [@codewithdary](https://www.instagram.com/codewithdary/)
10 |
11 | ## Technical Requirements
12 | • PHP 7.2.5 or higher
13 | • Composer installed
14 |
15 | ## Prerequisites
16 | • Basic PHP knowledge
17 | • Low level HTML & CSS knowledge
18 | • Object-Oriented Programming
19 |
20 | ## Course Overview
21 |
22 | | **Episode** | **Subject** |
23 | | ------------- |-------------|
24 | | Ep. 1 | Introduction to Symfony |
25 | | Ep. 2 | MVC Explained |
26 | | Ep. 3 | Installation & Setup for Mac |
27 | | Ep. 4 | Setting up VS Code for Symfony |
28 | | Ep. 5 | Setting up our project & directory explained |
29 | | Ep. 6 | Controllers in Symfony |
30 | | Ep. 7 | Route Parameters in Symfony |
31 | | Ep. 8 | Views in Symfony |
32 | | Ep. 9 | Twigs layouts & blocks explained |
33 | | Ep. 10 | How to create a database |
34 | | Ep. 11 | Introduction to Doctrine |
35 | | Ep. 13 | Doctrine Relationships Explained |
36 |
37 |
38 | ## 1. Introduction to Symfony
39 |
40 | Before we kick off, I do want to let you know that this course is not everything. There are loads of advanced Symfony topics left, this is just an introduction to Symfony.
41 |
42 | Make sure that you have a bit experience with front-end technologies like HTML5 and CSS3. JavaScript is not a must, but would make everything a bit more interactive and better looking if you do got experience with it.
43 |
44 | For you back-end skills, make sure that you have an outstanding understanding of procedural PHP, and a decent understanding of Object-Oriented PHP since terms such as ```extends```, ```classes```, ```interfaces```, ```objects```, ```scope``` and ```accessibility``` will be used quite a lot.
45 |
46 | The most important thing will be MVC. You don’t need to create an MVC structure with your eyes closed (we got Symfony for that) but you do need to know the concepts behind it since it will not be covered.
47 |
48 | ### **What is Symfony?**
49 | I get a lot of requests from people asking me what Symfony is. Usually, I respond with; **“Symfony is a full-stack PHP framework that uses a set of reusable components”**. Whether you’re a junior or senior developer, it costs a lot of time to create an application from scratch every single time, and that’s where Symfony comes into play.
50 |
51 | ### **Advantages of Symfony**
52 | 1. Faster Development
53 | 2. Use of Components
54 | 3. Reuse pieces of code
55 |
56 | **Coding standards**
57 | Every single programming language has its own set of coding standards. Most of them will be equal to another, but there are some slight changes here and there. Luckily, Symfony created their own coding standards which [you can find right here]( https://symfony.com/doc/current/contributing/code/standards.html). I recommend you to quickly scroll through them and see if you find something that you haven't seen before.
58 |
59 | ### How to use this course
60 |
61 | There are several ways on how you could approach this course. There are a lot of courses out there with more videos, but is that really the key to success?
62 |
63 | I like to keep my courses short and straight to the point. Not every single topic in Symfony will have a separate video, because we will be using certain elements within videos.
64 |
65 | In this course, we will be covering the following chapters:
66 | - Introduction
67 | - Installation & Configuration
68 | - Controllers & Routes
69 | - Views & Assets
70 | - Databases & Doctrine
71 | - We’re going to create a project
72 | - We’re going to talk about Authorization in Symfony
73 | - Services and Service Containers
74 | - We’re going to write tests, so Unit Tests, HTTP Tests and database tests
75 | - We’re going to dive into Mailing and Notifications
76 | - Then we got some random topics which might be important for you, so the queue, Jobs, Events, Broadcasting, sessions and cookies.
77 |
78 | ### **Source code** ##
79 |
80 | The source code of this course will be available in two ways, and the best possible way is through GitHub!
81 |
82 | The main branch will consists of all chapters in one single source code. Every single video I create has its own branch where you will see a pattern, since all branches start with the video number, followed with the title of the video. Example: {4-creating-first-project}.
83 |
84 | If you don’t like to work with GitHub, you will also find a zip file attached to every chapter where you will find a PDF file (this one), which will basically be the video written down for you, with the source code.
85 |
86 | ### **Invest time** ##
87 |
88 | This course will not be everything. You need to put extra work into it as well. You can’t just want tutorials on Udemy and YouTube and expect to be a pro in it.
89 |
90 | Most advanced developers will agree with me that you develop your skills by running into issues and finding the solutions yourself.
91 |
92 | How I like to work is showing you both the happy path and the unhappy path. IF you don’t agree with that, I’m sorry but thank me later.
93 |
94 | ## How to get in touch
95 |
96 | There are multiple ways on how you can get in touch if you’re running into issues. I got to say that it’s difficult at times to maintain and respond to everyone, but I’ll definitely do my best.
97 |
98 | ### **Github**
99 |
100 | The first way is through Github. My username is [Codewithdary](https://www.github.com/codewithdary), where you will find loads of repositories related to Symfony and Laravel.
101 |
102 | ### **Instagram**
103 |
104 | My [Instagram](https://www.instagram.com/codewithdary) username is codewithdary as well, and next to coding issues, you’ll find more personal stuff about me over here.
105 |
106 | ### **Udemy**
107 |
108 | You can of course always reach our on this platform!
109 |
110 | ### **YouTube**
111 |
112 | If you are interested in learning more about coding, you can check me out on [YouTube](https://www.youtube.com/channel/UCkzGZ6ECGCBh0WK9bVUprtw) where you’ll can find me under the name of Code With Dary. I’m a developer and educator who created online courses in PHP, JavaScript, Laravel and TailwindCSS to help everyone out.
113 |
114 | ### **Patreon**
115 |
116 | If you are interested in getting into my Discord group and interact with other up and coming developers (and me) about your coding issues, my [Patreon](https://www.patreon.com/user?u=30307830) will be the right place for you!
117 |
118 | ## Why should you use a framework?
119 |
120 | Early in the days, web development looked completely different than nowadays. Next to the components, developers we’re responsible for writing the code for the business logic as well. Most of you probably know that there are many frameworks and libraries available which will make it a lot easier to code, but it wasn’t always like that.
121 |
122 | With PHP, you will be using a lot of components and packages. Frameworks like Symfony and Laravel, prepackage a collection of third-party components together, which will eventually be a custom framework. What will that be? Think about things like:
123 | • Configuration files
124 | • Service providers
125 | • Prescribed directory structures
126 | • Application bootstraps
127 |
128 | All these points will define the benefit of using a framework, since someone else has already make decisions not just about individual components for you, but also about how those components should fit together.
129 |
130 | Let’s look at it the other way around. Where would you start yourself if you have to create a framework yourself? Probably somewhere with the route HTTP request, right? Since you need to evaluate all of the HTTP request and response libraries available, and pick the right one. Then what? Well, you need to pick a router, followed with a route configuration file. Where will you be storing these files? And don’t forget, where does the Controller fit? All these questions, are answered when you start using a framework.
131 |
132 | ## 2. MVC Explained
133 |
134 | In the first chapter of this course we have touched on MVC a little bit. In coding, MVC is a design pattern, or better to say a software architecture which stands for Model View Controller. When using MVC, you will structure your application by separating the domain, application, and business logic from the rest of the user interface.
135 |
136 | ### **Model**
137 | The model layer manages the fundamental behaviors and data of the application. It will interact with the requests, respond to instructions, and even notify observers in event-driven systems.
138 |
139 | ### **View**
140 | The view is basically the user interface of your application. What you will be doing is pulling data from the database in the model based on a request from the Controller, and translate it into data that you can use inside the view.
141 |
142 | ### **Controller**
143 | The Controller will take HTTP requests, so user input from the browser, gets the right data out of the database, validates the user input, and eventually sends a response back to the user.
144 |
145 | In the model, you don’t want to use View or Controller code. The other way around as well. You don’t want to perform SQL queries inside your controller, let alone in your view.
146 |
147 | All these components, are defined as the MVC design pattern. In my personal opinion, Symfony is huge because it’s using the Model View Controller design pattern. Well, I need to rephrase that, because Symfony contains MVC, but does not constrain it.
148 |
149 | ## 4. Installation
150 | -- To be Continued --
151 |
152 | Symfony has four different ways on how you could create a project. In my personal opinion, using the Symfony installer or the Composer installer are the easiest ways. I’ll be showing how you can create a project through both of them on Mac, Linux and Windows.
153 |
154 | ### **Symfony installer**
155 | In order to use the Symfony installer, we got to make sure that we create a Binary. Therefore, we need to perform the following command depending on your OS:
156 | ```
157 | Mac - curl -sS https://get.symfony.com/cli/installer | bash
158 | Linux - wget https://get.symfony.com/cli/installer -O - | bash
159 | Windows – Download the setup.exe right here -> https://get.symfony.com/cli/setup.exe
160 | ```
161 |
162 | As the URL implies, this will pull in Symfony’s CLI installer, which will allow you to install a Symfony project through the CLI. When you perform the command, you'll see that it will ask you to configure Symfony on your local system. I prefer to add a path to my configuration file, so let's copy the line that looks like this:
163 | ```
164 | export PATH=”$HOME/.symfony/bin:$PATH”
165 | ```
166 |
167 | Open a new tab inside the CLI, because we need to access the hidden ```bashrc``` file inside the root of our OS:
168 | ```
169 | nano ./bashrc
170 | ```
171 |
172 | Paste the link that we copied somewhere in the ```bashrc``` file.
173 |
174 | If we save our ```./bashrc``` file, we are ready to create our first project. In order to create a new project, you got to write down the keyword symfony, followed with the keyword new, followed with the folder name. In our case, let’s call it ```movies```. Be aware that this will be your project name.
175 | ```
176 | symfony new movies
177 | ```
178 |
179 | You have the option to pass in a ```--full``` flag which will install all packages that you need to build web application, be aware that the size of your project will be a lot bigger.
180 | ```
181 | symfony new movies --full
182 | ```
183 |
184 | You also have the option to change up your version number as well. If you perform the ```symfony new movies``` command, Symfony will always pull in a project with the most up to date version number. You can change this up by adding a ```--version={VERSION_NUMBER}``` flag to it.
185 | ```
186 | symfony new movies –version=4.0
187 | ```
188 |
189 | This command will install a Symfony project with a version number of 4.0.
190 |
191 | ### **Composer installer**
192 | The second method is to install Symfony through Composer. Make sure that you have Composer installed on your local machine before you perform the following command, otherwise it won’t recognize the keyword ```composer```. Inside the CLI, you need to perform the following command:
193 | ```
194 | composer create-project symfony/skeleton movies
195 | ```
196 |
197 | ### **Check if settings are OK**
198 | Like I’ve mentioned at the beginning of this repository, you need PHP 7.2.5 or higher installed on your local machine. In order to perform the command, we got to make sure that we are inside the Symfony folder that we just created. Let’s change directories.
199 | ```
200 | cd movies
201 | ```
202 |
203 | If you’re not sure if you got that installed, you can run the following command to see if your local machine meets the requirements.
204 | ```
205 | symfony check:requirements
206 | ```
207 |
208 | If you have your environment setup correctly, you will be hit with the following message:
209 | ```ruby
210 | [OK]
211 | Your system is ready to run Symfony projects
212 | ```
213 |
214 | ### Open project in the browser
215 | Symfony’s CLI comes with a web server that is very easy to use. In order to use it, you need to run the following command inside the project directory:
216 | ```
217 | symfony server:start
218 | ```
219 |
220 | This will return back a message which says that your web server is indeed listening, and it can be accessed through your localhost.
221 |
222 | ```ruby
223 | EXAMPLE
224 | [OK] Web server listening
225 | The web server is using PHP FPM 8.0.6
226 | http://127.0.0.1:8000
227 | ```
228 |
229 | 127.0.0.1 is the standard ipv4 address for projects that run on localhost and :8000 is the first available port.
230 |
231 | You can copy the link and paste it inside the browser, or you can perform the following command which will open it directly in the browser through the CLI:
232 | ```
233 | symfony open:local
234 | ```
235 |
236 | ## 5. Setting up VS Code for Symfony
237 | Setting up VS Code for Symfony
238 |
239 | Once you want to work with a framework such as Symfony, you need to make sure that you’re setting up your code editor in the right way.
240 |
241 | We obviously need to make sure that we install Visual Studio Code from their [official website](https://www.code.visualstudio.com).
242 |
243 | When you want to install an extension, you need to access the extensions market, this can be done in the left side bar, where you need to click on the 4 squares.
244 |
245 | I personally think that the following extensions are Must-Haves when working with Symfony:
246 | • Community Material Theme (Extra)
247 | • PHP Intelephense
248 | • PHPDoc Comment
249 | • PHP Namespace Resolver
250 | • HTML Snippets
251 | • JavaScript (ES6) code snippets
252 | • Symfony code snippets and Twig Support & yaml
253 | • Symfony for VSCode
254 | • Twig
255 | • Twig Language
256 | • Twig Language 2VScode Great Icons
257 | • Bracket Pair Colorizer
258 | • Emmet Live
259 |
260 |
261 | ## 6. Project structure
262 |
263 | If we open our project in any code editor, you can see a very thin project because we pulled in **Symfony’s skeleton**. These are all added in the root directory called ```movies```. The Symfony Skeletion doesn't add many dependencies, but only the components that are needed to run a Symfony project in the browser.
264 |
265 | | **Name** | **Explanation** |
266 | | ------------- |-------------|
267 | | bin | Has the ```console``` file which is the main entry point |
268 | | config | Default and sensible configuration files |
269 | | migrations | Place where you store your database migrations |
270 | | public | Has the ```index.php``` file which will be the main entry point for all dynamic http resources |
271 | | src | Most important folder, all code you write will be stored right here |
272 | | var | Contains all ```caches```, ```logs``` and files that are generated at runtime by the application |
273 | | vendor | Had the files that you pull in through Composer |
274 | | .env | You store individual working environment variables that you can use throughout your app |
275 | | composer.json | Specifies a common project properties, meta data and dependencies |
276 | | composer.lock | When running ```composer install``` for the first time, or when running ```composer update``` a lock file called composer.lock will be created |
277 | | symfony.lock | It is the proper lock file for Symfony recipes instead of trying to guess via the state of composer.lock |
278 |
279 |
280 | The biggest piece of advice I can give to you is to never update/delete the vendor directory because you’ll be running into conflicts when you need to update your packages. The best way to update/delete the vendor directory is to either overwrite the vendor directory or to overwrite functions, but we will get into that later on.
281 |
282 | ## 7. Controllers in Symfony
283 |
284 | Controllers play a huge role in the MVC pattern since they are basically classes that will organize the logic of one or more route together, **in one place**!
285 |
286 | Keep in mind that you don’t need to put all your application’s logic inside the controller, but see it as the traffic cops that route HTTP requests around your in your application.
287 |
288 | Before we create our first controller, we need to take a moment to talk about your ```configuration format```. In Symfony, you got the following options:
289 |
290 | | **Format** | **Explanation** |
291 | | ------------- |-------------|
292 | | YAML | Simple, clean and readable, but not all IDEs support autocompletion and validation for it |
293 | | XML | Autocompleted/validated by most IDEs and is parsed natively by PHP, but sometimes it generates configuration considered too verbose |
294 | | PHP | very powerful and it allows you to create dynamic configuration with arrays or a ConfigBuilder |
295 |
296 | I’m not going to tell you which one you should use, because every single one of them is a good option. Therefore, I recommend you to use the one you’re most comfortable with. We will be using ```annotations``` in this course so that’s what we will focus on.
297 |
298 | A pretty cool feature in Symfony is the console command (which is equal to Artisan in Laravel). It allows you to create certain files through the CLI. What’s the benefit of using Symfony's console command? Well, you don’t need to right click on a folder, create a new file, name it, add PHP tags, give it a namespace and a class name.
299 |
300 | Before we can use the make command, we got to make sure that we pull in Doctrine maker through Composer.
301 | ```
302 | composer require doctrine maker
303 | ```
304 |
305 | With Doctrine maker, we can create a controller (and more) with the following command:
306 | ```
307 | symfony console make:controller MoviesController
308 | ```
309 |
310 | The last param will be the name of your class and file. In our case, it will be ```MoviesController```. The output will be a ```success``` message with the path of our Controller. In our case, it will be stored in the ```src/Controller/``` folder where a file has been added with the name of ```MoviesController.php```.
311 |
312 | **Quick note**, keep in mind that the file name needs to be equal to the class name, otherwise you’ll run into some errors.
313 |
314 | By default, an new controller file will be using the following three use statements:
315 | ```ruby
316 | use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
317 | use Symfony\Component\HttpFoundation\Response;
318 | use Symfony\Component\Routing\Annotation\Route;
319 | ```
320 |
321 | The class we created extends the AbstractController, which is needed to return something.
322 | ```ruby
323 | class MoviesController extends AbstractController
324 | ```
325 |
326 | The real magic of our application will happen inside the ```MoviesController``` class, since we’re going to create routes and methods in here.
327 |
328 | Right above our ```index()``` method, you’ll see something which might look like a comment, but it’s actually a route as an attribute that will define the route for the method mentioned right below it.
329 |
330 | The first parameter will be the endpoint that you need to add inside the URL. In our case, it will be ```/movies```. The name is an optional parameter, which will define the name of our endpoint.
331 |
332 | ```ruby
333 | #[Route('/movies', name: 'movies')]
334 | ```
335 |
336 | If we navigate to the browser and change our endpoint to ```127.0.0.1:8000/movies```, you will see the JSON response that was automatically added inside the ```index()``` method.
337 |
338 | ### What will happen if the endpoint does not exist?
339 | This is a pretty interesting question since it will definitely happen that you hit the wrong endpoint. Let’s change our endpoint from ```/movies``` to ```/movie```.
340 |
341 | ```ruby
342 | #[Route('/movie', name: 'movies')]
343 | ```
344 |
345 | Let’s refresh the ```127.0.0.1:8000/movies``` endpoint we got open inside the browser, and you can see that we’ve been hit with the following message:
346 | ```
347 | No route found for “GET http://127.0.0.:8000/movies”
348 | ```
349 |
350 | Finally, our first error message. This error message appears because the endpoint does not exist.
351 |
352 | ### What is the difference with previous Symfony versions?
353 | If you are using an older PHP version or even maybe a better version in the future, your annotations or attributes will probably look different than mine, even if you Google around for issues with your route.
354 |
355 | Annotation methods used to look like this:
356 | ```ruby
357 | /**
358 | * @Route("/movies", name="movies")
359 | */
360 | public function index(): Response {
361 |
362 | }
363 | ```
364 |
365 | **Quick note**, the route above still works. You are not obligated to use the new method.
366 |
367 | ### What is the logic behind the Controller?
368 | If we open the ```/config/routes/annotations.yaml``` file (which actually isn’t an annotations file but a bundle), you will see that something is being done with a controller.
369 |
370 | ```ruby
371 | controllers:
372 | resource: ../../src/Controller/
373 | type: annotation
374 | ```
375 |
376 | What this piece of code will do is creating a route from the controller action methods and their route annotations.
377 |
378 | ## 8. Route Parameters
379 |
380 | One of the most common things in Symfony (and any other framework/programming language) are routes with parameters. In the previous chapter, we defined a basic route to ```/movies```. If we take a look at all the HTTP methods down below, you can see that this route should eventually get all available movies in the database.
381 |
382 | What if you want to show one specific movie to a user? Let’s say that we have a movie in our database/list with the name of Inception, do you want do define your route for every single movie as shown below?
383 | ```ruby
384 | #[Route('/movies/inception', name: 'movies')]
385 | ```
386 |
387 | Well, the answer is no… here’s when you can use route parameters. It’s basically a route that has a parameter inside the URL structure, which will be a variable. Since it’s a variable, we have the opportunity to change it based on the names we got inside our database.
388 |
389 | In order to define a route parameter, you need to wrap your variable inside curly braces right after the actual endpoint.
390 |
391 | ```ruby
392 | #[Route('/movies/{name}, name: 'movies')]
393 | ```
394 |
395 | Be aware that we’re going to pass in the name of a specific movie, but a variable that will represent that specific movie. Once again, this can be an id, name or slug.
396 |
397 | If we navigate to the browser and change our endpoint to ```127.0.0.1:8000/movies/inception```, you can indeed see that this works fine.
398 |
399 | When working on large web applications, you will probably use tons of endpoints to showcase pages to users. There’s a command in Symfony which will show you all routes that are available in your project.
400 | ```
401 | symfony console debug:router
402 | ```
403 |
404 | Next to the name parameter inside the route, you can add the HTTP verb you want to perform on your route.
405 | ```ruby
406 | #[Route('/movie', name: 'movies', methods:[‘GET’, ‘HEAD’)]
407 | ```
408 |
409 | ### Available HTTP methods on a resource
410 |
411 | | **Verb** | **Path** | **Action** | **Route Name** | **Description** |
412 | | ------------- |-------------| -----| ------------- |-------------|
413 | | GET | /movies | index | movies.index | Get all movies |
414 | | GET | /movies/create | create | movies.create | Get new created movies |
415 | | POST | /movies | store | movies.store | Create a new movie |
416 | | GET | /movies/{movie} | show | movies.show | Get data of specific movie |
417 | | GET | /movies/{movie}/edit | edit | movies.edit | Edit specific movie |
418 | | PUT/PATCH | /movies/{movie} | update | movies.update | Update a specific movies |
419 | | DELETE | /movies{delete} | destroy | movies.destroy | Delete a specific movie |
420 |
421 | ## 9. Views
422 |
423 | If you have reached it up until this point, you know the basics of controllers. The next logic step is to focus on views. A view represents the template that will be shown to the end user on the screen.
424 |
425 | We’re not going to create basic ```.html``` files but we’re going to use a custom templating engine called Twig. Compared to views in PHP, twig has its own syntax and learning curve.
426 |
427 | Views will be shown based on a method in the controller. By default, your ```index()``` methods returns JSON, and it’s finally time to get rid of it.
428 |
429 | In order to show a view from the controller, you need to return the ```render()``` method.
430 | ```ruby
431 | #[Route('/movies', name: 'movies')]
432 | public function index(): Response
433 | {
434 | return $this->render();
435 | }
436 | ```
437 |
438 | If your using a modern code editor, you will see that the ```render()``` method throws an error. This happens because it accepts the path of a twig template.
439 |
440 | By default, twig templates are stored inside the ```/templates``` folder in the root of our directory where you can find a base file called ```base.html.twig```. Let’s create a new file called ```/templates/index.html.twig``` and let’s also add a simple header right here.
441 | ```ruby
442 |
443 | Welcome to my Symfony course :)
444 |
445 | ```
446 |
447 | This obviously won’t work immediately, because remember, we do need to pass in the view inside the ```render()``` method.
448 |
449 | Keep in mind that you don’t need to define the ```/templates``` folder inside the ```render()``` method because it knows that it needs to look inside the templates folder.
450 | ```ruby
451 | #[Route('/movies', name: 'movies')]
452 | public function index(): Response
453 | {
454 | return $this->render('index.html.twig');
455 | }
456 | ```
457 |
458 | If we refresh our ```127.0.0.1:8000/movies``` endpoint, you’ll see the ```h1``` printed out.
459 |
460 | ### Optional parameters in the render method
461 | The ```render()``` method accepts another parameter which is optional. Later on, we’ll learn how to interact with the database inside the controller. Obviously, you need to send something back to the view. To do this, we can add a comma after our first parameter (which is the view name), then we’re going to return an array straight into the view.
462 | ```ruby
463 | #[Route('/movies', name: 'movies')]
464 | public function index(): Response
465 | {
466 | return $this->render('index.html.twig', [
467 | 'title' => 'Inception'
468 | ]);
469 | }
470 | ```
471 |
472 | It’s a little bit different to print out values inside twig since it needs to be wrapped around a double set of curly braces ```{{ }}```. Then inside the curly braces, we can simply write down the key name from the controller. We do not need to add a $ sign to let our file know that we're working with a variable, twig will automatically identify it as a variable.
473 |
474 | ```ruby
475 |
476 | {{ title }}
477 |
478 | ```
479 |
480 | ### More info about variables
481 | A pretty cool feature in Symfony is the ```dump()``` method, which is a function that will provide more information about a template variable.
482 | ```ruby
483 |
484 | {{ dump(title) }}
485 |
486 | ```
487 |
488 | If we refresh our ```127.0.0.1:8000/movies``` endpoint, you can see that the data type of our ```title``` is a string.
489 |
490 | ## 8. Twig layout explained
491 |
492 | When developing large scaled web applications, you usually want to reuse components, especially when it comes to layouts. You don’t want to redefine your stylesheet, JavaScript file, font awesome icons and all those other utilities on every single page.
493 |
494 | Even if we dive into the actual content of a page, you don’t want to define your head tags and/or footer tags for every single page.
495 |
496 | What you should be doing instead is using the base.html.twig file as your layout, and add content that changes inside the ```index.html.twig``` file.
497 |
498 | Let’s open our ```base.html.twig``` file and see what we got in here.
499 |
500 | ```ruby
501 |
502 |
503 |
504 |
505 | {% block title %}Welcome!{% endblock %}
506 | {# Run `composer require symfony/webpack-encore-bundle`
507 | and uncomment the following Encore helpers to start using Symfony UX #}
508 | {% block stylesheets %}
509 | {#{{ encore_entry_link_tags('app') }}#}
510 | {% endblock %}
511 |
512 | {% block javascripts %}
513 | {#{{ encore_entry_script_tags('app') }}#}
514 | {% endblock %}
515 |
516 |
517 | {% block body %}{% endblock %}
518 |
519 |
520 | ```
521 |
522 | Right here, you can see some elements that we haven’t seen before.
523 |
524 | | **Code** | **Explanation** |
525 | | ------------- |-------------|
526 | | {% block {NAME} %} {% endblock &} | A block is basically a place or location where a child template can extend their content. If we extend the base file inside the index file, you don’t need to define the title tags but just the blocks in case you want to change the value |
527 | | {% block body %} {% endblock %} | Main content of the index page will be replaced with the block body inside the body tags, this is the location where all the magic will happen
528 |
529 | Let’s navigate to the ```index.html.twig``` file and remove everything we got. If you want to overwrite the ```base.html.twig``` file, you got to make sure that you extend that page on the first line.
530 | ```ruby
531 | {% extends 'base.html.twig' %}
532 | ```
533 |
534 | What we’re doing right below our extends, is saying that we want to copy the entire ```base.html.twig``` page behind the scenes, and edit certain blocks.
535 |
536 | An example might be the following, where we extend the body block.
537 | ```python
538 | {% block body %}
539 |
540 | New body extended from the base.html.twig file
541 |
542 | {% endblock %}
543 | ```
544 |
545 | ### Loops inside twig
546 |
547 | Before we can loop over values inside our twig, we do need to create an array inside the controller that we pass to the view.
548 | ```ruby
549 | #[Route('/movie', name: 'movies')]
550 | public function index(): Response
551 | {
552 | $movies = [ 'Avengers: Endgame', 'Inception' , 'Loki', 'Black Widow'];
553 |
554 | return $this->render('index.html.twig', array(
555 | 'movies' => $movies
556 | ));
557 | }
558 | ```
559 |
560 | Adding ```{{ movies }}``` inside the view won’t work because you can’t print out an array as a string, so we got to make sure that we loop over our array values.
561 |
562 | ```ruby
563 | {% block body %}
564 | {% for movie in movies %}
565 |