Yii activeCheckBoxList - php

I have a strange probem
In AR model, Gift i have many_many relation with categories
'categories'=>array(self::MANY_MANY, 'GiftCategory',
'tbl_category_gift(gift_id, category_id)'),
And when i call $gift->categories it returns active record objects, and in database i see that values is stored correctly
But when i write
<? echo $form->checkBoxList($model, "categories", GiftCategory::listData()); ?>
In my checkboxlist only 1 value is selected if model have categories, i dont understand wtf is it, please, help :)
PROBLEM: Yii activeCheckBoxList displaying only 1 checked (only first)

It doesn't work because, in the words of the Yii creator Qiang:
...in activeListBox(), the second parameter should be an attribute
name, not a relation name. In your case, you may need to declare a new
property to store the selections.
I believe the same thing applies to activeCheckBoxList.
The way I solved this was as follows (this blog post was helpful Retrieving selected checkbox items in yii)
Add index option to your relation
'categories' => array(self::MANY_MANY,
'Category', 'post_category(post_id, category_id)','index'=>'id'),
Add a property to your model
public $selectedCategoryIds
Populate this attribute in afterFind
public function afterFind()
{
parent::afterFind();
$this->selectedCategoryIds = array_keys($this->categories);
}
Use this new "attribute in your view
<? echo $form->checkBoxList($model, "selectedCategoryIds", GiftCategory::listData()); ?>
In order to properly handle updating this data see Larry Ullman's article Handling Related Models in Yii Forms

<?php
echo CHtml::activeCheckBoxList($model, 'categories',
CHtml::listData(GiftCategory::model()->findAll(), 'id', 'title'),
array('checkAll' => ' Select All'));
?>

Related

Kohana add function return province name

I'm back again for another question, i'm trying and trying. But i can't get it fixed.
This is my issue;
I have a database table, with a ProvinceID this can alter from 1 to 12. But it's an ID of the province. The provinces are stored with the value pName in the table Provinces
I have the following code to alter the table, and join it with the preferences table
$veiling = ORM::factory('veilingen')
->select('veilingvoorkeur.*')
->join('veilingvoorkeur', 'LEFT')
->on('veilingen.id', '=', 'veilingvoorkeur.vId')
->find_all();
$this->template->content = View::factory('veiling/veilingen')
->bind('veiling', $veiling);
It displays correctly, in the view i have;
echo '<div class="row">';
foreach($veiling as $ve)
{
echo $ve->provincie;
}
?>
</div>
it displays the provincie id; but i want to add a function to it; So it will be transformed to a province name. Normally i would create a functions.php file with a function getProvince($provinceId)
Do a mysql query to grab the pName value from Provinces and that is the job. But i'm new to kohana. Is there an option to turn the province id to province['pName'] during the ORM selection part, or do i have to search for another solution. Which i can't find :(
So. Please help me on the road again.
Thanx in advance.
Kind regards,
Kevin
Edit: 1:08
I've tried something, and it worked. I used ORM in the view file, for adding a function;
function provincie($id){
$provincie = ORM::factory('provincies', $id);
return $provincie->pName;
}
But i'm not glad with this way of solution, is there any other way? Or am i have to use it this way?
Check out Kohana's ORM relationships. If you use this, you could access the province name by simply calling:
$ve->provincie->name;
The relationship definition could look something like:
protected $_belongs_to = array(
'provincie' => array(
'model' => 'Provincie',
'foreign_key' => 'provincie_id'
),
);
Note that if you have a table column called provincie the relationship definition I give above will not work. You'd either have to change the table column to provincie_id or rename the relationship to e.g. provincie_model.
The output you describe when you do echo $ve->provincie; suggests that you store the ID in a column called provincie, thus the above applies to you.
I'd personally go for the first option as I prefer accessing IDs directly with an _id suffix and models without any suffix. But that's up to you.
Edit: If you use Kohanas ORM relationships you could even load the province with the initial query using with() e.g:
ORM::factory('veiling')->with('provincie')->find_all();
This could save you hundreds of extra queries.

Creating dropdownlist with relations in yii

I am a newbie in Yii framework and now I try to create dropdownlist from related table.
I have table "News"[...a lot of fields,category] and "NewsCategories"[id,category_name].
In form for creating new record in News I want to create a dropdownlist in category field when user can choose a category_name, but id of category have to be recorder in a new record.
Help me please with it. Sorry for my English. I hope what I explain it understandable.
Here is how I created relations
Model News.php
public function relations()
{
// NOTE: you may need to adjust the relation name and the related
// class name for the relations automatically generated below.
return array(
'category'=>array(self::BELONGS_TO, 'NewsCategories', 'category'),
);
}
Model NewsCategories.php
public function relations()
{
// NOTE: you may need to adjust the relation name and the related
// class name for the relations automatically generated below.
return array(
'news'=>array(self::HAS_MANY, 'News', 'id'),
);
}
And how I try to create dropdownlist:
<?php echo $form->dropDownList($model,'category',CHtml::listdata(News::model()->with('category')->findAll(),'id','category_name'),array('empty'=>'(Select a category')));?>
When specifying relations, you don't need to specify primary key (id), because yii can deduct primary key from the model. You only need to specify the other end, so your NewsCategory relation should look like this:
'news'=>array(self::HAS_MANY, 'News', 'category'),
To get data suitable for drop-down list, use
CHtml::listData(NewsCategories::model()->findAll(), 'id', 'category_name');

hasOne relationship saving new record instead of using existing one

I have a Page model and a Category model. Basically, each page belongs to a category. The models are set up so Page belongsTo Category, and Category hasMany Page.
When adding new pages, I'm using this controller action:
public function admin_add() {
if($this->request->is('post')) {
$this->Page->create();
if($this->Page->saveAssocated($this->request->data)) {
$this->Session->setFlash('The page has been created.');
$this->redirect(array('action' => 'index'));
} else {
$this->Session->setFlash('Unable to save the page.');
}
}
}
and this is the view for that action:
<h1>Add Page</h1>
<?php
echo $this->Form->create('Page');
echo $this->Form->input('Page.title', array('required' => 'required'));
echo $this->Form->input('Page.body', array('type' => 'textarea', 'class' => 'redactor', 'required' => 'required'));
echo $this->Form->input('Category.name');
echo $this->Form->input('Page.in_header');
echo $this->Form->end('Save Page');
?>
Now, when I save a page with "Services" as the category, it all gets saved correctly. The page gets saved and the category with name of "Services" gets inserted and they both get linked up properly.
However, when I add another page with the same category of "Services", instead of using the existing record in the categories table Cake makes a new one and links that one instead. I need it to use the existing record.
How can I fix my view/controller/database to make this work properly?
Thanks!
You have several solutions to fix this.
The solution provided by pollirata is a very good one. Providing a select with existing categories is the simplest way for an user to know which categories already exist. Having a simple text input leads to spelling mistakes anyway or very similar categories names when you would only want one.
If you want to keep the text input, then you should check for existing categories in your Page.php model in the beforeSave() function: retrieve the categories list and match it against $this->data['Category']['name'] of the data you are trying to save. If an existing category matches, add its id in $this->data['Category']['id] so Cake does not create a new record.
When creating the records, there's no place where you specify the id of the existing Category. By that, Cake assumes that it is a new record, since there's no ID to use to search.
You need to provide that id of that category in order to help Cake understanding that the record already exists
Hope it helps

Which cakephp callback methods to choose?

I have table user which have fields username,password, and type. The type can be any or combination of these employee,vendor and client i.e a user can be vendor or client both or some another combination. For type field I have used the multiple checkbox, see the code below. This is the views/users/add.ctp file
Form->create('User');?>
Form->input('username');
echo $this->Form->input('password');
echo $this->Form->input('type', array('type' => 'select', 'multiple' => 'checkbox','options' => array(
'client' => 'Client',
'vendor' => 'Vendor',
'employee' => 'Employee'
)
));
?>
Form->end(__('Submit', true));?>
This is the code I have used in the model file. A callback method beforeSave
app/models/user.php
function beforeSave() {
if(!empty($this->data['User']['type'])) {
$this->data['User']['type'] = join(',', $this->data['User']['type']);
}
return true;
}
This code saves the multiple values as comma separated value in db.
The main problem comes when Im editing a user. If a user has selected multiple types during user creation I can't find the checkbox checked for that user types.
you should never be saving serialized data, json or csv in a field. This makes your life real hard later on down the line.
While habtm is one way to do things, if your binary maths is reasonable you might want to checkout bitmasks for this. here is a great post http://mark-story.com/posts/view/using-bitmasks-to-indicate-status
basics would be
1 = employee
2 = vendor
4 = client
// 8 = next_type
then, if the user was type employee & vendor the type would be 3 (1 + 2) and if it was a vendor & client the type would be 6 (2 + 4)
as you can see there is no way to mix it up, and bitwise works pretty good in mysql aswell so finds are pretty easy. See the post for much more detailed information
You should have a table types and a join table users_types.
What you're looking at is a HABTM relationship, so you should handle it like one.
In the joining UsersType model you should add a custom validation rule that checks if the current combination of types is allowed.
If you want to modify data after it's been found in the database, you can use the afterFind() callback in your model.
So in your case, put something like this is your user model:
function afterFind($results) {
$results['User']['type'] = explode(',', $results['User']['type']);
return $results;
}
There's more info on afterFind in the CakePHP manual.
That being said, it might be worth considering another approach, like a HABTM relationship as deceze first suggested above.

How to get related values in Yii?

Schema:
CITY
ID (int)
Name (string)
Status (int)
CITY_STATUS
ID (int)
Name (string)
When I display a city (in the View view), I want to display the related CITY_STATUS.Name value, instead of the CITY.Status value
When I add or update a city, I want to display a drop down of all CITY_STATUS.Names in the drop down
How do I do this in Yii?
Guess I'll answer it myself.
Question 1
Relations are easier if you setup a foreign key in your database first. To do this you need to use MySQL (not SQLite) with the InnoDB engine (not MyISAM), and the field in question needs an index on it. Then, Gii will setup the relations function for you automatically. Otherwise, you'll have to do it manually in the relations() function of the model in question.
To use a related value in a View:
In protected/views/[model name]/view.php, in the CDetailView attributes array, change
'Status'
to
array('label'=>'Status', 'value'=>$model->RelationName->Name)
where RelationName is the name of the relation
To use a related value in an Index view, change protected/views/[model name]/_view.php (note the underscore), for example in this case you would change
$data->Status
to
$data->RelationName->Name
To use a related value in an Admin view, in the CGridView widget call, in the columns array, replace say
'Status'
with
array('name'=>'Status', 'header'=>'Status', 'value'=>'$data->RelationName->Name')
(note the use of the variable $data, and not say $model or $dataProvider). Still trying to figure out how to sort and filter...
Question 2
To use a drop-down menu, in protected/views/[model name]/_form.php:
change
<?php echo $form->textField($model,'Status'); ?>
to
<?php echo $form->dropDownList($model,'Status', CHtml::listData(Status::model()->findAll(), 'ID', 'Name')); ?>
el chief, you are a gentleman and a scholar.

Categories