خوب Yii از این نظر خیلی منعطف تر و بهتر عمل کرده (بنظر من). بطور پیشفرض توی Yii نسخه 1.1 از BluePrint CSS و توی نسخه 2 از Bootstrap برای قالب استفاده شده و موتور قالب خاصی به کار نرفته هرچند به راحتی میتونه با Smarty و RainTPL و Twig و... ادغام بشه. اما ساختار فایلهای View در Yii به این صورته:
1- تم (Theme)
توی فایل تنظیمات میتونیم تم رو انتخاب کنیم (توی Yii هر تم میتونه فایلهای ویوی خاص خودش رو داشته باشه و به راحتی با تغییر یک پارامتر توی فایل تنظیمات، میشه تم رو عوض کرد) :
return array(
...
'theme'=>'mytheme',
...
);
اگه تم تعریف کنیم، فایلهای ویو از مسیر webroot/themes/mytheme/views خونده میشه (که mytheme اسم تمی هست که توی تنظیمات مشخص کردین) وگرنه از مسیر webroot/protected/views این فایلها مورد دستیابی قرار میگیره. ضمناً هر تم میتونه حاوی فایلهای CSS و JS و... مختص خودش باشه.
2- فایلهای Layout
توی هر کنترلر (یا کنترلر والد یعنی protected/components/Controller.php) میتونیم یک فیلد public بگذاریم که مشخص میکنه از چه layout خاصی باید استفاده بشه:
public $layout = '//layouts/layout1';
// or
public $layout = '/layouts/layout1';
اینجا اگه از // استفاده بشه، دنبال پوشه layouts توی مسیر ریشه تم یا مسیر ریشه views میگرده ولی اگه از / استفاده کنیم، برای هر ماژول میتونیم پوشه views داخلش بسازیم و layout مخصوص همون ماژول رو تولید کنیم و این یعنی هر ماژول میتونه به شکل متفاوتی ظاهر بشه (حتی با تم مختلف - برای مثال، سایت اصلی با یک قالب و بخش مدیریت با یک قالب دیگه ظاهر بشه و هر زمان خواستیم، قالب هرکدوم رو بطور جداگانه بتونیم تغییر بدیم)
ضمناً امکان تنظیم کردن layout بصورت جداگانه برای هر اکشن هم وجود داره. مثال:
class UserController extends Controller {
public $layout = '//layouts/layout1';
public function actionIndex() {
// uses layout1
}
public function actionView($id) {
$this->layout = '//layouts/layout2';
// uses layout2
}
}
ساختار یک Layout نمونه:
کد HTML:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<meta name="language" content="en" />
<!-- blueprint CSS framework -->
<link rel="stylesheet" type="text/css" href="<?php echo Yii::app()->request->baseUrl; ?>/css/screen.css" media="screen, projection" />
<link rel="stylesheet" type="text/css" href="<?php echo Yii::app()->request->baseUrl; ?>/css/print.css" media="print" />
<!--[if lt IE 8]>
<link rel="stylesheet" type="text/css" href="<?php echo Yii::app()->request->baseUrl; ?>/css/ie.css" media="screen, projection" />
<![endif]-->
<link rel="stylesheet" type="text/css" href="<?php echo Yii::app()->theme->baseUrl; ?>/css/main.css" />
<link rel="stylesheet" type="text/css" href="<?php echo Yii::app()->request->baseUrl; ?>/css/form.css" />
<title><?php echo CHtml::encode($this->pageTitle); ?></title>
</head>
<body>
<div class="container" id="page">
<div id="header"></div><!-- header image is embeded into the #header declaration in main.css -->
<div id="mainmenu">
<?php $this->widget('zii.widgets.CMenu',array(
'items'=>array(
array('label'=>'Projects', 'url'=>array('/project')),
array('label'=>'About', 'url'=>array('/site/page', 'view'=>'about')),
array('label'=>'Contact', 'url'=>array('/site/contact')),
array('label'=>'Admin', 'url'=>array('/admin/default/index'), 'visible'=>Yii::app()->user->checkAccess("admin")),
array('label'=>'Login', 'url'=>array('/site/login'), 'visible'=>Yii::app()->user->isGuest),
array('label'=>'Logout ('.Yii::app()->user->name.')', 'url'=>array('/site/logout'), 'visible'=>!Yii::app()->user->isGuest)
),
)); ?>
</div><!-- mainmenu -->
<?php if(isset($this->breadcrumbs)):?>
<?php $this->widget('zii.widgets.CBreadcrumbs', array(
'links'=>$this->breadcrumbs,
)); ?><!-- breadcrumbs -->
<?php endif?>
<?php echo $content; ?>
<div class="clear"></div>
<div id="footer">
Copyright © <?php echo date('Y'); ?> by TrackStar.<br/>
All Rights Reserved.<br/>
<?php echo Yii::powered(); ?>
</div><!-- footer -->
</div><!-- page -->
</body>
</html>
کمی بنظر ممکنه پیچیده بیاد ولی دقت کنید: این یک فایل HTML ساده است! یعنی فایلهای Layout در Yii یک قالب ساده HTML هستن که محتوای خروجی viewها رو میتونید در محل دلخواه با دستور زیر نمایش بدین:
<?php echo $content; ?>
3- فایلهای View
فایلهای ویو توی پوشه views (در مسیر تم یا مسیر پیشفرض ویوها) قرار میگیرن و وقتی تم تعریف کنیم، Yii اول توی پوشه views از مسیر تم دنبالش میگرده و اگه پیدا نکرد، توی پوشه views اصلی (داخل protected) دنبالش میگرده. ساختار یک یک فایل view نمونه:
کد HTML:
<?php $this->pageTitle=Yii::app()->name; ?>
<h1>Welcome to <i><?php echo CHtml::encode(Yii::app()->name); ?></i></h1>
<?php if(!Yii::app()->user->isGuest):?>
<p>
You last logged in on <?php echo Yii::app()->user->lastLogin; ?>.
</p>
<?php endif;?>
اگه دقت کنید، این هم یک فایل HTML ساده است. حالا چطوری این رو باید صدا بزنیم؟ فرض کنید توی کنترلر SiteController چنین دستوری داریم:
$this->render('index');
خوب این کد ساده باعث میشه دنبال فایل index.php (همون ویوی بالا) توی پوشه site (همنام با کنترلر) در پوشه views (اول توی پوشه تم و اگه نبود، توی پوشه views اصلی) بگرده و اون رو پردازش کنه. کل خروجی این ویو تحت عنوان متغیر content$ به فایل layout جاری (در اینجا layout1) داده میشه که در مکان دلخواه با دستوری که گفتیم (;echo $content) نشونش بده.
4- استفاده فایلهای Layout از هم (Layoutهای واسط)
فرض کنید من چند Layout فرعی دارم (مثلاً یک ستونه و دو ستونه و...) که اینها Body صفحه من رو میسازن و من میخوام همه اینها توی یک Layout کلی و بزرگتر (شامل Header و Footer و...) قرار بگیره. کافیه توی Layoutهای فرعی اینطوری کار کنم:
<?php $this->beginContent('//layouts/main'); ?>
<div id="content">
<?php echo $content; ?>
</div><!-- content -->
<?php $this->endContent(); ?>
در اینجا اگه این Layout به اسم فرضی views/layouts/column1 ذخیره شده باشه و منبیام توی یک کنترلر بگم:
public $layout = '//layouts/column1';
باعث میشه وقتی میگم (...)this->render$ هر فایل view که برای رندر انتخاب کردم، خروجی خودش رو تحت عنوان content$ به column1 بده و این layout هم اون محتوا رو توی div با "id="content میگذاره و باز خروجی خودش رو تحت عنوان متغیر content$ به layout اصلی یعنی //layouts/main یعنی فایل views/layouts/main.php میده که میتونه در مکان مناسب (بین Header و Footer) اون رو echo کنه.
5- ارتباط بین Viewها با هم
توی Yii علاوه بر دستور render دستورات دیگری هم در اختیار کنترلر هست. برای مثال:
renderPartial (یک ویو رو رندر میکنه ولی مستقیماً خروجی رو چاپ میکنه و تحویل Layout نمیده)
renderText (یک متن ساده رو رندر میکنه و تحویل Layout میده - برای مواقعی که میخواین یک متن ساده رو توی قالب صفحه نشون کاربر بدین و نمیخواین فایل View جداگانه براش بسازین).
...
اما کاربرد اینها چه ارتباطی به رابطه Viewها با هم داره؟ ربطش اینه که توی Viewهای در Yii با کمک متغیر this$ به شئ کنترلر دسترسی داریم و مثلاً توی یک ویو (فرضاً user/index) میتونیم این دستور رو بنویسیم:
$this->renderPartial('user/login');
که باعث میشه فرم لاگین (محتوای views/site/login.php) توی صفحه index (محتوای views/site/index.php) هم ظاهر بشه.
5- ارسال پارامتر به ویو توسط کنترلر
توی Yii میشه به دو روش برای View پارامتر فرستاد.
روش اول دسترسی مستقیم به فیلدهای کنترلر هست:
// in controller action
$this->x = 'ali';
$this->render('index');
// in index.php view file
echo $this->x; // output: ali
روش دوم، تعریف پارامتر مستقیماً برای خود View هست:
// in controller action
$this->render('index', array('x' => 'ali'));
// in index.php view file
echo $x; // output: ali
یعنی درواقع عناصر آرایه ای که اونطرف میفرستیم، اینطرف تبدیل به متغیرهای مستقل میشن.
-----
شاید بگین هنوز به این چیزها نرسیده بودیم و باز من جلو جلو جواب دادم ولی خواستم همین اول کار بگم وارد این مبحث نشین چون لاراول رسماً کم میاره. برای مثال معادل همین امکانات رو خوشحال میشم بدونم لاراول چطوری پیاده سازی میکنه.