Um Checkboxlist Com Atributos Da Activerecord É Possível?

Em minha CustomerExtended - é uma Customer Active Record extended - tenho um atributo public chamado $notifications, que é setado no método afterConstruct:




    class CustomerExtended extends Customer

    {

        public $notifications;


        public function afterConstruct()

        {

            parent::afterConstruct();


            $this->notifications = Array(

                'customer_notify_new_sms',

                'customer_notify_new_pokes',

                'customer_notify_news_by_email',

                'customer_notify_favorite_logged',

                'customer_notify_finantial_response'

            );

        }

    }

E Customer possui os seguintes atributos - são atributos concretos do banco de dados:




    $customer = new Customer();

    $customer->customer_notify_new_sms; // default is 1 on database

    $customer->customer_notify_new_pokes; // default is 1 on database

    $customer->customer_notify_news_by_email; // default is 1 on database

    $customer->customer_notify_favorite_logged; // default is 1 on database

    $customer->customer_notify_finantial_response; // default is 0 on database

Certo, eu preciso que o atributo $notification de CustomerExtended seja um array representando os atributos concretos - dos atributos correspondentes em Customer - para criar um checkboxlist.

Estou tentando encontrar uma solução, mas… Eu tentei isso:




    $model = new CustomerExtended();

    $form = new CActiveForm();


    echo $form->checkBoxList($model, 'notifications',

        Array(

            'customer_notify_new_sms' => 'News by SMS',

            'customer_notify_new_pokes' => 'Notify Pokes',

            'customer_notify_news_by_email' => 'Notify by e-mail',

            'customer_notify_favorite_logged' => 'Notify when favorite is logged',

            'customer_notify_finantial_response' => 'Notify finantial reports'

            )

        );

Mas o resultado é errado, porque o atributo customer_notify_finantial_response é 0 no banco de dados e no checkboxlist esta vindo como checked por padrão.

Existe uma forma de fazer isso e fazer melhor?

Sou novo aqui e não posso postar imagens externas para exemplificar.

Olá, Maykonn!

Tire-me uma dúvida: não entendi o porquê de replicar os atributos do modelo Customer em um atributo (array) do modelo (filho) CustomerExtended, se não tiver problema, explique isso.

Tem algum problema usar o checkBox? Veja se isso resolve:




<?php foreach ($model->notifications as $notification){

        echo $form->checkBox($model,$notification);

        echo $form->labelEx($model,$notification);

        echo $form->error($model,$notification);

      }

?>



Flw!

Olá,

Vou explicar o motivo.

Precisei escrever uma API para trabalhar melhor com formulários. Pois realmente é péssimo tentar manter um código limpo, passível de teste e manutenção utilizando os formulários gerados pelo Gii.

Essa abstração me permite gerar formulários em que cada uma das entradas deles sejam atributos - ou não - de uma ou várias Active Record.

A API permite isso - o porque de precisar de UserExtended e CustomerExtended é outro assunto, porém muito interessante que esta tomando forma nesse link:




public function actionCreate() {

    $user = new UserExtended();

    $customer = new CustomerExtended();


    $form = new CustomerForm(Array($user, $customer));

    $this->render('create', Array('form' => $form));

}



CustomerForm é uma AbstractForm - que faz parte da API. E fica dentro de uma pasta /forms por exemplo.

E então na view temos apenas isso:




<?php

    // ... Código HTML acima daqui ...

    $form->initWidget();

    $form->displayErrorSummary();

    $form->displayElements();

    $form->endWidget();

    // ... Código HTML abaixo daqui ...

?>



Então, chegando ao ponto do checkbox, precisava gerar um checkboxlis de uma forma fácil, e consegui fazendo isso:




CustomerForm extends AbstractForm {

    // overridden

    public function options()

    {

         $this->customerNotifications();

    }


    private function customerNotifications()

    {

        $checkboxlist = $this->getCustomerNotificationsAsCheckboxList();


        $this->options->notifications = Array(

            'type' => HtmlElement::CHECKBOX_LIST,

            'items' => $checkboxlist['items'],

            'checkedItems' => $checkboxlist['checkedItems'],

            'checkAll' => Yii::t('main', 'Check All'),

            'checkAllLast' => false

        );

    }


    private function getCustomerNotificationsAsCheckboxList()

    {

        $items = Array();

        $checkedItems = Array();

        $notifications = $this->customer->getAllowedNotifications();


        foreach($notifications as $notificationId) {

            $attrLabel = $this->customer->getAttributeLabel($notificationId);

            $items[] = Array('id' => $notificationId, 'name' => $attrLabel);


            $checked = (bool) $this->customer->$notificationId;

            if($checked) {

                $checkedItems[] = Array('id' => $notificationId, 'name' => $attrLabel);

            }

        }

        

        return Array('items' => $items, 'checkedItems' => $checkedItems);

    }

}



Tudo o que for configurado em options() será gerado no formulário - o trabalho pesado fica para o código que criei para abstrair formulários, e você apenas precisa acessar a API desse código para gerar seus forms de forma fácil, sem saber sobre a geração de formulário.

No trecho $this->customer->getAllowedNotifications() é onde obtenho um array das notificações que são atributos de CustomerExtended.

Em fim, resolvi o problema de gerar o checkboxlist corretamente no método getCustomerNotificationsAsCheckboxList(), mais precisamente no trabalho da variavel $checkedItems.

Ainda tenho um pouco de trabalho pela frente =)