10.

Generating URLs

Share this awesome video!

|

Most of these links don't go anywhere yet. Whatever! No problem! We're going to fill them in as we continue. Besides, most of our users will be in hypersleep for at least a few more decades.

But we can hook up some of these - like the "Space Bar" logo text - that should go to the homepage.

Open templates/base.html.twig and search for "The Space Bar":

69 lines | templates/base.html.twig
<!doctype html>
<html lang="en">
// ... lines 3 - 15
<body>
<nav class="navbar navbar-expand-lg navbar-dark navbar-bg mb-5">
<a style="margin-left: 75px;" class="navbar-brand space-brand" href="#">The Space Bar</a>
// ... lines 19 - 47
</nav>
// ... lines 49 - 66
</body>
</html>

Ok - let's point this link to the homepage. And yep, we could just say href="/".

But... there's a better way. Instead, we're going to generate a URL to the route. Yep, we're going to ask Symfony to give us the URL to the route that's above our homepage action:

36 lines | src/Controller/ArticleController.php
// ... lines 1 - 8
class ArticleController extends AbstractController
{
/**
* @Route("/")
*/
public function homepage()
{
// ... line 16
}
// ... lines 18 - 34
}

Why? Because if we ever decided to change this route's URL - like to /news - if we generate the URL instead of hardcoding it, all the links will automatically update. Magic!

The Famous debug:router

So how can we do this? First, find your terminal and run:

./bin/console debug:router

This is an awesome little tool that shows you a list of all of the routes in your app. You can see our two routes and a bunch of routes that help the profiler and web debug toolbar.

There's one thing about routes that we haven't really talked about yet: each route has an internal name. This is never shown to the user, it only exists so that we can refer to that route in our code. For annotation routes, by default, that name is created for us.

Generating URLs with path()

This means, to generate a URL to the homepage, copy the route name, go back to base.html.twig, add {{ path() }} and paste the route name:

69 lines | templates/base.html.twig
<!doctype html>
<html lang="en">
// ... lines 3 - 15
<body>
<nav class="navbar navbar-expand-lg navbar-dark navbar-bg mb-5">
<a style="margin-left: 75px;" class="navbar-brand space-brand" href="{{ path('app_article_homepage') }}">The Space Bar</a>
// ... lines 19 - 47
</nav>
// ... lines 49 - 66
</body>
</html>

That's it!

Refresh! Click it! Yes! We're back on the homepage.

But... actually I don't like to rely on auto-created route names because they could change if we renamed certain parts of our code. Instead, as soon as I want to generate a URL to a route, I add a name option: name="app_homepage":

36 lines | src/Controller/ArticleController.php
// ... lines 1 - 8
class ArticleController extends AbstractController
{
/**
* @Route("/", name="app_homepage")
*/
public function homepage()
{
// ... line 16
}
// ... lines 18 - 34
}

Run debug:router again:

./bin/console debug:router

The only thing that changed is the name of the route. Now go back to base.html.twig and use the new route name here:

69 lines | templates/base.html.twig
<!doctype html>
<html lang="en">
// ... lines 3 - 15
<body>
<nav class="navbar navbar-expand-lg navbar-dark navbar-bg mb-5">
<a style="margin-left: 75px;" class="navbar-brand space-brand" href="{{ path('app_homepage') }}">The Space Bar</a>
// ... lines 19 - 47
</nav>
// ... lines 49 - 66
</body>
</html>

It still works exactly like before, but we're in complete control of the route name.

Making the Homepage Pretty

We now have a link to our homepage... but I don't know why you'd want to go here: it's super ugly! So let's render a template. In ArticleController, instead of returning a Response, return $this->render() with article/homepage.html.twig:

36 lines | src/Controller/ArticleController.php
// ... lines 1 - 8
class ArticleController extends AbstractController
{
/**
* @Route("/", name="app_homepage")
*/
public function homepage()
{
return $this->render('article/homepage.html.twig');
}
// ... lines 18 - 34
}

For now, don't pass any variables to the template.

This template does not exist yet. But if you look again in the tutorial/ directory from the code download, I've created a homepage template for us. Sweet! Copy that and paste it into templates/article:

{% extends 'base.html.twig' %}
{% block body %}
<div class="container">
<div class="row">
<!-- Article List -->
<div class="col-sm-12 col-md-8">
<!-- H1 Article -->
<a class="main-article-link" href="#">
<div class="main-article mb-5 pb-3">
<img src="{{ asset('images/meteor-shower.jpg') }}" alt="meteor shower">
<h1 class="text-center mt-2">Ursid Meteor Shower: <br>Healthier than a regular shower?</h1>
</div>
</a>
<!-- Supporting Articles -->
<div class="article-container my-1">
<a href="#">
<img class="article-img" src="{{ asset('images/asteroid.jpeg') }}">
<div class="article-title d-inline-block pl-3 align-middle">
<span>Why do Asteroids Taste Like Bacon?</span>
<br>
<span class="align-left article-details"><img class="article-author-img rounded-circle" src="{{ asset('images/alien-profile.png') }}"> Mike Ferengi </span>
<span class="pl-5 article-details float-right"> 3 hours ago</span>
</div>
</a>
</div>
<div class="article-container my-1">
<a href="#">
<img class="article-img" src="{{ asset('images/mercury.jpeg') }}">
<div class="article-title d-inline-block pl-3 align-middle">
<span>Life on Planet Mercury: <br> Tan, Relaxing and Fabulous</span>
<br>
<span class="align-left article-details"><img class="article-author-img rounded-circle" src="{{ asset('images/astronaut-profile.png') }}"> Amy Oort </span>
<span class="pl-5 article-details float-right"> 6 days ago</span>
</div>
</a>
</div>
<div class="article-container my-1">
<a href="#">
<img class="article-img" src="{{ asset('images/lightspeed.png') }}">
<div class="article-title d-inline-block pl-3 align-middle">
<span>Light Speed Travel: <br> Fountain of Youth or Fallacy</span>
<br>
<span class="align-left article-details"><img class="article-author-img rounded-circle" src="{{ asset('images/astronaut-profile.png') }}"> Amy Oort </span>
<span class="pl-5 article-details float-right"> 2 weeks ago</span>
</div>
</a>
</div>
</div>
<!-- Right bar ad space -->
<div class="col-sm-12 col-md-4 text-center">
<div class="ad-space mx-auto mt-1 pb-2 pt-2">
<img class="advertisement-img" src="{{ asset('images/space-ice.png') }}">
<p><span class="advertisement-text">New:</span> Space Ice Cream!</p>
<button class="btn btn-info">Buy Now!</button>
</div>
<div class="quote-space pb-2 pt-2 px-5">
<h3 class="text-center pb-3">Trending Quotes</h3>
<p><i class="fa fa-comment"></i> "Our two greatest problems are gravity and paperwork. We can lick gravity, but sometimes the paperwork is overwhelming." <br><a href="https://en.wikipedia.org/wiki/Wernher_von_Braun">Wernher von Braun, Rocket Engineer</a></p>
<p class="pt-4"><i class="fa fa-comment"></i> "Let's face it, space is a risky business. I always considered every launch a barely controlled explosion." <br><a href="https://en.wikipedia.org/wiki/Aaron_Cohen_(Deputy_NASA_administrator)">Aaron Cohen, NASA Administrator</a></p>
<p class="pt-4"><i class="fa fa-comment"></i> "If offered a seat on a rocket ship, don't ask what seat. Just get on."<br><a href="https://en.wikipedia.org/wiki/Christa_McAuliffe">Christa McAuliffe, Challenger Astronaut</a>
</div>
</div>
</div>
</div>
{% endblock %}

It's nothing special: just a bunch of hardcoded information and fascinating space articles. It does make for a pretty cool-looking homepage. And yea, we'll make this all dynamic once we have a database.

Generating a URL with a {wildcard}

One of the hardcoded articles is the one we've been playing with: Why Asteroids Taste like Bacon! The link doesn't go anywhere yet, so let's fix that by generating a URL to our article show page!

Step 1: now that we want to link to this route, give it a name: article_show:

36 lines | src/Controller/ArticleController.php
// ... lines 1 - 8
class ArticleController extends AbstractController
{
// ... lines 11 - 18
/**
* @Route("/news/{slug}", name="article_show")
*/
public function show($slug)
{
// ... lines 24 - 33
}
}

Step 2: inside homepage.html.twig, find the article... and... for the href, use {{ path('article_show') }}:

81 lines | templates/article/homepage.html.twig
// ... lines 1 - 2
{% block body %}
<div class="container">
<div class="row">
<!-- Article List -->
<div class="col-sm-12 col-md-8">
// ... lines 10 - 18
<!-- Supporting Articles -->
<div class="article-container my-1">
<a href="{{ path('article_show') }}">
// ... lines 23 - 29
</a>
</div>
// ... lines 32 - 56
</div>
// ... lines 58 - 77
</div>
</div>
{% endblock %}

That should work... right? Refresh! No! It's a huge, horrible, error!

Some mandatory parameters are missing - {slug} - to generate a URL for article_show.

That totally makes sense! This route has a wildcard... so we can't just generate a URL to it. Nope, we need to also tell Symfony what value it should use for the {slug} part.

How? Add a second argument to path(): {}. That's the syntax for an associative array when you're inside Twig - it's similar to JavaScript. Give this a slug key set to why-asteroids-taste-like-bacon:

81 lines | templates/article/homepage.html.twig
// ... lines 1 - 2
{% block body %}
<div class="container">
<div class="row">
<!-- Article List -->
<div class="col-sm-12 col-md-8">
// ... lines 10 - 18
<!-- Supporting Articles -->
<div class="article-container my-1">
<a href="{{ path('article_show', {slug: 'why-asteroids-taste-like-bacon'}) }}">
// ... lines 23 - 29
</a>
</div>
// ... lines 32 - 56
</div>
// ... lines 58 - 77
</div>
</div>
{% endblock %}

Try it - refresh! Error gone! And check this out: the link goes to our show page.

Next, let's add some JavaScript and an API endpoint to bring this little heart icon to life!