Introduction: Controllers in MVC and channel note
What's up developers and welcome back to a new video where we'll be diving into controllers and Symfony. Quick pause: do you want to support the channel and want me to continue on creating content? You can support the channel on Patreon right now where you get benefits like a private Discord group where you can share your coding issues and other developers will help you out. If you are interested to join the link will be in the description down below. In the MVC pattern controllers play a huge role since they are basically classes that organize a logic of one or more routes together in one place. You shouldn't see your controller as a place where you put all your application's logic but it's better to think of controllers as traffic cops that route HTTP requests around your application.
In order to create your controller in Symfony you need to define your configuration format first. In Symfony there are four options and one is actually quite old. You've got YAML, XML, PHP and the old one which are the annotations. Any of these options is a good option. Don't get me wrong, in my opinion you should choose one where you're the most comfortable with. If I could give my honest opinion, YAML is a bit difficult to read and annotations simplifies the process but that's because I'm used to it. Annotations also allow you to do the configuration directly inside the controller. So we need to pull it in through the CLI and I don't want to use an external client right now because I don't want to keep switching screens. So what we can do is to open the integrated terminal in Visual Studio Code: inside the top menu let's click on Terminal and let's click on New Terminal.
Installing annotations via Composer in the integrated terminal
All right, inside the terminal let's run: composer require annotations. This command will pull in everything we need in order to use annotations. Now it has been done so it's time to create our controller. Instead of creating the file ourselves we can use the CLI in order to make our first controller. So what we can do inside the CLI is basically saying: symfony console, then we're going to say what we want to do so we want to make something: a controller followed with the controller name. Let's say MoviesController. Now we're also adding the word Controller right here which is quite important to have. Now remember the name that we're adding right here so MoviesController will also be the name of our file but also the class name so don't forget to use PascalCase right here.
Maker command missing and installing maker with workaround
Developers on the internet have been arguing for many years if controllers should be singular or plural and honestly just choose something you're comfortable with. I'm comfortable with using plural but if you think it should be singular go ahead and call it MovieController; the logic will work in the same exact way. Now once we perform this command you will see that we finally got our first error message. Now if I make my terminal a little bit bigger you'll see that the error is saying that the make command has not been defined. Now we can double check that we can see which commands are available in Symfony by performing the symfony console command. Right here you'll see an entire list of commands and flags that we can perform. And I'm not going to cover all of them because there are quite a lot, but what I do want to test is the help command right here. So let's hit the arrow up to get our last console command and let's add a space: help. As you could see there is a list of options that we could add right here but there's one help command that we can perform which is the bin/console help list right here. I'm not going to go in depth on it otherwise we'll lose track of the actual video which we already did because we were talking about controllers. With Composer we need to make sure that we pull in maker in order to make commands. So let's do that: let's say composer require maker. Now as you could see we just ran into an error message. Now there is a package that needs to be installed in Symfony 8 that has not been updated with the PHP version that it needs to use. Now I found a workaround. Now what we can do is to open the composer.json and let's make it a little bit smaller. And right inside our require section let's require a package. Let's name it laminas/laminas-code:~4.5.0 and don't forget to end it up with a comma. Now what we can do is to save it and inside the terminal we can say composer install to update our composer.lock. All right that has been fixed. Now what we can do right now is to say composer require maker and what this will do is install the maker package. As you can see it has been fixed so let's create our controller one more time: let's say symfony console make:controller called MoviesController.
Generated controller file and file structure walkthrough
If we hit enter you can see that a new file has been created inside the src folder where there is a folder called Controller with a file name of MoviesController.php and down below you'll see a green box with a success message inside of it. Now let's open it. Let's open our src folder and let me make the terminal a little bit smaller. Controller folder and our MoviesController. You'll see a file structure right here that you will see a lot in Symfony files. Now it always starts off with a PHP opening tag followed with the namespace App\Controller. Now by default it has pulled in three use statements right here. These are and should always be defined at the top of our page below the namespace because they allow you to use these classes however you want. Now below our use statements we got the place where the real magic happens. We got a class right there called MoviesController which has and needs to be the same name as the file. It also extends the AbstractController that I just mentioned inside the use statement right here as the first use statement. And before we continue on let me actually show you why use statements should be placed at the top of our page. If we copy our statement of the AbstractController and remove it and paste it at the bottom of our page, save it, you will see that the AbstractController is getting an error right now because the AbstractController does not exist inside the use statement. Now the reason why is because we're defining it right after we're using it which cannot be done. So let me undo everything.
Routes as attributes, testing the JSON response, and legacy annotations
Then we're going inside our class. Well this line of code and this might be something that's new for you if you haven't used frameworks before and in particular a Symfony framework. What we're doing right here is called a Route as an attribute that defines the route for a particular method. It's called a Route method saying that whenever the /movies endpoint is being hit the index method right here will be returned to the browser. Now let's test it out; let's see if we're getting this JSON object back inside of the browser. Let's navigate to the browser. Let's change the endpoint to /movies. Our JSON response which was automatically added inside the controller class has been printed out right here. If we navigate back to Visual Studio Code and change our endpoint to let's say /movie, save it and navigate back to the browser, let's refresh it, you'll see that the endpoint does not exist so it has not been found because we obviously just said, well change the route of the public function index method to /movie. If we navigate back to Brave and change your endpoint to /movie you will see the same JSON object that has been printed out. If you're using an older PHP version or maybe even a better one in the future your annotations or attributes might look different than mine. Now this is a pretty new method when you want to define your route. Let me show you the old way just in case you're on the internet searching for issues that are not related to annotations or routes. So what we can do is to go right below our public function index and create a new method called public function let's say altMethod. We're going to add a colon right after the parentheses and we're going to say that this method needs to return a Response. Right now we can add our curly brace. All right. And this is actually a new method since PHP 7.1 and it's called a return type declaration. Our response will throw an error right now because we haven't defined a Response. Now we have added an extension in Visual Studio Code that will create DocBlocks for us. So let's do that: let's select our method, press Shift-Command-I and this will create a new block above our code as you could see right here which in your eyes might look like a comment but it's actually the annotations method. At the moment it's returning a Response, but what we can do is defining our route right here. So let's remove the return Response. Now let's say @Route parentheses. Now the Route method accepts two parameters: the first one is actually the endpoint and the second one is a name. So let's say double quotes; inside the double quotes let's say /alt. So let's go right outside of it and add a comma space name, let's set it equal to a value of a string and let's name it "old". Now what we can do next is to copy this return, this JSON object that we have inside our index method and paste it right inside the MoviesController. Instead of saying the message is "Welcome to our new controller" let's rename it to altMethod. Now let's save it. Let's navigate back to the browser. Let's change our endpoint to /alt and as you can see our response has been printed out with the response of altMethod. The old annotation method still works fine but in my opinion we should just stick with a new method rather than the old one. So let's get rid of the piece of code that we created. So right here let's remove this entire piece of code. All right. Now what is the logic behind all of this? Well that can be found inside the config folder where you have a routes folder followed with an annotations.yaml file. This file isn't actually an annotations file but the right word is actually a bundle. What this file will do is creating a route from the Controller folder right here based on our annotation. That being said this was it for this video where we created a new controller and went over the basics of it. If you do like my content and you want to see more leave this video a thumbs up and if you're new to this channel please hit the subscribe button.