Compared to Zend, Symfony requires me to do a little more work to setup my first page. But those extra steps also give me a lot more power right off the bat. Today I'm just going to get a basic page setup that accepts the "name" parameter in the url and echoes it back out in the form "Hello {name}!". Simple, right? I hope.
I don't want to recreate the
Symfony documentation, but I need to outline my steps. In Zend, the default framework install always renders an HTML view. In Symfony, there is a way to use special annotations to accomplish this, but it is definitely optional. The
pro here is that I can specify exactly what Symfony should return with a little more clarity than in Zend. The
con is that I have to be sure to manually return something every time.
First, we need to define the route that we'll use for this page. When the front controller receives the request is looks at known routes and finds the first match. If it fails to find a match the user will see an error.
To create the new route I open up:
APP_PATH/src/Company/DemoBundle/Resources/routing.yml.
I want to start from scratch so I delete the existing contents of the file (Symfony created this when the bundle was generated). I enter the following route information:
company_demo_default_hello:
pattern: /hello/{name}
default: {_controller: CompanyDemoBundle:Default:hello }
The first line is the name of the route. I want to keep all my routes organized, so I use the pattern {COMPANY}_{BUNDLE}_{CLASS}_{CONTROLLER}. This may be overkill, but for now it works.
The second line is the pattern that we want to match. The brackets around "name" indicated that this is a value that symfony should expect. If the value isn't there then the route isn't matched and we'll get an error.
The third line sets the defaults for this route. Here we need to tell symfony which controller to run. The convention follows a familiar pattern: {BUNDLE}_{CLASS}_{CONTROLLER}.
Done. Our route will now point users to the hello controller, which I'm going to create now.
I open up ".../DemoBundle/Controller/Default". I remove the auto-created defaultAction function since I removed the route as well. From here I need to tell Symfony I want to use the Response object in my code. The Response object is the primary way of getting information back to the user. There are variants such as the RedirectResponse object, but all controllers will return a Response object of some kind. I add the following line just above my class declaration:
use Symfony\Component\HttpFoundation\Response;
and add my new action in the class:
public function helloAction()
{
return new Response('Hello!');
}
Let's test. Running localhost/APP_PATH/web/app_dev.php/hello/Bob displays "Hello!". Note that right now I haven't connected "Bob" to my action. However I must include "Bob" for the route to match.
Let's add the name now.
I just need to update my helloAction code to expect the name parameter:
public function helloAction($name)
{
return new Response('Hello ' . $name . '!');
}
There we go. Now navigating to the page I see "Hello Bob!". Changing the name to "John" gives me "Hello John!". Symfony automatically connects the {name} from the routing.yml file to the $name argument of the helloAction. What's really cool, is that Symfony doesn't care how many arguments or what order I put them in, it will match up my arguments by name so that I have them available in my controller.
Now we need to set a default. If I don't put a name in the URL, I need it to default to "Sam". So I open up my routing.yml one more time and update the defaults parameter:
defaults: { _controller: CompanyDemoBundle:Default:hello, name: "Sam" }
Now when I visit app_dev.php/hello I get "Hello Sam!".
Note that ".../app_dev.php/hello/" will not lead me here. The extra slash does not match the route. I want to look into this some more to better understand. But I can add an extra route with the pattern "/hello/" and direct it to the same controller as a workaround. The other option is using routing annotations, but I'm gonna save that for another day.