DEV Community

James Robb
James Robb

Posted on • Edited on

How to build a paginated blog using the DEV API

In the previous post in this series we discussed how we could setup a clean implementation for interactive with the DEV API.

In this post we will now use the DevPostFetcher class that we implemented during the previous post to build a simple paginated MVC application. For this we will be using PHP, Composer as our package manager and Flight-php as our router.

In the next post in this series we will refactor our code from a one page script to a proper MVC architecture.

Setting up

Initialise our project files

Let's create our initially required files by running the following in the terminal:

# Mac/Linux
touch .htaccess composer.json index.php

# Windows without WSL/GitBash installed
echo "" | tee .htaccess composer.json index.php
Enter fullscreen mode Exit fullscreen mode

.HTACCESS

Note: The .htaccess is an apache server configuration file, if you prefer NGINX or another alternative, feel free to use that. Also, if you are following along in another language such as node, you can just ignore this file too.

Let's setup our .htaccess file by adding the following content to it:

RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.*)$ index.php [QSA,L]
Enter fullscreen mode Exit fullscreen mode

This basically just says that if the request url is not an accessible file or directory, send the request to the index.php. Using QSA stands for "Query String Append" and tells the request that if any query parameters such as ?id=1 for example were passed in the original request, it should also send these parameters also to the index.php during the rewrite. The L flag stands for "Last" and tells the .htaccess to not use any other rewrite rules as this should be the last one processed.

Project dependencies

Currently we only have one project dependency required and that is Flight. To install Flight we will use the Composerpackage manager. This is a package manager for PHP just like NPM is for Node or Nuget is for .NET.

Firstly we need to install composer, to do this follow the composer installation instructions. Once this is done we can verify our installation by running composer -V in our terminal. If any errors occur, please refer back to the installation instructions.

To install Flight, all we need to do now is run:

composer require mikecao/flight
Enter fullscreen mode Exit fullscreen mode

The composer.json should look like this:

{
  "require": {
    "mikecao/flight": "^1.3"
  }
}
Enter fullscreen mode Exit fullscreen mode

You will also have noticed that a composer.lock file and a vendor directory have been generated. The lock file tells composer how your dependencies work together and at what versions. The vendor folder is where all your dependencies live and an autoloader is provided, we will use this soon to be able to use our project dependencies.

index.php

This is our applications entry point and where we will be working from now on. To get started, we should add the following to our index.php file:

<?php

require_once __DIR__ . "/vendor/autoload.php";
Enter fullscreen mode Exit fullscreen mode

This will require the autoload file generated when we required the Flight framework via Composer in the previous section. Now we are setup and ready to begin.

Routing

Flight is a really simple but powerful micro framework for routing, you can build simple APIs all the way to MVC applications once you know how it works should you wish. I personally use Flight if I work on PHP services since it has a small footprint and provides an enjoyable experience to use.

To begin, in our index.php we can add the following lines to register our first route:

use flight\Engine as Router;

$router = new Router();

$router->route("/", function(){
    echo "Hello world!";
});
Enter fullscreen mode Exit fullscreen mode

This will call the flight\Engine namespace from the autoload file and allow us to use it with the name Router. The $router variable is an instance of a new Router and we register a route using the route() function on that instance. In this case, it will simply echo back the message "Hello world!" to us when we load the homepage. We can test this by running the following in our terminal:

php -S localhost:8080
Enter fullscreen mode Exit fullscreen mode

This will run the built-in server from PHP itself on localhost:8080 and when we load that url, we can see our message: "Hello world!". Simple, right?

Posts routing

Now we understand the very basic usage of Flight we can begin building out our posts routes. In our index.php lets add a new /posts route:

$router->route("/posts", function() {
    $request = Flight::request();
    $devPosts = new DevPostFetcher("your_api_key");
    if(isset($request->query["page"])) {
        $page = (int) $request->query["page"];
        $page = $page !== 0 ? $page : 1;
        $devPosts->setPage($page);
    }
    $posts = $devPosts->fetch();
    print_r($posts);
});
Enter fullscreen mode Exit fullscreen mode

This registers the /posts route, uses the global request static method on the Flight constant afforded to us by the Flight library. Checks if there is a query parameter called page and if there is, cast it to an integer and if the integer casting comes back as 0, we know it wasn't a number set as the page parameter and thus we default to 1, otherwise we use the page number provided.

This won't work yet however as we don't currently have access to the DevPostFetcher class. To use this we should create another file in the project root called DevPostFetcher.php and paste in the DevPostFetcher class but I advise reading the previous article before continuing this post as it offers some insight into the workings of the class and also some information of issues with local development and SSL.

Once you have created the DevPostFetcher.php file and added the class into it, we just need to do one more thing and that is to require that file into our index.php, we can do this by adding the following below our previous require_once statement:

require_once __DIR__ . "/DevPostFetcher.php";
Enter fullscreen mode Exit fullscreen mode

Now go to localhost:8080/posts and you should see a JSON dump of your Dev.to posts appearing. If you have any authorisation or SSL errors, ensure you have set things up correctly as outlined in the previous post in this series.

Pagination

Pagination is now really simple since we just need to pass a query parameter calles page with a valid number, for example: /posts?page=3 which will return, by default, post number 20 up to 30. If no posts exist on page 3 however, for example if we only have 10 posts, ofcourse any page above page 1 by default won't return anything. In this case, we can do whatever we like from a redirect to /posts to show page 1 or we could show a special UI for this case or we can even just throw an error. For me, I will build a custom UI for this case and in the next section we will add a simple UI for our posts list.

Building the user interface

Flight makes rendering views a doddle. First we create a views directory and add a layout.php, no_posts.php and posts.php inside it.

In the layout.php add the following content:

<html>
  <head>
    <title><?php echo $page_title ?></title>
  </head>
  <body>
    <?php echo $body_content ?>
  </body>
</html>
Enter fullscreen mode Exit fullscreen mode

In the no_posts.php add the following content:

<p>No posts found!</p>
Enter fullscreen mode Exit fullscreen mode

Finally, in the posts.php add the following content:

<ul>
  <?php foreach($posts as $post): ?>
    <li>
      <a href="<?php echo $post['url']; ?>">
        <?php echo $post['title']; ?>
      </a>
    </li>
  <?php endforeach; ?>
</ul>
Enter fullscreen mode Exit fullscreen mode

Then we can change our /posts route to look like so:

$router->route("/posts", function() {
    $request = Flight::request();
    $devPosts = new DevPostFetcher("your_api_key");
    if(isset($request->query["page"])) {
        $page = (int) $request->query["page"];
        $page = $page !== 0 ? $page : 1;
        $devPosts->setPage($page);
    }
    $posts = $devPosts->fetch();

    if(count($posts) < 1) {
      Flight::render('no_posts', [], 'body_content');
    } else {
      Flight::render('posts', ['posts' => $posts], 'body_content');
    }

    Flight::render('layout', ['page_title' => "Posts"]);
});
Enter fullscreen mode Exit fullscreen mode

This will check if any posts were returned for the page requested and if there weren't any, we render the no_posts template into the body_content variable. If posts were returned, we render the posts template into the body_content variable. Either condition that is met to generate the body_content variable will be rendered into the layout file.

Conclusions

In this post we setup a very simple paginated blog using PHP, Composer and Flight. In the next post we will tidy up the codebase and refactor our setup to follow less of a "scratch pad" approach and use a more traditional MVC structure.

Top comments (0)