תחי ישראל - אין לנו ארץ אחרת

תחי ישראל -אין לנו ארץ אחרת

MVC וארגון קוד ה-PHP

מחבר:
בתאריך:

PHP היא ללא ספק שפה שקל ללמוד וליישם, אבל גם שפה שיכולה להתדרדר בקלות לקוד ספגטי, שבו סוגים שונים של קוד מבולגנים ביחד באופן שמקשה על תחזוקת הקוד, הכנסת שינויים ותיקון באגים. על מנת למנוע את התדרדרות הקוד, כדאי לארגן אותו לקבצים ולתיקיות. הרעיון של הפרדת קוד ה-JavaScript וה-CSS משאר רכיבי הקוד הוא מובן מאליו, אבל כיצד להפריד את החלק הלוגי שהאחראי לו הוא PHP מחלק התבנית שבו העיקר הוא ההטמ"ל?

אולי הפתרון הפשוט ביותר הוא להפריד את החלק של הלוגיקה (שבה מטופלים המשתנים ונקבע ערכם) לקובץ או לתיקייה נפרדת, ולהטמיע את המשתנים בהטמ"ל בחלק אחר של האפליקציה. אם נבחר בפתרון זה, החלק הלוגי יכונה Controller (פקד), בעוד קובץ התבנית יכונה View.

 

eBook cover The essentials of Object Oriented PHP

 

בדוגמה הבאה, הקובץ controller.php משמש בתור הפקד, והוא מקבל מידע ממקור נתונים (מסד נתונים, API חיצוני וכיו"ב), מעבד את המידע, ומספק את הנתונים שיותר מאוחר ישמשו בקובץ התבנית. המידע שמשמש את הפקד מקובץ במערך $cars, ומחזיק את המודלים של המכוניות ואת מחירם. אנו בודקים האם המכונית יקרה באמצעות הפונקציה expensiveOrNot, ומאחסנים את התוצאה במערך חדש ששמו $carsReviewed.

// Get the price and returns whether it is expensive or not
function expensiveOrNot($price)
{
  if($price > 30000) return "יקר";
  return "לא יקר";
}
 
$cars = array ("Bmw" => array("model" => "2-Series", "price" => "32000"),
      "Audi" => array("model" => "A3","price" =>"29900") );
 
// Perform some logic on the data to find out whether the car is expensive.
$carsReviewed = array("Bmw" => array("model" => "2-Series", "price" => "32000", "expensiveOrNot" =>expensiveOrNot(32000) ),
"Audi" => array("model" => "A3", "price"=>"29900", "expensiveOrNot"=>expensiveOrNot(29900) ) );

עכשיו, בקובץ התבנית, אנו יכולים להטמיע את המשתנים שעברו עיבוד ב-Controller לתוך ההטמ"ל, אבל קודם עלינו להכליל את קובץ ה- Controller:

<?php require "controller.php"; ?>
<!doctype html>
<html>
<head> </head>
<body>
<p> BMW <?=$carsReviewed["Bmw"]["model"]?> <?=$carsReviewed["Bmw"]["expensiveOrNot"]?> ו Audi <?=$carsReviewed["Audi"]["model"]?> <?=$carsReviewed["Audi"]["expensiveOrNot"]?>. </p>
</body>
</html>

תוצאה:
BMW 2-Series יקר ו- Audi A3 לא יקר.

הפרדת הלוגיקה מהתצוגה עשויה לייעל את העבודה כשעובדים בצוות מפני שהיא מאפשרת למתכנתים לעבוד על הצד הלוגי של האפליקציה ולהשאיר למעצבים לעבוד על קובץ התבנית, בלי שיפריעו אחד לשני.

המודל

ראינו שהפרדת הלוגיקה מהתצוגה באפליקציה יכולה להועיל, אבל עוד לא טיפלנו באותו חלק של האפליקציה שעובד מול מקור הנתונים. אותו חלק שעובד מול מסד הנתונים מכונה המודל (Model), ויש בו את כל מה שצריך כדי לטפל במקור הנתונים. תפקידו לשלוף את המידע ממסד הנתונים, לעדכנו, למחוק ולהכניס נתונים וכל זאת תוך שמירה על אבטחת המידע.

 

ההקשר הרחב –mvc

עד כה למדנו שבאפליקציה יכולים להיות שלושה מרכיבים:

1. המודל שמטפל במקור הנתונים
2. ה-View שבו שוכנים קבצי התבנית
3. ה- Controller שמתאם בין ה- Viewובין המודל

כשאנו מפרידים את האפליקציה שלנו ל- Model, View ול- Controllerאנו משתמשים בדפוס תכנותי (design pattern) ששמו mvc (ראשי תיבות של Model, View and Controller).

design pattern הם בראש ובראשונה דרך בדוקה ומחושבת היטב לתכנון מבנה הקוד בדרך ברורה שמקובלת ומובנת על ידי קהילת המתכנתים. קיימים כמה עשרות design pattern, וביניהם החשוב ביותר למתכנתי PHP הוא דפוס ה-mvc.

 

זרימת המידע ב-mvc

ל-controller יש תפקיד מיוחד בדפוס ה-mvc בתור המתווך בין המודל וה-view. ה-controller מקבל את המידע שהמודל שולף ממקור הנתונים, מעבד אותו ומעביר ל-View לצורך הצגה. הוא גם עובד בכיוון ההפוך, כשהמידע שמתקבל מהמשתמש (דוגמת מידע שמתקבל מטפסים) מועבר ל-controller לעיבוד ולהפניה ל-Model. התרשים הבא יכול לסייע בהבנת זרימת המידע ב-MVC:

mvc explained

לאחר שהאפליקציה מקבלת מידע מהמשתמש (לדוגמה אחרי שמשתמש הזין מידע לטופס והגיש אותו), המידע מועבר לקונטרולר, שמעבד את המידע ומחליט לאיזה מהמחלקות של המודל להעביר את המידע, ואז המודל מסנן את הנתונים ומאחסן, מעדכן, או מוחק את המידע לפי הצורך. המידע יכול לעשות את הדרך ההפוכה מהמודל לקונטרולר לעיבוד נוסף (דוגמת לאיזה דף להפנות את המשתמש או איזה מידע להציג למשתמש), ואז המידע מוצג למשתמש ב-View.

 

ה-MVC הפשוט ביותר – שליפת הנתונים ממקור הנתונים

בדוגמה הבאה נבדוק האם מכונית יקרה בדרך ה-MVC. בדוגמה הזו, המידע מוזן למודל, לפני שהוא מעובד בקונטרולר ומועבר להצגה ב-View. מחלקת המודל מקבלת ומחזירה את המידע אודות המכונית (באפליקציה בעולם האמיתי רוב הסיכויים שתקבל את המידע ממסד הנתונים).

class Model {
  // Store the data
  private $carPrice;
 
  // Set the data
  public function setPrice($price)
  {
     $this -> carPrice = $price;
  }
 
  // Get the data
  public function getPrice()
  {
      return $this -> carPrice;
  }
}

מחלקת ה- Controllerהיא המתווך. היא מקבלת את המידע אודות מחיר המכונית מהמודל ובודקת האם המכונית יקרה.

class Controller {
  private $model;
  private $limit = 30000;
 
   // Set the model so we can use its data
  public function __construct(Model $model)
  {
      $this -> model = $model;
  }
 
   // Set the data in the module
  public function setPrice($price)
  {
      $this->model->setPrice((int)$price);
  }
 
   // Some logic to check if the price is expensive
  public function expensiveOrNot()
  {
     if($this->model->getPrice() > $this->limit) return "יקר";
      return "לא יקר";
  }
}

המחלקה View מקבלת את המידע אחרי עיבודו בקונטרולר, ומציגה אותו למשתמש:

class View {
  private $controller;
 
   // Set the controller so we can use it
  public function __construct(Controller $controller)
  {
      $this->controller = $controller;
  }
 
   // Output the data after processing it by the controller
  public function output()
  {
      return $this->controller->expensiveOrNot();
  }
}

עכשיו, אנחנו יכולים ליישם את הקוד. אנו מזינים את מחלקת ה- Model במחיר, קוראים לקונטרולר שיבצע את הלוגיקה שלו, ומציגים את התוצאה באמצעות מודל ה- View:

// The data can come from the database
$priceToCheck = 31000;
 
// The data is retrieved by the model
$model1 = new Model();
$model1 -> setPrice($priceToCheck);
 
// We need the controller in order to process the data
$controller1 = new Controller($model1);
 
// We need the view in order to output the processed data
$view1 = new View($controller1);
echo $output = $view1 -> output();

והתוצאה: יקר

את התוצאה ניתן להטמיע עכשיו בהטמ"ל.

 

ה-MVC הפשוט ביותר (חלק 2) – או מה קורה כשמתקבל מידע מהמשתמש?

הדוגמה שלנו ל- MVC לא יכולה להיות מושלמת בלי שנספק לה את האפשרות לקבל מידע מהמשתמש ולהעביר אותו למודל. המידע מהמשתמש יכול להיות מוזן לאפליקציה דרך טופס ששולח את הנתונים ב-post. לדוגמה:

$priceToCheck = $_POST['price'] = 29900;

עכשיו אנחנו צריכים שהקונטרולר יעביר את המידע למודל, ולפיכך אנו מוסיפים לקונטרולר את המתודה setPrice(), שיכולה לקבוע את המחיר במודל.

class Controller {
  private $model;
  private $limit = 30000;
  
  // Set the model so we can use its data
  public function __construct(Model $model)
  {
      $this -> model = $model;
  }
  
   // Set the data in the module
   public function setPrice($price)
   {
      $this->model->setPrice((int)$price);
   }
  
  // Some logic to check if the price is expensive
  public function expensiveOrNot()
  {
     if($this->model->getPrice() > $this-> limit) return "יקר";
      return "לא יקר";
  }
}

עכשיו, אנחנו יכולים לחבר את הקצוות, בכדי להציג את המידע:

// The data can come from the user
// e.g. through a post request

$priceToCheck = $_POST['price'] = 29900;
 
// We need the model to store the data
$model2 = new Model();
 
// We need the controller in order to get the user data
// and process it before passing it to the Model

$controller2 = new Controller($model2);
$controller2 -> setPrice($_POST['price']);
 
// We need the view in order to output the processed data
$view2 = new View($controller2);
echo $output = $view2 -> output();

והתוצאה: לא יקר

את התוצאה ניתן להטמיע בהטמ"ל.

 

לסיכום

דפוס ה-mvc חשוב מאוד למתכנתי PHP מפני שהוא מכריח אותנו להפריד את הלוגיקה מהתצוגה ובכך מסייע לנו בכתיבת אפליקציות שיהיה לנו קל יותר לתחזק ולהרחיב.

 

המדריך מבוסס על "The essentials of Object Oriented PHP" שמלמד PHP מונחה עצמים באמצעות דוגמאות ותרגילים הקליקו על התמונה כדי לרכוש את ה-eBook:

eBook cover The essentials of Object Oriented PHP

 

למדריכי ה-PHP מונחי העצמים

 

 

אהבתם? לא אהבתם? דרגו!

0 הצבעות, ממוצע 0 מתוך 5 כוכבים

 

 

המדריכים באתר עוסקים בנושאי תכנות ופיתוח אישי. הקוד שמוצג משמש להדגמה ולצרכי לימוד. התוכן והקוד המוצגים באתר נבדקו בקפידה ונמצאו תקינים. אבל ייתכן ששימוש במערכות שונות, דוגמת דפדפן או מערכת הפעלה שונה ולאור השינויים הטכנולוגיים התכופים בעולם שבו אנו חיים יגרום לתוצאות שונות מהמצופה. בכל מקרה, אין בעל האתר נושא באחריות לכל שיבוש או שימוש לא אחראי בתכנים הלימודיים באתר.

למרות האמור לעיל, ומתוך רצון טוב, אם נתקלת בקשיים ביישום הקוד באתר מפאת מה שנראה לך כשגיאה או כחוסר עקביות נא להשאיר תגובה עם פירוט הבעיה באזור התגובות בתחתית המדריכים. זה יכול לעזור למשתמשים אחרים שנתקלו באותה בעיה ואם אני רואה שהבעיה עקרונית אני עשוי לערוך התאמה במדריך או להסיר אותו כדי להימנע מהטעיית הציבור.

שימו לב! הסקריפטים במדריכים מיועדים למטרות לימוד בלבד. כשאתם עובדים על הפרויקטים שלכם אתם צריכים להשתמש בספריות וסביבות פיתוח מוכחות, מהירות ובטוחות.

המשתמש באתר צריך להיות מודע לכך שאם וכאשר הוא מפתח קוד בשביל פרויקט הוא חייב לשים לב ולהשתמש בסביבת הפיתוח המתאימה ביותר, הבטוחה ביותר, היעילה ביותר וכמובן שהוא צריך לבדוק את הקוד בהיבטים של יעילות ואבטחה. מי אמר שלהיות מפתח זו עבודה קלה ?

השימוש שלך באתר מהווה ראייה להסכמתך עם הכללים והתקנות שנוסחו בהסכם תנאי השימוש.

הוסף תגובה חדשה

 

 

ענה על השאלה הפשוטה הבאה כתנאי להוספת תגובה:

דג למים הוא כמו ציפור ל...?