Handling Checkboxes in Yii with non-Boolean Values

July 25, 2010 — 7 Comments
The Yii Book If you like my writing on the Yii framework, you'll love "The Yii Book"!

On a recent Yii-based project, managing one of the Models required a whole slew of checkboxes to indicate that yes, the quality does apply, or no, it does not. In this case, the value being stored in the database for each attribute was a single letter: Y/N. However Yii, when showing the form to update an item, needs the checkbox value to be a Boolean, in order to properly pre-check the box. Changing the database wasn’t an option in this case, so I had to figure out a good conversion process. In this post, I’ll tell you exactly how I solved this issue.As I said, for the item in question, the database table had multiple columns, each of which only stored either Y or N. As an example, think of a users table with multiple opt-in options: newsletters, offers, etc. When the user creates and updates their account, presenting these as checkboxes is appropriate. But for the administrator, it’d probably be best to view user preferences by just seeing Y/N for each option (although the code I’m going to present wouldn’t be significantly different if you stored 1/0).

The protected/views/modelName/_form.php file defines the form that’s used to both create and update an individual record. In it, checkboxes are created using:

<?php echo $form->checkBox($model,'attribute'); ?>

I can pass an array of options to the checkbox() method in order to tweak how it behaves. In my example, I want to set the values assigned to the Model in both the checked and unchecked states. Here’s how you do that:

<?php echo $form->checkBox($model,'attribute',array('value' => 'Y', 'uncheckValue'=>'N')); ?>

The value option literally creates the value=”Y” code in the checkbox HTML. The uncheckValue option is something that Yii adds that allows you to indicate what the value should be if the box is not checked. It’s a nice addition, saving you from having to add code in the Model to define the value when the box isn’t checked.

So now my Model will receive, and the database will store, either Y or N, depending upon whether the box is checked or not. The next hurdle comes for properly handling updates. An update uses this same form, but the above code alone will not automatically check the box should the database store the value Y for the given attribute. My solution, then, was to convert Y to true and N to false when retrieving the Model item, but only on an update. In the other situations where a Model record might be retrieved and used, the Y/N values are preferable.

In the Controller for this Model, the update action is where I want to start my changes. That method first loads an individual Model using the Controller’s loadModel() method:

public function actionUpdate() {
    $model=$this->loadModel();

After this point, I want to convert all instances of Y/N to true/false, so I invoke a Model method (I’ll define next) to perform that task:

$model->convertToBooleans();

The convertToBooleans() method is defined in the Model. It first defines an array of all attributes that need the conversion:

public function convertToBooleans() {
    $attributes = array('newsletter', 'offers', ...);

This list of strings must exactly match the names of the corresponding Model attributes. From here, there are a couple of ways to proceed. One obvious route is to loop through the array using a foreach. Within the foreach, the ternary operator is used to assign to the Model’s attribute a Boolean based upon its current value:

foreach ($attributes as $attr) {
    $this->$attr = ($this->$attr == 'Y') ? true : false;
}

So that’s all you need to do to make this work. But if you’re like me and you prefer to make your methods as atomic as possible, you could create a separate Model method that performs the specific conversion:

public function convertAttributeToBoolean($attr) {
    $this->$attr = ($this->$attr == 'Y') ? true : false;
}

In this case, the convertToBooleans() method needs to call this other method for each item in the array. The array_map() PHP function can apply a function to every element in an array:

array_map('someFunction', $someArray);

To use an object method, use this syntax:

array_map(array($object, 'methodName'), $someArray);

So the convertToBooleans() method could do this:

array_map(array($this, 'convertAttributeToBoolean'), $attributes);

And that’s what you need to do to make form checkboxes work with non-Boolean database values (MySQL does support storing of Booleans, though). Remember that you first need to update the _form.php script, which will be used for both adding and updating records. Then you only need to convert the Y/N values to Booleans when you go to update a record.

I hope this helps and thanks for reading. Let me know if you have any questions or comments. Thanks, Larry!

If you enjoyed this post, then please consider following me using your favorite social media, the RSS feed, and/or by subscribing to my newsletter. Or go crazy, and buy one or more of my books . Thanks!

7 responses to Handling Checkboxes in Yii with non-Boolean Values

  1. I have values 1/0 in the database for a few columns. I used

    $form->checkBox($model,’attribute’,array(‘value’ => ‘1’, ‘uncheckValue’=>’0′)); ?>

    With the above code, I am able to show the checks/unchecks properly while loading the update form, but when I try to save the changes, I cannot save the values. I dont get any errors either.

    Could you provide some lead into it?

    • Sorry for the delayed reply (the comment slipped through the cracks). If you’re still having problems with this, have you confirmed what values are being received when the form is submitted? Also, is the model being saved but the new values aren’t or is the model not being saved at all?

  2. Infact, I am not able to save some of the text fields as well.

    I have a date field on the form, which is stored as unix timestamp in the database. So I use CJuiDatePicker to show the date and use a “beforeSave” function to convert the date to unix timestamp. And this field gets saved when i change it from the datepicker. This is something strange. Any clues?

  3. Solved:

    I had generated the the controller and view using the CRUD command line. but when I used the ‘crud generator’ from Gii, things worked.
    There was probably something wrong with code generated from the command line.

  4. well, i think I had the same kind of problems. and I fix it. The problem is the validation rules returned from ActiveRecord. you have to add a valid validation rule for that attribute. refer to http://www.yiiframework.com/doc/guide/1.1/en/form.model#declaring-validation-rules here. When you use CRUD, it will generate the rules for u. So it is only applied when you update db schema

Trackbacks and Pingbacks:

  1. Creating Forms with the Yii Framework – Larry Ullman - January 20, 2011

    [...] Handling Checkboxes in Yii with non-Boolean Values [...]

Comments are great, but I'd strongly prefer any requests for assistance get made in the support forums. Thanks!