آموزش mvc در php با یک مثال ساده
در این آموزش نحوه ایجاد یک برنامه PHP ساده را با الگوی MVC توضیح خواهیم داد. فریمورک های MVC (مخفف (Model-View-Controller در صنعت به طور گسترده مورد استفاده قرار می گیرند زیرا مزایای بسیاری برای توسعه ساخت یافته و سریع ارائه می دهند. فریمورک های MVC برای بسیاری از زبان های برنامه نویسی از دات نت گرفته تا PHP وجود دارد.
MVC چیست؟
MVC یک الگوی طراحی است که برای جدا کردن داده ها (Models)، رابط کاربری (Views) و منطق برنامه (Controllers) استفاده می شود. برای درک بهتر باید دانش کافی در مورد PHP و OOP (برنامه نویسی شی گرا) داشته باشید.
ساخت یک فریمورک PHP MVC ساده
می توانید از Docker، XAMPP یا هر برنامه دیگری برای محیط توسعه خود برای ایجاد یک ساختار ساده برای فریمورک PHP MVC استفاده کنید.
یک پوشه جدید در پوشه پروژه های خود ایجاد کنید. در اینجا پوشه جدید را با نام “simple-php-mvc” ایجاد کرده و سپس وارد آن می شویم.
حالا در اینجا پوشه های اصلی زیر را برای الگوی MVC ایجاد می کنیم:
- app
- config
- public
- views
- routes
برای شروع دو فایل مهم index.php و htaccess را می سازیم.
فایل پیکربندی htaccess
ابتدا در پوشه public یک فایل با نام index.php می سازیم.
حالا به پوشه اصلی (root) پروژه خود برگشته و یک فایل جدید به نام .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) است و ماژول 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 است. این یک مزیت بزرگ است زیرا می توانید درخواست خود را در یک مکان کنترل کنید، منبع درخواست را شناسایی کرده و یک پاسخ صحیح ارائه دهید.
با استفاده از htaccess و هدایت ترافیک به پوشه public بقیه ساختار پروژه برای همه مخفی خواهد بود.
در حال حاضر پروژه شما به شکل زیر است:
ساختار پوشه برنامه PHP MVC
app
config
public
index.php
views
routes
.htaccess
بوت استرپ فریمورک PHP MVC
در این مرحله به یک روش برای بوت استرپ برنامه و بارگیری کد نیاز دارید. همانطور که گفتیم index.php در پوشه public نقطه ورود است، به همین دلیل فایل های لازم را در آن وارد می کنیم.
اول از همه فایل پیکربندی را بارگیری می کنیم:
// config وارد کردن فایل
require_once ‘../config/config.php’;
فایل config.php در پوشه config قرار دارد.
در داخل فایل پیکربندی می توانیم تنظیمات فریمورک را ذخیره کنیم. به عنوان مثال می توانیم نام برنامه، مسیر ریشه و همچنین پارامترهای اتصال پایگاه داده را ذخیره کنیم:
<?php
//نام سایت
define(‘SITE_NAME’, ‘your-site-name’);
// مسیر ریشه
define(‘APP_ROOT’, dirname(dirname(__FILE__)));
define(‘URL_ROOT’, ‘/’);
define(‘URL_SUBFOLDER’, ”);
// پارامترهای پایگاه داده
define(‘DB_HOST’, ‘your-host’);
define(‘DB_USER’, ‘your-username’);
define(‘DB_PASS’, ‘your-password’);
define(‘DB_NAME’, ‘your-db-name’);
Autolader
برای بارگیری بدون دردسر کلاس های آینده از PSR-4 autoloading با 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
حالا اگر پوشه ریشه پروژه را بررسی کنید، یک پوشه جدید به نام vendor می ببینید که شامل فایل autoload.php و پوشه composer است.
فایل index.php را باز کنید و کد زیر را به سادگی در ابتدای آن اضافه کنید:
require_once ‘../vendor/autoload.php’;
از اینجا به بعد می توانید از App به عنوان نقطه شروع فضای نام خود استفاده کنید، مانند زیر:
use AppControllersMyController;
در ادامه مفاهیم اختصاری در MVC را بررسی می کنیم.
Model در MVC
model یا مدل، یک شی برای نمایش داده ها است. یک model روی ساختار جدول پایگاه داده مدل می شود و با عملگرهای پایگاه داده (ایجاد، خواندن، به روزرسانی و حذف) تعامل دارد.
فرض کنید یک جدول برای محصولات با نام Products شبیه جدول زیر دارید:
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 در پوشه app ایجاد می کنیم. سپس یک فایل جدید به نام Product در پوشه Models می سازیم.
مدل Product به صورت زیر خواهد بود:
<?php
namespace AppModels;
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 در MVC
view یا نما، مسئول گرفتن داده ها از کنترلرها و نمایش مقادیر آنها است. موتورهای الگوی زیادی برای PHP وجود دارد، از Twig گرفته تا Blade. برای این آموزش MVC فقط از HTML ساده برای ساده کردن کارها استفاده خواهیم کرد.
برای ایجاد یک view جدید یک فایل جدید به نام 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>
حالا view برای دریافت شی (product$) و نمایش مقادیر آن آماده است.
Controller در MVC
Controller یاکنترلر (یا کنترل کننده) قلب منطق برنامه است و مسئولیت پذیرش ورودی و تبدیل آن به دستورات برای model یا view را بر عهده دارد.
یک پوشه جدید به نام Controllers در پوشه app ایجاد می کنیم و یک فایل کنترلر جدید به نام ProductController.php می در آن سازیم. محتوای آن:
<?php
namespace AppControllers;
use AppModelsProduct;
use SymfonyComponentRoutingRouteCollection;
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ها نیاز داریم. می خواهیم با آدرس هایی کار کنیم که خواندن آنها آسان است و شامل کلماتی برای توصیف محتوای صفحه وب باشند،. بنابراین به یک سیستم routing یا مسیردهی نیاز داریم.
می توانیم سیستم مسیر خود را ایجاد کنیم یا چون از composer برای بارگیری خودکار استفاده کردیم، می توانیم پکیج های اکوسیستم سیمفونی (Symfony) را جستجو و بررسی کنیم و هوشمندانه کار کنیم!
چگونه می توانیم از کامپوننت مسیردهی سیمفونی (Symfony Routing Component) استفاده کنیم؟ در آدرس https://symfony.com/doc/current/create_framework/routing.html مستنداتی وجود دارد.
اول از همه، کامپوننت را نصب می کنیم:
composer require symfony/routing
حالا اگر داخل پوشه vendor را بررسی کنید، یک پوشه جدید به نام Symfony ایجاد شده است.
پیاده سازی سیستم مسیردهی برای فریمورک MVC را شروع می کنیم. هدفمان این است که با باز کردن آدرس URL /product/1، مقادیر محصول با ID = 1 نمایش داده شود.
یک فایل جدید به نام web.php در پوشه routes ایجاد می کنیم، این فایل شامل تمام مسیرهای برنامه خواهد بود.
<?php
use SymfonyComponentRoutingRoute;
use SymfonyComponentRoutingRouteCollection;
// 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 برای ایجاد و لیست همه مسیرهای مورد نیاز خود استفاده می کنیم. با صفحه یک محصول واحد شروع می کنیم.
سپس موتور مسیردهی را ایجاد می کنیم. یک فایل جدید به نام Router.php در داخل پوشه app می سازیم و کد زیر را در داخل آن قرار می دهیم:
<?php
namespace App;
use SymfonyComponentRoutingRequestContext;
use SymfonyComponentRoutingRouteCollection;
use SymfonyComponentRoutingMatcherUrlMatcher;
use SymfonyComponentRoutingExceptionMethodNotAllowedException;
use SymfonyComponentRoutingExceptionResourceNotFoundException;
use SymfonyComponentRoutingExceptionNoConfigurationException;
class Router
{
public function __invoke(RouteCollection $routes)
{
$context = new RequestContext();
// 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، درخواست URL را می گیرد و بررسی می کند که آیا با یکی از مسیرهای تعریف شده در routes/web.php مطابقت دارد یا نه. اگر تطبیقی وجود داشته باشد، تابع call_user_func_array جادو می کند و متد درست از کنترلر درست را فراخوانی می کند.
علاوه بر این از تابع array_walk برای تبدیل نوع مقادیر عددی به مقادیر عدد صحیح (integer) استفاده کردیم زیرا در متدهای کلاس خود نوع اعلان صریح را به کار برده بودیم.
حالا می توانیم سیستم مسیرها را در فایل 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 را باز کرده و نتیجه را مشاهده کنیم. بدیهی است که مقادیر فعلا خالی هستند. مقادیری برای محصول وارد می کنیم:
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 به دست آورید.
چگونه برنامه نویس شویم؟ (9 نکته برای شروع و ورود به بازار کار)
صفحه اصلی
حالا بیایید مسیر صفحه اصلی را آماده کنیم. routes/web.php را باز کرده و مسیر جدید را اضافه کنید:
$routes->add(‘homepage’, new Route(constant(‘URL_SUBFOLDER’) . ‘/’, array(‘controller’ => ‘PageController’, ‘method’=>’indexAction’), array()));
بدیهی است ما باید کنترلر جدید PageController را ایجاد کنیم:
<?php
namespace AppControllers;
use AppModelsProduct;
use SymfonyComponentRoutingRouteCollection;
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’;
}
}
و view جدید:
<!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 برای این قسمت ها را جدا کنیم.
بهبود فریمورک PHP MVC
اتصال به پایگاه داده و ORM، session، کوکی ها، کنترلرهای بهتر صفحه که از پارامترهای مختلف صفحه استفاده می کنند یا هر ویژگی دیگری را می توانید به راحتی اضافه کنید اما در این مقاله فقط روش ساخت یک MVC PHP ساده را بررسی کردیم.
حتما دانلود کنید: آموزش صفر تا صد PHP و جزوه
نتیجه گیری
پس از اطمینان از الگوی MVC پیشنهاد می کنیم شروع به کار با Laravel یا Symfony کنید! متوجه خواهید شد که فرآیند توسعه سریعتر از استفاده از PHP محض است.