amranich/ajax-router

Handle your AJAX requests efficiently

v1.0.7 2023-12-04 15:41 UTC

This package is auto-updated.

Last update: 2024-04-04 16:42:12 UTC


README

packagist tests License

Getting Started

composer require amranich/ajax-router

You can copy/paste this code snippet for a quick start.

We're using Guzzle PSR-7 interface implementation here, but you can use any other library you like as long as it implements the same interface.

<?php

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

use GuzzleHttp\Psr7\Request;
use GuzzleHttp\Psr7\Response;
use AmraniCh\AjaxRouter\Route;
use AmraniCh\AjaxRouter\Router;
use AmraniCh\AjaxRouter\Dispatcher;
use GuzzleHttp\Psr7\ServerRequest;
use Lazzard\Psr7ResponseSender\Sender;

try {
    $request = ServerRequest::fromGlobals();
    
    // the 'X-requested-with' header is commonly used to inform the server that a request 
    // is sent via the XMLHttpRequest object on the client-side, a lot of JavaScript libraries 
    // like jQuery already send this header automatically, this check can add a small security
    // layer to your app because HTTP headers can be spoofed very easily, so don't count on
    // only that check.
    if (!$request->hasHeader('X-requested-with') 
        || strtolower($request->getHeader('X-requested-with')[0]) !== 'XMLHttpRequest') {
        throw new BadRequestException("Accept only AJAX requests.");
    }
    
    // to organize your project, you can put your routes in a separate file like in an array
    // and require it in the second parameter of the router constructor.  
    $router = new Router($request, 'route', [
    
        // ?route=getPost&id=1005
        Route::get('getPost', function ($params) {
        
            // PSR7 responses are a little annoying to work with, you always have extra HTTP layers 
            // in your app that extend the base PSR7 response class, think of a class like JsonResponse, 
            // and in the constructor add the content-type header and pass it to the parent class.
            $response = new Response;

            $response->getBody()->write(json_encode([
                'id' => $params['id'],
                'title' => 'Best Places to Visit in Marrakech',
                'description' => 'Example of post description',
                'created_at' => '2022-02-27 03:00:05'
            ]));

            return $response->withHeader('Content-type', 'application/json');
        }),
    ]);

    $dispatcher = new Dispatcher($router);
    $dispatcher->dispatch();

} catch (Exception $ex) {
    $response = new Response(
        $ex->getCode() ?: 500,
        ['Content-type' => 'application/json'],
        json_encode(['message' => $ex->getMessage()])
    );

    $sender = new Sender;
    $sender($response);
}

Usage Tips

Route to controller/class method

If you like to put the business logic in a separate class or in a controller, you can route your requests to them like this :

Route::get('getPost', [PostController::class, 'getPost']);

Or :

Route::get('getPost', 'PostController@getPost');

// register the controller class or instance in the router
$router->registerControllers([
    PostController::class,
]);

If the controller/class has some dependencies that must be passed within the constructor, you can still instantiate the controller on yourself :

$router->registerControllers([
    new PostController($dependencyOne, $dependencyTwo)
]);

Catch route actions exceptions

I want to catch exceptions that only occurs from my routes actions, and not those thrown by the library or somewhere else, how I can do that ?

Answer :

$dispatcher->onException(function (\Exception $ex) {
    // $ex exception thrown by a route action
});

Get current route

You can access the current route object using the static method getCurrentRoute of the Route class.

$route = Router::getCurrentRoute();
$route->getName();
$route->getMethods();
$route->getValue();

Background

The idea of the library came to my mind a long time ago when I was mostly developing web applications using just plain PHP, some of these applications were performing a lot of AJAX requests into a single PHP file, that file can have a hundred lines of code that process these requests depending on a function/method name that sent along with the request, so I started to think of what I can do to improve the way that these requests are handled, and improve the code readability and maintainability.

Prizes

This package wins the PHP Innovation Award (February 2022) Issued by phpclasses.org

🏆 Prize : One elePHPant mascot. https://www.php.net/elephpant.php

📜 Certificate : https://amranich.dev/certs/phpclasses-february-2022-innovation-award.pdf

They support this project

68747470733a2f2f7265736f75726365732e6a6574627261696e732e636f6d2f73746f726167652f70726f64756374732f636f6d70616e792f6272616e642f6c6f676f732f6a625f7371756172652e706e67