نحوه استفاده از مدل و ارتباط با کنترلر

[font="Tahoma"] [rtl]

این تکه کد که داخل فایل سایت کنترلر هستش نحوه استفاده از مدل رو نوشته که یه متغیر را تعریف کرده و اومده ازدستور زیر استفاده کرده. من مدل مربوط به فایل LoginForm رو باز کردم ولی هیچ متغیر و یا تابعی به اسم attributes ندیدم. این جریان ارتباط چطوریه

[/rtl]


$model->attributes=$_POST['LoginForm'];




public function actionLogin()

	{

		if (!defined('CRYPT_BLOWFISH')||!CRYPT_BLOWFISH)

			throw new CHttpException(500,"This application requires that PHP was compiled with Blowfish support for crypt().");


 		$model=new LoginForm;


 		// if it is ajax validation request

		if(isset($_POST['ajax']) && $_POST['ajax']==='login-form')

		{

			echo CActiveForm::validate($model);

			Yii::app()->end();

		}


 		// collect user input data

		if(isset($_POST['LoginForm']))

		{

			$model->attributes=$_POST['LoginForm'];

			// validate user input and redirect to the previous page if valid

			if($model->validate() && $model->login())

				$this->redirect(Yii::app()->user->returnUrl);

		}

		// display the login form

		$this->render('login',array('model'=>$model));

	}

[rtl]

[/rtl]

[rtl]

[/rtl]

[rtl]

[/rtl] [/font]

[rtl][font="Tahoma"]

نیازی نیست که شما کلمه attributes را ببینید.

کاری که انجام می شود این است که محتوای LoginForm شما توسط مد Post برای کنترلر ارسال می شه.

در کنترلر نمونه ای از مدل که همان فیلدهای LoginForm شما هستند ساخته می شود و با مقادیر پست شده پر می شوند

توسط validate سازگاری ها با rules تعریف شده بررسی می شود و نهایتا از طریق فراخوانی فیلدها مقادیر قابل استفاده می شوند.[/font]

[/rtl]

[rtl]

اینکه نیازی نیست ببینیم رو من نفهمیدم. الان باید یه همچین چیزی تو مدل - کلاس به صورت متغیر یا تابع نباید باشه؟ من تو مفهوم این تیکه کد موندم.

اگه به رول میره چرا ما مستقیم از اون استفاده نمیکنیم یا بهش معرفی کنیم چک بکنه؟

[/rtl]

[rtl]

در کنترلر ابتدا نمونه ای از مدل ساخته می شود که کلاس مدل که شامل فیلدها و قوانین می باشند در LoginForm تعریف شده است.

بعد از اینکه نمونه ساخته شد باید مقدار دهی شود یعنی با مقادیری که کاربر در فرم خود پست کرده تکمیل شوند. 2 روش برای پر کردن مقادیر وجود دارد روش اول تکمیل موردی یعنی فیلد به فیلد مدل ساخته شده را با فیلد به فیلد فرم پست شده تکمیل کنیم

روش دوم که مورد سوال شما هست massive assignment است که مدل ر ا به طور یکجا با مقادیر فرم پر می کند

این روش که massive assignment نام دارد کلیه مقادیر فرم را یکجا در مدل قرار می دهد.

[/rtl]


    $model->attributes=$_POST['LoginForm'];

[rtl]

مراحل انجام کار :

1- ساخت نمونه از روی کلاس مدل

2- پر کردن مقادیر نمونه با مقادیر فرستاده شده در فرم پست شده

3- بررسی صحت. بعد از اینکه مقادیر وارد شد باید بررسی یا Validation انجام شود به این صورت که مقادیر قرار داده شده را با قوانین تعریف شده مطابقت می دهد و اگر همخوانی وجود نداشته باشد false را بر می گرداند

[/rtl]

[rtl][font="Tahoma"]

این مساله به خاطر اینه که مدل LoginForm شما از کلاس CFormModel و اون هم از کلاس CModel وراثت گرفتند، و شما با استفاده از این دستور، متد setAttributes رو که در CModel تعریف شده فراخوانی میکنید.[/font]

[/rtl]

[font="Tahoma"][rtl]

سلام،

فکر کنم خیلی دوست داری با دم شیر بازی کنی :D

البته دوستان خیلی خوب و علمی کاربرد متد attributes در سطح بالای فریم ورک رو گفتند ولی من حدس میزنم جواب سوالت رو نگرفتی!

تو سوالت اینه که فلسفه کارکرد متد attributes چگونست؟

اگر حدس من درست بوده باشه بایستی بگم که سوالت خوب و منطقی بود!

اما جوابش رو شاید توی هیچ راهنما و کتاب YII نمیتونی پیدا کنی، مگر اینکه خودت کدهای فریم ورک رو بخونی.

در یک کلام فریم ورک YII اینکارو به صورت جادویی انجام میده!

سعی میکنم به زبون خیلی ساده بهت بگم چطور! ;)

از بالا شروع میکنیم به trace برنامه.

اینطور نوشته شده:

[/rtl]




$model=new LoginForm;

$model->attributes=$_POST['LoginForm'];



[rtl]

مدلی از نوع LoginForm ساخته شده و سپس متد attributes اون فراخوانی شده. پس میریم توی مدل LoginForm سراغ متد attributes.

ولی همچین چیزی توش نیست!

اما این مدل از یک کلاس دیگه به نام CFormModel به ارث برده شده (extend شده) پس شاید متد attributes توی اون کلاس باشه. پس میریم سراغ اون کلاس که در framework/web/CFormModel.php قرار داره (اگر از IDE های پیشرفته مثلاً Eclipse استفاده کنی، با نگه داشتن Ctrl و کلیک روی اسم کلاس، مستقیم میری توی فایل اون کلاس)

خب فایل CFormModel.php باز شد ولی اینجا هم خبری از متد attributes نیست! ولی نا امید نمیشیم و ادامه میدیم!

این کلاس هم از CModel ارث بری کرده پس میریم سراغ فایلش یعنی framework/base/CModel.php اما همچنان اینجا هم اثری از متد attributes نیست!

اما یک متد به اسم getAttributes هست! شبیهش هست ولی خودش نیست! پس شاید بهش نزدیک شدیم!

میریم جلوتر…

کلاس CModel هم از کلاس CComponent ارث بری کرده پس به سراغ فایلش framework/base/CComponent.php میریم.

ولی اینجا هم اثری از متد attributes نیست!

پس چی شد؟!

سر کاریم؟!

حالا فهمیدید چرا گفتم فریم ورک YII اینکارو به صورت جادویی انجام میده؟!

برای توضیح این جادو، لازم یکم به جد بزرگ YII یعنی PHP برگردیم! (اینا همه خانوادگی جادوگرن!!! :D )

یه کد ساده داریم بدین صورت:

[/rtl]




<?php

class Test {

    public $param;

}


$obj = new Test();

$obj->param = "Hello";

echo $obj->param; //output: Hello

?>



[rtl]

خب مشخه یک attribute به نام param که درون سطح کلاس تعریف شده مقدار دهی میشه و چاپ میشه که عبارت Hello در خروجی ظاهر میشه.

اما وقتی که متغییر param در سطح کلاس تعریف نشده، شاید کد بازهم درست کار کنه، یعنی شاید خود PHP به صورت داخلی متغییر رو بسازه و انتساب رو انجام بده. اما شما کنترلی روی این قضیه ندارید. برای اینکه اون رو مدیریت یا سفارشی کنید اینجا از یک متد سیستمی به اسم ‎__set()‎ استفاده میشه.

مثال:

[/rtl]




<?php

class Test {

    function __set($name, $value) {

        $this->$name = $value * 2;

    }

}


$obj = new Test();

$obj->param = 100;

echo $obj->param; //output: 200

$obj->yii = 30;

echo $obj->yii; //output: 60

?>



[rtl]

در این مثال توجه کنید متغییرهای param و yii در سطح کلاس تعریف نشدند ولی نه تنها مقدار میگیرند بلکه حتی در لحظه ای که مقدار میگیرند عملیاتی رو روشون انجام دادیم.

حالا برمیگردیم سر قضیه خودمون!

تا جایی پیش رفتیم که به آخرین کلاس یعنی CComponent رسیدیم، در این کلاس دقت کنید این متد رو میبینید:

[/rtl]




public function __set($name,$value)

{

    $setter='set'.$name;

    if(method_exists($this,$setter))

        return $this->$setter($value);

:

:

:



[rtl]

میبینید که به متغییری که در کلاس مقدار دهی میشه یه set چسبونده بعد با method_exists سعی کرده چک کنه آیا همچین متدی درون کلاس جاری تعریف شده یا نه و اگر وجود داشت اون رو صدا بزنه و البته value رو هم بهش پاس بده تا توی اون یه بلایی به سرش بیاد!

مثلاً اگر ما بنویسیم:

[/rtl]




$model->yii = 'yes it is';



[rtl]

چون yii جزو متغییرهای سطح کلاس نیست (و دقیقاً هم نباید باشه) بنابراین متد ‎__set()‎ وارد عمل میشه و چک میکنه آیا متدی به نام setYii وجود داره یا نه، اگر وجود داشت مقدار ‘yes it is’ رو به همون متد ارسال میکنه.

حالا به اول داستان برمیگردیم. اونجایی که نوشته شده بود:

[/rtl]




$model->attributes = $_POST['LoginForm'];



[rtl]

متدی به نام attributes درسته که وجود نداره اما با این توضیحاتی که دادم، سعی میشه setAttributes پیدا بشه و مقدار ‎$_POST[‘LoginForm’]‎ به همون متد ارسال بشه.

پس از این به بعد بایستی دنبال setAttributes بگردیم. اگر یه مرحله به عقب برگردیم در کلاس CModel میتونیم اون رو پیدا کنیم که ‎$values که ما به صورت یک آرایه بهش پاس دادیم رو گرفته و یک به یک مقادیر رو درون کلیدشون ریخته.

یعنی اگر ‎$_POST[‘LoginForm’]‎ به صورت زیر باشه:

[/rtl]




Array (

    'username' => 'iran', 

    'password' => 'yii',

)



[rtl]

کار setAttributes اینه که این آرایه رو میگیره و iran رو میریزه توی یه متغییر در سطح کلاس به نام username (که در کلاس تعریف نشده) و همینطور yii رو درون password (که در کلاس تعریف نشده) بنابراین پس از اون ما میتونیم به این نحو از اونها استفاده کنیم:

[/rtl]




echo $model->username; //output: iran

echo $model->password; //output: yii



[rtl]

اگر متد attributes در فریم ورک تعریف نمیشد ما مجبور بودیم اینطور مقادیر رو انتساب بدیم:

[/rtl]




$model->username = $_POST['LoginForm']['username'];

$model->password = $_POST['LoginForm']['password'];



[rtl]

که اگر تعداد فیلدها زیاد باشه کار وقت گیر و تکراریه. بنابراین متد attributes با اون داستان پشت پردش رو ساختند تا تنها بنویسیم:

[/rtl]




$model->attributes = $_POST['LoginForm'];



[rtl]

و دیگر هیچ!

ببخشید زیاد حرف زدم.

خواستم موضوع رو زیاد باز کنم تا دوستان مبتدی تر هم بتونن استفاده کنند، چون خیلی از دوستان درمورد نحوه عملکرد پشت پرده فریم ورک پرسیده بودند و به نوعی با این مطلب فکر میکنم روش trace کردن کد رو هم یاد گرفتند تا بقیه چیزها رو خودشون بتونن کشف کنند.

امیدوارم توضیحات مفید واقع شده باشه.

موفق باشید

نبی

[/rtl][/font]

[rtl] احسنت دقیقا به چیزی که میخواستم اشاره کردی ممنونم دوست عزیز. [/rtl]

[font="Tahoma"][rtl]سلام. باز هم ممنون. یکی از مواردی که تو برنامه نویسی بهش معتقد هستم اینه که نمیشه همهیش با ازمون و خطا برناه نویسی یاد گرفت مگر اینکه پیش زمینه ای باشه.

همین بلاگ ساده ای که با فریم ورک ایی ساخته شده رو کسی نتونه واقعا درک کنه چی به چیه نمیتونه بعدا درست کد بزنه همش رو هواست. خودش هم نمیفهمه چی به چیه.

من هم هنوز کتاب آقای برجیان رو دارم مطالعه میکنم و سعی میکنم تا جایی که امکان داره این بلاگ رو درک کنم بدونم روند کارش چطوریه خواستم خودم بنویسیم دیگه کپی پیست هام کمتر بشه. هنوز بعضی جاهای دیگه از این سری مشکلات هست که از اساتید عزیز خواهم پرسید.

[/rtl]

[/font]

[rtl][font="Tahoma"]خواهش.

در خدمتیم

[/font][/rtl]

[right]سلام، من سه یا چهار روزی هست شروع به یادگیری Yii کردم اما واقعیتش با خوندن کتاب خیلی گیج شدم چون همش تئوری بود.رفتم چندتا کلیپ از آپارت دیدم یکم قضیه دستم اومد.

از gii برای ساخت فرم استفاده کردم دیدم چیز زیادی دستگیرم نشد پس شروع کردم خودم یکی یکی فایل مورد نیاز رو توو models و controller و view ساختم، تا حدودی هم خوب پیش رفتم اما الان به یه مشکل بر خوردم:

این قسمت controller هستش:[/right]




<?php

/*

	

*/

class TestdbController extends Controller{

	//set action index.

	public function actionIndex(){

		

		$model = new IndexForm;

		

		if( isset($_POST["IndexForm"]) ){

			$model->attributes = $_POST["IndexForm"];

		}

		

		$this->render('index', array("model"=>$model));

	}

}

[right]

این هم CFormModel هست:

[/right]




<?php


class IndexForm extends CFormModel{

	public $name;

	public $email;

	public $id;

	

	public function rules(){

		return array(

			//name and email required.

			array('name'),

			array('email'),

			//id is optional.

			//array('ID'),

		);

	}

	

}



[right]

این هم index توو view هستش:

[/right]




<?php

/*@var $this TestdbController*/

/*@var $model IndexForm*/

/*@var $form CActiveForm*/

$this->pageTitle = Yii::app()->name . '- Database Tester';

$this->breadcrumbs = array( 'Database Tester', );

?>

<p>Please fill out the following form.</p>

<?php

	$form = $this->beginWidget('CActiveForm', array(

													'id'=>'index-form',

													'enableClientValidation'=>true,

													'clientOptions'=>array(

														'validateOnSubmit'=>true,

													),

													)

							   );

?>


<div style="width:auto;">

	<?php echo $form->labelEx($model, 'Enter your name:'); ?>

    <?php echo $form->textField($model, 'name'); ?>

    <?php echo $form->error($model, 'name'); ?>

</div>

<div style="width:auto;">

	<?php echo $form->labelEx($model, 'Enter your E-mail:'); ?>

    <?php echo $form->textField($model, 'email'); ?>

    <?php echo $form->error($model, 'email'); ?>

</div>

<?php $this->endWidget(); ?>



[right]

موقعی که اجرا میکنم این خطا رو میده.چرا؟

[/right]

IndexForm has an invalid validation rule. The rule must specify attributes to be validated and the validator name.

[font="Tahoma"]

[rtl]

اگه به خطا توجه کنید متوجه میشید که مشکل از validation rule شماست که در این مورد باید به صورت زیر نوشته بشه

[/rtl]




array('name, email', 'required'),



[rtl]

بهتره قبل از استفاده ، راهنمای yii رو مطالعه بفرمایید.

[/rtl][/font]

Reza m آره ممنون یکم که باهاش کار کردم متوجه شدم مشکل کجاست.

من یه سوال دیگه دارم؛

شما به عنوان کسی که کاملاً به

Yii

مسلطه این نوع کدنویسی برای اضافه کردن اطلاعات به دیتابیس رو میپسندید؟؟واقعاً برام مهمه ممنون میشم جواب بدید یا بهم ایمیل بزنید.


<?php


class IndexForm extends CFormModel{

	public $name;

	public $email;

	public $id;

	

	public function rules(){

		return array(

			//name and email required.

			array('name, email', 'required'),

			array('email', 'email'),

			//id is optional.

			//array('ID'),

		);

	}

	

	public function updateTable(){

		$sql = "INSERT INTO yii_test (name, email) VALUES (:name, :email)";

		$command = Yii::app()->db->createCommand($sql);

		$command->bindValue(":name", $this->name);

		$command->bindValue(":email", $this->email);

		$command->execute();

	}

}

[rtl]چه کاری داداش. خود کنترلرش این کار را براتون انجام میده.

اگر gii استفاده می کنید در گزینه هایی که دارد یک گزینه به نام CRUD دارد این را برای هم جدولتون بزنید بعد ببینید چه کار میکند. برای اطلاعات بیشتر اینجا را یه نگاهی بندازید.

در ضمن دوست عزیز وقتی پستی می زنید و مطلبی را می نویسید یک گزینه اون بالا توی style ها هست به نام RTL که نوشته هایتان را درست برای فارسی درست می کنه.

[/rtl]

[font="Tahoma"]

[right][rtl]آقا ممنون اما چون تازه دارم یاد میگیرم نمیخوام از gii استفاده کنم، اگر کار راحت باشه برام نمیتونم درست یادبگیرم.درباره لینکی که دادی ممنون دارم میخونمش :)[/rtl][/right][/font]

http://www.yiiframework.com/doc/guide/1.1/en/database.ar#creating-record

http://www.yiiframework.com/wiki/19/how-to-use-a-single-form-to-collect-data-for-two-or-more-models/#c9743

[rtl]به نظر بنده این فریمورک مبحث برای وقت صرف کردن زیاد دارد. خودتان را با این مباحث درگیر نکنید. شما از gii استفاده کنید بعد ها برای درک بهتر ذخیره رکورد یا بروز رسانی آن وقت دارید. حتی با گذشت زمان و درگیر شدن بیشتر با فریمرک این امر خیلی سریعتر اتفاق خواهد افتاد انشاء الله.[/rtl]