In this video we make a start on the implementation of our wallpaper / desktop background website. This is a gentle introduction, primarily involved with:

  • downloading Symfony
  • setting up Bootstrap and some basic styles
  • creating our Gallery controller
  • creating the Gallery view / TWig template
  • displaying some content in the gallery

Rather than dive in and start setting up Doctrine entities and creating fixtures and all that jazz, we are going to start with the simple stuff, and work our way up.

With this in mind, we are going to start with a single image that we can find via Google image search (or wherever), and then use this image in a 'hardcoded' fashion. This is good enough to prove our basic setup works, gives us a quick and easy win, and also forms the basis for making the whole thing dynamic.

Before we can do any of this, we need to download Symfony.

As has been mentioned in the introduction to this course, I'm not going to go into as much depth with concepts that we have already covered before. Installing Symfony was covered in this video, so I'm going to assume you either know how to do this, or ask that you please view this video first.

In my case, I'm going to have my project be called "wallpaper" - so imaginative am I - and as we are on Symfony v3.2.8 at the time of recording, my output looks like this:

➜ ~/Development symfony wallpaper

 Downloading Symfony...

        5.5 MiB/5.5 MiB ▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓  100%

 Preparing project...

 ✔  Symfony 3.2.8 was successfully installed. Now you can:

    * Change your current directory to /home/chris/Development/wallpaper

    * Configure your application in app/config/parameters.yml file.

    * Run your application:
        1. Execute the php bin/console server:start command.
        2. Browse to the http://localhost:8000 URL.

    * Read the documentation at http://symfony.com/doc

I will then cd (change directory) into the wallpaper directory and immediately do a composer update. It's surprising how many of the dependencies will have some new patches to apply.

cd wallpaper
composer update

With the project downloaded and updated, I would then follow the instructions further and ensure to start up the local webserver:

php bin/console server:start

At this point a URL - http://localhost:8000 should be visible in your terminal, clicking on which should take you to a browser showing the basic Symfony start point.

Make sure to open the project in your editor / IDE of choice here.

Next, we need to make some initial tweaks to the templates that Symfony provides. We're going to add in Bootstrap's CSS files via the CDN links provided on getbootstrap.com, and our own CSS file for any overrides / local tweaks we want to add in:

<!DOCTYPE html>
<!-- /app/Resources/views/base.html.twig -->
<html>
    <head>
        <meta charset="UTF-8" />
        <title>{% block title %}Welcome!{% endblock %}</title>
        <!-- Latest compiled and minified CSS -->
        <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" 
              integrity="sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u" 
              crossorigin="anonymous">
        <link rel="stylesheet" href="{{ asset('css/styles.css')" />
        {% block stylesheets %}{% endblock %}
        <link rel="icon" type="image/x-icon" href="{{ asset('favicon.ico') }}" />
    </head>
    <body>
        {% block body %}{% endblock %}
        {% block javascripts %}{% endblock %}
    </body>
</html>

As you can see, we've added in the entry from getbootstrap.com, and also an entry that we've passed as a parameter to the asset function. Our publicly accessibly path will be our web directory, so our next step is to create a new directory inside the web directory, into which we need to add a single file - styles.css.

You are free to skip this step, of course.

cd web
mkdir css
touch css/styles.css
cd ..

Feel free to do this via your editor, via a file explorer, or the console. There's no difference.

We don't need to add any entries into the css/styles.css file right now, but it gets that task out of the way all the same. One thing to note here, there is reasoning for the way in which the styles are listed inside the head tag.

First comes the Bootstrap CSS. This is the most generic stylesheet that we are applying to this project.

Next comes our custom styles.css file. Any changes we make in here will take precedence over any CSS defined in the Bootstrap sheet. In other words, if we had .img inside the Bootstrap stylesheet, and we declared .img again inside our styles.css file, then ours would "win" when it came time to display.

Lastly we have the inclusion of {% block stylesheets %}{% endblock %}. Now, I'd recommend you don't use this. Stick with the styles.css file. But it's there because you may wish to use it, or as I infrequently do, use it for debugging. Honestly though, you could get rid of this.

Adding a Wallpaper

To as quickly as possible make things that bit more interesting, we're now going to add in a basic gallery layout.

We don't need to worry about creating the image upload capability just yet. Instead, we're going to do this manually, and then use some hardcoded data to display one (or several) images on the page.

The nice thing about this is not only does it provide a very quick proof of concept, but it also is very similar to how our site will work once we involve images coming from the database.

First up, we are going to need a picture.

If you have a selection of wallpapers already then cool, feel free to use one of those.

If you don't then head over to Google Images, and use some generic term - "summer", "winter", "autumn", "cars" - that sort of thing to find an image to use. You could also use the images from the code repository for this project.

Once inside Google Image search you can click "Tools" then in the pop up menu, select "Size" and put in some exact dimensions to get just those that meet your requirements. For the purposes of my demo, I chose to use 1920x1080, aka 1080p, as I thought this was a popular resolution. It turns out that 1366x768 is by far the most popular resolution used on modern desktop computers (at the time of writing), so if you plan to put this site live then factor this in to your downloading.

One other thing to note: if you are going to put your site online then be sure to filter images by those that are allowed for reuse.

If all of that seems like to much hard work then feel free to use the one I used in the video.

The important part here is not the image that you use, but rather than location in which you save it.

Save the image inside your projects web directory. It doesn't matter too much where inside this directory that this file goes, but in my case I'm putting this under web/images/my-image-file-name.jpg. The reason we must put the image inside (or some subfolder of) the web directory is that this is our web root. In other words, this directory will be publicly accessible - and we want our users to be able to see our images. You can read a little more about this on the official Symfony docs.

Gallery Controller

To actually see this image on our site we must start writing a little code. Hoorah, finally!

I'm going to start by renaming the provided DefaultController.php file to GalleryController.php, and I'm going to change the contents accordingly:

<?php

// /src/AppBundle/Controller/GalleryController.php

namespace AppBundle\Controller;

use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;

class GalleryController extends Controller
{
    /**
     * @Route("/gallery", name="gallery")
     */
    public function indexAction()
    {
        return $this->render('gallery/index.html.twig', [
            'images' => [
                'summer-morning-in-fort-collins.jpg',
            ]
        ]);
    }
}

If any of this is new to you then I would again point you towards this video where we have covered basic controller actions in more detail.

Essentially we have a Route annotation that makes the /gallery route available on our website.

When we load the /gallery route this indexAction will be called.

This in turn will return the output of rendering our gallery/index.html.twig file. This file does not yet exist. We will create it momentarily.

Inside this template we will expect to have access to an array, in which there will be a key called images. This key of images will be expected to contain an array of strings, each one representing an image filename.

Ok, so it's not the most robust system, but it should be good enough.

Let's look at the template:

<!-- /app/Resources/views/gallery/index.html.twig -->

{% extends 'base.html.twig' %}


{% block body %}

    <div class="row">
        {% for image in images %}
        <div class="col-sm-6 col-md-4">
            <a href="#" class="thumbnail">
                <img src="/images/{{ image }}" alt="...">
            </a>
        </div>
        {% endfor %}
    </div>

{% endblock %}

We can see a for loop that will loop through all the images that we passed in from the controller. Each image (singular) will be an element from the images (plural) array. In our case that means each image will be a string - summer-morning-in-fort-collins.jpg.

When we expand on this a little later on, we will work with objects, but the general principles are the same.

Here we're saying that for every element in our images array we want to render the markup inside the {% for ... %} block:

<div class="col-sm-6 col-md-4">
    <a href="#" class="thumbnail">
        <img src="/images/{{ image }}" alt="...">
    </a>
</div>

In other words, each element will get put in a div that contains an img wrapped in a link. For now the link doesn't really work (href="#") but we will fix this as we continue on.

The image itself will expect to be found by looking in the web root - in other words our web directory, then inside the images directory, and whatever string we gave (in full, including the extension) should be the file name.

Providing you gave the right file name when adding your entry to the images array inside the controller, and that the path is correct (e.g. web/images/) then you should be able to visit your /gallery page and see a 'thumbnail' of your picture.

One thing to note here is that this isn't really a thumbnail. It's the full size image that Bootstrap has shrunk nicely for us. This is important as it means we're still really loading the huge full size image. We will need to address this problem as we go through the project, as otherwise, we will not only burn more bandwidth than we need too, but more importantly the UX will be awful for those on slow connections.

And that pretty much gets us where we need to be for the moment. In the next video we will add in pagination, still keeping our setup as simple as possible. The cool thing is we can switch from using arrays to database-backed objects without much change here, so we aren't doing a bunch of work for nothing. Which is nice :)


Code For This Course

Get the code for this course.

Code For This Episode

Get the code for this episode.

Share This Episode

If you have found this video helpful, please consider sharing. I really appreciate it.


Episodes in this series

# Title Duration
1 Introduction and Site Demo 02:14
2 Setup and a Basic Wallpaper Gallery 08:43
3 Pagination 08:24
4 Adding a Detail View 04:47
5 Creating a Home Page 11:14
6 Creating our Wallpaper Entity 07:50
7 Wallpaper Setup Command - Part 1 - Symfony Commands As a Service 05:56
8 Wallpaper Setup Command - Part 2 - Injection Is Easy 08:53
9 Wallpaper Setup Command - Part 3 - Doing It With Style 05:37
10 Doctrine Fixtures - Part 1 - Setup and Category Entity Creation 08:52
11 Doctrine Fixtures - Part 2 - Relating Wallpapers with Categories 05:56
12 EasyAdminBundle - Setup and Category Configuration 06:02
13 EasyAdminBundle - Wallpaper Setup and List View 07:46
14 EasyAdminBundle - Starting with Wallpaper Uploads 05:57
15 Testing with PhpSpec to Guide Our Implementation 03:39
16 Using PhpSpec to Test our FileMover 05:34
17 Symfony Dependency Testing with PhpSpec 08:47
18 Defensive Counter Measures 06:32
19 No Tests - Part 1 - Uploading Files in EasyAdminBundle 11:02
20 No Tests - Part 2 - Uploading Files in EasyAdminBundle 07:05
21 Don't Mock What You Don't Own 09:36
22 You've Got To Take The Power Back 07:36
23 Making Symfony Work For Us 08:56
24 Testing The Wallpaper File Path Helper 15:11
25 Finally, It Works! 14:56
26 Why I Prefer Not To Use Twig 16:50
27 Fixing The Fixtures 11:20
28 Untested Updates 14:30
29 Untested Updates Part Two - Now We Can Actually Update 06:33
30 Adding an Image Preview On Edit 12:31
31 Delete Should Remove The Wallpaper Image File 11:02
32 Getting Started Testing Wallpaper Updates 10:02
33 Doing The Little Before The Big 08:13
34 Tested Image Preview... Sort Of :) 07:36
35 Finishing Up With a Tested Wallpaper Update 10:44
36 Test Driven Wallpaper Delete - Part 1 11:11
37 Test Driven Wallpaper Delete - Part 2 11:57
38 EasyAdminBundle Login Form Tutorial 08:01