روز برنامه‌نویس مبارک 🤩🎉 از هدایای روز برنامه‌نویس جا نمونی ⌛
۰ ثانیه
۰ دقیقه
۰ ساعت
۰ علی طباطبایی
تمرین پیاده سازی global middlewares
جامعه پی اچ پی ایجاد شده در ۰۶ بهمن ۱۴۰۰

خب من در شروع کار اول اومدم یک دایرکتوری به نام Global درون دایرکتوری Middlewares ایجاد کردم که این دایرکتوری حاوی تمام کلاس‌های گلوبال middleware ای هست که قراره نوشته بشن و در دایرکتوری Middlewares نیز یک فایل ایجاد کردم به نام GlobalMiddleWares.php که درون این فایل یک کلاس هست که میتوان با استفاده از متد get درون آن لیستی از نام کلاس تمامی گلوبال middleware‌ها داشت.

درون دایرکتوری Global یک فایل با نام blockChrome.php ایجاد کردم که میاد برای تمامی مسیر‌های تعریف شده مرورگر کروم رو میبنده.

دایرکتوری ها :

83aa-Screenshot (934).png

فایل GlobalMiddleWares.php :

 
namespace App\\Middlewares;
use App\\Middlewares\\Global\\blockChrome;
class GlobalMiddlewares
{
    private array|null $globals = [
        blockChrome::class,
    ];
    public function get():array|null
    {
        return $this->globals;
    }
}

فایل blockChrome.php :‌

 
namespace App\\Middlewares\\Global;
use App\\Middlewares\\contract\\MiddlewareInterface;
use hisorange\\BrowserDetect\\Parser as Browser;
class blockChrome implements MiddlewareInterface
{
    public function handle()
    {
        if(Browser::isChrome())
            die("chrome is not supported");
    }
}

در کلاس Route به تمامی مسیر هایی که ایجاد می‌شوند یک پارامتر ۴ ام پیش فرض در حین ساختشون اختصاص داده میشه که لیست تمامی میدل ور‌های گلوبال را در بر میگیرند .

 
namespace App\\Core\\Routing;
use Exception;
use App\\Middlewares\\GlobalMiddleWares;
class Route
{
    private const VERBS  = array('get', 'post', 'put' ,"update","delete");
    private static array $routes = [];
    
    #------------------------------
    public static function add(array|string $method ,string $uri , $action = null , array|null $middleware = []):void
    {
        $method = (is_array($method)) ? $method : [$method];
        $globalMiddlewares = new GlobalMiddlewares();
        $globalMiddlewaresList =  $globalMiddlewares->get();
        self::$routes[] = ["method" => $method, "uri" => $uri , "action" => $action , "middleware" => $middleware , "globalMiddlewares" => $globalMiddlewaresList ?? null];
    }
    #-------------------------------
    public static function __callStatic(string $name, array $arguments):void
    {   
        if(!in_array($name,self::VERBS))
            throw new Exception("method not supported !");
        [$uri , $action , $middleware ] = [$arguments[0] , $arguments[1] ?? null , $arguments[2] ?? null, ];
        self::add($name, $uri, $action , $middleware);
    }
    #-------------------------------
    public static function routes():array
    {
        return self::$routes;
    }
    #------------------------------
}

کلاس Router

 
namespace App\\Core\\Routing;
use Exception;
use App\\Core\\Request;
use App\\Utilities\\Url;
use App\\Core\\Routing\\Route;
use App\\Middlewares\\GlobalMiddleWares;
class Router 
{
    const BASE_CONTROLLER = "App\\Controllers\\\\";
    private object $request;
    private array|null $routes;
    private array|null $currentRoute;
    public function __construct()
     {
        $this->request = new Request();
        $this->routes = Route::routes();
        $this->currentRoute = $this->findRoute($this->request);
        #run globall middleware
        $this->run_global_middlewares($this->currentRoute);
        #run Middlewares
        $this->run_route_middlewares($this->currentRoute);
    }
    #------------------------------
    private function doesItHaveGlobalMiddlewares(array|null $route):bool
    {
        if(is_null($route) || is_null($route["globalMiddlewares"]))
            return false;
        return true;
    }
    #------------------------------
    private function doesItHaveMiddlewares(array|null $route):bool
    {
        if(is_null($route) || is_null($route["middleware"]))
            return false;
        return true;
    }
    #-------------------------------
    private function run_global_middlewares(array|null $route)
    {
        $globalMiddlewares = $route["globalMiddlewares"];
        if(!$this->doesItHaveGlobalMiddlewares($this->currentRoute))
            return;
        foreach ($globalMiddlewares as $global_middleware_class )
        {
            $global_middleware_object = new  $global_middleware_class;
            $global_middleware_object->handle();
        }
       
    }
    #------------------------------
    private function run_route_middlewares(array $route)
    {
        if(!$this->doesItHaveMiddlewares($this->currentRoute))
             return;
        $middleware = $route["middleware"];
        foreach ($middleware as $middleware_class) 
        {
            $middleware_object = new $middleware_class;
            $middleware_object->handle();
        }
    }
    #------------------------------
    private function findRoute(Request $request):array|null
    {
        foreach($this->routes as $route)
        {
            if( in_array( $request->method() , $route["method"]) and $request->uri() === $route["uri"])
                    return $route;
        }
        return null;
    }
    #------------------------------
    private function isInvalidRequest(Request $request ):bool
    {
        
        foreach($this->routes as $route)
        {
            if(!in_array( $request->method() , $route["method"]) and $request->uri() === $route["uri"])
                    return true;
        }        
        return false;
    }
    #------------------------------
    private function dispatch405():void
    {
        header("HTTP/1.0 405 Method Not Allowed");
        die("invalid request method");
    }
    #------------------------------
    private function dispatch404():void
    {
        header("HTTP/1.0 404 Not Found");
        view("Errors.404");
        die();
    }
    #------------------------------
    private function dispatch($route):void
    {
            $action = $route["action"];
            //actions 
            #=> NULL
            if(is_null($action) or empty($action))
                return;
            #=> closures
            if(is_callable($action))
                $action();
            #=>"controller@method"
            if(is_string($action))
                $action = explode("@",$action);
            #=>["controller" ,"method"]
            if(is_array($action))
            {
                [$className,$method] = [self::BASE_CONTROLLER . $action[0],$action[1]];
                
                if(!class_exists($className))
                    throw new Exception("class {$className} not Exists!");
                $controller = new $className();
                if(!method_exists($className , $method))
                    throw new Exception("method {$method} not Exists!");
                $controller -> {$method}();
            }      
    }
    #------------------------------
    public function run():void
    {
        #405 : invalid request method
        if($this->isInvalidRequest($this->request))
                $this->dispatch405();
        #------------------------------
        #404 : uri not exists
        if(is_null($this->currentRoute))
                $this->dispatch404();
        #------------------------------
        $this->dispatch($this->currentRoute);
    }
}

و در کلاس Router با اجرای متد run_global_middlewares برای تمامی مسیر‌های تعریف شده میدل ور‌های گلوبال اجرا می‌شوند که در این مثال خاص مرورگر کروم برای تمام مسیر‌های پروژه بسته می‌شوند.

فایل web.php :

 defined("BASEPATH") or die("No direct script access allowed !");
use App\\Core\\Routing\\Route;
use App\\Middlewares\\blockFireFox;
#----- home ------
Route::get("/","HomeController@index");
#------------------------------
#---- archive ----
Route::get("/archive","ArchiveControlller@index");
Route::get("/archive/posts","ArchiveControlller@posts");
Route::get("/archive/articles","ArchiveControlller@articles");
Route::get("/archive/products","ArchiveControlller@products");
#------------------------------
#------ todo -----
Route::get("/todo/list","TodoController@list",[blockFireFox::class]);