Index.php: Best Strategies to design and implement routes in Slim?

Folks, my question is about how to design clean and readable files/classes to handle the routes. If you take a look at any example on the internet, the simplest way is to put many of the following into index.php :

$app->get("/pattern", function( $request, $response, $args){ //the whole code here } );

But that does not look clean to me. Imagine you have many routes, an API , middlewares and so on. Not to mention all configuration (errorHandlers and many other container settings).

I would like to know if some of you have designed something to solve this problem. My personal approach by now is:

index.php:

  • I’m coding all config in here (declare container variables for Twig, Monolog, Erro handling, not too much code)
  • include routes files, using the following strategy:
# index.php
// configs up here

/*
 * Routes
 */
//some "core" routes
require_once "routes.php";
//routes for auth like, /login, /logout and declare Middleware that have to do with authentication/authorization
require_once "routes-auth.php";
//routes I use from a PHP shell
require_once "routes-cli.php";
//I have not created one, but is intended to put all API routes here, maybe one file per version:
//routes-api_v1.php , routes-api_v2.php ...
require_once "routes-api.php";
//all other middlewares
require_once "routes-middleware.php";
//ends with:
$app->run();

But it is not enough for me. the next step I use is to implement the route cycle like these:

# some of the routes-xxxx.php looks like:
Route::get('/', 'Core\ctrl\CoreController:home')->setName('homePage');
Route::get('/hello[/{name}]', 'Core\ctrl\CoreController:sayHello')->setName('hello');
Route::get('/protected', 'Core\ctrl\CoreController:callProtectedResource')->setName('protected');
# I stactified the call based on https://github.com/silentworks/madmin-api , from Andrew Smith, a Slim developer. Looks cleaner to me.

# now the call is delegated to one of the Controllers . I divide controllers by subjects, so I do not have many functions in one class

# the Core\ctrl\CoreController.php :
public static function home(SlimHttpRequest $request, SlimHttpResponse $response, $args)
	{
		try {
			$cmd = new HomeCommand($request, $response, $args);
                        //the process() make it simple to reuse the same code by other function:
			$cmd->process();
                        //the same processed data could be easily transformed to be used by Twig or JSON ajax response
			$cmd->respondWithHtml();
		} catch (Exception $e) {
			throw $e;
		}
	}

# inside the HomeCommand.php 
class HomeCommand extends AbstractCommand {
	
	public function __construct(\Slim\Http\Request $request, \Slim\Http\Response $response, $args){
		parent::__construct ($request, $response, $args );
	}
	
	public function process() {
		$request  = new MobileRequest( $this->request );
		$isMobile = $request->isMobile();
		$this->data = array("isMobile" => $isMobile);

               
               // When necessary, Persistent Layer would be called from here.
                //I use Doctrine, so I would call the Entity Manager here:
                $em = DAO::em(); //my dao with doctrine configs
                $personsDAO = $em->getRepository("dao\Person")->findBy(array(), array("name" => "ASC" );
                $this->data = array("persons" => $personDAO); //now twig view can iterate over this list
                return $this;
	}
	
	public function respondWithJson() {
		// used to respond to Ajax calls with a JSON representation of the data
	}
	
	public function respondWithHtml() {
		return App::object()->getContainer()->view->render($this->response, 'home.html', $this->data);
	}
}

What do you think about this strategy? Any better ideas?

Thanks in advance,
using Slim since 2.1 release. Now migrated my projects to Slim 3.

I’ve come to use basically the same strategy you are using (ie: separate controller classes which implement their interface as needed). This works well for me and seems quite scaleable (from a codebase point of view).

If someone has a better idea, I’d be happy to hear it, but this is the best I’ve managed to come up with so far.

Thanks, @TheLobos .
By the way, https://github.com/domnikl/DesignPatternsPHP/ is a great resource for Design Patterns, but focused on PHP. I always take a look at it when planning something, like the one above.

Thanks @marcelbonnet for the link, looks very useful.

@marcelbonnet I’ve just recently come across the same concern and I pretty much set up my API similar to yours, however, mine is a bit simpler but requires a granular structure.

I’ve pretty much come up with dividing my API into services similar to this:

$api = $url[1];
$service = $url[2];

switch ($api) {
  case "blog":
    switch ($service) {
        case "posts":
	  // api/blog/posts/
	  require 'api/services/blog/posts.routes.php';
	  break;

	case "admin":
	  // api/blog/admin/
	  require 'api/service/blog/admin.routes.php';
	  break;
  }
  break;
}

In each routes file contains basically the $app->request route and goes from there. This way I can also make configurations based on the service rather than the route. So the admin service would have authentication before anything happens, along with post/put methods, while the posts routes would just have get methods. Since I’m just returning JSON and not views I don’t have to deal much with controllers, just database model classes extended from Eloquent to handle transactions and any heavy lifting that needs to be done.

@robrothedev, thanks for sharing your design! I would need more time to try it and comment my own impressions, but it looks interesting - marked here to remember later.