# زبان های اسکریپتی > PHP > Yii Framework >  روش ساخت صفحه کانفیگ شخصی (حل شد)

## shadecute

سلام
فرض کنیم ما یه سیستم با ماژول های مختلف داریم 

برای مثال در ویو ماژول یک 50 نوشته نمایش داده میشه
در ویو ماژول  دو 20 نوشته نمایش داده میشه
و ....

برای این که این اعداد رو تغییر بدم هر دفعه باید برم و در کد این اعداد رو تغییر بدم 
حالا من چظوری می تونم در یک فایل کانفیگ که به دیتابیستم وصل میشه این اعداد و ارقام رو در سیستم Set کنم 
که این فایل کانفیگ به همه ماژول ها هم دسترسی داشته باشه هر تغییری در کانفیگ دادم در کل ماژول هام اعمال بشه

----------


## SlowCode

سلام
میتونی تو فایل کانفیگ main.php این مقادیر رو به آرایه params اضافه کنی، مثلا:

    'params'=>array(
        // this is used in contact page
        'adminEmail'=>'webmaster@example.com',
        'newsViewLimit'=>50,
        'productsViewLimit'=>20,
    ),

واسه دسترسی هم اینطور عمل میکنی:

echo Yii::app()->params['newsViewLimit'];

----------


## shadecute

ممنون دوست من خیلی عالی بود تونستم درستش کنم فقط در مورد اینکه چظوری به دیتا بیس هم متصل بشه میشه راهنمایی کنید ؟ که این مقادیر رو در دیتا بیس ست کنیم .

----------


## MMSHFE

یکی از کارهایی که توی برخی پروژه ها لازم میشه و کارفرما میخواد اینه که بتونه تنظیمات سایت رو (که معمولاً توی بخش params از فایل تنظیمات تعیین میکنید)، توی بخش مدیریت، ویرایش کنه. برای این کار من روش زیر رو توصیه میکنم:
توی فایل components/Controller.php که کلاس والد تمام کنترلرهای شماست، این متد رو اضافه کنید:
protected function beforeAction($action) {
    // overwrite params with the DB version
    $params = Yii::app()->params->toArray();
    $keys = array_keys($params);
    foreach($keys as $key) {
        $setting = Settings::model()->find(array('condition'=>'`key`=:key','params'=>ar  ray(':key'=>$key)));
        if($setting != null) {
            $params[$key] = $setting->value;
        }
    }
    Yii::app()->params = $params;
    return parent::beforeAction($action);
}
حالا یک جدول به اسم settings توی دیتابیس با سه فیلد id و key و value بسازین که id کلید اصلی و key و value از نوع varchar با سایز 255 هست و key رو هم UNIQUE کنید. حالا برای تمام پارامترهایی که توی params معرفی کردین، یک رکورد توی این جدول ایجاد کنید که key میشه اندیس مربوطه در آرایه params (مثلاً adminEmail) و value هم مقدار پیشفرض اون هست (مثلاً webmaster@example.com). حالا تنها کاری که لازمه اینه که مدل مربوطه رو با Gii بسازین و اسمش رو هم Settings بگذارین.

اگه به کد فوق دقت کنید، میبینید که میاد مقادیر این جدول رو میخونه و توی آرایه params میچینه و Yii::app()->params رو هم با مقادیری که از دیتابیس خونده مقداردهی میکنه. از اونجا که این کار توی رویداد beforeAction انجام میشه، قبل از اینکه هر عملیاتی اتفاق بیفته، تنظیمات موجود در دیتابیس جایگزین تنظیمات موجود در فایل config/main.php میشه.

----------


## shadecute

استاد تشکر 
من این مراحل رو طی کردم 
1- فایل params.php  ساختم با مفادیری مشخص و تو فایل کانفیگم اینکلود کردم.


```
    'params'=>require(dirname(__FILE__).'/params.php'),
```

2- داخل فایل  params رو اینشکلی پر کردم
<?php
return array(

    'adminEmail'=>'info@mysite.com',
    'postsPerPage'=>10,

);



3- متدی که شما دادید رو در components/Controller.php کپی کردم
4- جداول رو ایجاد کردم و با Gii مد و ویو کنترل رو ایجاد کردم

من الان وارد ویرایش مقادیر میشم در http://localhost/site/settings/update/1   و مثلا ایمیل رو تغییر میدم در دیتا بیس تغییر میکنه اما در params  تغییری ایجاد نمیشه 
ببخشید خیلی تازه کارم و سوالات مبتدی می پرسم.

آیا رد داخل خود فایل params.php  باید مقادیر Settings  رو بخونم؟ میشه بیشتر راهنمایی کنید من تمام مراحل رو طبق آموزش رفتم اما تو خود params.php چیزی تغییر نمیکنه
ممنونم

----------


## MMSHFE

نه دیگه نیازی نیست فایل رو تغییر بدین. الان توی صفحات سایتتون اگه Yii::app()->params['adminEmail'] رو بخونید، میبینید که اون چیزی که تو دیتابیس گذاشتین چاپ میشه نه اون چیزی که توی فایل تنظیمات هست. درواقع شما الان امکان تغییر پویای پارامترها رو دارین، بدون اینکه لازم باشه فایل تنظیمات اصلی رو دست بزنید. هروقت هم خواستین به تنظیمات اصلی برگردین کافیه رکورد مربوطه رو از جدول توی دیتابیس حذف کنید.

----------


## shadecute

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

----------


## shadecute

فقط یه سوال . از Yii::app()->params['paramName']میشه تو خود فایل config.php هم استفاده کرد؟
نام اصلی سایت از کانفیگ اصلی 
    'name'=>'وبسایت من',

 
خونده میشه حالا من همین name  رو تو params بردم و اینبر خوندمش Yii::app()->params['name'] اما Var_dump  میگیرم در مقدار NULL  بر میگرده البته فقط در کانفیگ ولی جایی دیگه echo  میکنم مشکلی نداره
دلیلش چی می تونه باشه؟

----------


## MMSHFE

نه تو خودش نمیشه چون هنوز شئ Application ساخته نشده. به index.php اصلی نگاه کنید. میبینید که فایل config رو میخونه و با کمک اون شئ رو میسازه. بنابراین توی خود فایل تنظیمات هنوز شئ وجود نداره که مقادیرش رو بخونیم. بجای این کار توی برنامه از Yii::app()->params['name'] بجای Yii::app()->name استفاده کنید (جاهایی که میخواستین اسم پروژه چاپ بشه).

----------


## shadecute

سلام یه سوال برام پیش اومده ما جدول رو درست کردیم key و value از نوع varchar با سایز 255 هست
خب تو گرید ویو همه فیلدامنو با textField لود میشه 
حالا اگر ما یه گزینه های دیگه داشته باشیم مثلا فعال یا غیر فعال بودن سایت رو بخوایم در ستینگ کار کنیم و با checkbox  مقدارشو بخوام بگیرم نمیشه
چون همه فیلد های key و value از نوع varchar هست و تو گرید ویو همه با textField لود میشه . این وسط چطوری می تونم مثل نمونه بالا از checkbox و یا _textArea_ استفاده کنم؟

----------


## MMSHFE

یا باید با گرید ویو کار نکنید و خودتون دستی صفحه رو بسازین و برای بخشهایی که میخواین چک باکس باشه مقادیر رو از تو آرایه چک کنید و یا اینکه یک فیلد دیگه به جدول اضافه کنید (مثلاً isBoolean) که برای فیلدهای چک باکس مقدارش 1 میشه و توی گرید ویو بگین اگه این فیلد 1 بود، تکست نگذاره و چکباکس بسازه. در کل روش دستی رو ساده تر و بهتر میدونم تا اینکه بخواین درگیر بشین با گرید ویو. البته میتونید خودتون یک گرید ویوی سفارشی بسازین.

----------


## shadecute

ممنون 
از روش دستی که فرمودید میشه یه مثال بزنید دستی منظورتون چطوریه. :متفکر:

----------


## MMSHFE

منظورم اینه که ویوی مربوط به تنظیمات رو خودتون بسازین. مثلاً من یک تگ سلکت میگذارم و میگم تنظیمات رو انتخاب کنه. وقتی انتخاب کرد، برحسب نوعش، چک باکس یا تکست باکس نشون میدم و تنظیمات رو هم بعدش ذخیره میکنم.

----------


## shimafaraz

سلام و عرض ادب. من بر روی وبلاگ Yii این کارهارو انجام دادم تا پارامترها رو در ستینگ تغییر بدم موفق شدم بعد از کلی کار انجامش بدم اما یه سوال 
که این دوستمون پرسیده بودن.
===
_:حالا اگر ما یه گزینه های دیگه داشته باشیم مثلا فعال یا غیر فعال بودن  سایت رو بخوایم در ستینگ کار کنیم و با checkbox  مقدارشو بخوام بگیرم  نمیشه
چون همه فیلد های key و value از نوع varchar هست و تو گرید ویو همه با  textField لود میشه . این وسط چطوری می تونم مثل نمونه بالا از checkbox و  یا textArea استفاده کنم؟_
===
من همچین موردی رو می خوام روش کار کنم اما نتونستم تازه کارم ممنون میشم یک سمپل بزارید دوستان

----------


## shimafaraz

:افسرده:  ویو مربوط به تنظیمات رو چطوری ایجاد کنم که بتونه دیتا نشون بده و ذخیره کنه در دیتابیس؟ :خیلی عصبانی: 

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

----------


## MMSHFE

دستی بسازین. لازم نیست حتماً با Gii ساخته بشه. میتونید با CActiveForm کار کنید و از متدهای اون برای تولید چک باکس و... استفاده کنید.

----------


## shimafaraz

> دستی بسازین. لازم نیست حتماً با Gii ساخته بشه. میتونید با CActiveForm کار کنید و از متدهای اون برای تولید چک باکس و... استفاده کنید.


مرسی  :افسرده:  ببخشید سوالاتم ابتداییه تازه 7 روزه  با Yii  دارم کار میکنم خیلی جاهاش برام گنگه شدیدا پوزش میخوام....
من در ویو settings  یه فایل php  به اسم test.php  ایجاد کردم. که کدش اینجوریه 


```
<div class="form">
    <p class="alert alert-info">ویرایش تنظیمات</p>
<?php
$form = $this->beginWidget('CActiveForm', array (
        'id' => 'setting-form',
        'enableAjaxValidation' => false,
        'htmlOptions' => array (
                'class' => 'form-horizontal' 
        ) 
));
?>
    <div class="form-group">
        <label for="name" class="col-sm-3 control-label">نام کاربری </label>
        <div class="col-sm-3">
        <?php echo CHtml::textField('email',Yii::app()->params['email'],array('class'=>'form-control'))?>
        </div>

    </div>
    
    
    
        <div class="form-group">
        <label for="name" class="col-sm-3 control-label">فعال بودن</label>
        <div class="col-sm-3">
       <?php echo $form->checkBox($model,Yii::app()->params['active'], array('value'=>1, 'uncheckValue'=>0)); ?>))?>
        </div>

    </div>


    <div class="form-group">
        <div class="col-sm-offset-2 col-sm-10">
  <?php echo CHtml::submitButton( 'ویرایش',array('class'=>'btn btn-success','name'=>'btnSettingEdit')); ?>
        </div>
    </div>
<?php $this->endWidget(); ?>

</div>
<!-- form -->
```

تا اینجا درست انجام دادم؟ می خوام پارامتر email  و active  رو اینجا ادیت کنم .که اکتیو چک باکسه
اگر اشتباه نکنم باید تو مرحله ی بعد تو SettingsController  باید اکشنش رو بنویسم؟ درسته؟ خب اکشنش رو نمی دونم چی  باید بنویسم امکانش هست یه سمپل اکشن بدید که این فرمه کار کنه
( تو  مدل که نیازی نیست کدی بنویسیم؟)
ممنون از زحمات شما

----------


## MMSHFE

نه باید خودتون یه CFormModel بسازین (مثل مدل LoginModel توی پروژه Skeleton اولیه که خود فریمورک براتون میسازه) و پارامترها رو داخلش تعریف کنید و بعد برای اون بیاین با CActiveForm فرم ویرایش درست کنید. تا فردا براتون یه نمونه اگه فرصت کردم میگذارم ولی فکر میکنم خودتون بتونین انجام بدین. ولیدیشن رولها رو هم باید بنویسید. مثلاً یه فیلد active داخلش تعریف کنید و براش رول boolean بگذارین و required نباشه. اینطوری میتونه کاربر توی فرم انتخابش نکنه. موقعی که فرم سابمیت میشه هم با validate چک میکنید خطایی نباشه و اگه نبود، اونوقت فیلدها رو توی Yii::app()->params قرار میدین یا توی دیتابیس ذخیره میکنید که در دفعات بعدی از اونجا خونده بشه.

----------


## MMSHFE

ببینید یه مثال ساده میزنم. فرض کنید توی دیتابیس توی جدول تنظیمات سه فیلد داریم: name و email و rtl که دوتای اولی متنی هستن و سومی چک باکس هست. خوب با این اوصاف، من میام برای جدول Settings یه فرم مدل میسازم:
class SettingsForm extends CFormModel
{
    public $name;
    public $email;
    public $rtl;

    public function rules()
    {
        return array(
            array('name, email', 'required'),
            array('name', 'length', 'max'=>255),
            array('email', 'email'),
            array('rtl', 'boolean'),
        );
    }

    public function attributeLabels()
    {
        return array(
            'name'=>'نام سایت',
            'email'=>'پست الکترونیک',
            'rtl'=>'راست به چپ',
        );
    }
}
خوب حالا با کمک Gii میایم توی قسمت Form Generator یه فرم میسازیم و کمی تغییرش میدیم تا این شکلی بشه:


```
<div class="form">
<?php $form=$this->beginWidget('CActiveForm', array(
    'id'=>'settings-form',
    'enableAjaxValidation'=>true,
)); ?>
    <p class="note">Fields with <span class="required">*</span> are required.</p>
    <?php echo $form->errorSummary($model); ?>
    <div class="row">
        <?php echo $form->labelEx($model,'name'); ?>
        <?php echo $form->textField($model,'name'); ?>
        <?php echo $form->error($model,'name'); ?>
    </div>
    <div class="row">
        <?php echo $form->labelEx($model,'email'); ?>
        <?php echo $form->textField($model,'email'); ?>
        <?php echo $form->error($model,'email'); ?>
    </div>
    <div class="row">
        <?php echo $form->labelEx($model,'rtl'); ?>
        <?php echo $form->checkBox($model,'rtl'); ?>
        <?php echo $form->error($model,'rtl'); ?>
    </div>
    <div class="row buttons">
        <?php echo CHtml::submitButton('Submit'); ?>
    </div>
<?php $this->endWidget(); ?>
</div>
```

به checkBox آخر دقت کنید. حالا باید کنترلر/اکشن مربوطه رو بسازیم. من اومدم یه SettingsController با اکشن index ساختم ولی شما میتونید با هر کنترلر/اکشن دلخواه کار کنید:
class SettingsController extends Controller
{
    public function actionIndex()
    {
        $model = new SettingsForm;
        if(isset($_POST['ajax']) && $_POST['ajax'] === 'settings-form') {
            echo CActiveForm::validate($model);
            Yii::app()->end();
        }
        if(isset($_POST['SettingsForm'])) {
            $model->attributes = $_POST['SettingsForm'];
            if($model->validate()) {
            }
            // now save $model->attributes in DB
        }
        $this->render('index', array('model'=>$model));
    }
}
اگه جایی مشکل بود بفرمایید تا بیشتر توضیح بدم.

----------


## shimafaraz

سلام ممنون از توجه شما
استاد من مراحل زیر رو انجام دادم
طبق فرمایش شما
1- در داخل پوشه ی models  اومدم یه فایل php  به نام SettingsForm ساختم و داخلش کد شما رو قرار دادم و فقط چون اسم فیلدام چیز دیگری بود به صورت زیر وارد کردم
<?php
class SettingsForm extends CFormModel
{
    public $name;
    public $adminEmail;
    public $active;
 
    public function rules()
    {
        return array(
            array('name,adminEmail','required'),
            array('name','length', 'max'=>255),
             array('adminEmail', 'adminEmail'),
            array('active', 'boolean'),
        );
    }
 
    public function attributeLabels()
    {
        return array(
            'name'=>'نام سایت',
            'adminEmail'=>'پست الکترونیک',
            'active'=>'فعال کردن',
        );
    }
}
فقط اون خطی که قرمز کردم نمیزاره فرمم کار کنه وقتی خذفش میکنم فرم لود میشه در صورتی که باشه پیغام زیر رو میده
* 		include(adminEmail.php): failed to open stream: No such file or directory	*



بعدش اومدم در مسیر Views در settings یک فایل به اسم test.php  درست کردم
و داخلش رو همین کدرو گذاشتم



```
<div class="form">
<?php $form=$this->beginWidget('CActiveForm', array(
    'id'=>'settings-form',
    'enableAjaxValidation'=>true,
)); ?>
    <p class="note">Fields with <span class="required">*</span> are required.</p>
    <?php echo $form->errorSummary($model); ?>
    <div class="row">
        <?php echo $form->labelEx($model,'name'); ?>
        <?php echo $form->textField($model,'name'); ?>
        <?php echo $form->error($model,'name'); ?>
    </div>
    <div class="row">
        <?php echo $form->labelEx($model,'adminEmail'); ?>
        <?php echo $form->textField($model,'adminEmail'); ?>
        <?php echo $form->error($model,'adminEmail'); ?>
    </div>
    <div class="row">
        <?php echo $form->labelEx($model,'active'); ?>
        <?php echo $form->checkBox($model,'active'); ?>
        <?php echo $form->error($model,'active'); ?>
    </div>
    <div class="row buttons">
        <?php echo CHtml::submitButton('Submit'); ?>
    </div>
<?php $this->endWidget(); ?>
</div>
```

 بعدش در  خود SettingsController اکشن رو قرار دادم به اسم test اینجوری
     public function actionTest()
    {
        $model = new SettingsForm;
        if(isset($_POST['ajax']) && $_POST['ajax'] === 'settings-form') {
            echo CActiveForm::validate($model);
            Yii::app()->end();
        }
        if(isset($_POST['SettingsForm'])) {
            $model->attributes = $_POST['SettingsForm'];
            if($model->validate()) {
            }
            // now save $model->attributes in DB
        }
        $this->render('test', array('model'=>$model));
    }
با تمام این مراحل که شما فرمودید فرمم لود میشه ولی داخل فیلد ها خالیه و وقتی چیزی داخلش می نویسمو Save  می کنم چیزی در دیتابیس ذخیره نمیشه
کجای کارم اشکال داره؟ اسم table  تودیتابیس هم settings  هست که بر اساس آموزش اولیه تاپیک خودتون آموزش داده بودید پیش رفتم

----------


## MMSHFE

خوب شما الان یه فرم مدل دارین نه یه اکتیورکورد. باید اونجایی که کامنت گذاشتم گفتم تو دیتابیس ذخیره کنید، یه شئ از مدل Settings بسازین یا همونی که هست رو بخونین و فیلدهاش رو با فیلدهای متناظر از مدل فرم مقداردهی کنید و بعد با صدا زدن متد save روی اکتیورکورد، اون رو توی دیتابیس ذخیره کنید.

----------


## shimafaraz

:افسرده:       public function actionTest()
    {
        $model = new SettingsForm;
        if(isset($_POST['ajax']) && $_POST['ajax'] === 'settings-form') {
            echo CActiveForm::validate($model);
            Yii::app()->end();
        }
        if(isset($_POST['SettingsForm'])) {
            $model->attributes = $_POST['SettingsForm'];
            if($model->validate()) {
            }
        $model=new Settings;

        if (isset($_POST['Settings'])) {
            $model->attributes=$_POST['Settings'];
            if ($model->save()) {
            }
        }        }
        $this->render('test', array('model'=>$model));
    }
 :افسرده: 
اشتباه نوشتم :( کار نمیکنه گیج شدم :گریه:

----------


## MMSHFE

باید فیلدهاتون توی دیتابیس همنام با فیلدهای مدل فرم باشه وگرنه باید جداگانه ذخیره کنید. برای مثال:
public function actionTest()
{
    $model = new SettingsForm;
    if(isset($_POST['ajax']) && $_POST['ajax'] === 'settings-form') {
        echo CActiveForm::validate($model);
        Yii::app()->end();
    }
    if(isset($_POST['SettingsForm'])) {
        $model->attributes = $_POST['SettingsForm'];
        if($model->validate()) {
            $settings = new Settings;
            if(isset($_POST['Settings'])) {
                $settings->attributes = $model->attributes;
                /* OR assign fields individually if field names are different
                 * e.g. :
                 * $settings->appname = $model->name;
                 * $settings->adminmail = $model->adminEemail;
                 * $settings->is_active = $model->active;
                 */
                if ($settings->save()) {
                }
            }
        }
    }
    $this->render('test', array('model'=>$model));
}
برای اعتبارسنجی ایمیل هم باید اینطوری بنویسید:
public function rules()
{
    return array(
        array('name,adminEmail','required'),
        array('name','length', 'max'=>255),
         array('adminEmail', 'email'),
        array('active', 'boolean'),
    );
}
دقت کنید که اسم ولیدیتور ایمیل، email هست و اسم فیلد شما adminEmail

----------


## shimafaraz

استاد ممنون من همین کد رو استفاده کردم public function actionTest()
{
    $model = new SettingsForm;
    if(isset($_POST['ajax']) && $_POST['ajax'] === 'settings-form') {
        echo CActiveForm::validate($model);
        Yii::app()->end();
    }
    if(isset($_POST['SettingsForm'])) {
        $model->attributes = $_POST['SettingsForm'];
        if($model->validate()) {
            $settings = new Settings;
            if(isset($_POST['Settings'])) {
                $settings->attributes = $model->attributes;
          
                 $settings->name = $model->name;
                 $settings->adminEemail = $model->adminEmail;
                 $settings->active = $model->active;
             
                if ($settings->save()) {
                }
            }
        }
    }
    $this->render('test', array('model'=>$model));
}
اما نشد
ذخیره نشد
اسامی فیلد ها ر و هم درست وارد کردم  اینم عکس دیتابیس من

demo.jpg

----------


## MMSHFE

خوب شما الان رکورد دارین نه فیلد. باید اینطوری کار کنید:
public function actionTest()
{
    $model = new SettingsForm;
    if(isset($_POST['ajax']) && $_POST['ajax'] === 'settings-form') {
        echo CActiveForm::validate($model);
        Yii::app()->end();
    }
    if(isset($_POST['SettingsForm'])) {
        $model->attributes = $_POST['SettingsForm'];
        if($model->validate()) {
            $settings = new Settings;
            if(isset($_POST['Settings'])) {
                foreach($_POST['Settings'] as $key => $value) {
                    if($setting = Settings::model()->find('LOWER(`key`)=:key',array(':key'=>strtolower  ($key)))) {
                        $setting->value = $value;
                        $setting->save();
                    }
                }
            }
        }
    }
    $this->render('test', array('model'=>$model));
}
اگه میخواین موقع نمایش فرم هم مقادیر قبلی توش نوشته شده باشه باید بعد از ساخت شئ مدل فرم (settings) فیلدهاش رو با مقدار value رکورد متناظر از جدول settings توی دیتابیس پر کنید.

----------


## shadecute

درود بر استاد شهرکی و دوستان برنامه نویس سال نو مبارک
-
دوستان این صفحه رو ببینید 

یک  روش ساخت کانفیگ هست . من واسه تمرین یکمی اجراش کردم و بدون مشکلم کار  میکنم ولی به جای دیتابیس مقادیر رو رمز نگاری میکنه و در یک فایل  params.inc ذخیره و از همین فایل می خونه تنظیمات رو .
آیا استفاده از این روش رو پیشنهاد میکنید؟
مورد تاییده؟ 
اینکه در params.inc تنظیمات رمز نگاری میشه و ذخیره میشه ایرادی فنی و امنیتی نداره؟ ممنون میشم راهنمایی کنید

----------

