За последние 24 часа нас посетили 74156 программистов и 10157 роботов. Сейчас ищет 2171 программист ...

Кружок по Yii

Тема в разделе "Прочие вопросы по PHP", создана пользователем Psih, 9 июл 2010.

?

Пользуетесь ли вы Yii?

  1. Нет, не пользуюсь.

    3 голосов
    33,3%
  2. Нет, у меня другой людимый фреймворк.

    1 голосов
    11,1%
  3. Начинаю с ним работать.

    3 голосов
    33,3%
  4. Да пользуюсь, всё хорошо.

    2 голосов
    22,2%
  1. Psih

    Psih Активный пользователь
    Команда форума Модератор

    С нами с:
    28 дек 2006
    Сообщения:
    2.674
    Симпатии:
    6
    Адрес:
    Рига, Латвия
    В свете моих начинаний на этом фреймворке и крайне положительных эмоциях по его использованию, делаю тему, дабы мы объединялись и решали насущные вопросы. Я конечно со всем помочь не смогу, но свою порцию геммороя я решил и даже уже запостил один баг репорт в баг трекер :)

    Тему прилепляю, флудеров и любителей похоливарить буду вычищать, не обижайтесь :)

    З.Ы. На опрос в тему не отвечать - созлдайте отдельный топик если вам интересно обсудить.
     
  2. Psih

    Psih Активный пользователь
    Команда форума Модератор

    С нами с:
    28 дек 2006
    Сообщения:
    2.674
    Симпатии:
    6
    Адрес:
    Рига, Латвия
    И так пошел 3-й месяц, как я серьёзно засел за Yii. Основной проект, который я на нём сделал и продолжаю сейчас делать - это админка и автоматизация обменя всяких электронных валют (это легко) и ваучеров (а вот это гемморой, т.к. API не существует в принципе, или гребёт грабительские проценты).

    На данный момент есть 3 части:

    • * Админка со списками, гридами, попапами и прочей туфтой. Так же используется встроенная система прав (хватит для любой корпоративной системы любых размеров).
      * Легкий фронт-енд для пополнения Skype в автоматическом режиме.
      * Обработчик пополнения Skype в виде демона. Тоже от и до на Yii.

    Впечатления.

    Админка
    Задача по созданию грида для показывания всего этого дела с сортировкой и простейшими фильтрами с полным CRUD набором сводится к 2-м кликам в кодогенераторе Gii прямо из WEB панели. Дальше остаётся только настроить продвинутые фильтры (опции у массива) и прописать альтернативное отображение данных в ячейках если нужно (к примеру 2 поля показать в виде одного).
    Всё легко и просто, когда разберёшься в основах. Продвинутые вещи делаются быстро и легко, благо всё JS часть на jQuery, что радует.
    Конечно не без недоработок, но учитывая кол-во разработчиков (коих всего 6 или 7), то прогресс впечатляет. Пожелания помочь встречают на ура, баги чинят быстро (зарепортил один 3 недели назад, уже починили и релизнули). Им бы энергию наших жителей формума php.ru да на пользу, фреймворк бы взорвал умы PHP программистов уже через пол года :)

    Да, одна особенность - конфигурационные массивы у них ориентированы на замыкания, прямо как в jQuery. Делают это с помощью eval, но с 5.3 можно использовать замыкания, т.к. их поддержка уже давно сделана. Сейчас перебрался на 5.3 уже у себя локально, уже завтра опробую как оно с замыканиями, обещает быть невъебенно круто :)

    Фронтедн
    Простая форма в 6 полей (изначально было 4, потом добавилось ещё 2). Не совсем простое добавление в базу. Сделалось просто на ура, Layout подкоректировал и заверстал свой дизайн за 20 минут (для формы много не нужно, но то, как это сделалось легко удивило).

    Демон
    Как оказалось, Yii не просто позволяет писать консольные скрипты, но и целые приложения, которые в свою очередь могут запускать отдельные команды, записанные как самостоятельные скрипты. В общем на этой базе как раз и работает их консольный генератор yiic. При этом вам доступны все компоненты, модули, модели и консольные комманды, которые описаны в вашем приложении. Я пока особо не разогнался, но выглядет впечатляюще. Конфиги легко делаются для разных точек входа свои, просто пишем имя конфига прямо в точке входа - ну что может быть проще, не правда ли?

    Из минусов: Довольно оторванная от реальности дока. Впрочем над ней вечно не хватает человек, что бы доработать. О проблеме все знают, но желающих помочь почти нету. Разработчики не успевают. API хорошо документирован, но почти нет примеров. Иногда встречаются опции, которые вообще не описаны. Благо их названия говорят сами за себя (к примеру htmlOptions опция есть у всего, что генерирует html разметку, но нигде нету описания что же там за опции вообще поддерживаются или хотя бы намёка на то, что key => value пары трансформируются в attribute="value"). Сильно спасает гугл и офф. форум + русский форум на yiiframework.ru.

    В недра особо не лазил, но в основном куда залазил - хорошо написано. Излишней ООПешности пока не наблюдал, вроде как кратко и ясно. Стройная ООП модель позволяет переопределить любой класс в системе так, как нужно вам и через конфиг его подгрузить вместо системных. Самые базовые конечно вряд-ли, но всё что в серединке бутерброда уже легко поддаётся модификации через ООП.

    Сам фреймворк ставится как библиотека рядом с приложениями и так и юзается. Если приложению нужно что-то изменить в самом фреймворке - наследуем, переопределяем и готово. К фреймворку даже не прикасались.

    В основном это пока в общем всё. Пока ещё не настолько погрузился в него, но работа не стоит на месте и планируется более серьёзный функционал - посмотрим как Yii себя покажет.
     
  3. 440Hz

    440Hz Старожил
    Команда форума Модератор

    С нами с:
    21 дек 2012
    Сообщения:
    7.983
    Симпатии:
    1
    Адрес:
    Оттуда
    покаж кусок кода своего?
     
  4. Psih

    Psih Активный пользователь
    Команда форума Модератор

    С нами с:
    28 дек 2006
    Сообщения:
    2.674
    Симпатии:
    6
    Адрес:
    Рига, Латвия
    440Hz
    А который тебя интересует больше всего? А то мест много :)
     
  5. MiksIr

    MiksIr Активный пользователь

    С нами с:
    29 ноя 2006
    Сообщения:
    2.333
    Симпатии:
    44
    Т.е. там есть средства генерирования админки по модели? Ну для банальных списков? А связи с другими моделями поддерживаются (имею ввиду в админке).

    Есть желание освоить какой-то фреймворк под задачи клепания сайтов дизайн-студии.. для тех, кого удалось отговорить от битрикса ;) Вот размышляю, или свой допилить, который из симфони вырос или какой-то готовый взять.

    Работа с моделями интересна - выборка - поиск.
     
  6. Psih

    Psih Активный пользователь
    Команда форума Модератор

    С нами с:
    28 дек 2006
    Сообщения:
    2.674
    Симпатии:
    6
    Адрес:
    Рига, Латвия
    MiksIr
    Генерацию связей не тестил, т.к. я не определяю Foreign keys в MySQL. Но relations естественно есть и выглдят вот так:
    PHP:
    1. <?php
    2.  
    3. /**
    4.  * This is the model class for table "transactions".
    5.  */
    6. class Transactions extends CActiveRecord
    7. {
    8. // ....
    9.     /**
    10.      * @return array relational rules.
    11.      */
    12.     public function relations()
    13.     {
    14.         // NOTE: you may need to adjust the relation name and the related
    15.         // class name for the relations automatically generated below.
    16.         return array(
    17.             'skype' => array(self::HAS_ONE, 'SkypeTransactions', 'sky_id'),
    18.             'account' => array(self::BELONGS_TO, 'Accounts', 'trn_by_account'),
    19.             'vouchers' => array(self::HAS_MANY, 'Vouchers', 'trn_id'),
    20.             'countVouchers' => array(self::STAT, 'TransactionVouchers', 'tvc_trn_id'),
    21.         );
    22.     }
    23. // .....
    24. }
    Здесь задано 4 связи как видите. Связи задаются в моделях с обоих сторон. О какой админке идёт речь я не знаю, Yii это фреймворк, не CMS. Но позволяет собирать админки легко и быстро.

    Щас отдельным постом приведу примеры.
     
  7. Psih

    Psih Активный пользователь
    Команда форума Модератор

    С нами с:
    28 дек 2006
    Сообщения:
    2.674
    Симпатии:
    6
    Адрес:
    Рига, Латвия
    Вот вам модель (я опустил 4 метода по генерации отчётов, поскольку они всёравно были сделаны в лоб и в обход возможностей фреймворка. Да и занимают ещё 300 строк скучного кода):
    PHP:
    1. <?php
    2.  
    3. /**
    4.  * This is the model class for table "transactions".
    5.  */
    6. class Transactions extends CActiveRecord
    7. {
    8.     /**
    9.      * The followings are the available columns in table 'transactions':
    10.      * @var integer $trn_id
    11.      * @var string $trn_started_on
    12.      * @var string $trn_finished_on
    13.      * @var string $trn_total
    14.      * @var string $trn_total_real
    15.      * @var string $trn_status
    16.      * @var string $trn_error_code
    17.      * @var string $trn_email
    18.      * @var integer $trn_by_account
    19.      * @var string $trn_purse
    20.      * @var string $trn_paysystem
    21.      * @var string $trn_rate
    22.      * @var string $trn_wm_id
    23.      * @var string $trn_operator_status
    24.      * @var string $trn_system_status
    25.      */
    26.  
    27.     public $trnvouchers;
    28.  
    29.     /**
    30.      * Returns the static model of the specified AR class.
    31.      * @return Transactions the static model class
    32.      */
    33.     public static function model($className=__CLASS__)
    34.     {
    35.         return parent::model($className);
    36.     }
    37.  
    38.     /**
    39.      * @return string the associated database table name
    40.      */
    41.     public function tableName()
    42.     {
    43.         return 'transactions';
    44.     }
    45.  
    46.     /**
    47.      * @return array validation rules for model attributes.
    48.      */
    49.     public function rules()
    50.     {
    51.         // NOTE: you should only define rules for those attributes that
    52.         // will receive user inputs.
    53.         return array(
    54.             array('trn_started_on, trn_total, trn_email, trn_by_account, trn_purse, trn_paysystem, trn_rate, trn_system, trn_operator_status, trn_system_status', 'required'),
    55.             array('trn_by_account', 'numerical', 'integerOnly'=>true),
    56.             array('trn_total, trn_total_real, trn_rate', 'length', 'max'=>10),
    57.             array('trn_status', 'length', 'max'=>13),
    58.             array('trn_error_code', 'length', 'max'=>15),
    59.             array('trn_email, trn_purse', 'length', 'max'=>100),
    60.             array('trn_paysystem', 'length', 'max'=>4),
    61.             array('trn_wm_id', 'length', 'max'=>20),
    62.             array('trn_finished_on, trn_operator_status, trn_system_status', 'safe'),
    63.             // The following rule is used by search().
    64.             // Please remove those attributes that should not be searched.
    65.             array('trn_id, trn_started_on, trn_finished_on, trn_total, trn_total_real, trn_status, trn_error_code, trn_email, trn_by_account, trn_purse, trn_paysystem, trn_rate, trn_wm_id, trn_system, trn_ip', 'safe', 'on'=>'search'),
    66.         );
    67.     }
    68.  
    69.     public function defaultScope()
    70.     {
    71.         return array(
    72.             'order'=>'trn_started_on DESC',
    73.         );
    74.     }
    75.  
    76.     /**
    77.      * @return array relational rules.
    78.      */
    79.     public function relations()
    80.     {
    81.         // NOTE: you may need to adjust the relation name and the related
    82.         // class name for the relations automatically generated below.
    83.         return array(
    84.             'skype' => array(self::HAS_ONE, 'SkypeTransactions', 'sky_id'),
    85.             'account' => array(self::BELONGS_TO, 'Accounts', 'trn_by_account'),
    86.             'vouchers' => array(self::HAS_MANY, 'Vouchers', 'trn_id'),
    87.             'countVouchers' => array(self::STAT, 'TransactionVouchers', 'tvc_trn_id'),
    88.         );
    89.     }
    90.  
    91.     /**
    92.      * @return array customized attribute labels (name=>label)
    93.      */
    94.     public function attributeLabels()
    95.     {
    96.         return array(
    97.             'trn_id' => 'ID',
    98.             'trn_started_on' => 'Start',
    99.             'trn_finished_on' => 'End',
    100.             'trn_total' => 'Total',
    101.             'trn_total_real' => 'Real total',
    102.             'trn_status' => 'Status',
    103.             'trn_error_code' => 'Error Code',
    104.             'trn_email' => 'Email',
    105.             'trn_by_account' => 'By Account',
    106.             'trn_rate' => 'Rate',
    107.             'trn_paysystem' => 'Money gateway',
    108.             'trn_purse' => 'Purse',
    109.             'trn_wm_id' => 'WM ID',
    110.             'trn_system' => 'System',
    111.             'trn_operator_status' => 'Operator status',
    112.             'trn_system_status' => 'System status',
    113.             'account.uac_login' => 'Processed by',
    114.             'trn_ip' => 'Customer IP',
    115.             'countVouchers' => 'Vouchers (search by code)',
    116.             'skype.sky_currency' => 'Skype account used',
    117.         );
    118.     }
    119.  
    120.     /**
    121.      * Retrieves a list of models based on the current search/filter conditions.
    122.      * @return CActiveDataProvider the data provider that can return the models based on the search/filter conditions.
    123.      */
    124.     public function search()
    125.     {
    126.         // Warning: Please modify the following code to remove attributes that
    127.         // should not be searched.
    128.  
    129.         $criteria=new CDbCriteria;
    130.  
    131.         $criteria->with = array('account', 'countVouchers');
    132.  
    133.         $criteria->compare('trn_id',$this->trn_id);
    134.  
    135.         $criteria->compare('trn_started_on',$this->trn_started_on,true);
    136.  
    137.         $criteria->compare('trn_finished_on',$this->trn_finished_on,true);
    138.  
    139.         $criteria->compare('trn_total',$this->trn_total,true);
    140.  
    141.         $criteria->compare('trn_total_real',$this->trn_total_real,true);
    142.  
    143.         $criteria->compare('trn_status',$this->trn_status,true);
    144.  
    145.         $criteria->compare('trn_error_code',$this->trn_error_code,true);
    146.  
    147.         $criteria->compare('trn_email',$this->trn_email,true);
    148.  
    149.         $criteria->compare('trn_by_account',$this->trn_by_account);
    150.  
    151.         $criteria->compare('trn_purse',$this->trn_purse,true);
    152.  
    153.         $criteria->compare('trn_paysystem',$this->trn_paysystem,true);
    154.  
    155.         $criteria->compare('trn_rate',$this->trn_rate,true);
    156.  
    157.         $criteria->compare('trn_wm_id',$this->trn_wm_id,true);
    158.  
    159.         $criteria->compare('trn_system', $this->trn_system, true);
    160.  
    161.         $criteria->compare('trn_ip', $this->trn_ip, true);
    162.  
    163.         $criteria->compare('trn_operator_status', $this->trn_operator_status, true);
    164.  
    165.         $criteria->compare('trn_system_status', $this->trn_system_status, true);
    166.  
    167.         // В данном случае тут таким образом обошел баг из 1.1.2, когда реляция работала для пейджера, но терялась для самого запроса почему-то. В 1.1.3 вроде починили, пока не проверил :)
    168.         $criteria->join = 'LEFT JOIN '.TransactionVouchers::model()->tableName().' AS thevouchers ON t.trn_id = thevouchers.tvc_trn_id';
    169.         if (!empty($this->trnvouchers->tvc_code)) {
    170.             $criteria->compare('tvc_code', $this->trnvouchers->tvc_code);
    171.             $this->countVouchers = $this->trnvouchers->tvc_code;
    172.         }
    173.  
    174.         if (!empty($this->account->uac_login)) {
    175.             $criteria->compare('account.uac_login', $this->account->uac_login);
    176.         }
    177.  
    178.         return new CActiveDataProvider(get_class($this), array(
    179.             'criteria'=>$criteria,
    180.             'pagination'=>array(
    181.                 'pageSize' => 10,
    182.             ),
    183.         ));
    184.     }
    185. }
    70% кода сделал генератор, остальное я уже просто доправил до нужной кондиции и своей извращённой логике :)
    Самое приятное в генераторе, это то, что вы можете прямо из него перегенерировать модель после изменений в базе и она с помощью diff добавит то, что нужно, не трогая ваш код. При этом, когда вы работаете из WEB панели, любезно предоставит вам красивый diff для просмотра прямо в браузере по желанию.

    А вот к модели и контроллер (не обрезанный):
    PHP:
    1. <?php
    2.  
    3. class TransactionsController extends SBaseController
    4. {
    5.     /**
    6.      * @var string the default layout for the views. Defaults to 'column2', meaning
    7.      * using two-column layout. See 'protected/views/layouts/column2.php'.
    8.      */
    9.     public $layout='column2';
    10.  
    11.     /**
    12.      * @var CActiveRecord the currently loaded data model instance.
    13.      */
    14.     private $_model;
    15.  
    16.     /**
    17.      * Displays a particular model.
    18.      */
    19.     public function actionView()
    20.     {
    21.  
    22.         $model = $this->loadModel();
    23.  
    24.         $criteria=new CDbCriteria;
    25.         $criteria->addColumnCondition(array('tvc_trn_id' => $model->trn_id));
    26.  
    27.         $trn_vouchers = new CActiveDataProvider('TransactionVouchers', array(
    28.             'criteria'=> $criteria,
    29.         ));
    30.  
    31.         $criteria=new CDbCriteria;
    32.         $criteria->addColumnCondition(array('vch_trn_id' => $model->trn_id));
    33.  
    34.         $result_vouchers = new CActiveDataProvider('Vouchers', array(
    35.             'criteria' => $criteria
    36.         ));
    37.  
    38.         $ukash_online = Params::model()->findByAttributes(array('name' => 'Ukash automatics'))->value == "on" ? true : false;
    39.  
    40.         $this->renderPartial('view',array(
    41.             'model'=> $model,
    42.             'trn_vouchers' => $trn_vouchers,
    43.             'result_vouchers' => $result_vouchers,
    44.             'ukash_online' => $ukash_online
    45.         ));
    46.     }
    47.  
    48.     /**
    49.      * Creates a new model.
    50.      * If creation is successful, the browser will be redirected to the 'view' page.
    51.      */
    52.     public function actionCreate()
    53.     {
    54.         $model=new Transactions;
    55.  
    56.         // Uncomment the following line if AJAX validation is needed
    57.         // $this->performAjaxValidation($model);
    58.  
    59.         if(isset($_POST['Transactions']))
    60.         {
    61.             $model->attributes=$_POST['Transactions'];
    62.             if($model->save())
    63.                 $this->redirect(array('view','id'=>$model->trn_id));
    64.         }
    65.  
    66.         $this->render('create',array(
    67.             'model'=>$model,
    68.         ));
    69.     }
    70.  
    71.     /**
    72.      * Updates a particular model.
    73.      * If update is successful, the browser will be redirected to the 'view' page.
    74.      */
    75.     public function actionUpdate()
    76.     {
    77.         $model=$this->loadModel();
    78.  
    79.         // Uncomment the following line if AJAX validation is needed
    80.         // $this->performAjaxValidation($model);
    81.  
    82.         if(isset($_POST['Transactions']))
    83.         {
    84.             $model->attributes=$_POST['Transactions'];
    85.             if($model->save()) {
    86.                 $this->redirect(array('view','id'=>$model->trn_id));
    87.             }
    88.         }
    89.  
    90.         $this->render('update',array(
    91.             'model'=>$model,
    92.         ));
    93.     }
    94.  
    95.     /**
    96.      * Lists all models.
    97.      */
    98.     public function actionIndex()
    99.     {
    100.         $model=new Transactions('search');
    101.  
    102.         $model->account = new Accounts();
    103.         $model->trnvouchers = new TransactionVouchers();
    104.  
    105.         /**
    106.          * @todo Remove when it is fixed in Yii 1.1.3
    107.          */
    108.         $model->setAttributes(
    109.             array(
    110.                 'trn_total_real'=>NULL,
    111.                 'trn_status'=>NULL,
    112.                 'trn_system' => NULL,
    113.                 'trn_system_status' => NULL,
    114.                 'trn_operator_status' => NULL,
    115.             )
    116.         );
    117.  
    118.         if(isset($_GET['Transactions'])) {
    119.             $model->attributes=$_GET['Transactions'];
    120.             if (isset($_GET['Transactions']['trnvouchers'])) {
    121.                 $model->trnvouchers->attributes = $_GET['Transactions']['trnvouchers'];
    122.             }
    123.             if (isset($_GET['Transactions']['account'])) {
    124.                 $model->account->attributes = $_GET['Transactions']['account'];
    125.             }
    126.         }
    127.  
    128.         $this->render('index',array(
    129.             'model'=>$model,
    130.         ));
    131.     }
    132.  
    133.     /**
    134.      * Manages all models.
    135.      */
    136.     public function actionAdmin()
    137.     {
    138.         $model=new Transactions('search');
    139.  
    140.         /**
    141.          * @todo Remove when it is fixed in Yii 1.1.3
    142.          */
    143.         $model->setAttributes(
    144.             array(
    145.                 'trn_total_real'=>NULL,
    146.                 'trn_status'=>NULL,
    147.                 'trn_system' => NULL,
    148.                 'trn_system_status' => NULL,
    149.                 'trn_operator_status' => NULL,
    150.             )
    151.         );
    152.  
    153.         if(isset($_GET['Transactions']))
    154.             $model->attributes=$_GET['Transactions'];
    155.  
    156.         $this->render('admin',array(
    157.             'model'=>$model,
    158.         ));
    159.     }
    160.  
    161.     public function actionStatus() {
    162.  
    163.         $model = $this->loadModel();
    164.  
    165.         if (!in_array($model->trn_status, array('success', 'failed'))) {
    166.  
    167.             if(isset($_POST['Transactions']))
    168.             {
    169.                 $model->attributes=$_POST['Transactions'];
    170.                 $model->trn_finished_on = new CDbExpression('NOW()');
    171.                 if ($model->trn_status == "success") {
    172.                     $model->trn_total_real = $this->trn_total;
    173.                 }
    174.                 if ($model->trn_system == "skype") {
    175.                     if ($model->save()) {
    176.                         $sky_trn = SkypeTransactions::model()->findbyPk($model->trn_id);
    177.                         $sky_trn->sky_status = $model->trn_status == "success" ? "success" : "error";
    178.                         $sky_trn->sky_password = str_repeat('*', 8);
    179.                         $sky_trn->sky_finished = new CDbExpression('NOW()');
    180.                         $sky_trn->save();
    181.                         $this->redirect(array('view','id'=>$model->trn_id));
    182.                     }
    183.                 } else {
    184.                     if ($model->trn_status == "success") {
    185.                         $sql = 'SELECT SUM(tvc_amount)
    186.                                 FROM '.TransactionVouchers::model()->tableName().'
    187.                                 WHERE tvc_trn_id = :id';
    188.                         $db = $model->getDbConnection()->CreateCommand($sql);
    189.                         $model->trn_total_real = $db->queryScalar(array(':id' => $model->trn_id));
    190.                     }
    191.                     if($model->save()) {
    192.                         if ($model->trn_status == 'success') {
    193.                             /* If save was a success then make a payment */
    194.                             // Общая сумма реальная для выплаты в выбранной системе пользователя
    195.                             $total = number_format(round($model->trn_total_real * $model->trn_rate, 2), 2, '.', '');
    196.                             //echo $total;
    197.                             // Кошелёк клиента
    198.                             $purse = $model->trn_purse;
    199.                             // Платёжная система
    200.                             $wm_id = $model->trn_wm_id;
    201.                             // Платёжная система
    202.                             $paysys = $model->trn_paysystem;
    203.                             // E-Mail клиента
    204.                             $email = $model->trn_email;
    205.                             // Система ваучеров
    206.                             $system = $model->trn_system;
    207.  
    208.                             include('../confukash/autopay.inc');
    209.                         }
    210.                         $this->redirect(array('view','id'=>$model->trn_id));
    211.                     }
    212.                 }
    213.  
    214.             }
    215.  
    216.             $this->renderPartial('status',array(
    217.                 'model'=>$model,
    218.             ));
    219.         } else {
    220.             $this->redirect(array('view','id'=>$model->trn_id));
    221.         }
    222.     }
    223.  
    224.     public function actionOpstatus()
    225.     {
    226.         $model = $this->loadModel();
    227.         if(isset($_POST['Transactions']))
    228.         {
    229.             $model->attributes=$_POST['Transactions'];
    230.             if($model->save()) {
    231.                 $this->redirect(array('view','id'=>$model->trn_id));
    232.             }
    233.         }
    234.         $this->renderPartial('opstatus',array(
    235.                 'model'=>$model,
    236.         ));
    237.     }
    238.  
    239.     public function actionReports()
    240.     {
    241.         $transactions = new Transactions();
    242.         $transactionVouchers = new TransactionVouchers();
    243.  
    244.         $this->render('reports', array(
    245.             'last24hrs' => $transactions->getLast24Reports(),
    246.             'vouchers_data_24hrs' => $transactionVouchers->getLast24Reports(),
    247.             'payout_totals_24hrs' => $transactions->getLast24PayoutTotals(),
    248.         ));
    249.     }
    250.  
    251.     public function actionReportsInterval() {
    252.         $transactions = new Transactions();
    253.         $transactionVouchers = new TransactionVouchers();
    254.  
    255.         if (!isset($_GET['start']) || empty($_GET['start'])) {
    256.             $start = date('Y-m-d');
    257.         } else {
    258.             $start = $_GET['start'];
    259.         }
    260.  
    261.         if (!isset($_GET['end']) || empty($_GET['end'])) {
    262.             $end = date('Y-m-d');
    263.         } else {
    264.             $end = $_GET['end'];
    265.         }
    266.  
    267.         $this->render('reports_period', array(
    268.             'data'=> $transactions->getTotalReports($start, $end),
    269.             'vouchers_data' => $transactionVouchers->getTotalReports($start, $end),
    270.             'payout_totals' => $transactions->getPayoutTotals($start, $end),
    271.             'start' => $start,
    272.             'end' => $end
    273.         ));
    274.     }
    275.  
    276.     /**
    277.      * Returns the data model based on the primary key given in the GET variable.
    278.      * If the data model is not found, an HTTP exception will be raised.
    279.      */
    280.     public function loadModel()
    281.     {
    282.         if($this->_model===null)
    283.         {
    284.             if(isset($_GET['id']))
    285.                 $this->_model=Transactions::model()->findbyPk($_GET['id']);
    286.             if($this->_model===null)
    287.                 throw new CHttpException(404,'The requested page does not exist.');
    288.         }
    289.         return $this->_model;
    290.     }
    291.  
    292.     /**
    293.      * Performs the AJAX validation.
    294.      * @param CModel the model to be validated
    295.      */
    296.     protected function performAjaxValidation($model)
    297.     {
    298.         if(isset($_POST['ajax']) && $_POST['ajax']==='transactions-form')
    299.         {
    300.             echo CActiveForm::validate($model);
    301.             Yii::app()->end();
    302.         }
    303.     }
    304. }
    305.  
     
  8. MiksIr

    MiksIr Активный пользователь

    С нами с:
    29 ноя 2006
    Сообщения:
    2.333
    Симпатии:
    44
    А, значит неверно понял. Я думал он уже подошел к стадии CMF и по модели генерит заготовки для админки - типа список - редактирование и т.д. В банальных сайтах это в общем рутинная и нудная задача =(
     
  9. MiksIr

    MiksIr Активный пользователь

    С нами с:
    29 ноя 2006
    Сообщения:
    2.333
    Симпатии:
    44
    А использование модели?
    Ну т.е. пример из контроллера для получения списка по заданным критериям
     
  10. Psih

    Psih Активный пользователь
    Команда форума Модератор

    С нами с:
    28 дек 2006
    Сообщения:
    2.674
    Симпатии:
    6
    Адрес:
    Рига, Латвия
    В этом плане кодогенератор у них сделан так, что в него проще парёной репы создать свои шаблоны и генерировать уже всё с них, избегая долгой и нудной рутины. Написал один раз и только пользуйся. Я до этого ещё не добрался, так что на вашей совести :)
    Вообще CRUD он генерирует на ура: список, администрирование (админский грид), добавление, удаление, редактирование - всё генерируется. Шаблоны только подправил под себя и готово (или сделал свои шаблоны).
     
  11. Psih

    Psih Активный пользователь
    Команда форума Модератор

    С нами с:
    28 дек 2006
    Сообщения:
    2.674
    Симпатии:
    6
    Адрес:
    Рига, Латвия
    Добавил контроллер к модели
     
  12. Psih

    Psih Активный пользователь
    Команда форума Модератор

    С нами с:
    28 дек 2006
    Сообщения:
    2.674
    Симпатии:
    6
    Адрес:
    Рига, Латвия
    А вот навёрнутый view для главного грида:
    PHP:
    1. <?php
    2. $this->breadcrumbs=array(
    3.     'Transactions',
    4. );
    5.  
    6. $this->menu=array(
    7.     array('label'=>'Create Transactions', 'url'=>array('create')),
    8.     array('label'=>'Manage Transactions', 'url'=>array('admin')),
    9. );
    10. $data = Transactions::model();
    11. ?>
    12. <?php echo CHtml::link('View reports for today', '/transactions/reports')?> | <?php echo CHtml::link('View reports', '/transactions/reportsInterval')?>
    13. <br /><br />
    14. <h1>Transactions</h1>
    15. <?php $this->widget('zii.widgets.grid.CGridView', array(
    16.     'id'=>'transactions-grid',
    17.     'dataProvider'=>$model->search(),
    18.     'filter'=>$model,
    19.     'rowCssClassExpression' => '"rows ".$data->trn_status',
    20.     'selectableRows' => 1,
    21.     'selectionChanged' => 'transactionGridView',
    22.     'pager' => array(
    23.         'pageSize' => 50
    24.     ),
    25.     'columns'=>array(
    26.         array(
    27.             'name' => 'trn_id',
    28.             'htmlOptions' => array('width' => '40'),
    29.         ),
    30.         array(
    31.             'name' => 'trn_system',
    32.             'filter' => array('ukash' => 'ukash', 'psc' => 'psc', 'cashu' => 'cashu', 'skype' => 'skype'),
    33.         ),
    34.         array(
    35.             'name' => 'trn_system_status',
    36.             'type' => 'html',
    37.             'filter' => array(
    38.                 'new' => 'new',
    39.                 'good' => 'good',
    40.                 'bad' => 'bad',
    41.             ),
    42.             'value' => '"<span class=\"".$data->trn_system_status."\">".$data->trn_system_status."</span>"',
    43.         ),
    44.         array(
    45.             'name' => 'trn_operator_status',
    46.             'type' => 'html',
    47.             'filter' => array(
    48.                 'new' => 'new',
    49.                 'good' => 'good',
    50.                 'bad' => 'bad',
    51.             ),
    52.             'value' => '"<span class=\"".$data->trn_operator_status."\">".$data->trn_operator_status."</span>"',
    53.         ),
    54.         array(
    55.             'name' => 'trn_total',
    56.             'type' => 'html',
    57.             'value' => '$data->trn_system == "skype" ? $data->trn_total." ".$data->skype->sky_currency : $data->trn_total." / <strong>".$data->trn_total_real."</strong>"'
    58.         ),
    59.         array(
    60.             'name' => 'trn_status',
    61.             'value' => '$data->trn_status.($data->trn_error_code != "" ? " (".$data->trn_error_code.")" : "")',
    62.         ),
    63.         'trn_email',
    64.         'trn_started_on',
    65.         'trn_finished_on',
    66.         array(
    67.             'name' => 'trn_paysystem',
    68.             'type'=>'html',
    69.             'value' => '($data->trn_status == "success") ? "<strong>".number_format($data->trn_total_real * $data->trn_rate, 2, ".", "")." ".$data->trn_paysystem."</strong>" : "<strong>".$data->trn_paysystem."</strong>"',
    70.             'filter' => array(
    71.                 'WMZ' => 'WMZ',
    72.                 'WME' => 'WME',
    73.                 'STR' => 'STR',
    74.                 'PMU' => 'PMU',
    75.                 'LRU' => 'LRU',
    76.                 'LIQ' => 'LIQ',
    77.                 'GDP' => 'GDP',
    78.                 'ECU' => 'ECU',
    79.                 'PEC' => 'PEC',
    80.                 'LRE' => 'LRE'
    81.  
    82.             )
    83.         ),
    84.         'trn_purse',
    85.         array(
    86.             'name' => 'trn_rate',
    87.             'htmlOptions' => array('width' => '40'),
    88.         ),
    89.         'trn_ip',
    90.         array(
    91.             'name' => 'account.uac_login',
    92.             'filter' => '<input type="text" value="'.$model->account->uac_login.'" name="Transactions[account][uac_login]" />',
    93.         ),
    94.         array(
    95.             'name' => 'countVouchers',
    96.             'filter' => '<input type="text" value="'.($model->countVouchers == '0' ? '' : $model->countVouchers).'" name="Transactions[trnvouchers][tvc_code]" />',
    97.             'htmlOptions' => array('width' => '150'),
    98.         ),
    99.         array(
    100.             'class'=>'CButtonColumn',
    101.             'template' => '{setstatus}',
    102.             'buttons' => array(
    103.                 'setstatus' => array(
    104.                     'label' => 'Operator status',
    105.                     'url' => 'Yii::app()->createUrl("/transactions/opstatus", array("id" => $data->trn_id))',
    106.                     'click' => 'opstatus',
    107.                 ),
    108.             )
    109.         ),
    110.     ),
    111. ));?>
    112. <script type="text/javascript">
    113. function transactionGridView(id) {
    114.     $data = $.fn.yiiGridView.getSelection(id);
    115.     if ($data.length == 1) {
    116.         openWindow('/transactions/view/'+$data[0], 600, 700, 'trn'+$data[0], 'yes');
    117.     }
    118.     return false;
    119. }
    120.  
    121. function opstatus(id) {
    122.     var url = $(this).attr('href');
    123.     return openWindow(url, 600, 700, 'opstatus', 'yes');
    124. }
    125.  
    126. /**
    127.  * Open pop-up window
    128.  *
    129.  */
    130. function openWindow(url, width, height, name, scrollbars)
    131. {
    132.     if (typeof scrollbars == 'undefined') {
    133.         scrollbars = 'no';
    134.     }
    135.     var top = Math.ceil((screen.height - height)/2);
    136.     var left = Math.ceil((screen.width - width)/2);
    137.  
    138.     if (typeof name == undefined || name == null){
    139.         name = Math.round(999999 * Math.random());
    140.     }
    141.     var win = window.open(url,name ,'width='+width+',height='+height+',location=no,status=no,toolbar=no,menubar=no,resizable=no,scrollbars='+scrollbars+',top='+top+',left='+left);
    142.     win.focus();
    143.     return false;
    144. }
    145. </script>
    146.  
    Как я уже писал, замыкания тут прямо таки плачутся что бы их вставили. В ближайшее время шаблон соответственно преобразится :)
     
  13. MiksIr

    MiksIr Активный пользователь

    С нами с:
    29 ноя 2006
    Сообщения:
    2.333
    Симпатии:
    44
    Ух как все сложно то ;) Старею ;)
     
  14. Psih

    Psih Активный пользователь
    Команда форума Модератор

    С нами с:
    28 дек 2006
    Сообщения:
    2.674
    Симпатии:
    6
    Адрес:
    Рига, Латвия
    Что радует ещё, так это то, что если Active Record не справляется - не нужно опускаться до голого SQL. Есть так называемое DAO, на базе которого работает ActiveRecord. По сути это query builder, и сволочь удобный. Вот пример использования на примере валидатора модели:
    PHP:
    1. <?php
    2. class From extends CFormModel {
    3.  
    4.     public function checkSystem()
    5.     {
    6.         $sql = 'SELECT exr_rate, exr_code
    7.                 FROM exchange_rates
    8.                 WHERE exr_status = :status AND exr_id = :id
    9.                     AND FIND_IN_SET(:site, exr_site) AND exr_system = :system';
    10.         $params = array(
    11.             ':id' => $this->system,
    12.             ':system' => 'skype',
    13.             ':site' => $this->getDomain(),
    14.             ':status' => 'enabled',
    15.         );
    16.         $this->rate_data = Yii::app()->getDb()->createCommand($sql)->queryRow(true, $params);
    17.         if ($this->rate_data === false) {
    18.             $this->addError('system', Yii::t('app', 'Invalid payment method selected!'));
    19.         }
    20.     }
    21. }
    На самом деле это можно было сделать и через ActiveRecord (даже FIND_IN_SET через CDbExpression подставился бы легко), но мне было лень на клиентском проекте добавлять целую модель ради простой валидации в одном месте :)

    А что там сложного то? На самом деле тут какраз всё до опупения просто, нужно всего-лишь ознакомится с азами Yii и посмотреть API по CGridView, моделям, контроллерам и views. Большая часть из этого есть в Yii Cookbook.
     
  15. Костян

    Костян Активный пользователь

    С нами с:
    12 ноя 2009
    Сообщения:
    1.722
    Симпатии:
    1
    Адрес:
    адуктО
    что то не видно тут билдера, но я думаю так писать удобно (билдеры считаю удобными только для базового ActiveRecord-а), сам почти так пишу, только плейсхолдеры типизирую.
    PHP:
    1. <?php
    2.  $sql = 'SELECT exr_rate, exr_code
    3.                  FROM exchange_rates
    4.                  WHERE exr_status = ? AND exr_id = ?i
    5.                      AND FIND_IN_SET(?, exr_site) AND exr_system = ?'
     
  16. Psih

    Psih Активный пользователь
    Команда форума Модератор

    С нами с:
    28 дек 2006
    Сообщения:
    2.674
    Симпатии:
    6
    Адрес:
    Рига, Латвия
    Костян
    Ну я не стал извращаться с моделью, CDbCriteria (WHERE, JOIN's, ORDER BY, etc...) и CDbExpression. У меня пока небыло возможности хорошенько расковырять и сделать всё совсем правильно. Сроки поджимали. Щас будет чуть полегче, я многое переделаю the Yii way и тогда покажу. Считайте это быдлокодом для Yii, ибо по сути так оно и есть :)
     
  17. MiksIr

    MiksIr Активный пользователь

    С нами с:
    29 ноя 2006
    Сообщения:
    2.333
    Симпатии:
    44
    Да как-то прсто привык немного к другим вывертам. Типа
    PHP:
    1. <?php
    2. class UserCarVinsController extends acController
    3. {
    4.   protected     $actions = array("display"=>array(),
    5.                                  "results"=>array('params' => array(0 => 'vin') ) );
    6.  
    7.  
    8.   public function display()
    9.   {
    10.   }
    11.  
    12.   public function results()
    13.   {
    14.     $vin = trim($this->request->get('vin'));
    15.  
    16.     if (!$this->request->hasPost() || !$vin)
    17.     {
    18.       $this->redirect(array('action'=>'display'));
    19.       return;
    20.     }
    21.  
    22.     $car_vin = $this->dm->findFirst('CarVin', array('vin'=>$vin));
    23.     $res = !$car_vin->isNew();
    24.  
    25.     $this->passToView('result', $res);
    26.   }
    27. }
    28.  
     
  18. Psih

    Psih Активный пользователь
    Команда форума Модератор

    С нами с:
    28 дек 2006
    Сообщения:
    2.674
    Симпатии:
    6
    Адрес:
    Рига, Латвия
  19. MiksIr

    MiksIr Активный пользователь

    С нами с:
    29 ноя 2006
    Сообщения:
    2.333
    Симпатии:
    44
    Да.. может даже слишком круто ;)
     
  20. MiksIr

    MiksIr Активный пользователь

    С нами с:
    29 ноя 2006
    Сообщения:
    2.333
    Симпатии:
    44
    Вот есть у меня модель с кучей полей значения которые - списки. Причем, довольно статичные и пихать их в базу не хочется в том числе и из соображений производительности. Уносить во вью тоже не хочется - в нескольких местах используется.

    Хотелось бы определить модель, где будет массивом прописаны данные списка и слинковать ее с основной. Но я так понимаю, что не получится это ибо в relations указываем на эктив-рекорд модели только? CFormModel туда не подсунуть? Мож встречал реализации онного? Или эктив-рекорд использовать, только переопределить find на свой... в общем, примерчик бы ;)
     
  21. MiksIr

    MiksIr Активный пользователь

    С нами с:
    29 ноя 2006
    Сообщения:
    2.333
    Симпатии:
    44
    Или просто создать эти списки в виде статических arrayaccess классов, положить в extensions и вызывать их. Во view все же не дело все это помещать, ибо хочется еще и в валидаторе проверить...
     
  22. Psih

    Psih Активный пользователь
    Команда форума Модератор

    С нами с:
    28 дек 2006
    Сообщения:
    2.674
    Симпатии:
    6
    Адрес:
    Рига, Латвия
    MiksIr
    Возьми CModel за основу и реализуй хоть CActiveRecord аналог, который не будет данные тягать из базы :) Ну а дальше можно и relations задать. Разве что это немного через чур если данных таких не много.

    Или сделать extension/component класс и просто использовать их в модели как статичные или записывать в properties нужной модели.
     
  23. MiksIr

    MiksIr Активный пользователь

    С нами с:
    29 ноя 2006
    Сообщения:
    2.333
    Симпатии:
    44
    Да вот я тоже думаю, что самому сейчас аналог CActiveRecord делать - это излишне будет. Т.е. в качестве развлекаловки то может пойти, но у меня тут живой проект, на котором решил попробовать Yii ;) Другое дело, если где-то готовые решения проскакивали - по-этому и спросил. Пока пробую просто вспомогательные классы implements ArrayAccess.
     
  24. Psih

    Psih Активный пользователь
    Команда форума Модератор

    С нами с:
    28 дек 2006
    Сообщения:
    2.674
    Симпатии:
    6
    Адрес:
    Рига, Латвия
    MiksIr
    Заодно просмотри базовые классы Yii - там есть много полезных заготовок. API reference yii.base раздел.
     
  25. MiksIr

    MiksIr Активный пользователь

    С нами с:
    29 ноя 2006
    Сообщения:
    2.333
    Симпатии:
    44
    Немного не IDE-friendly он... вот что. Куча всего не описано, что могло бы, плюс куча пересечений классов - пришлось разбираться что исключать из анализа IDE =(