مقدمه
می توان گفت (Model View Controller) MVC چهارچوبی برای سازمان دهی کدهاست که بسیار مورد توجه توسعه دهندگان قرار گرفته است. بهطور کلی MVC یک معماری نرم افزاری و روشی برای سازمان دهی کدهاست . این معماری اولین بار در سال ۱۹۷۰ برای زبان Smalltalk ایجاد شد، بعدها توسعه دهندگان متوجه شدند که استفاده از این معماری در وبسایت ها نیز میتواند موثر باشد.
در سال ۲۰۰۲ اولین فریم ورک جاوا به نام Spring با این معماری عرضه شد، از آن موقع به بعد مدل MVC روز به روز میان فریم ورکهای دیگر به شکلی متفاوت رواج پیدا کرد و به طور گسترده مورد استفاده قرار گرفت چون مزایای زیادی برای توسعه سریع و ساختار یافته دارد و برای بسیاری از زبان های برنامه نویسی از DotNet تا PHP وجود دارد.
در آموزش پروژه محور PHP MVC ما شما را با چارچوب MVC مبتنی بر PHP آشنا خواهیم کرد. برای آموزش باید دانش خوبی از زبان برنامه نویسی PHP و اصول شی گرایی OOP داشته باشید. در ادامه با آموزش پروژه محور php mvc با ما همراه باشید.
MVC چیست؟
همانطور که قبلاً هم اشاره شد MVC یک الگوی طراحی است که برای جدا کردن داده ها Models، رابط های کاربر Views و منطق برنامه Controller استفاده می شود. بگذارید برای هر کدام از این سه مفهوم توضیحاتی ارائه دهیم:
مولفه Model: این بخش مربوط به منطق تجاری و داده های برنامه است. می توان از آن برای انجام اعتبارسنجی داده ها، پردازش داده ها و ذخیره آن ها استفاده کرد. داده ها می توانند از نوع :
- Flat file
- Data base
- XML document
و سایر منابع داده معتبر باشد.
مولفه View (نما): این بخش به ارائه داده ها به کاربر می پردازد که معمولا به شکل صفحات HTML است.
مولفه Controller (کنترلر): قسمتی که به درخواست منابع کاربران از سرور می پردازد به عبارت دیگر کنترلر بسته به منابع درخواستی , مدل ها و نماها را به یکدیگر پیوند می دهد.
در شکل زیر معماری MVC نشان داده شده است.
ساخت یک چهارچوب ساده PHP MVC
در آموزش پروژه محور php mvc ابتدا یک ساختار ساده با چارچوب MVC برای PHP ایجاد میکنیم (فرض بر این است که از Xamp استفاده می کنید.) فولدری می سازیم و وارد آن می شویم، یک پوشه جدید به نام Simple-php-mvc ایجاد میکنیم و به داخل آن پوشه می رویم. حالا پوشه های پایه برای MVC را ایجاد می کنیم پس ۵ پوشه با نام های زیر در داخل فولدر Simple-php-mvc ایجاد می کنیم:
- app
- config
- public
- views
- routes
قبل از شروع، دو فایل مهم PHP MVC ساده ی خود را ایجاد می کنیم که عبارتنداز: index.php و htaccess.
پیکربندی htaccess در PHP MVC
وارد پوشه public شده و فایلی به نام index.php ایجاد می کنیم. اکنون، در سطح ریشه پروژه خود یک فایل جدید به نام htaccess. ایجاد می کنیم. سپس آن را باز می کنیم و این کد را داخل htaccess قرار می دهیم:
<IfModule mod_rewrite.c> RewriteEngine On # Stop processing if already in the /public directory RewriteRule ^public/ - [L] # Static resources if they exist RewriteCond %{DOCUMENT_ROOT}/public/$1 -f RewriteRule (.+) public/$1 [L] # Route all other requests RewriteRule (.*) public/index.php?route=$1 [L,QSA] </IfModule>
htaccess یک فایل کانفیگ یا پیکربندی برای وب سرور آپاچی (Apache HTTP Server) است. دستورالعمل mod_rewrite به آپاچی میگوید: هر درخواستی به index.php واقع در پوشه public ختم شود. این به این معنی است که اگر https://simple-php-mvc/page1، https://simple-php-mvc/page2 یا https://simple-php-mvc/page3 را مرور کنید، همه آنها در نهایت در index.php تحت public، که نقطه ورود چارچوب PHP MVC شما است قرار می گیرند. این یک مزیت بزرگ است زیرا اکنون می توانید درخواست خود را در یک مکان بررسی کنید و بفهمید که چه منبعی درخواست شده است و پاسخ مناسب را ارائه دهید.
app config public index.php views routes .htaccess
استفاده Bootstrapt در PHP MVC
یکی از محبوبترین ابزارهای طراحی صفحات وب که علاوه بر ایجاد صفحات وب، نرمافزارهای تحت وب را نیز میسازد، Bootstrapt است. این ابزار رایگان شامل دستورات HTML و CSS میباشد. همچنین حاوی توابع جاوا اسکریپت برای تولید و نمایش فرمها، ستونها، دکمهها و تبها است و بسیاری از ابزارهای مورد نیاز طراحی وب را نیز دارا میباشد.
اکنون به راهی برای Bootstrap کردن برنامه و بارگذاری کد مورد نیاز خود نیاز دارید. قبلاً گفتیم که index.php نقطهی ورود بوده و در زیر پوشه public قرار دارد به همین دلیل ما فایل های لازم را در آنجا قرار می دهیم. اول از همه، فایل پیکربندی را بارگذاری می کنیم، در اینجا محتوای index.php به صورت زیر است:
// Load Config require_once '../config/config.php';
اکنون می توانیم یک فایل config.php در زیر پوشه config ایجاد کنیم. در داخل فایل config میتوانیم تنظیمات فریمورک را ذخیره کنیم، برای مثال میتوانیم نام برنامه، مسیر روت و البته پارامترهای اتصال پایگاه داده را ذخیره کنیم:
<?php //site name define('SITE_NAME', 'your-site-name'); //App Root define('APP_ROOT', dirname(dirname(__FILE__))); define('URL_ROOT', '/'); define('URL_SUBFOLDER', ''); //DB Params define('DB_HOST', 'your-host'); define('DB_USER', 'your-username'); define('DB_PASS', 'your-password'); define('DB_NAME', 'your-db-name');
بارگذاری خودکار (Autoloader)
در ادامه آموزش پروژه محور php mvc به بحث Autoloader می رسیم. ما میخواهیم این امکان را داشته باشیم که کلاسهای مورد نیاز را بدون دردسر بارگیری کنیم و بعد از بارگیری خودکار PSR-4 (استانداری برای کدنویسی PHP) با Composer استفاده میکنیم.
Composer یک مدیر وابسته به PHP است، به شما این امکان را می دهد که کتابخانه های مورد نیاز در پروژه را اعلام کنید و آنها را برای شما مدیریت خواهد کرد. ابتدا در سطح ریشه، باید فایلی به نام composer.json ایجاد کنیم و محتوای زیر را اضافه کنیم:
{ "name": "gmaccario/simple-mvc-php-framework", "description": "Simple MVC PHP framework: a demonstration of how to create a simple MVC framework in PHP", "autoload": { "psr-4": { "App\\": "app/" } } }
سپس، با فرض اینکه قبلاً composer را روی سیستم خود نصب کرده اید، دستور زیر را (در سطح ریشه پروژه خود) اجرا کنید:
composer dump-autoload
اگر اکنون پوشه root خود را بررسی کنید، می توانید پوشه جدیدی به نام vendor را مشاهده کنید که حاوی فایل autoload.php و پوشه composer است. index.php را باز کنید و کد زیر را در ابتدای فایل اضافه کنید:
require_once '../vendor/autoload.php';
از این پس، می توانید از App به عنوان نقطه شروع namespace خود استفاده کنید، مانند این:
use App\Controllers\MyController;
مدل MODEL
مدل شیئی است که داده های شما را نشان می دهد. مدل بر اساس ساختار جدول پایگاه داده شما مدل می شود و با عملیات پایگاه داده (ایجاد، خواندن، به روز رسانی و حذف) تعامل خواهد داشت. به عنوان مثال، اگر یک جدول محصولات دارید:
CREATE TABLE IF NOT EXISTS products ( id int(10) NOT NULL auto_increment, title varchar(255) collate utf8_unicode_ci NOT NULL, description text collate utf8_unicode_ci, price decimal(12,5) NOT NULL, sku varchar(255) collate utf8_unicode_ci NOT NULL, image varchar(255) collate utf8_unicode_ci NOT NULL, PRIMARY KEY (id) ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci AUTO_INCREMENT=1;
اول از همه، اجازه دهید یک پوشه جدید به نام Models در زیر پوشه برنامه بسازیم. سپس بیایید یک فایل جدید به نام Product تحت Models ایجاد کنیم. محصول مدل شما این خواهد بود:
<?php namespace App\Models; class Product { protected $id; protected $title; protected $description; protected $price; protected $sku; protected $image; // GET METHODS public function getId() { return $this->id; } public function getTitle() { return $this->title; } public function getDescription() { return $this->description; } public function getPrice() { return $this->price; } public function getSku() { return $this->sku; } public function getImage() { return $this->image; } // SET METHODS public function setTitle(string $title) { $this->title = $title; } public function setDescription(string $description) { $this->description = $description; } public function setPrice(string $price) { $this->price = $price; } public function setSku(string $sku) { $this->sku = $sku; } public function setImage(string $image) { $this->image = $image; } // CRUD OPERATIONS public function create(array $data) { } public function read(int $id) { } public function update(int $id, array $data) { } public function delete(int $id) { } }
و نتیجه همین خواهد بود که شما با متدها، اشیایی را که باید بر اساس مدل با مقادیر واقعی پر شوند را ایجاد خواهید کرد.
نما VIEW
View وظیفه دارد داده ها را از کنترلر گرفته و مقادیر آن را نمایش دهد. فریم ورک های زیادی برای PHP وجود دارد، از Twig گرفته تا Blade. در این آموزش پروژه محور PHP MVC، ما فقط از HTML ساده برای تسهیل در کارها استفاده خواهیم کرد. برای ایجاد نمای جدید باید یک فایل جدید به نام product.php در زیر پوشه views ایجاد کنیم. بر اساس ویژگی های محصول، می توانیم یک HTML ساده مانند این بنویسیم:
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1"> <meta name="description" content=""> <meta name="author" content=""> <link rel="shortcut icon" href="favicon.png"> <title>Simple PHP MVC</title> <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.5.2/css/bootstrap.min.css"> </head> <body> <section> <h1>My Product:</h1> <ul> <li><?php echo $product->getTitle(); ?></li> <li><?php echo $product->getDescription(); ?></li> <li><?php echo $product->getPrice(); ?></li> <li><?php echo $product->getSku(); ?></li> <li><?php echo $product->getImage(); ?></li> </ul> <a href="<?php echo $routes->get('homepage')->getPath(); ?>">Back to homepage</a> <section> <script src="https://code.jquery.com/jquery-3.6.0.min.js" integrity="sha256-/xUj+3OJU5yExlq6GSYGSHk7tPXikynS7ogEvDej/m4=" crossorigin="anonymous"></script> <script src="https://stackpath.bootstrapcdn.com/bootstrap/4.5.2/js/bootstrap.min.js"></script> </body> </html>
اکنون نما برای دریافت شی محصول (product$) و نمایش مقادیر آن آماده است. در ادامه آموزش پروژه محور php mvc به بحث CONTROLLER می رسیم.
کنترلر CONTROLLER
کنترلر قلب منطق برنامه است. مسئول پذیرش ورودی و تبدیل آن به دستورات مدل یا view است. بیایید یک پوشه جدید به نام Controllers در زیر پوشه برنامه بسازیم و یک فایل کنترلر جدید به نام ProductController.php به صورت زیر ایجاد کنیم:
<?php namespace App\Controllers; use App\Models\Product; use Symfony\Component\Routing\RouteCollection; class ProductController { // Show the product attributes based on the id. public function showAction(int $id, RouteCollection $routes) { $product = new Product(); $product->read($id); require_once APP_ROOT . '/views/product.php'; } }
می بینید که بسیار ساده است، همه چیز می توانست پیچیدهتر باشد، مثلا ما میتوانستیم یک کلاس Controller والد، یک روش view و سایر توابع کمکی ایجاد کنیم. ولی فعلا برای شروع همین کافی است.
سیستم routing
اکنون ما به مکانیزمی برای سروکار داشتن با URL ها نیاز داریم. ما می خواهیم از یک URL دوست استفاده کنیم. به عبارت دیگر، ما می خواهیم با آدرس های وب که به راحتی قابل خواندن هستند و شامل کلماتی هستند که محتوای صفحه وب را توصیف می کنند، سروکار داشته باشیم.
ما به یک سیستم مسیریابی یا همان routing نیاز داریم. میتوانیم سیستم مسیریابی خودمان را ایجاد کنیم، یا از بارگذاری خودکار استفاده کنیم، همچنین میتوانیم کار هوشمندانه ای انجام دهیم و بستههای اکوسیستم گسترده Symfony را بررسی کنیم. بنابراین، بیایید ببینیم چگونه می توانیم از کامپوننت مسیریابی Symfony استفاده کنیم.
اول از همه، کامپوننت را نصب می کنیم. بعد از نصب اگر داخل پوشه فروشنده را بررسی کنید، می بینید که یک پوشه جدید به نام Symfony ایجاد شده است. بیایید پیاده سازی سیستم مسیریابی را برای چارچوب MVC خود شروع کنیم. هدف نمایش مقادیر محصول با ID=1 هنگام مرور URL /product/1 است. یک فایل جدید به نام web.php در زیر پوشه routes ایجاد می کنیم. این فایل شامل تمام مسیرهای برنامه ما خواهد بود.
<?php use Symfony\Component\Routing\Route; use Symfony\Component\Routing\RouteCollection; // Routes system $routes = new RouteCollection(); $routes->add('product', new Route(constant('URL_SUBFOLDER') . '/product/{id}', array('controller' => 'ProductController', 'method'=>'showAction'), array('id' => '[0-9]+')));
ما از کلاس های Route و RouteCollection از مؤلفه Symfony Routing برای ایجاد و فهرست کردن همه مسیرهای مورد نیاز خود استفاده می کنیم و با یک صفحه محصول شروع می کنیم که البته این کافی نیست و باید این بسته را نیز نصب کنیم:
composer require symfony/http-foundation
حالا بیایید موتور مسیریابی را ایجاد کنیم. یک فایل جدید به نام Router.php در پوشه برنامه خود اضافه می کنیم و این کد را داخل آن قرار دهید:
<?php namespace App; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\Routing\RequestContext; use Symfony\Component\Routing\RouteCollection; use Symfony\Component\Routing\Matcher\UrlMatcher; use Symfony\Component\Routing\Exception\MethodNotAllowedException; use Symfony\Component\Routing\Exception\ResourceNotFoundException; use Symfony\Component\Routing\Exception\NoConfigurationException; class Router { public function __invoke(RouteCollection $routes) { $context = new RequestContext(); $request = Request::createFromGlobals(); $context->fromRequest(Request::createFromGlobals()); // Routing can match routes with incoming requests $matcher = new UrlMatcher($routes, $context); try { $matcher = $matcher->match($_SERVER['REQUEST_URI']); // Cast params to int if numeric array_walk($matcher, function(&$param) { if(is_numeric($param)) { $param = (int) $param; } }); // https://github.com/gmaccario/simple-mvc-php-framework/issues/2 // Issue #2: Fix Non-static method ... should not be called statically $className = '\\App\\Controllers\\' . $matcher['controller']; $classInstance = new $className(); // Add routes as paramaters to the next class $params = array_merge(array_slice($matcher, 2, -1), array('routes' => $routes)); call_user_func_array(array($classInstance, $matcher['method']), $params); } catch (MethodNotAllowedException $e) { echo 'Route method is not allowed.'; } catch (ResourceNotFoundException $e) { echo 'Route does not exists.'; } catch (NoConfigurationException $e) { echo 'Configuration does not exists.'; } } } // Invoke $router = new Router(); $router($routes);
کد کاملا واضح است اما اجازه دهید کمی آن را توضیح دهیم: تطبیق کننده URL درخواست را از URI می گیرد و بررسی می کند که آیا با مسیرهای تعریف شده در routes/web.php مطابقت دارد یا خیر. اگر تطابق وجود داشته باشد، تابع call_user_func_array هوشمندانه عمل می کند و متد درست از کنترلر مناسب را فراخوانی می کند.
علاوه بر این، ما از تابع array_walk برای قالب مقادیر عددی به مقادیر صحیح استفاده کردیم، زیرا در روشهای کلاس خود از اعلان نوع صریح استفاده میکردیم. اکنون می توانیم سیستم مسیرها را در فایل index.php قرار دهیم:
<?php // Autoloader require_once '../vendor/autoload.php'; // Load Config require_once '../config/config.php'; // Routes require_once '../routes/web.php'; require_once '../app/Router.php';
اکنون که سیستم مسیریابی را آماده کردیم، میتوانیم صفحه /product/1 را مرور کنیم و نتیجه را ببینیم. بدیهی است که مقادیر اکنون خالی هستند. بیایید مقداری جعلی به محصول اضافه کنیم (در داخل ProductController.php):
public function read(int $id)
{
$this->title = 'My first Product';
$this->description = 'Lorem ipsum Lorem ipsum Lorem ipsum Lorem ipsum Lorem ipsum Lorem ipsum Lorem ipsum Lorem ipsum ';
$this->price = 2.56;
$this->sku = 'MVC-SP-PHP-01';
$this->image = 'https://via.placeholder.com/150';
return $this;
}
و دوباره صفحه /product/1 را مرور می کنیم. اکنون می توانید اتصال پایگاه داده خود را اضافه کنید و مقادیر را از پایگاه داده با استفاده از یک پرس و جو خام یا یک ORM مانند Doctrine یا Eloquent برگردانید.
صفحه اصلی Home page
بیایید اکنون مسیر صفحه اصلی را آماده کنیم. routes/web.php را باز کنید و مسیر جدید را اضافه کنید:
$routes->add('homepage', new Route(constant('URL_SUBFOLDER') . '/', array('controller' => 'PageController', 'method'=>'indexAction'), array()));
بدیهی است که باید کنترلر جدید PageController را ایجاد کنیم:
<?php namespace App\Controllers; use App\Models\Product; use Symfony\Component\Routing\RouteCollection; class PageController { // Homepage action public function indexAction(RouteCollection $routes) { $routeToProduct = str_replace('{id}', 1, $routes->get('product')->getPath()); require_once APP_ROOT . '/views/home.php'; } }
و دیدگاه جدید :
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1"> <meta name="description" content=""> <meta name="author" content=""> <link rel="shortcut icon" href="favicon.png"> <title>Simple PHP MVC</title> <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.5.2/css/bootstrap.min.css"> </head> <body> <section> <h1>Homepage</h1> <p> <a href="<?php echo $routeToProduct ?>">Check the first product</a> </p> <section> <script src="https://code.jquery.com/jquery-3.6.0.min.js" integrity="sha256-/xUj+3OJU5yExlq6GSYGSHk7tPXikynS7ogEvDej/m4=" crossorigin="anonymous"></script> <script src="https://stackpath.bootstrapcdn.com/bootstrap/4.5.2/js/bootstrap.min.js"></script> </body> </html>
از آنجایی که ما از همان کد برای سرصفحه و پاورقی استفاده میکنیم، میتوانیم یک پوشه طرحبندی ایجاد کنیم و کد آن قطعات HTML را جدا کنیم. برای پیمایش صفحه، مرورگر خود را باز کنید و این URL را مرور کنید:
http://localhost/
URL دقیق به تنظیمات شما بستگی دارد. به عنوان مثال چنانچه از Docker برای محیط محلی خود استفاده کنید، پس URL می تواند کمی متفاوت باشد.
http://localhost:8887/
این پروژه یک کیت شروع ساده است و اگر محیط شما به درستی پیکربندی شده باشد، به خوبی کار می کند.
سخن پایانی در مورد آموزش پروژه محور php mvc
عنوان این پست آموزش پروژه محور php mvc بود و در مورد MVC نویسی با زبان برنامه نویسی PHP موارد و نکات مهمی مطرح شد. سه مولفه اصلی MVC یعنی مدل، نما و کنترلر بصورت کامل همرا با توضیحات پیاده سازی شد و در نهایت توانستیم یک routing روی آنها اعمال کنیم.
بدیهی است این آموزش برای راه اندازی و استارت اولیه شما در پروژه هایی MVC با PHP می باشد و برای کسب مهارت بایستی تمرین و تکرار و فعالیت داشت. امیدواریم مطالب فوق برای شما عزیزان مفید باشد در پایان مقاله ما را در زمینه کسب درآمد اینترنتی در وقت و حوصله مناسب مطالعه فرمایید. موفق و پیروز باشید.