کنترلرها

مجتبی پاکزاد کدایگنایتر 3.1.9 در حال تکمیل رایگان

کنترلرها در کدایگنایتر قلب اپلیکیشن شما هستند. زیرا آن‌ها تصمیم می‌گیرند که چگونه ریکوئست‌های HTTP را هَندل کنند.

کنترلر چیست؟

یک کنترلر به زبان ساده یک فایل کلاس است که به گونه‌ای نامگذاری می‌شود که از طریق URIها در دسترس است.  URI زیر را در نظر بگیرید:

example.com/index.php/blog/

در مثال بالا، کدایگنایتر سعی می‌کند کنترلری با نام Blog.php را بیابد و آن را لود کند. هنگامی که نام کنترلر با اولین سگمنت URI منطبق بود، آن کنترلر لود خواهد شد.

مثال نمایش Hello world

یک فایل با نام Blog.php ایجاد کنید. کد زیر در این فایل، یک کنترلر ساده با یک اکشن در آن است.

<?php
class Blog extends CI_Controller {

        public function index()
        {
                echo 'Hello World!';
        }
}

این فایل باید در دایرکتوری application/controllers ذخیره شود.

مهم: دقت کنید که حتما نام فایل Blog.php به صورت کپیتال (Capital) شروع شود، یعنی با حرف B بزرگ.

حالا URL زیر را در مرورگر خود باز کنید:

example.com/index.php/blog/

اگر پیام Hello World را مشاهده کردید، به معنی این است که کنترلر را به درستی ایجاد کرده‌اید.

مهم: اسامی کلاس‌ها باید با حروف بزرگ شروع شوند.

مثال زیر یک نامگذاری معتبر است:

<?php
class Blog extends CI_Controller {

}

اما، کد زیر از نظر نامگذاری کلاس کنترلر، نامعتبر است:

<?php
class blog extends CI_Controller {

}

همیشه اطمینان حاصل کنید که کنترلر شما از یک کنترلر دیگر (مثلا CI_Controller) ارث‌بری شده است تا متدهای آن را به ارث ببرد.

متدها

در مثال بالا، نام متد index() است. متد index، اکشن پیش‌فرض کنترلر است و در صورت خالی بودن سگمنت دوم URI، همیشه لود می‌شود. روش دیگر نمایش Hello World به صورت زیر است:

example.com/index.php/blog/index/

سگمنت دوم URI، متدی از کنترلر را مشخص می‌کند که قرار است فراخوانی شود. متد comments را به کنترلر اضافه می‌کنیم:

<?php
class Blog extends CI_Controller {

        public function index()
        {
                echo 'Hello World!';
        }

        public function comments()
        {
                echo 'Look at this!';
        }
}

با لود URL زیر، متد comments لود می‌شود.

example.com/index.php/blog/comments/

حالا باید پیام Look at this را مشاهده کنید.

ارسال سگمنت‌های URI به متدهای کنترلر

اگر URI بیش از دو سگمنت داشته باشد، سایر سگمنت‌ها به عنوان پارامترهای متد به آن ارسال می‌شوند. برای مثال اگر URI زیر را در نظر بگیریم:

example.com/index.php/products/shoes/sandals/123

سگمنت‌های سوم و چهارم (sandals و 123)، به متد shoes کنترلر products پاس داده می‌شوند.

<?php
class Products extends CI_Controller {

        public function shoes($sandals, $id)
        {
                echo $sandals;
                echo $id;
        }
}
مهم: اگر از ویژگی مسیریابی URI استفاده شود،سگمنت‌هایی به متد ارسال می‌شوند که در ruleهای مسیریاب مشخص شده باشند.

تعریف کنترلر پیش‌فرض

می‌توان در مسیریاب کدایگنایتر، تنظیماتی را برای تعیین کنترلر پیش‌فرض انجام داد. برای مثال وقتی کنترلر مشخص نشده باشد، یعنی در روت (Root) سایت، کنترلر پیش‌فرض به ریکوئست پاسخ می‌دهد. برای تعریف کنترلر پیش‌فرض، فایل application/config/routes.php را باز کنید و متغییر زیر را به عنوان کنترلر پیش‌فرض مقداردهی کنید.

$route['default_controller'] = 'blog';

در این مثال، blog نام کلاس کنترلری است که می‌خواهید به عنوان کنترلر پیش‌فرض استفاده کنید. حالا اگر فایل index.php را لود کنید، پیام Hello World را مشاهده می‌کنید.

تغییر در رفتار فراخوانی اکشن

همانطور که قبلا گفته شد، سگمنت دوم URI معمولا، متدی از کنترلر را مشخص می‌کند که قرار است فراخوانی شود. کدایگنایتر به دولوپرها اجازه بازنویسی (override) این رفتار (behavior) را با استفاده از متد _remap() می‌دهد.

public function _remap()
{
        // Some code here...
}
مهم: اگر در کنترلر شما متدی با نام _remap() وجود داشته باشد، صرفنظر از اینکه چه چیزی در URI شما وجود دارد، همیشه فراخوانی می‌شود. این متد رفتار عادی که مشخص می‌کند با هر URI چه متدی فراخوانی شود را بازنویسی می‌کند و به شما اجازه می‌دهد تا ruleهای مسیریابی خوتان را تعریف کنید.

متد فراخوانی شده (که معمولا سگمنت دوم URI است)، به عنوان پارامتر به متد _remap() پاس داده می‌شود.

public function _remap($method)
{
        if ($method === 'some_method')
        {
                $this->$method();
        }
        else
        {
                $this->default_method();
        }
}

هر سگمنت دیگری که در URL وجود داشته باشد، به عنوان پارامتر دوم به‌متد _remap() ارسال می‌شود. پارامتر دوم اختیاری است و آرایه‌ای از سگمنت‌ها است. این آرایه می‌تواند در ترکیب با فانکشن call_user_func_array() استفاده شود تا رفتار پیش‌فرض کدایگنایتر را شبیه‌سازی کند. مثال:

public function _remap($method, $params = array())
{
        $method = 'process_'.$method;
        if (method_exists($this, $method))
        {
                return call_user_func_array(array($this, $method), $params);
        }
        show_404();
}

پردازش خروجی

کدایگنایتر کلاسی با نام output دارد که مسئول ارسال اتوماتیک داده‌های رندر شده نهایی به مرورگر است. در برخی موارد، ممکن است بخواهید داده‌های نهایی را قبل از ارسال به مرورگر مورد پردازش قرار دهید. با افزودن متد _output() به کنترلر، داده‌های خروجی نهایی به این متد ارسال خواهند شد.

مهم: اگر در کنترلر شما متدی با نام _output() وجود داشته باشد، همیشه به جای نمایش مستقیم داده‌های نهایی، این متد توسط کلاس output فراخوانی می‌شود. خروجی نهایی به عنوان اولین پارامتر این متد، به آن ارسال می‌شود.

برای مثال:

public function _output($output)
{
        echo $output;
}
توجه: دقت کنید که متد _output() داده‌ها را در وضعیت نهایی خود دریافت می‌کند. داده‌های مربوط به بنچمارک و مصرف مموری رندر خواهند شد، اگر قابلیت کش را فعال کرده باشید، فایل‌های کش نوشته می‌شوند و اگر از این قابلیت استفاده کرده باشید، هدرها به مرورگر ارسال خواهند شد، قبل از اینکه به متد _output() تحویل داده شوند. برای اینکه خروجی کنترلر به درستی کش شود، کد زیر را در متد _output() بنویسد:
if ($this->output->cache_expiration > 0)
{
        $this->output->_write_cache($output);
}
اگر از این قابلیت استفاده کنید، ممکن است زمان اجرای صفحه و آمار مصرف مموری کاملا دقیق و صحیح نباشند، زیرا هر پردازشی که در این متد انجام شود را نادیده می‌گیرند.

متدهای پرایوت (Private methods)

در برخی موارد ممکن است نیاز به مخفی کردن برخی متدها از دسترسی عمومی داشته باشید. به منظور دستیابی به این مهم، تنها کافیست که آن متدها را به صورت private یا protected تعریف کنید، در نهایت این متدها با ریکوئست از طریق URI فراخوانی نخواهند شد. برای مثال اگر متدی مانند مثال زیر داشته باشید:

private function _utility()
{
        // some code
}

تلاش برای دسترسی به آن با URI زیر نتیجه ای جز،خطای 404 نخواهد داشت.

example.com/index.php/blog/_utility/

سازماندهی و دسته‌بندی کنترلرها در ساب‌دایرکتوری‌ها

اگر در حال ساخت اپلیکیشن بزرگی هستید، ممکن است بخواهید کنترلرهای اپلیکیشن خود را با ساختار سلسله مراتبی در ساب دایرکتوری ها دسته‌بندی کنید. کدایگنایتر به شما اجازه انجام این کار را می‌دهد. کافیست ساب‌دایرکتوری‌های مورد نظر خود را در دایرکتوری application/controllers بسازید و کلاس‌های کنترلر اپلیکیشن را در آن‌ها قرار دهید.

توجه: هنگامی که از این ویژگی استفاده می‌کنید، اولین سگمنت URI باید به نام دایرکتوری اشاره کند. برای مثال، اگر کنترلر شما در مسیر زیر باشد:
application/controllers/products/Shoes.php
برای فراخوانی کنترلر بالا، URL باید چیزی شبیه این باشد:
example.com/index.php/products/shoes/show/123

هر کدام از ساب‌دایرکتوری‌ها ممکن است شامل یک کنترلر پیش‌فرض باشند که اگر URL فقط دربردارنده نام آن ساب‌دایرکتوری باشد، کنترلر پیش‌فرض آن فراخوانی خواهد شد. با استفاده از default_controller در فایل application/config/routes.php نام این کنترلر را مشخص کنید. همچنین کدایگنایتر به شما اجازه می‌دهد تا با استفاده از ویژگی مسیریابی URI، آن ها را ریمپ (Remap) کنید.

متد سازنده‌ کنترلرها

اگر تمایل به استفاده از متد سازنده در هر کدام از کنترلرهای خود دارید، باید کد زیر را در آن قرار دهید:

parent::__construct();

علت نوشتن این خط کد، این است که متد سازنده کنترلر شما،متد همنام کلاس والد خود را بازنویسی می‌کند، بنابراین باید متد سازنده کلاس والد را در متد سازنده کنترلر خود فراخوانی کنید. مثال

<?php
class Blog extends CI_Controller {

        public function __construct()
        {
                parent::__construct();
                // Your own constructor code
        }
}

اگر بخواهید برخی پراپرتی‌ها را به صورت پیش‌فرض مقداردهی کنید، یا وقتی که کلاس فراخوانی می‌شود یکسری پردازش را انجام دهید، متدهای سازنده بسیار کاربردی هستند. متدهای سازنده مقدار را برنمی‌گردانند، اما می‌توانند بکسری کارها را به صورت پیش‌فرض انجام دهند.

اسامی رزرو شده متدها

از آنجایی که کلاس کنترلر شما، کنترلر اصلی اپلیکیشن را توسعه (extend) می‌کند، باید دقت کنید که نام متدهای کنترلر شما با نام‌های رزرو شده کنترلر اصلی همنام نباشد تا از بازنویسی متدهای کنترلر اصلی جلوگیری شود.

مهم: هرگز نباید نام متد را همنام با نام کنترلر انتخاب کنید. اگر این‌کار را انجام دهید و کنترلر متد __construct() نداشته باشد، آنگاه متد Index::index() به عنوان متد سازنده و در نقش متد __construct() ظاهر می‌شود. این ویژگی به خاطر پس‌سازگاری با PHP4 است.
منبع
Controllers