Creating the Repositories Component


In this video we are going to continue on with what we learned in the previous video regarding template layouts, passing variables to our templates, and organising our code in a way that helps avoid a big ball of tangled mess as our project grows.

To keep ourselves learning new things, even though conceptually what we are doing here is very similar to the profile / sidebar, in this video we will vary things up to keep things interesting.

Again, our real data will be coming from an API call to GitHub, e.g. GET https://api.github.com/users/codereviewvideos/repos, which returns something similar too:

[
  {
    "id": 43006190,
    "name": "ansible",
    "full_name": "codereviewvideos/ansible",
    "owner": {
      "login": "codereviewvideos",
      "id": 12968163,
      "avatar_url": "https://avatars.githubusercontent.com/u/12968163?v=3",
      "gravatar_id": "",
      "url": "https://api.github.com/users/codereviewvideos",
      "html_url": "https://github.com/codereviewvideos",
      "followers_url": "https://api.github.com/users/codereviewvideos/followers",
      "following_url": "https://api.github.com/users/codereviewvideos/following{/other_user}",
      "gists_url": "https://api.github.com/users/codereviewvideos/gists{/gist_id}",
      "starred_url": "https://api.github.com/users/codereviewvideos/starred{/owner}{/repo}",
      "subscriptions_url": "https://api.github.com/users/codereviewvideos/subscriptions",
      "organizations_url": "https://api.github.com/users/codereviewvideos/orgs",
      "repos_url": "https://api.github.com/users/codereviewvideos/repos",
      "events_url": "https://api.github.com/users/codereviewvideos/events{/privacy}",
      "received_events_url": "https://api.github.com/users/codereviewvideos/received_events",
      "type": "User",
      "site_admin": false
    },
    "private": false,
    "html_url": "https://github.com/codereviewvideos/ansible",
    "description": "",
    "fork": false,
    "url": "https://api.github.com/repos/codereviewvideos/ansible",

    ...

    "forks_count": 1,
    "mirror_url": null,
    "open_issues_count": 0,
    "forks": 1,
    "open_issues": 0,
    "watchers": 1,
    "default_branch": "master"
  },
  {
  ...
  }
]

I've shortened the output considerably here, as the specific contents are not really that important. Feel free to open up the URL yourself and take a look at the real output.

If you're not familiar with JSON, there is something that may not be immediately obvious when looking at this data, compared to the response from the GET https://api.github.com/users/codereviewvideos in the previous video.

Notice, on the very first line of the output there is a [. This is exactly the same as in PHP from version 5.4 onwards (short hand array syntax) - it means the result / data is an array.

This makes sense as we only have one user profile, but we - potentially - have many repositories.

Notice also, on the next line is the { bracket, which represents the starting of an Object. And after all the data, a closing backet - }, followed by another object. And so on.

So, putting this together, we can see here that the call to /users/codereviewvideos returned a single object containing our data. And now we can see that a call to /users/codereviewvideos/repos returns an array containing zero or more objects. After all, your profile may not have any repositories.

Our json_decode statement won't change, but this time we will get back an array containing zero or more arrays, one per repository.

Just like last time, we are going to re-arrange the returned data to better suit our needs.

Template

Let's start by creating a simple template structure to contain our repository data:

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

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

{% block body %}
    <div class="col-sm-3">
        {% include :githut:profile.html.twig' %}
    </div>

    <div class="col-sm-9">
        {% include :githut:repos.html.twig' %}
    </div>
{% endblock %}

The repos template (plural) contains the wrapper / container that will contain the individual repository information:

<!-- app/Resources/views/githut/repos.html.twig -->

<div class="row">
    <div class="col-sm-12">

        <div class="well">

            Important Stats

            <div class="pull-right">
                <span class="label label-primary">Repositories: {{ repo_count }}</span>
                <span class="label label-success">Most Stars: {{ most_stars }}</span>
            </div>

        </div>

        <div class="panel panel-default">
            <div class="panel-heading">
                <h3 class="panel-title">Repo List</h3>
            </div>

            <ul class="list-group">
                {% for repo in repos %}
                <li class="list-group-item">{% include ':githut:repo.html.twig' %}</li>
                {% endfor %}
            </ul>
        </div>

    </div>
</div>

And then again, extracting out the individual repo into its own template:

<!-- app/Resources/views/githut/repo.html.twig -->

<a href="{{ repo.url }}">{{ repo.name }}</a>
<br />
<span class="small">{{ repo.description }}</span>
<span class="pull-right">
    {{ repo.stargazers_count }} <i class="glyphicon glyphicon-star"></i>
</span>

Please watch the video if you don't understand how we got to the above, as this is explained in more detail.

Controller Update

In the very next video we are going to make this data dynamic - hoorah, no more manual array hacking.

However, it is really important that you understand how this is done on a manual basis, if you are to understand how this happens when the data is dynamic. The point being that in the vast majority of real world cases, we are not going to sit and hand craft an array for every template. But the dynamic data will simply be the same 'shape' as the manual data we have created.

Let's continue fleshing out the controller action from the previous video:

    /**
     * @Route("/", name="githut")
     */
    public function githutAction(Request $request)
    {
        $templateData = [
            'avatar_url'  => 'https://avatars.githubusercontent.com/u/12968163?v=3',
            'name'        => 'Code Review Videos',
            'login'       => 'codereviewvideos',
            'details'     => [
                'company'   => 'Code Review Videos',
                'location'  => 'Preston, Lancs, UK',
                'joined_on' => 'Joined on Fake Date For Now',
            ],
            'blog'        => 'https://codereviewvideos.com/,
            'social_data' => [
                'followers'    => 11,
                'following'    => 22,
                'public_repos' => 33,
            ],
            // new data here
            'repo_count' => 100,
            'most_stars' => 50,
            'repos' => [
                [
                    'url' => 'https://codereviewvideos.com',
                    'name' => 'Code Review Videos',
                    'description' => 'some repo description',
                    'stargazers_count' => '999',
                ],
                [
                    'url' => 'http://bbc.co.uk',
                    'name' => 'The BBC',
                    'description' => 'not a real repo',
                    'stargazers_count' => '666',
                ],
                [
                    'url' => 'http://google.co.uk',
                    'name' => 'Google',
                    'description' => 'another fake repo description',
                    'stargazers_count' => '333',
                ],
            ],
        ];

        return $this->render('githut/index.html.twig', templateData);
    }

As mentioned earlier, our repositories array contains sub arrays that individually contain the relevant information for one repository.

Working with these sub-arrays is what gives us access to the dot notation syntax in the repo.html.twig template. Again, if unsure, watch the video where this is explained further.

One thing you may have noticed is that the most_stars field is not something that is on the GitHub API response. This is fine, we will create the logic for this field by working out which of our repositories has the most stars. It's a little nerdy, but it's fun.

And with all the pieces in order to display data, we can now concentrate on refactoring to a dynamic version of our site using Guzzle to talk to GitHub's API, pulling back real data, and removing the need for us to exercise our copy / paste skills.

Code For This Course

Get the code for this course.

Episodes