במאמר הקודם הדגמנו כיצד יוצרים אפליקציה בסיסית באמצעות זנד, במאמר הזה אנו נמשוך לעסוק באותה אפליקציה ונדבר על Base Controllers.
בכל אפליקציה ישנן כמה מתודות שמשתמשים בהן בכמה ובכמה מקרים. דוגמא טובה היא מתודות אבטחה שמשתמשים בהן באופן זהה כמעט בכל טופס שיש באפליקציה. אבל כמובן שאפשר לחשוב על מתודות נוספות שמשתמשים בהם בקונטרולרים שונים וב-Actions שונים. דרך מסוימת לטפל במתודות כאלו היא לא לכתוב אותן בכל קונטרולר אלא ליצור Base Controller שבו יש את כל מה שאנו צריכים. אני לא אוהב להשתמש ב-Base Controller כי הוא נוטה להתנפח ולספוח אליו מלא מתודות שמוטב להן שלא היו בו. ופחי זבל עדיף שיהיו בעיריה ולא בתוכנה שלי. א-מ-מ-ה, בזנד פריימוורק יש מקומות טובים מאד לשים מתודות משותפות ועל המקומות האלו אנו נלמד בהמשך. בינתיים – נתייחס ל-Base Controllers.
לשם הדוגמא, אני אצור מתודה שמטפלת בכל נושא ה-tokens באפליקציה שלנו. מה זה tokens? זו שיטת אבטחה שמטרתה לוודא שהטפסים שלנו נשלחים באמת מהדפים שיצרנו ואין איזה פרחחון ששולח אלינו מידע שלא מהטופס שלנו.
השיטה היא פשוטה ביותר, אני מייצר איזשהו סוג של token בטופס שלי, שולח אותו אל השרת ושם מוודא שה-token נכון ותקף מול ה-Session של המשתמש. במידה וכן, אני מעבד את הבקשה. במידה ולא אני שולח את הבקשה לאלף עזאזלים.
אני משתמש לשם הדוגמא באפליקציה שיצרנו במאמר הקודם. ראשית, אני אצור קובץ בשם BaseController.php (עדיף לא להשתמש ב-CLI> כדי לייצר אותו אלא ליצור אותו לבד.
<?php
Zend_Loader::loadClass('Zend_Controller_Action');
Zend_Loader::loadClass('Zend_Session_Namespace');
class BaseController extends Zend_Controller_Action
{
protected function generateToken($seed='The^SeeD&Of#Love!%') {
$token = md5($seed.mktime());
$globalSession = new Zend_Session_Namespace('global_data');
$globalSession->token = $token;
return $token;
}
protected function tokenCheck($tokenToCheck=’’) {
$globalSession = new Zend_Session_Namespace('global_data');
$returnValue = (!empty($tokenToCheck) and $tokenToCheck==$globalSession->token);
return $returnValue;
}
}
מה שיש בקונטרולר הזה הוא קריאה ל-Zend_Controller_Action ול-Zend_Session_Namespace על מנת שאנו נוכל לרשת את Zend_Controller_Action. בקונטרולר יש גם שתי מתודות שהן protected (כלומר, רק מי שיורש מה-Base Controller יכול להשתמש בהן). אחת מהן יוצרת את ה-Token והשניה בודקת אותו. אין לי יותר מדי מה להסביר עליהן למעט השימוש ב-Zend_Session_Namespace שהיא בעצם ה-API לכל נושא ניהול ה-Session. רוצים לדעת עוד? מעולה! בדיוק בשביל זה יש את ה-Programmer's Reference Guide שמכיל את כל המתודות ומה שתרצו על זנד. שם יש מידע מפורט על Sessions.
אחרי שיצרנו את ה-BaseController, אנחנו צריכים לטפל ב-IndexController, ראשית, צריך שהוא יירש את BaseController ולא את Zend_Controller_Action, לפיכך נעשה את זה כך:
class IndexController extends BaseController
עכשיו עלינו לשנות את הקונטרולר כדי שיכיל את ההתיחסויות ל-Token, בגדול, כאשר הקונטרולר נטען (ה-indexAction) הוא יוצר Token וכאשר אנו שולחים את הטופס (extractAction) הוא בודק את ה-Token, במידה והבדיקה נכשלה, הוא עושה redirect ל-index במקום להחזיר את התוצאות.
הנה הקוד המלא שעושה את זה, הוא די פשוט לניתוח – הדגשתי את החלקים החשובים אבל אין פה משהו שאמור להפתיע אתכם:
< ?php
class IndexController extends BaseController
{
public function init()
{
/* Initialize action controller here */
}
public function indexAction()
{
$this->view->token = $this->generateToken();
}
public function extractAction()
{
$token = Zend_Filter::get($this->getRequest()->getPost('token'), 'StripTags');
$tsearch = Zend_Filter::get($this->getRequest()->getPost('tsearch'), 'StripTags');
if (!$this->tokenCheck($token)) {
$this->_redirect('/index/index');
return false;
}
$this->generateToken();
$twitterSearch = new Zend_Service_Twitter_Search('json');
$searchResults = $twitterSearch->search("$tsearch", array('lang' => 'en'));
$result = $searchResults['results'];
$this->view->tsearch = $tsearch;
$this->view->result = $result;
}
}
אחרי זה נותר לי להוסיף רק שדה hidden שיכיל את ה-Token שלנו:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/
xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
<title>Search Tweets!</title>
</head>
<body>
<form method="POST" action="http://192.168.123.100/mytwit/public/index/extract" name="mainform">
<label for="tsearch">Twitter search phrase:</label>
<input type="hidden" id="token" name="token" value="<?php echo $this->token;?>"/>
<input name="tsearch" id="tsearch" value="Israel" />
<input type="Submit" name="submit" id="submit" value="Get My Tweets!" />
</form>
</body>
</html>
הדבר האחרון שנותר לי הוא להוסיף את קובץ ה-BaseController.php אל ה-includes שלי. יש כמה שיטות לעשות את זה. השיטה המכוערת ביותר היא להכניס
require_once('/var/www/mytwit/application/controllers/BaseController.php');
לכל קובץ וקובץ שבו אנו מבצעים הורשה של BaseController. דרך קצת פחות אידיוטית היא להכניס את השורה הזו ב-bootstrap או ב-index.php מעט לפני ה-bootstrap. דרך אלגנטית יותר היא להוסיף את ה-include ב-apache עצמו או להוסיף library שכוללת את ה-BaseController.
כאמור, במקרה של זנד אני מעדיף להשתמש ב-Helpers, Plugins או בשיטות אחרות מלבד BaseController שנוטות להתנפח במלא מתודות. אבל לפעמים ה-design מכתיב שימוש ב-BaseController ואני חייב לנהוג ככולי עלמא.
במאמר הבא אנו נלמד על helpers ב-Zend FrameWork.