Creating a simple web application using PHP and the Slim Framework.

Slim is a micro framework for PHP. I created a task application to help me learn about how Slim works. Its a pretty neat framework and it doesn’t take a lot to get started. I think its really great for building apis but you could use it for applications easily. To learn more about the Slim framework visit their website – https://www.slimframework.com/.

You can find my code on GitHub. You should be able to run the application after you have downloaded it with a few steps. The steps are outlined in the README.md documentation. To get it go to the link here https://github.com/wyntonfranklin/slim-tutorial.

The task application is pretty simple. It has a main page that lists all your task. You can view, edit and delete a task. The header (blue) as an input where you can quick create a task. The top menu allow you to create a task and go to the login page. User authentication and identity is not done as yet. I didn’t really find a solution that I was ok with but the login page is there.

Slim Application Structure

So the folder structure of a slim application is pretty straight forward.

Slim folder structure

Public Folder

The public folder is where you should point your application. It has the main index.php file that sets up the application. You can load your settings from here as well.

The Src Folder

The src folder has your dependencies, settings, routes and middleware. I put my controllers and classes in here as well. I just require them in the index.php file. You can autoload your own classes using composer apparently.

The Templates Folder

The templates folder has my twig templates. Your html and php templates files can go here. You have to tell the renderer which folder you are using though.

The Vendor Folder

The vendor folder is used by composer. That’s it basically. Not much here. Composer makes setting up your application easier.

Creating the Task Application

So the first step for me was creating the routes. Basically once your app is up and running you want to know about navigation. How to you get your app to display stuff. This is all handled in the routes.php file.

$app->get('/test', function (Request $request, Response $response, array $args) {
    $response->getBody()->write("Hello, World");
    return $response;
});

Above you can see a simple route. It is a get request and will only accept get requests. Once you navigate to this url you should see hello world output. This is pretty basic and helps your understand about routing. You can do a lot of things with routing. Notice the anonymous function and the args attribute. The args attribute has the parameters you want from your get requests.

$app->get('/', \ToDoController::class . ':home');

My Routes where a bit different because I went using a controller pattern instead. What the above does is call the function from the controller class given. In the controller you will have to supply the same arguments seen below.

  public function home($request, $response, $args)
    {
       $data = array();
       $this->view->render($response,'main.twig',$data);
        return $response;
    }

So we still have access to the request, response and args parameters so will can operate properly. Once you understand routing your are halfway there you can create as many routes as you please.

Dependencies

Dependencies is an important section. Basically to create a proper controller I had to pass dependencies to it. Dependencies are located in your dependencies.php.

To get access to the twig views I had add this section to my dependencies. Note that I first get the settings to get the template path. So you can change your template paths to suit.

$container['view'] = function ($c) {
    $settings = $c->get('settings');
    $view = new Slim\Views\Twig($settings['view']['template_path'], $settings['view']['twig']);
    // Add extensions
    $view->addExtension(new Slim\Views\TwigExtension($c->get('router'), $c->get('request')->getUri()));
    $view->addExtension(new Twig_Extension_Debug());
    return $view;
};

To add my database to my controller I added these lines of code. Again I added these values in settings and then I got them out of settings and created the PDO object.

$container['db'] = function ($c) {
    $db = $c['settings']['db'];
    $pdo = new PDO('mysql:host=' . $db['host'] . ';dbname=' . $db['dbname'],
        $db['user'], $db['password']);
    $pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
    $pdo->setAttribute(PDO::ATTR_DEFAULT_FETCH_MODE, PDO::FETCH_ASSOC);
    return $pdo;
};

My Controller Construct then requires these dependencies but as you realize in the routes I don’t add them there they are added “automatically”. Well not really but you don’t need to actually add them.

  public function __construct(\Slim\Views\Twig $view, PDO $db, \Slim\Flash\Messages $flash)
    {
       $this->view = $view;
       $this->db = $db;
       $this->flash = $flash;
    }

So in the dependencies file I now create my ToDoController and add it to the dependencies. Whenever this Controller is used the dependencies added here are added to the constructor so you don’t have to do it again.

$container['ToDoController'] = function($c) {
    $view = $c->get("view"); // retrieve the 'view' from the container
    $db = $c->get('db');
    $flash= $c->get("flash");
    return new ToDoController($view, $db, $flash);
};

I am adding three dependencies. The twigs view, the PDO called db and flash. This means I have access to these objects in my controller. This made it easier to render views, get access to the database and add flash messages.

The ToDoController

Alot if not all of my logic is done in the controller. I used the ToDo class as an object to store my task information from the database but that’s it. In a real world application things might not play out the same way.

 public function home($request, $response, $args)
    {
   $this->view->render($response,'main.twig',array());
        return $response;
    }

The setup is basic. To render a view you use the renderer from the slim twig view. It takes the response object, a template name and an array. Anything you put in the array you can access in the twig template. Twig is pretty cool templating engine for PHP. Its very easy to learn.

Post Request

So if you created a post route and you want to get back the data – the add function in the ToDoController is what creates a new task. This shows how to get POST data.

 public function add($request, $response, $args)
    {
        if($request->isPost()){
            $postValues = $request->getParsedBody();
            $name = $postValues["task"];
            $details = $postValues["details"];
            $author = $postValues["author"];
            $this->createTask($name, $details, $author);
            $this->addFlashMessage("success","Task Created");
            return $response->withRedirect('/',301);
        }
    }

The getParsedBody method from the request object gives you an array of the POST attributes. You can then use the response object to redirect. The other methods are private methods in the controller. Feel free to check out what they do.

GET Attributes

Check out the edit function from the controller. It takes the id from the url and loads the correct task object.

    public function edit($request, $response, $args)
    {
        $this->addData("pageTitle","Slim Todo - Edit Task");
        $task = $this->getTask($args['id']);
        $this->addData("todo", $task);
        $this->addData("successMessage",$this->getFlashMessage("success")[0]);
        $this->view->render($response,'edit.twig', $this->getData());
        return $response;
    }

Using the args attribute I can easily gain access to the id from the edit route. Once I get the id I can get the task using the getTask() method which is another private function in the controller.

The edit function uses a special type of route that hasn’t been seen before. Its basically just a placeholder for the attribute that would be passed in the request. This however ensures that only request in that format will be shown. The {id} is a placeholder for the id attribute. This requests requires that the url is /edit/1. Or whatever the value of the id is.

$app->get('/edit/{id}', \ToDoController::class . ':edit');

Ajax Requests

Ajax request are not any different than normal post or get response except that you can use the request object to check for xhr. The quickAdd() function demonstrates this. It checks for post data and xhr.

    public function quickAdd($request, $response, $args)
    {
        if($request->isPost() && $request->isXhr()) {
            $body = $request->getParsedBody();
            if(isset($body["task"])){
                $this->createTask($body["task"],$body["task"],"");
            }
        }else{
            return $response->write("You Shouldn't be here");
        }
    }

Database Functions – CRUD Operations

In order to get the tasks or to edit a task we need to access the database. Since our controller already has the PDO object we can easily query the database. Below we’ll implement the getTasks() function from the controller.

   private function getTasks()
    {
        $query = $this->db->query('SELECT * FROM slim_tasks');
        $results = $query->fetchAll(PDO::FETCH_ASSOC);
        $tasks = array();
        foreach ($results as $row){
            $tdo = new ToDo();
            $tasks[] = $tdo->create($row);
        }
        return $tasks;
    }

In the above code we’ll get the PDO object and query using a select statement. We then fetch the results and loop through them. We create a new ToDo object each time and add them to the tasks array. We then return the tasks array. Pretty simple. Pretty clean. The controller has similar functions to edit, update, delete tasks. Of course you can check them out.

Flash Messages

Flash messages can be created and retrieved via a few helper functions.

    private function addFlashMessage($key, $message)
    {
        $this->flash->addMessage($key, $message);
    }

    private function getFlashMessage($key)
    {
        return $this->flash->getMessage($key);
    }

For this to actually work apparently you need to do somethings like this cause the data is returned as an array even if its one value.

$this->getFlashMessage("success")[0]

In template file you can access check for attributes – well in twig – like below.

{% if successMessage is not empty %}
   <div class="alert alert-success" role="alert">
      {{ successMessage }}
   </div>
{% endif %}

The ToDo Model

The ToDo class holds the task information. The method of most value is the create method. It takes the data from a query and adds the attributes to the class. It then returns the updated object.

 public function create($row)
    {
        $this->task = $row["name"];
        $this->details = $row["details"];
        $this->author = $row["author"];
        $this->id = $row["task_id"];
        return $this;
    }

Well thats it. Slim is a pretty neat framework. Easy to setup. Easy to use. Check out some screenshots below.

2 thoughts on “Creating a simple web application using PHP and the Slim Framework.

  1. HEY, very well written, this is very useful for me I want to ask some queries.
    Which is better, PHP or Python? Why? Should I learn PHP in 2019? Is it still worth it? Why is PHP hated by so many developers? How can current development work?

    Like

    1. Which is better. Very subjective. However Python is a top language currently and you will be wise to have it in your tool box. PHP is great for quick web development. You can still learn it has it still ranks high in real ratings (not fan boy stats). PHP is hated because its in to hate PHP. It is also hated because programs built without frameworks in PHP are often not written correctly but work. Using a framework is necessary to avoid messy code but in PHP frameworks are highly optional. More complex reasons make it bad for mathematical tasks but its really great for CRUD apps. Learn both or pick one. Up to you bro. Languages exists for one reason to solve problems.

      Like

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s