I'm using cakephp 2.1 and let me tell you: I just love it.
In my form I have a field that can have multiple answers (checkboxes).
I don't want to create a database field for each option, nor use an HABTM.
Update:
Since I needed several sets of flags, I went the $hasAndBelongsToMany way. (allos to add new flags without fixing the code but editing a table (eg. via phpmyadmin).
1.- Made a table/model for each set of flags I need:
2.- In my main model, declared the relation to each:
var $hasAndBelongsToMany = array('Sample','Format','Report','Openend','Dataproce','Prefield');
3.- In my main Controller, populated an array per table to use:
$openends = $this->Project->Openend->find('list', array(
//'order' => 'name'
));
4.- And use the arrays in the view:
echo $this->Form->input('Dataproce', array('label' => false, 'type' => 'select', 'multiple' => 'checkbox', 'size' => 2));
=== Old question starts here; correct answer worked for only one set of flags ===
I'd like to save a string and use it to to magically create a group of checkboxes that belong to a single data field.
I'm in the middle of it already.
my view:
echo $this->Form->input('pr_reports', array('type' => 'select',
'multiple' => 'checkbox',
'options' => array('0' => 'Interrnal',
'1' => 'Disposition',
'2' => 'Web Disposition',
'3' => 'Marginal',
'4' => 'Custom')))
my controller add method, before saving
// Used serialize() to convert the array to string
$dataString = serialize($this->request->data['Project']['pr_reports']);
$this->request->data['Project']['pr_reports'] = $dataString;
The string is being saved allright (encoded it seems but is ok: a:5:{i:0;s)
My question is how would I go when editing the record in order for the checkboxes to check themselves accordingly? That is, where do I unserialize() the string field and handle this on the edit view?
Is there a better way for this?
Thank you very much for any help.
Carlos García
==== After solution, troubles to have more than one field with a different set of flags
data is only saved for one field, ignoring the other ====
Hello;
For one field on the table it works just fine as noted;
I'm having a hard time using another field (separate set of flags).
It seems only one behaviour is attached; I was wondering if I should attach them differently.
my fields:
pr_data_format` tinyint(3) unsigned NOT NULL,
pr_report_format` tinyint(3) unsigned NOT NULL,
my controller
$this->Project->Behaviors->attach('Bitmasked', array('mappedField'=>'pr_data_formats', 'bits'=>'Project::pr_data_formats'));
$this->Project->Behaviors->attach('Bitmasked', array('mappedField'=>'pr_report_formats', 'bits'=>'Project::pr_report_formats'));
my model
const STATUS_ASCII = 1;
const STATUS_SPSS = 2;
const STATUS_EXCEL = 4;
const STATUS_CUSTOM = 8;
public static function pr_data_formats($value = null) {
$options = array(
self::STATUS_ASCII => __('ASCIId'),
self::STATUS_SPSS => __('SPSSBd'),
self::STATUS_EXCEL => __('Exceld'),
self::STATUS_CUSTOM => __('Customd'),
);
return parent::enum($value, $options);
}
const REP_ASCII = 1;
const REP_SPSS = 2;
const REP_EXCEL = 4;
const REP_CUSTOM = 8;
public static function pr_report_formats($value = null) {
$options = array(
self::REP_ASCII => __('ASCIIr'),
self::REP_SPSS => __('SPSSBr'),
self::REP_EXCEL => __('Excelr'),
self::REP_CUSTOM => __('Customr'),
);
return parent::enum($value, $options);
}
my view
echo $this->Form->input('pr_data_formats', array('options' => Project::pr_data_formats(), 'multiple' => 'checkbox'));
echo $this->Form->input('pr_report_formats', array('options' => Project::pr_report_formats(), 'multiple' => 'checkbox'));
Just can't figure it out, tried:
$this->Project->Behaviors->attach('Bitmasked', array('mappedField'=>'pr_report_formats', 'bits'=>'Project::pr_report_formats'), array('mappedField'=>'pr_data_formats', 'bits'=>'Project::pr_data_formats'));
but no use, only one field is updated.
Can you help? We'll use some 4 or 5 flagsets.
Thank you so much.
Carlos
a proper way to do this is using a behavior. this keeps your model clean and can be applied to several models simply by putting this in your model:
public $actsAs = array('MyBehavior');
now, for serializing I use my Jsonable Behavior:
http://www.dereuromark.de/2011/07/05/introducing-two-cakephp-behaviors/
it basically makes your input array a storable string on save and the string back to an array on read. you could easily adjust this to your needs.
BUT for what you want to do with multiple checkboxes there is even a better thing - bitmasks. I developed a so called Bitmasked behavior - you would need to use 1,2,4,8,... but other than that its the same thing:
http://www.dereuromark.de/2012/02/26/bitmasked-using-bitmasks-in-cakephp/
I use it exactly for the same thing.
Related
I m new in Laravel 8. Please give any suggestion for the given below code or answer my question:
Given below is my code an example of what i really want to get:
my data is :
[{"column_1_1":"value_1_1","column_1_2":"value_1_2"},{"column_2_1":"value_2_1","column_2_2":"value_2_2"}]
and I want
Array
(
[0] => stdClass Object
(
[column_1_1] => value_1_1
[column_1_2] => value_1_2
)
[1] => stdClass Object
(
[column_2_1] => value_2_1
[column_2_2] => value_2_2
)
)
I am adding this answer as the other is showing only one way and is the least used... Mine is the Laravel way, the one you should always use and the most you are going to see all the time...
If you have a Model who's property is, for example, data, you don't have to overwrite how it is read by doing getDataAttribute and use json_decode...
If that property/field is a JSON/TEXT in your database (hence storing JSON), you just have to cast it.
class YourModel extends Model
{
protected $casts = [
'data' => 'array'
];
}
So later you can do:
foreach ($model->data as $item) {
...
}
And store info in it like:
$array = ['products' => ['item1', 'item2'], 'quantity' => 2];
$model->data = $array;
And it will get saved on the database like {products: ["item1", "item2"], quantity: 2}
Bro you just need to add the accessor method in your model like:
Guess you have xyz column in your database
public function getXyzAttribute($xyz)
{
return json_decode($xyz);
}
It will directly return the array.
Hope it worked. :)
I'm trying to detect when the date has changed inside a regular "date" field
Have seen a few forum posts about how this can be done with text fields and dropdown, but it doesn't work for date fields.
Also tried:
'displayParams' =>
array (
'javascript' => 'onchange="checkStatusOption(this)"',
),
In the editviewdefs.php, but it didn't work (works for text fields though)
The closest I've got it actually just tracking every click on on the screen and then checking the before and after state of the date field, but it's obviously not a very elegant solution
Here's the code from the extended editview
function display() {
parent::display();
$js = <<<EOT
<script type="text/javascript" language="JavaScript">
// Capture initial state
calendar_before = document.getElementById("contract_date_c").value;
// Wait for any click to take place anywhere on the screen
$(document).click(function() {
// Capture state after we clicked somewhere
calendar_after = document.getElementById("contract_date_c").value;
// Compare the before and after
if(calendar_before != calendar_after) {
// Change detected
alert("Something's changed eh?" + calendar_before +" "+ calendar_after);
}
// Set the new state of the before_calendar
calendar_before = document.getElementById("contract_date_c").value;
});
}
</script>
EOT;
// now I output the javascript
echo $js;
}
UPDATE:
I also tried the suggested solution
1) Created a file custom/modules/un_inventory/contract_date_c_change.js and put the following inside:
function yourCustomFunction(formElement){
console.log(formElement);
}
2) Included a reference to that file in the metadata file (made sure it loads it):
array (
'file' => 'custom/modules/un_inventory/contract_date_c_change.js',
),
3) Attached the updateCallback to the field:
array (
'name' => 'contract_date_c',
'label' => 'LBL_CONTRACT_DATE',
// Checks if this field got filled up and shows hidden form field
'displayParams' =>
array (
'updateCallback' => 'yourCustomFunction();',
),
),
But nothing happens when I change that date field
Check this out (just tested in SuiteCRM 7.11) for a datetime field, for other fields take a look at this answer to another SO question
First, include your custom JS in the editviewdefs.php (example for Accounts module)
'includes' =>
array (
0 =>
array (
'file' => 'modules/Accounts/Account.js',
'file' => 'custom/modules/Accounts/myCustomFile.js',
),
),
Create the custom JS file custom/modules/Accounts/myCustomFile.js .
function yourCustomFunction(formElement){
console.log(formElement);
}
Then update the field you want to monitor for changes (contractsigned_c in the example) using the following code in the editviewdefs.php:
array (
'name' => 'contractsigned_c',
'label' => 'LBL_CONTRACTSIGNED',
'displayParams' =>
array (
'updateCallback' => 'yourCustomFunction(this)',
),
),
Now do a Repair and Rebuild inside the Admin/Repair section and voilà it should work :)
You can add the JS function on the function display() if you want, its the samething, the function will be called right after native combo update. It will look like this combo_contractsigned_c.update(); yourCustomFunction(this)
use this . it is working
YAHOO.util.Event.addListener('your_field_name', 'change', function(){
// your code here
});
How can I display Organisation value in view, I tried this , but it does not work
Code in Model :
function getOrganisationName($organisation_id){
return $orgaName = $this->find('list',array('conditions' => array('Organisation.id' => $organisation_id), //array of conditions
'fields' => array('Organisation.name')));
}
Code in Controller :
$orgName = $this->Organisation->getOrganisationName($organisation_id);
$this->set(compact('indicators', 'organisations', 'rejections', 'projects', 'organisation_id','orgName'));
code in view :
echo $orgName['organisation']['name'];
Firstly, Code in your view should be
echo $orgName['Organisation']['name'];
Also you can use cakephp findById($id) or find(‘first’) to retrieve your data.
I simply need to get the selected value from a query string. Currently I just get the index of the list and not the actual value. I cant use Post as I need the value for a pagination search.
I dont get an error but just the number of the index of the list returned. The answer must be simple and I have tried many combinations. I have tried ['Student'] in front of the query as well.
I just couldnt see the answer in the docs and previous posts on this topic didnt work for me either. I am stuck.
The query string has a number {url}students/myindex5?address_suburb=1 //suburb should be a string and it appears as a string in the drop down list
public function myindex5() {
$this->set('filterSuburb', $this->Student->find('list', array(
'fields' => array('Student.address_suburb')
)));
$havefilter = false;
$tsub = $this->request->query['address_suburb'];
// $tsub = array_combine($tsub, $tsub);//didnt work
debug($tsub); //I just get the index value of the list
if (!empty($tsub)) {
// ...
View
echo $this->Form->create('Student', array(
'type' => 'get',
'url' => array('controller' => 'students', 'action' => 'myindex5')
));
echo $this->Form->input('address_suburb', array(
'options' => $filterSuburb,
'empty' => '(choose one)')
);
echo $this->Form->end('Search');
For reference
how to get the selected values from a drop down list in cake php
http://book.cakephp.org/2.0/en/core-libraries/helpers/form.html
When you use a select input, the value send is the value of the option tag:
<select>
<option value="1">Option 1</option>
</select>
If I choose "Option 1", you will get 1, not "Option 1".
If you want to change the value attribute, you need to set something else to the FormHelper::input method options parameter, something like:
array(
'value1' => 'Text 1',
/** etc. **/
);
If you want your value to be ids of Student, just change your find call to:
$this->set('filterSuburb', $this->Student->find('list', array(
'fields' => array('Student.id', 'Student.address_suburb')
)));
If you look at find('list') documentation, you'll see this:
When calling find('list'), the fields passed are used to determine what should be used as the array key and value, and optionally what to group the results by.
So passing Student.id and Student.address_suburb will output a select with Student.id as option value and Student.address_suburb as option text.
If you want something else than Student.id, just change it in the find('list') call, you can even change it to have option like <option value="redcliff">redcliff</option> (same value and text), by doing:
$this->set('filterSuburb', $this->Student->find('list', array(
'fields' => array('Student.address_suburb', 'Student.address_suburb')
)));
Using the example in the Cookbook:
http://book.cakephp.org/2.0/en/core-libraries/behaviors/tree.html
If you debug() this you get a flat array() of category(id => name)
Which is fine for most purposes, but if you wanted to create navigation based on this and had a slug for the URL, rather than the id, you're out of luck.
I'm aware that I could use $this->Category->find('threaded') in the controller to get all fields but it lacks the convenience of the flat list because I have to create a recursive function to generate the links using the slug, exactly what I'd hoped to avoid.
So what's the best way to get the additional Category.slug field I need in the view?
CakePHP's generateTreeList() method allows you to choose the keys and values that are returned. If, for example, you wished to return a list that had the slug as the key and the link text as the value, you could use the $keyPath and $valuePath parameters to make it so:
$data = $this->Category->generateTreeList(null, "{n}.Category.slug", "{n}.Category.text", '_');
debug($data); die;
might produce:
array(
["my-categories"] => "My Categories",
["fun"] => "_Fun",
["sport"] => "__Sport",
["surfing"] => "___Surfing",
["skating"] => "___Skating",
["friends"] => "__Friends",
["gerald"] => "___Gerald",
["gwendolyn"] => "___Gwendolyn",
["work"] => "_Work",
["trips"] => "__Trips",
["national"] => "___National",
["international"] => "___International",
["other-peoples-categories"] => "Other People's Categories",
["extreme-fishing"] => "_Extreme fishing"
)