PDA

View Full Version : چند تا سوال در مورد کار با فریم ورک yii دارم



mostafa_shoakry
پنج شنبه 28 آذر 1392, 10:53 صبح
با سلام خدمت دوستان و اساتید محترم.
من چنتا سوال در مورد نحوه استفاده و کار با فرم ورک yii دارم:
1- برای استفاده از Controller ها و Model و View حتما باید از Gii استفاده کنم؟
2- من دو قسمت سایت دارم مثلا Admin و Site تو CodeIgniter دوتا کنترل می ساختیم یکی برای مدیریت و یکی هم برای قسمت سایت و می یومدیم تو پوشه View یه پوشه برای Site و یکی هم برای Admin ایجاد می کردم ( برای نظم دادن بیشتر بود ) و شروع می کردم به ایجاد صفحات خودم. تو yii چجوری اینکارو انجام بدم؟
بازم سوالی به ذهنم اومد می پرسم

MMSHFE
پنج شنبه 28 آذر 1392, 11:02 صبح
اجباری به استفاده از Gii نیست ولی اگه استفاده کنید، کدهای استانداردتر و مرتب تری برای شما تولید میشه. ضمناً بهتره برای بخش مدیریت کلاً یک Module (ماژول) جداگانه بسازید.

mostafa_shoakry
پنج شنبه 28 آذر 1392, 11:20 صبح
بیشترین دلیل این سوالاتم اینه که می خوام یه پروژه رو همراه با آموزش شما ببرم جلو.
من تا اونجا که آموزش شمارو دیدم ( البته فقط تا درس 3 ) وقتی با CRUD یه کلاس ایجاد می کنیم میاد View رو خودش ایجاد میکنه ولی من می خوام ویو خودمو ایجاد کنم.

MMSHFE
پنج شنبه 28 آذر 1392, 11:25 صبح
خوب اگه میخواین ویوها رو خودتون بسازین، فقط Controller رو بعد از مدل ایجاد کنید و اکشنهای Create و Update و Delete و Index و View رو خودتون بهش دستی اضافه کنید و ویوهای دلخواهتون رو هم توی پوشه ای که به اسم کنترلر تو پوشه views ساختین، باز بصورت دستی ایجاد کنید و با یکی از متدهای render یا renderPartial توی اکشن موجود در کنترلر، صداشون بزنید.

mostafa_shoakry
دوشنبه 16 دی 1392, 01:18 صبح
من الان تعدادی Controller و Model واسه Links,News و غیره ساختم حالا چند تا سوال:
1. با توجه به اینکه می خوام view خودمو بسازم و با توجه به اینکه گفتین اول Model ایجاد کنم و بعد Controller بسازم ولی من اینو رعایت نکردم ، آیا نیاز هست همه چیه پاک کنم و از اول بسازم؟ منظورم Model و Controller هایی که ایجاد کردم هستن.
2. من الان یک Module برای admin درست کردم و در قسمت module در config اونو اضافه کردم حالا چجوری نزارم که کاربر admin که لاگین نکرده و یا دیگر کاربران عادی به Controller های من دسترسی نداشته باشن؟
3. من برای قسمت admin و site خودم واسه هر کدوم یه layout جداگانه درس کردم که هر کدوم header,footer و content جداگانه ای دارن. حالا من در کجا مشخص کنم که در هنگام فراخوانی قسمت مدیریت من کدوم layout و برای قسمت دیگر یعنی سایت کدوم layout اجرا بشه؟ و این layout هارو باید در کجا ایجاد کنم؟
ممنون

MMSHFE
دوشنبه 16 دی 1392, 11:25 صبح
1- نه نیازی نیست. فرضاً اگه الآن View رو ساختین و مدل و کنترلر یادتون رفته، میتونید جداگانه اونها رو بسازین یا اینکه یک View رو ساختین (مثلاً create) و بقیه رو میخواین Gii بسازه. کافیه موقعی که توی Gii روی Preview کلیک کردین، قبل از کلیک روی Generate تیک کنار Viewهایی که نمیخواین براتون بسازه رو بردارین.
2- توی پوشه modules/admin یک فایل به اسم AdminModule.php برای شما ساخته شده که یک متد (event) داره به اسم beforeControllerAction که قبل از هر Action توی هر Controller داخل این ماژول صدا زده میشه. کافیه توی اون، کدی شبیه این بنویسید:


public function beforeControllerAction($controller, $action)
{
if(parent::beforeControllerAction($controller, $action))
{
if(!Yii::app()->user->isGuest && (($model = Users::model()->findByPk(Yii::app()->user->id)) == null || $model->username != 'admin')) {
throw new CHttpException(403, 'Unauthorized Access');
}
return true;
}
return false;
}

همونطور که میبینید، اگه کاربر لاگین نکرده باشه یا شناسه کاربریش admin نباشه، خطای 403 تولید میشه و action کار نمیکنه. حالا میتونید توی متد filters همه actionها رو با خیال راحت برای همه کاربران باز بگذارین چون خود ماژول داره دسترسی رو چک میکنه.
3- توی کنترلرهایی که توی ماژول میسازین، یک فیلد public به اسم layout$ اضافه کنید:

public $layout = '/layouts/adminLayout';
اگه دقت کنید، میبینید که اول رشته، بجای // از / استفاده شده. درنتیجه بجای اینکه توی پوشه views اصلی که توی protected هست، دنبال فایل adminLayout بگرده، توی پوشه views خود ماژول دنبالش میگرده. توی خود Viewها هم اگه میخواین خروجی تحویل یک Layout دیگه داده بشه، باید اینطوری کار کنید:


<?php $this->beginContent('/layouts/admin'); ?>
<?php echo $content; ?>
<?php $this->endContent(); ?>

اینجا هم همونطور که میبینید، از / بجای // استفاده شده که به Yii میفهمونه باید توی Layoutهای موجود در پوشه views خود ماژول دنبال admin.php بگرده.
اما توی کنترلرها و ویوهای سایت اصلی (نه ماژول admin) باید از // در ابتدای مسیر layout استفاده کنید تا توی views موجود در خود پوشه protected دنبالش بگرده. بطور خلاصه، // میشه پوشه ریشه application شما (یعنی پوشه protected) و / میشه پوشه ریشه ماژولی که کنترلر یا ویو توی اون قرار داره.

MMSHFE
دوشنبه 16 دی 1392, 19:49 عصر
تابع نه، فیلد. اگه امکان داره، TeamViewer بدین تا روی سیستمتون توضیح بدم.

Tarragon
سه شنبه 17 دی 1392, 08:39 صبح
آقای شهرکی ببخشید من یک سری سوال دارم :)
ببخشید (من الان اموزش 4 هستم).
اول اینکه استاده از phpunit لازمه!؟
دوم اینکه اون فیلتر که استفاده می کنید در پروژه TaskStar نمی فهمم کارش چیه!
و سوم اینکه کلید های خارجی یکی از دوستان توضیح دادم اما بازم کامل متوجه نشدم ممنون می شم شما هم توضیح بدید.
ممنونم.

MMSHFE
سه شنبه 17 دی 1392, 10:29 صبح
1- خیر استفاده از phpUnit لازم نیست ولی اگه به تست کردن بخشهای مختلف پروژه با استفاده از phpUnit عادت کنید و تستهای استاندارد برای برنامه بنویسید، دیگه نیازی نیست هربار که یک قابلیت اضافه میشه یا یکنفر از اعضای تیم، بخشی از پروژه رو تغییر میده، دوباره یک یا چند ماه نسخه آزمایشی دست مشتری بدیم تا اشکالهای کار در بیاد. میتونیم یک تست استاندارد بنویسیم و هربار توی کد تغییری میدیم، اون تست رو مجدداً اجرا کنیم و اگه با موفقیت انجام شد، یعنی کد جدید هم مثل قبلی داره درست کار میکنه.

2- منظورتون رو دقیقتر بگین. منظورتون متد filterProjectContext هست یا متد filters ؟

3- کلید خارجی، در حالت عادی یعنی یک فیلد توی یک جدول که به فیلد کلید اصلی یک جدول دیگه وصله. مثلاً فیلد cat_id توی جدول posts که به فیلد id از جدول categories وصل میشه. حالا اگه موتور دیتابیس/جدول شما InnoDB باشه، میتونید برای این کلیدهای خارجی، قید (Constraint) هم تعریف کنید (توی MyISAM باید خودتون به کدهایی که مینویسید، شبیه سازیش کنید). قیدها چند حالت دارن (Cascade و Restrict و...). برای مثال، اگه روی عمل Update یک کلید خارجی، قید RESTRICT بگذارین، باعث میشه تا وقتی که یک رکورد از جدول اصلی، ازطریق کلید اصلی به یکسری رکوردهای دیگه توی جدول مرتبط ازطریق کلید خارجی مرتبطه، به شما اجازه تغییر کلید اصلی رو نده. یا مثلاً اگه روی عمل Delete یک کلید خارجی، قید CASCADE بگذارین، وقتی یک رکورد رو از جدول اصلی حذف میکنید، تمام رکوردهایی که با کلید اصلی اون، توی جدول مرتبط ازطریق کلید خارجی در ارتباط هستن، اونها هم حذف بشن (مثلاً با حذف یک category تمام postهای مربوط به اون category هم حذف بشه، بدون اینکه نیاز به کدنویسی دستی داشته باشین یا نگران باشین که ممکنه یک رکورد از دستتون در رفته باشه و حذفش نکرده باشین).

mostafa_shoakry
سه شنبه 17 دی 1392, 10:56 صبح
استاد یه سوال:
من می خوام یه بخش برای عضو گیری درست کنم که اعضا بیان عضو بشن و مدیر هم بتونه اعضا رو ساماندهی کنه یعنی این قابلیت رو داشته باشه که مدیر بیاد سطح دسترسی برای اعضا تعیین کنه.
تا اونجا که خوندم برای این کار بعد از فعال سازی ماژول admin یک کنترلر user تعریف کنیم و خودش تمام قابلیت هارو پیاده سازی می کنه ، آیا برداشت من صحیح است یا باید خودم تمام قابلیت های عضو گیری، تعیین سطح دسترسی ، محرومیت و ... رو کنترل کنم؟

MMSHFE
سه شنبه 17 دی 1392, 11:08 صبح
خودتون باید جدول Users رو ایجاد کنید و مدل و CRUD رو هم براش تعریف کنید و یکسری امکانات رو به کاربران عادی بدین (مثلاً register و login برای همه کاربران (*) باز باشه ولی یکسری اکشن مثل confirm و setRole و... برای کاربر مدیر فقط باز باشه) و برای تعیین سطوح دسترسی و... هم مطابق پکیج آموزشی، از RBAC باید استفاده کنید. Extensionهای خوبی هم برای این کار توی خود سایت Yii موجوده.

Tarragon
سه شنبه 17 دی 1392, 13:34 عصر
1- توی windows xp چطوری نصب می شه؟!
2- filterProjectContext منظورمه.
ممنون

MMSHFE
سه شنبه 17 دی 1392, 13:43 عصر
1- توی Path ویندوز باید مسیر فایل php.exe و همچنین مسیر پوشه frameworks توی پوشه yii رو اضافه کنید. باید موارد فرقی نداره.
2- توی کنترلر Issue این متد رو تعریف کردیم:


/**
* @return array action filters
*/
public function filters()
{
return array(
'accessControl', // perform access control for CRUD operations
'projectContext + create index admin', //check to ensure valid project context
);
}

و بعد متدی به اسم filterProjectContext ساختیم با این کد:


/**
* In-class defined filter method, configured for use in the above filters() method
* It is called before the actionCreate() action method is run in order to ensure a proper project context
*/
public function filterProjectContext($filterChain)
{
//set the project identifier based on either the GET input
//request variables
if(isset($_GET['pid']))
$this->loadProject($_GET['pid']);
else
throw new CHttpException(403,'Must specify a project before performing this action.');

//complete the running of other filters and execute the requested action
$filterChain->run();
}

بدین ترتیب، قبل از اعمال create و index و admin ابتدا این فیلتر اجرا میشه تا مطمئن بشیم pid (یعنی id پروژه) به روش Get ارسال شده.

sh.n.n786
سه شنبه 17 دی 1392, 16:11 عصر
درود و ...
چطوري اين Object هارو داخل yii دست كاري كنم جاشو پيدا نكردم


this->widget('zii.widgets.CMenu', array(
'items' => array(
array('label' => 'Home', 'url' => array('/site/index')),
array('label' => 'About', 'url' => array('/site/page', 'view' => 'about')),
array('label' => 'Contact', 'url' => array('/site/contact')),
array('label' => 'Login', 'url' => array('/site/login'), 'visible' => Yii::app()->user->isGuest),
array('label' => 'Users', 'url' => array('/users'), 'visible' => ???? ),
array('label' => 'Logout (' . Yii::app()->user->name . ')', 'url' => array('/site/logout'), 'visible' => !Yii::app()->user->isGuest)
),
));


ميخوام كه اين دسترسي فقط به اديمن داده بشه و كسي نتونه اون ببينه به جاي ???? چي بنويسم؟
ممنون

Tarragon
سه شنبه 17 دی 1392, 16:51 عصر
سلام
منم یه سوال دیگه داشتم در مورد mvc هستش.
راستش من هنوز کاملا تفاوت model و controller رو نفهمیدم. می خوام یکم بیشتر توضیح بدید(فایل slideshow mvc شما رو دیدم.)
کدوم دستورات در model قرار می گیره و کدوم دستورات در controller؟
ممنونم.

MMSHFE
سه شنبه 17 دی 1392, 16:58 عصر
...ميخوام كه اين دسترسي فقط به اديمن داده بشه و كسي نتونه اون ببينه به جاي ???? چي بنويسم؟
ممنون
یک متد به کلاس Users اضافه کنید با چنین کدی:


public static function IsAdmin() {
if(Yii::app()->user->isGuest) {
return false;
}
$user = Users::model()->findByPk(Yii::app()->user->id);
if($user == null || $user->username != 'admin') {
return false;
}
return true;
}

حالا بجای ???? بنویسید ()Users::IsAdmin

MMSHFE
سه شنبه 17 دی 1392, 17:01 عصر
سلام
منم یه سوال دیگه داشتم در مورد mvc هستش.
راستش من هنوز کاملا تفاوت model و controller رو نفهمیدم. می خوام یکم بیشتر توضیح بدید(فایل slideshow mvc شما رو دیدم.)
کدوم دستورات در model قرار می گیره و کدوم دستورات در controller؟
ممنونم.
بهتر بود درمورد MVC یک تاپیک جداگانه توی خود بخش PHP میساختین. ولی بهرحال، مدل فقط شامل کدهایی هست که مربوط به کار روی داده ها در سیستمهای ذخیره سازی دائمی (مثل دیتابیس و فایل و...) هستن (شامل اعمالی مثل خوندن، نوشتن، استخراج ارتباط بین جداول و...) و کنترلر، شامل کدهایی هست که منطق برنامه رو تشخیص میدن. مثلاً اگه میخواین ببینید یک کاربر مجوز انجام یک کار خاص رو داره یا نه و اون کار، فقط برای کاربر admin مجازه، توی کنترلر، یک درخواست به مدل میدین تا رکورد مربوط به کاربر لاگین شده رو به شما برگردونه (این کار توی مدل انجام میشه) و دوباره توی کنترلر، فیلد username رو چک میکنید که admin هست یا نه و اگه نبود، پیغام خطا میدین (خطا توسط ویو مناسب، تولید میشه و کنترلر اون ویو رو صدا میزنه).

mostafa_shoakry
یک شنبه 22 دی 1392, 12:01 عصر
سلام
الان برای قسمت Admin یه ماژول ساختم حالا لزومی داره واسه قسمت دیگه یعنی site ماژول بسازم یا از همون کنترلر های موجود استفاده و فیلتر تعریف می کنم؟

MMSHFE
یک شنبه 22 دی 1392, 12:41 عصر
نه دیگه نیازی نداره. قسمتهای معمولی سایت رو نیازی نیست ماژول بسازین مگه اینکه بخواین توی یک پروژه دیگه ازش استفاده کنید (مثلاً یک ماژول برای گالری عکس که شامل مدل و ویو و کنترلر خاص خودش باشه).

mostafa_shoakry
دوشنبه 23 دی 1392, 13:10 عصر
سلام
من به ماژول ادمین accessRules دادم. وقتی می خوام برم قسمت پنل مدیریت منو به site/login ریدایرکت می کنه ولی من می خوام به admin/login یه admin/users/login بره. کد زیر رو هم اضافه کردم ولی باز نشد


public function beforeControllerAction($controller, $action)
{
if(parent::beforeControllerAction($controller, $action))
{
if(!Yii::app()->user->isGuest && (($model = Users::model()->findByPk(Yii::app()->user->id)) == null || $model->username != 'admin')) {
//throw new CHttpException(403, 'Unauthorized Access');
$this->redirect(array('admin/users'));

}
// this method is called before any module controller action is performed
// you may place customized code here
return true;
}
else
return false;
}


چی کار کنم؟

mostafa_shoakry
دوشنبه 23 دی 1392, 22:13 عصر
چطوری یک سیستم ورود برای پنل مدیریت سایتم درست کنم؟ :افسرده:

MMSHFE
سه شنبه 24 دی 1392, 01:05 صبح
توی متد accessRules دسترسی به اکشنها رو برای همه کاربران ( * ) باز کنید. حالا توی رویداد beforeControllerAction میتونید عمل Redirect خودتون رو بنویسید.

mostafa_shoakry
سه شنبه 24 دی 1392, 20:24 عصر
دارم قسمت ورود به پنل مدیریت سایت رو درست می کنم.کارایی که کردم به این ترتیب هست:
1.ماژول admin درس کردم و بهش filter و accessRules رو اضافه کردم
2.یک usercontroller درست کردم و یک Model هم درست کردم که از ActiveRecord ارث بری می کنه (extend)
سوالی که دارم این هست:
1.من برای ساخت لاگین از activerecord استفاده کردم ولی نمونه هایی که دیدم همشون از CUserIdentity استفاده می کنند.آیا منم باید از اون استفاده کنم؟
2.اگه باید از CUserIdentity استفاده کنم اونو کجا باید ایجاد کنم و چجوری با Database ارتباط بدم؟
3.آیا CUserIdentity خودش session رو ایجاد می کنه؟
4.آیا باید CUserIdentity را به همراه ActiveRecord استفاده کنم؟
با تشکر

MMSHFE
سه شنبه 24 دی 1392, 21:14 عصر
نیازی به استفاده از CUserIdentity نیست ولی اگه باهاش کار کنید، کارتون راحتتره. Yii خودش session رو مدیریت میکنه ولی اگه از CUserIdentity استفاده کنید، بطور خودکار مدیریت کوکی و سشن کاربران رو بعهده میگیره.

Tarragon
چهارشنبه 25 دی 1392, 15:10 عصر
سلام
با اجازه صاحب تاپیک!
اقای شهرکی من الان برای requester_id و owner_id دارم لیست یوزر هارو اماده می کنم اما نمی دونم چرا ارایه خالیه!
اگر می شه کمک کنید. اگر نیاز هست تشریف بیارید ریدکال یوزر نیم پسورد teamviewer بدم خدمتتون.

MMSHFE
چهارشنبه 25 دی 1392, 16:18 عصر
من توی RC آنلاین هستم.

mostafa_shoakry
پنج شنبه 26 دی 1392, 08:23 صبح
بالاخره فک کنم لاگین تموم شد ولی باز چنتا سوال دارم:
1. الان از کجا بدونم کاربر وارد شده اگه نام کاربری و رمز عبور داده شده صحیح باشد پس کد زیر اجرا می شه


class UserIdentity extends CUserIdentity
{

public function authenticate()
{
$record=users::model()->findByAttributes(array('username'=>$this->username));

if($record===null)
{
$this->errorCode=self::ERROR_USERNAME_INVALID;
}
else if(md5(SHA1($record->password)) != $this->password) // here I compare db password with password field
{
$this->errorCode=self::ERROR_PASSWORD_INVALID;
}
else
{
$this->setState('UserID',$record->id);
$this->errorCode=self::ERROR_NONE;

}
return !$this->errorCode;
}
}

الان چجوری چک کنم ببینم که $record->id هست یا نیست؟
2.آیا سیشن رو خودش درس می کنه ، اگه آره کجاست $this->setState() هست؟
3. من می خوام تمام پسورهای ورودیم به این شکل رمز بشه


md5(SHA1($password)

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

MMSHFE
پنج شنبه 26 دی 1392, 10:36 صبح
جواب مورد 1 :
نه کلاً مسیر رو اشتباه رفتین. الآن شما رمز توی دیتابیس رو دوباره Hash میکنید درحالی که رمزی که کاربر وارد کرده باید Hash بشه. ببینید من توی یکی از پروژه ها چطوری کار کردم:
1- توی protected/config/main.php این پارامتر رو تعریف کردم:


...
'params' => array(
...
'pepper'=>sha1('http://www.ncis.ir'),
...
),
...

2- توی مدل User این دو متد رو اضافه کردم:


...
public static function hashPassword($password) {
for($i = 0; $i < 1000; $i++) {
$password = sha1(md5($password) . Yii::app()->params['pepper']);
}
return $password;
}
...
public function validatePassword($password) {
return $this->hashPassword($password) === $this->password;
}
...

3- این attribute و event رو به مدل اضافه کردم:


...
private $_attributesBackup;
...
public function afterFind() {
$this->_attributesBackup = $this->attributes;
}
...

همونطور که میبینید و احتمالاً واضحه، به محض اینکه یک مدل پیدا میشه (با متدهای find و findAll و...) یک کپی از attributeهاش توی فیلد private به اسم attributesBackup_$ ذخیره میشه (در ادامه توضیح میدم چرا اینکار رو انجام میدیم).
4- این متد رو هم اضافه کردم که اگه بیرون از کلاس خواستیم فیلد فوق رو ببینیم (بدون امکان تغییر)، برامون مقدور باشه:


...
public function getOriginalAttribute($attribute) {
if($this->_attributesBackup) {
return $this->_attributesBackup [$attribute];
}
return null;
}
...

5- توی همون مدل، این Event رو تعریف کردم:


protected function afterValidate() {
parent::afterValidate();
if(!$this->hasErrors() && $this->getOriginalAttribute('password') != $this->password) {
$this->password = $this->hashPassword($this->password);
}
}

همونطور که میدونید، به محض اینکه عناصر فرم validate میشن، این متد فراخوانی میشه و اگه خطایی توی validationها نباشه و رمز اصلی (توی attributeBackup) با رمزی که توی مدل جاری هست (و validationها روش اعمال شده) فرق داشته باشه، رمز موجود در مدل Hash میشه. اگه این چک کردن رمزی که توی مدل جاری هست رو با رمز مدل اصلی که موقع find استخراج شده، مقایسه نکنیم، هربار که میخوایم مدل رو update کنیم (مثل Edit User) رمز قبلی دوباره Hash میشه و درنتیجه دیگه کاربر نمیتونه لاگین کنه درحالی که الآن، تنها درصورتی عمل Hash انجام میشه که رمز واردشده در مدل جاری با رمز مدل اصلی (زمان find) فرق کرده باشه (کاربر توی فرم Edit رمز جدید وارد کرده باشه).
حالا بریم سراغ کنترلر UserController
6- اول از همه متد Login رو ببینید:


...
public function actionLogin() {
$model = new LoginForm();
// 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));
}
...

دیگه نیاز به توضیح نداره که بعد از model->validate$ متد afterValidate اونطرف صدا زده میشه و بقیه کارها چطور انجام میشه و اگه به دقت فیلمها رو دنبال کرده باشین، خودتون باید توی ذهنتون بتونید منطق کار رو ترسیم کنید.
7- برای اطلاعات بیشتر، متد Update رو هم ببینید چطور نوشتم:


...
public function actionUpdate($id) {
if($id != Yii::app()->user->id) {
throw new CHttpException(403, 'دسترسی غیرمجاز');
}
$model = $this->loadModel($id);

if(isset($_POST ['Users'])) {
$model->name = $_POST ['Users'] ['name'];
$model->email = $_POST ['Users'] ['email'];
$model->mobile = $_POST ['Users'] ['mobile'];
$model->state_id = $_POST ['Users'] ['state_id'];
$model->favsms = isset($_POST ['Users'] ['favsms']);
$model->favmail = isset($_POST ['Users'] ['favmail']);
$model->searchsms = isset($_POST ['Users'] ['searchsms']);
$model->searchmail = isset($_POST ['Users'] ['searchmail']);
if($_POST ['Users'] ['password'] !== '' && $_POST ['Users'] ['password'] == $_POST ['Users'] ['password_repeat']) {
$model->password = $_POST ['Users'] ['password'];
}
if($model->save())
$this->redirect(array ('view', 'id' => $model->id));
else
$this->render('error', array ('errors' => $model->getErrors()));
}
$this->render('update', array ('model' => $model, 'states' => States::getStates()));
}
...

علت اینکه attributeهای مدل رو یکی یکی با معادل POST_$ مقداردهی کردم و از روش مرسوم $model->attributes = $_POST['Users']; استفاده نکردم هم بخاطر این بود که توی فرم ویرایش اطلاعات کاربر، اجازه ویرایش همه عناصر رو نداده بودم و درنتیجه یکسری مقادیر موردنیاز برای مقداردهی یکجای همه attributeها توی فرم Submitشده وجود نداشت و Validationها با خطا مواجه میشد (بخاطر required بودن یکسری مقادیر). البته میشد با on توی validation بیایم و بگیم برای update چه چیزهایی required هستن اما چون من از همین کنترلر برای مدیریت کاربران (توسط کاربر admin) استفاده میکردم، نخواستم validation ruleها رو پیچیده کنم و بجاش یک متد Update برای مدیر نوشتم و دسترسی رو فقط به کاربر admin دادم.
حالا بریم سراغ UserIdentity :
8- یک فیلد private اضافه کنید:


...
private $_id;
...

9- متد getId رو که از کلاس CUserIdentity ارث برده، بازنویسی کنید:


...
public function getId() {
return $this->_id;
}
...

10- متد authenticate رو اینطوری بنویسید:


...
public function authenticate() {
$user = Users::model()->find('LOWER(username)=? AND confirmed=1', array(strtolower($this->username)));
if($user === null) {
$this->errorCode = self::ERROR_USERNAME_INVALID;
}
elseif(!$user->validatePassword($this->password)) {
$this->errorCode = self::ERROR_PASSWORD_INVALID;
}
else {
$this->_id = $user->id;
$this->username = $user->name;
$this->errorCode = self::ERROR_NONE;
}
return $this->errorCode == self::ERROR_NONE;
}
...

علت بازنویسی متد getId اینه که در حالت عادی (روش کار پیشفرض CUserIdentity) مقدار Yii::app()->user->id و Yii::app()->user->username یکیه و با این روش، الآن اولی دقیقاً ID کاربر توی دیتابیس و دومی هم username (در اینجا برحسب نیاز من در پروژه، فیلد name رکورد در دیتابیس) رو برمیگردونه.
اگه جایی هنوز ابهام داره، بفرمایید تا بیشتر توضیح بدم.

MMSHFE
پنج شنبه 26 دی 1392, 10:44 صبح
جواب سؤال 2 : با متدها و attributeهای شئ Yii::app()->session کار کنید.

MMSHFE
پنج شنبه 26 دی 1392, 10:45 صبح
جواب سؤال 3 : توی جواب سؤال 1 گفته شد. تنها کاری که باید انجام بدین، تغییر متد hashPassword توی مدل User هست تا مطابق الگوریتم خودتون بشه.

mostafa_shoakry
پنج شنبه 26 دی 1392, 11:39 صبح
الآن شما رمز توی دیتابیس رو دوباره Hash میکنید درحالی که رمزی که کاربر وارد کرده باید Hash بشه.
آره اونو اشتباه نوشته بودم یادم رفت تصحیحش کنم :لبخند:
تو این کد چرا از for استفاده کردین؟ این واسه اینه که خیلی محکم کاری می کنین دیگه؟ :لبخند:


public static function hashPassword($password) {
for($i = 0; $i < 1000; $i++) {
$password = sha1(md5($password) . Yii::app()->params['pepper']);
} return $password;
}

MMSHFE
پنج شنبه 26 دی 1392, 11:53 صبح
بله. وقتی 1000 بار رمزگذاری تکرار میشه، هم احتمال پیدا شدنش توی Dictionaryها کم میشه و هم عمل چک کردن رمز، کند میشه و اگه سایتتون درمقابل Bruteforce Attack باگ داشته باشه و نگرفته باشین، بجای 1 سال زمان برای بازشدن رمز، 1000 سال زمان لازمه.

mostafa_shoakry
پنج شنبه 26 دی 1392, 13:17 عصر
جواب سؤال 2 : با متدها و attributeهای شئ Yii::app()->session کار کنید.
بازم مزاحم همیشگی :خجالت:
باور کنین خجالت می کشم سوال بپرسم.
من سیشن رو کجا باید استارت بزنم و کجاها باید چک کنم ببینم که کاربر لاگین کرده یا نه؟
یه سایت کوچولو بتونم را بندازم که دیگه تمومه انقدر هم دردسر نمی دم :لبخند:

MMSHFE
پنج شنبه 26 دی 1392, 13:28 عصر
شما نباید کاری بکنید. خود Yii استارت میکنه و هرجا خواستین ببینید کاربر لاگین کرده یا نه فقط کافیه با Yii::app()->user->isGuest چک کنید.

engmmrj
پنج شنبه 26 دی 1392, 17:02 عصر
استاد در قسمت migration اگر بخواهیم یک فیلد مثلا از نو varchar 32 کارکتر باشد باید چه حرکتی انجام بدیم ؟

MMSHFE
پنج شنبه 26 دی 1392, 17:17 عصر
توی مقدار اون فیلد بنویسید varchar(32) یا اگه طولش ثابته بنویسید char(32) و در ادامه اگه میخواین اجازه بدین null باشه بنویسید DEFAULT NULL و در غیر اینصورت بنویسید NOT NULL

engmmrj
پنج شنبه 26 دی 1392, 17:20 عصر
توی مقدار اون فیلد بنویسید varchar(32) یا اگه طولش ثابته بنویسید char(32) و در ادامه اگه میخواین اجازه بدین null باشه بنویسید DEFAULT NULL و در غیر اینصورت بنویسید NOT NULL
Collation فیلد را latin1_swedish_ci انتخاب میکنه برای اینکه utf8 بشه باید یکار کنیم ؟

MMSHFE
پنج شنبه 26 دی 1392, 17:23 عصر
توی تنظیمات کامپوننت db گزینه charset رو روی utf-8 ست کنید. هم تو main.php و هم تو console.php

engmmrj
پنج شنبه 26 دی 1392, 17:30 عصر
در هر دو فایل utf8 است ولی بازم موقع create به این مشکل میخورم !

'db'=>array(
'connectionString' => 'mysql:host=localhost;dbname=yii',
'emulatePrepare' => true,
'username' => 'root',
'password' => '',
'charset' => 'utf8',
),

mahmod2000
پنج شنبه 26 دی 1392, 18:31 عصر
توی دیتابیستون ببینید utf8 هست یا نه

Tarragon
پنج شنبه 26 دی 1392, 19:02 عصر
با سلام
دوستان عزیز دقت کنید زمان ساخت دایتابیس انکد دیتابیس رو utf8 بزارید.

engmmrj
پنج شنبه 26 دی 1392, 19:06 عصر
توی دیتابیستون ببینید utf8 هست یا نه
حق با شما بود :لبخندساده:

mostafa_shoakry
شنبه 28 دی 1392, 10:04 صبح
سلام
خسته نباشید استاد.
من می خوام قسمت مدیریت لینک هارو درست کنم.ولی به چندتا مشکل برخورد کردم:
قسمت ویو من


<form id="validate" method="post" action="<?php echo Yii::app()->createUrl('admin/links/create') ?>">
<div class="formWizard">
<div class="row-fluid">
<div class="span2">
<span class="fLabel">عنوان</span>
</div>
<div class="span10">

<input type="text" id="name" name="name">
</div>
</div>
</div>

<div class="formWizard">
<div class="row-fluid">
<div class="span2">
<span class="fLabel">لینک</span>
</div>
<div class="span10">
<input type="text" data='url' name="url">
</div>
</div>
</div>
<div class="formButtons">
<div class="row-fluid">
<div class="span12" align="right">
<button type="reset" class="button sButton bSky">پاک کردن</button>
<button type="submit" class="button sButton bOlive">ثبت</button>
</div>
</div>
</div>
</form>


اینم کنترلر :


public function actionCreate()
{

$model = new Links;
if(isset($_POST['name'],$_POST['url']) && !empty($_POST['name']) && !empty($_POST['url']))
{
//var_dump($_POST['name']);
if($model->validate())
{
$model->title = $_POST['name'];
$model->destination = $_POST['url'];
$model->save();
}
}
$this->render('index',array('model' => $model));
}


اینم رول من در Model


public function rules()
{
// NOTE: you should only define rules for those attributes that
// will receive user inputs.
return array(
array('title, destination', 'required' ),
array('title, destination', 'length', 'max'=>255),
// The following rule is used by search().
// @todo Please remove those attributes that should not be searched.
array('id, title, destination', 'safe', 'on'=>'search'),
);
}


حالا سوالات :
1.آیا خود Yii دستورات Injection رو چک و رفعش می کنه ؟
2.وقتی می خوام عمل save در دیتا بیس رو انجام بدم اصلا validation نمی زاره که بخش save من اجرا بشه، چی کار کنم validation اجرا بشه؟
3.در قسمت ویو من آیا حتما باید خاصیت name را به صورت مثلا


<input type="text" id="name" name="Links[name]">

تعریف کنم؟( در اینجا من فقط به صورت name استفاده کردم. )
ممنون

masato
شنبه 28 دی 1392, 10:19 صبح
1-بله
2-مطمئن هستید که ویو رو درست نوشتید
3- فک کنم ویو رو اشتباه نوشتید
ویو رو کلا اشتباه نوشتید یه بار دیگه طریق ساخت ویو فرم رو نگاه کنید

engmmrj
شنبه 28 دی 1392, 11:33 صبح
ببینید و ایده بگیرید
http://www.yiiframework.com/doc/guide/1.1/en/form.view

mostafa_shoakry
شنبه 28 دی 1392, 12:25 عصر
بازم نشد.
همچنان validate گیر می ده .
بعد اینکه submit زدم خطا می ده که فیلدها نباید خالی باشد :افسرده:

MMSHFE
شنبه 28 دی 1392, 13:31 عصر
دقت کنید که شما الآن اول دارین validate رو صدا میزنید و بعد، attributeهای مدل رو Set میکنید. خوب طبیعیه که پیغام بده attributeها خالی هستن! متد actionCreate رو اینطوری بنویسید:


public function actionCreate()
{
$model = new Links;
if(isset($_POST['Links']))
{
$model->attributes = $_POST['Links'];
if($model->validate() && $model->save())
{
$this->redirect(array('view', 'id'=>$model->id));
}
else
{
$this->render('error', $model->errors);
}
}
$this->render('index', array('model' => $model));
}

و توی فرمتون هم اسامی عناصر رو بصورت [Links[name و [Links[url بگذارین.

Tarragon
شنبه 28 دی 1392, 15:33 عصر
سلام
خواستم تا مشکل این کد رو بپرسم :

$this->widget(
'zii.widgets.CListView',
array(
'data' => $IssueDataProvider,
'itemView' => '/issue/_view'
)
);

Property "CListView.data" is not defined.

masato
شنبه 28 دی 1392, 16:11 عصر
اینطوری بنویس


$this->widget('zii.widgets.CListView', array(
'dataProvider'=>$dataProvider,
'itemView'=>'_view_categories',
'ajaxUpdate'=>true,
'id'=>'ull',
'enableSorting'=>true,
'template'=>"{items}\n{pager}",
'enablePagination'=>true,
'ajaxType'=>'GET',
'ajaxUrl'=>null,

));

MMSHFE
شنبه 28 دی 1392, 16:33 عصر
ویجت ListView خاصیتی به اسم data نداره و باید از dataProvider استفاده کنید. اینطوری بنویسید:


$this->widget(
'zii.widgets.CListView',
array(
'dataProvider' => $IssueDataProvider,
'itemView' => '/issue/_view'
)
);

Tarragon
شنبه 28 دی 1392, 17:46 عصر
خیلی ممنون.
ببخشید آقای شهرکی شما تو پروژه TrackStar وقتی می خواهید نام owner رو بنویسید میاید می گید اگر owner_id وجود داشتم بیاید name اون رو بنویس. حالا اگر من بجای این کار یا فانکشن بنویسم مثل getTypeText (مثلا getOwnerText) و این کارا رو اونجا بکنم و مقدار آخر رو برگردونم فرقی داره؟ استفاده از کدوم بهتره؟ کدوم رو شما پیشنهاد می کنید؟

MMSHFE
یک شنبه 29 دی 1392, 02:31 صبح
فرق خاصی نداره. هرجور خودتون راحتتر هستین میتونید کار کنید. من خودم شخصاً Relation تعریف میکنم و بعد اینطوری مینویسم:

echo $project->owner->name;

mostafa_shoakry
یک شنبه 29 دی 1392, 22:37 عصر
سلام
من می خوام بررسی کنم ببینم که یه مقداری قبلا اگه در دیتا بیس ذخیره شده و کاربر بخواهد باز اون مقدارو وارد کنه خطا بدهد.
تا اونجا که مطلالعه کردم از تابع rules در model استفاده میشه و از validate ی به اسم exist میشه استفاده کرد.متاسفانه نتونستم هیچ نمونه کدی پیدا کنم . فقط فهمیدم که می شه تابع رو به صورت


public function rules()
{
// NOTE: you should only define rules for those attributes that
// will receive user inputs.
return array(
array('title, destination', 'required' ),
array('title, destination', 'length', 'max'=>255),
array('title' ,'exist' , 'on' => 'checkExist'),
array('destination','url'),
// The following rule is used by search().
// @todo Please remove those attributes that should not be searched.
array('id, title, destination', 'safe', 'on'=>'search'),
);
}

و نمونه کدی که پیدا کردم به این شکل هست:



public function ValidatorName($attribute,$params) { ... }


حالا سوالم اینه که 1. من چی attribute و params رو باید به تابع بفرستم؟
2. آیا برای چک کردن نیاز به استفاده model هستم؟ اگه بله خوب model از کجا می دونه که کدوم فیلد باید چک بشه؟

engmmrj
دوشنبه 30 دی 1392, 00:23 صبح
سلام
من می خوام بررسی کنم ببینم که یه مقداری قبلا اگه در دیتا بیس ذخیره شده و کاربر بخواهد باز اون مقدارو وارد کنه خطا بدهد.
تا اونجا که مطلالعه کردم از تابع rules در model استفاده میشه و از validate ی به اسم exist میشه استفاده کرد.متاسفانه نتونستم هیچ نمونه کدی پیدا کنم . فقط فهمیدم که می شه تابع رو به صورت


public function rules()
{
// NOTE: you should only define rules for those attributes that
// will receive user inputs.
return array(
array('title, destination', 'required' ),
array('title, destination', 'length', 'max'=>255),
array('title' ,'exist' , 'on' => 'checkExist'),
array('destination','url'),
// The following rule is used by search().
// @todo Please remove those attributes that should not be searched.
array('id, title, destination', 'safe', 'on'=>'search'),
);
}

و نمونه کدی که پیدا کردم به این شکل هست:



public function ValidatorName($attribute,$params) { ... }


حالا سوالم اینه که 1. من چی attribute و params رو باید به تابع بفرستم؟
2. آیا برای چک کردن نیاز به استفاده model هستم؟ اگه بله خوب model از کجا می دونه که کدوم فیلد باید چک بشه؟
در validate فیلد مورد نظر مقدار unique را اضافه کنید

array('email', 'required','unique' )

mostafa_shoakry
دوشنبه 30 دی 1392, 00:29 صبح
در validate فیلد مورد نظر مقدار unique را اضافه کنید

array('email', 'required','unique' )
دست طلا حل شد :قلب:

MMSHFE
سه شنبه 01 بهمن 1392, 08:30 صبح
لطفاً برای مطرح کردن سؤالات جدید، تاپیک جدید با عنوان مناسب ایجاد کنید. این تاپیک داره به یک تاپیک شلوغ با موضوعات مختلف تبدیل میشه و کسی که مشکل مشابهی داره، برای پیدا کردن راه حل به مشکل برخورد میکنه.