Simple question about organising files


#1

Hi,

Sorry if the question looks dumb, I’m new to Slim. Just read the docs and wondered how you can have each request in a separate file without having to include all of them in the index.php file, where the router resides. Is there any way of parsing only the index.php and only the corresponding route on each single API call?

Thanks.


#2

This is actually no problem for PHP. The routes should also not have much influence on performance. I don’t want to sound rude, but can I ask what problem are you trying to solve?


#3

Thanks for replying odan.

In my mind the best way to organise the APIs is to have an “api” folder which would have an “index.php” file and several other PHP files, one for each entry point (i.e. “books.php”, “users.php”, “bikes.php”,… whatever).

So then the index.php file should look like this:

include(“books.php”);
include(“users.php”);
include(“bikes.php”);

$app = new \Slim\App;
$app->get(“/books", Books()); // in books.php
$app->get(“/users", Users()); // in users.php
$app->get(“/bikes", Bikes()); // in bikes.php
$app->run();

This approach would parse every single API endpoint in every API call, which is not ideal. My question is if there is any way to not having to include all the files in index.php. Or is that acceptable?


#4

Hello @djibarian,

You can use autoloading, so PHP will automatically look up a class definition without the need for include statements. Look up PSR-4 autoloading using composer for more information.

An example can be found in the Slim tutorial It defines where to look up class files in composer.json:

{
    // ... configuration not relevant to autoloading left out
    "autoload": {
        "psr-4": {
            "": "classes/"
        }
    }
}

The definition above defines that classes in the default namespace can be found in the classes/ folder. If you look in index.php, you will see:

// this line loads the autoload map generated with composer, which contains the definition above
require __DIR__ . '/../vendor/autoload.php';

// TicketMapper class is used, without including the file. It will be look up the classes folder
// as defined in composer.json
$mapper = new TicketMapper($this->db);

I recommend using namespaces instead of putting classes in the global namespace for a non-trivial project.


#5

My question is if there is any way to not having to include all the files in index.php.

Yes, just use the PSR-4 autoloader (via composer) and the Slim Container Resolution.

File: public/index.php

require_once __DIR__ . '/../vendor/autoload.php';

$app = new \Slim\App();
$app->get('/books', \App\Action\BooksIndexAction::class); // in src/Action/BooksIndexAction.php
$app->get('/users', \App\Action\UsersIndexAction::class); // in src/Action/UsersIndexAction.php
$app->get('/bikes', \App\Action\BikesIndexAction::class); // in src/Action/BikesIndexAction.php
$app->run();

File: src/Action/BooksIndexAction.php

<?php

namespace App\Action;

use Psr\Http\Message\ResponseInterface;
use Slim\Http\Request;
use Slim\Http\Response;

class BooksIndexAction
{
    public function __invoke(Request $request, Response $response, $args): ResponseInterface
    {
        $response->getBody()->write("Hello World");
        
        return $response;
    }
}

Add the namespace “App” into your composer.json and run composer update

 "autoload": {
    "psr-4": {
      "App\\": "src"
    }
  },

Personally, I prefer to use this approach with actions in order not to violate the SRP principle and to allow my IDE to find and refactor this classes.

You could also take a look at the Slim Skeleton project.


#6

Thank you very much @llvdl and @odan for the clear responses.