بارگذاری Controller از URL

Load Controller from URL

25 بهمن 1399
بارگذاری controller از URL

در قسمت قبل کلاس ساده ای را سر هم کردیم که پارامترهای ارسالی در URL را echo می کرد. در این جلسه می خواهیم این کدها را تکمیل کنیم.

اول از همه به کد جلسه قبل نگاهی بیندازید:

class Core {
    protected $currentController = 'Pages';
    protected $currentMethod = 'index';
    protected $params = [];

    public function __construct(){
      $this->getUrl();
    }

    public function getUrl(){
      echo $_GET['url'];   
    }
  }

در این کد تابع getUrl مشکل دارد. اگر کسی به آدرس localhost/traversymvc برود به خطا برمی خورد چرا که هیچ پارامتری در این آدرس وجود ندارد! بنابراین اول باید چک کنیم که پارامتری وجود دارد یا نه، سپس آن را echo کنیم:

public function getUrl(){
      if(isset($_GET['url'])){
        $url = rtrim($_GET['url'], '/');
        $url = filter_var($url, FILTER_SANITIZE_URL);
        $url = explode('/', $url);
        return $url;
      }
    }

تابع rtrim اسلش (/) آخر را از آدرس URL حذف می کند. filter_var را نیز در این قسمت برای امن کردن URL استفاده می کنیم تا آدرس URL تنها کاراکترهایی را داشته باشد که URL ها مجاز به داشتنشان هستند. تابع explode نیز پارامترها را بر اساس علامت اسلش از هم جدا می کند و به صورت یک آرایه در یک متغیر قرار می دهد. همچنین در آخر متغیر url را return می کنیم تا بعدا آن را پردازش کنیم (Echo کردن فقط جهت تفهیم مطلب به شما بود).

برای مشاهده پارامترها (برای خودمان) در این آرایه می توانیم دستور زیر را در constructor قرار دهیم:

print_r($this->getUrl());

حالا باید بر اساس پارامترهای ارسالی به دنبال کنترلر مناسب آن بگردیم بنابراین می گوییم:

public function __construct(){

      $url = $this->getUrl();

      // Look in controllers for first value
      if(file_exists('../app/controllers/' . ucwords($url[0]). '.php')){
        // If exists, set as controller
        $this->currentController = ucwords($url[0]);
        // Unset 0 Index
        unset($url[0]);
      }

اگر یادتان باشد در جلسه قبل گفتیم که تمامی فایل های libraries باید با حرف بزرگ انگلیسی شروع شوند. اینجا با استفاده از تابع ucwords پارامترها را بر همین اساس تغییر می دهیم تا شبیه کنترلر (controller) ها شوند. file_exists نیز چک می کند تا ببیند آیا پارامتر ارسالی اول (ایندکس صفر) دارای فایلی به همان نام در libraries است یا خیر؛ اگر وجود داشته باشد بنابراین کنترلر فعلی (currentController) ما خواهد بود و در آخر نیز index صفر را حذف می کنیم.

اگر دقت کنید تابع file_exists طوری آدرس دهی شده است که انگار در index.php هستیم. میدانید چرا؟ اگر یادتان باشد پروژه را طوری تنظیم کردیم که تمام صفحات به index.php ختم شده و از آن عبور کند! دلیلش این است!

حالا که کنترلر جدید پیدا شده است باید آن را require کنیم و یک نمونه از آن بسازیم:

// Require the controller
      require_once '../app/controllers/'. $this->currentController . '.php';

سپس از آن یک شیء می سازیم (نمونه سازی):

// Instantiate controller class
      $this->currentController = new $this->currentController;

تا اینجای کار کنترلر برنامه را عوض کردیم اما هنوز هیچ کنترلری را ننوشته ایم بنابراین باید وارد پوشه controllers شویم و کنترلرهای خودمان را بسازیم. ابتدا فایلی به نام pages.php می سازیم و برای تست کردن کد زیر را در آن می گذاریم:

<?php
  class Pages {
    public function __construct(){
      echo 'Pages loaded';
    }
  }

سپس به آدرس localhost/traversymvc بروید. چرا این آدرس؟ به دلیل این که قرار بر پیش فرض بودن pages به عنوان کنترلر بود بنابراین باید تست کنیم تا ببینیم اگر صفحه یا پارامتری را به برنامه ندهیم آیا pages کنترل صفحه را به دست خواهد گرفت یا خیر. با ورود به این آدرس پیام Pages loaded نمایش داده می شود و مطمئن می شویم که برنامه ما کار می کند.

از آنجا که هنوز کنترلری به نام posts نداریم، اگر به آدرس localhost/traversymvc/posts برویم باز هم صفحه pages کنترل را به دست می گیرد. بنابراین یک فایل دیگر (در همان پوشه controllers) به نام posts.php ایجاد کرده و برای تست کد زیر را در آن می گذاریم:

<?php
  class posts {
    public function __construct(){
      echo 'posts loaded';
    }
  }

حالا اگر به آدرس localhost/traversymvc/posts برویم پیام posts loaded برایمان نمایش داده می شود. اما فعلا فایل posts.php را حذف می کنیم چرا که جزو core (هسته ی) فریم ورک ما نیست.

دانلود فایل کدها تا این قسمت

Map کردن متدها و کار با پارامتر دوم URL

تا این قسمت پارامتر اولی که برای URL در نظر گرفته بودیم را به کنترلر خاص خودش متصل کرده ایم. اگر یادتان باشد قرار بود چنین چیزی داشته باشیم:

class Core {
    protected $currentController = 'Pages';
    protected $currentMethod = 'index';
    protected $params = [];
}

پارامتر اول که به صورت پیش فرض توسط pages کنترل می شد و حالا نوبت به کنترل پارامتر دوم رسیده است. پارامتر دوم یک متد خواهد بود به طور مثال اگر به آدرس localhost/traversymvc/pages/about برویم یعنی در کنترلر یا همان کلاس pages به دنبال متدی به نام about باشیم. از آنجا که این پارامتر، پارامتر دوم ما محسوب می شود، ایندکس آن 1 می باشد (در جلسات ابتدایی عرض کردیم که مدیریت این پارامترها به شکل آرایه خواهد بود).

به فایل Core.php برگردید تا با استفاده از کد زیر به دنبال پارامتر دوم بگردیم:

// Check for second part of url
      if(isset($url[1])){
        // Check to see if method exists in controller
        if(method_exists($this->currentController, $url[1])){
          $this->currentMethod = $url[1];
          // Unset 1 index
          unset($url[1]);
        }
      }

نکته مهم: به یاد داشته باشید که تمام این کدها را در constructor کلاس core مینویسیم.

کار کد بالا این است که به دنبال پارامتر دوم ([1]url$) بگردد سپس ببیند آیا این متد در فلان کنترلر موجود است یا خیر. برای این کار از تابع method_exists استفاده کرده ایم که دو پارامتر می گیرد؛ پارامتر اول کنترلر مورد نظر و پارامتر دوم متدی است که دنبال آن می گردید. اگر پارامتر دوم وجود داشته باشد آن را به عنوان currentMethod بعدی تنظیم می کنیم. در آخر هم آن را از آرایه url$ حذف می کنیم (دلیلش را توضیح خواهم داد).

حالا باید این پارامتر را دریافت کنیم بنابراین می گوییم:

// Get params
      $this->params = $url ? array_values($url) : [];

این کد می گوید پارامترها را از url بگیر و به آرایه خالی params که در ابتدای جلسات ساختیم اضافه کن، در غیر این صورت آرایه را به صورت خالی باقی بگذار.

در آخر نیز از تابع call_user_func_array استفاده می کنیم؛ این تابع، یک تابع شخصی را گرفته و پارامترهایی که شما به آن می دهید را اجرا می کند:

// Call a callback with array of params
      call_user_func_array([$this->currentController, $this->currentMethod], $this->params);

حالا باید متد مورد نظر ما بارگذاری شود و پارامترها را به آن بدهیم. برای تست کردن این مسئله به فایل Pages.php بروید و یک متد ساده به نام about ایجاد کنید:

public function about(){
      echo "this is about";
    }

حالا به آدرس localhost/traversymvc/pages/about میرویم و باید پیام this is about را ببینیم تا بفهمیم کدهایمان به درستی کار می کنند. اگر کد بالا را به روش زیر بنویسیم:

public function about($id){
      echo $id;
    }

سپس به آدرسی مانند localhost/traversymvc/pages/about/33 برویم، پیام خروجی عدد 33 خواهد بود!

تا اینجای کار را خوب پیش رفتیم اما اگر الان به آدرس localhost/traversymvc برویم به خطا برخورد میکنیم! چرا؟ از آنجا که Pages کنترلر پیش فرض ما است، index نیز متد پیش فرض آن است بنابراین باید متدی به نام index در Pages داشته باشیم:

public function index(){
      
    }

دانلود فایل کدها تا این جلسه

امیدوارم از این قسمت لذت برده باشید.

تمام فصل‌های سری ترتیبی که روکسو برای مطالعه‌ی دروس سری آموزش ساخت شبکه اجتماعی توصیه می‌کند:
نویسنده شوید
دیدگاه‌های شما

در این قسمت، به پرسش‌های تخصصی شما درباره‌ی محتوای مقاله پاسخ داده نمی‌شود. سوالات خود را اینجا بپرسید.