I have a form for creating a task, and when creating it, user is asked to select which employees will be assigned to it. There may be just one employee or even up to 10. I allow user to dynamically create those input fields on the go, but the array that i get after the form submition looks like this:
array(
'Event' => array(
'project_id' => '62',
'user_id' => '23',
'user_id2' => '24',
'user_id4' => '28',
'user_id8' => '30',
'hours' => '6',
'minutes' => '0',
'assignment' => '',
'material' => 'safsaf',
'date' => '2013-10-12',
)
)
The problem is I do not know how to iterate over the user_ids.
Is it possible to save the IDs as a list? Or is there any other solution?
Use CakePHP's find('list') to retrieve the $users in an key=>value array, then set the multiple attribute of the input to true:
echo $this->Form->select('Model.field', $users, array('multiple' => true));
$attributes['multiple'] If ‘multiple’ has been set to true for an
input that outputs a select, the select will allow multiple
selections:
Related
print array
array(
'Order' => array(
'id' => '1',
'base_price' => '65',
'min_price' => '95',
)
)
Is it possible to remove the key('Order') when you retrieving data? if Not how can I use array_shift or end in one line and to prevent below error?
I am getting this error Only variables should be passed by reference when I remove the key from array.
$orders = array_shift or end ($this->Order->read(null, $id));
debug($orders);
You want only id from it then following code will help you
$arrOrderId=Set::extract("/Order/id",$data);
here $data is your array from where you want to delete this "Order" key.
You will get following array when you do debug($arrOrderId);
[0]=>1
if you want base_price then write following code
$arrOrderId=Set::extract("/Order/base_price",$data);
You can use Set functions for manipulating arrays:
Set::extract($array, 'Order');
Will output:
array(
'id' => '1',
'base_price' => '65',
'min_price' => '95',
)
If you need to do this on every output, you can override afterFind() method on your model.
Please see the docs:
http://book.cakephp.org/2.0/en/core-utility-libraries/set.html#Set::extract
http://book.cakephp.org/2.0/en/core-utility-libraries/set.html#Set::classicExtract
I'm getting a little confused with what exactly cakePHPs Sanitize::clean() method should do. Currently when I'm adding a record I'm doing this:
$this->request->data = Sanitize::clean($this->request->data, array('encode' => true, 'remove_html' => true));
However, this still leaves & and \n in my database when they use & and press enter in a textarea. How can I stop this? I thought remove_html => true would have done this?
Do I need to go as far as doing a str_replace()
Also some of the records with the \n 's in them have hundreds of trailing backslashes meaning the break any views they are displayed on.
Could someone point me in the right direction? Thanks
Update as per Nunsers answer
I've now added the following after the clean:
foreach ($this->request->data['Expense'] as &$expense) {
$expense['detail'] = Sanitize::stripWhitespace($expense['detail']);
}
unset($expense);
However, it does remove whitespace but still leaves lots of \n\n\n\n\n\
Heres a debug of $this->request->data:
array(
'submit' => 'Save',
'Expense' => array(
(int) 0 => array(
'date' => array(
'day' => '27',
'month' => '06',
'year' => '2013'
),
'sitename' => 'test',
'detail' => 'test test\n\ntest\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n',
'ExpenseCode' => array(
'ExpenseCode' => '1'
),
'billable' => '1',
'amount' => '1',
'miles' => '',
'total' => '1',
'billable_mileage' => '',
'recorded_global_mileage_rate' => '0.4'
),
(int) 1 => array(
'date' => array(
'day' => '27',
'month' => '06',
'year' => '2013'
),
'sitename' => 'test',
'detail' => '\n\n\n\n\n\n\n\n\n\n\n\n\n\ntest',
'ExpenseCode' => array(
'ExpenseCode' => '4'
),
'billable' => '1',
'amount' => '10',
'miles' => '',
'total' => '10',
'billable_mileage' => '',
'recorded_global_mileage_rate' => '0.4'
)
),
'CashFloat' => array(
'amount' => ''
),
'ExpenseClaim' => array(
'user_id' => '3',
'claim_status_id' => '1'
)
)
I'd like to strip thouse \n's out really as I dont want them break views.
More results
Even when I cut out the cake function and use its code directly inline via :
$expense['detail'] = preg_replace('/\s{2,}/u', ' ', preg_replace('/[\n\r\t]+/', '', $expense['detail']));
I still get the same (debug($expense['detail']) from the loop:
'test 10 spaces before this then pressing enter lots \n\n\n\n\n\n\n\n\n\n\n\n\n\n\n'
I've also tried just a basic trim() which didnt work at all.
Working solution (apart from the &)
This will remove any number of
\n
from the string
foreach ($this->request->data['Expense'] as &$expense) {
$expense['detail'] = str_replace("\\n", ' ', $expense['detail']);
$expense['detail'] = Sanitize::stripWhitespace($expense['detail']);
}
// Unset referance var from above loop
unset($expense);
Decided to keep the &
And just use html_entity_decode() when echoing it out in a view
Hope that helps someone!
According to the docs, the clean method does not do what you want.
First, for the \n characters, you should call another Sanitize function. Sanitize::clean() has a carriage option, but that only removes the \r characters. So, after (or before) calling the clean method, call stripWhitespaces. Unfortunately, this functions only receives a string, so you need to call it in a loop (or if you know the string you want to sanitize, use it for just that).
$cleanOfSpacesString = Sanitize::stripWhitespace($dirtyString);
That function removes this characters: \r, \n and \t, and replace 2 or more spaces with just one.
And for &, the docs says that remove_html removes html tags and also does a htmlentities($string, ENT_QUOTES, $defaultCharset, true) to the string. So if that htmlentities is not working for you, you'll have to use another function not incuded in the Sanitize class.
If you think this behaviour is something you want to have inside the helper, extend the Sanitize helper to include stripWhiteSpaces inside the clean function and to also replace the htmlentities function with something that works for you. If it's just for this case, add those functions in the controller, after calling Sanitize::clean
Update as per Jason's update to my answer
I found it weird that the stripWhitespaces function didn't work as you wanted. And here is the explanation of why I think it didn't.
You want to remove \n from a string like this
'test test\n\ntest\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n'
and the preg_replace inside stripWhitespaces is this
preg_replace('/[\n\r\t]+/', '', $str)
That regex will remove newlines, returns and tabs, but on a string like this
'test test
test
' //and a lot more newlines
So the difference here is that you're passing the newlines (maybe the tabs and returns also, I don't know) as strings, real\+n, and so, the preg_replace cake does is not useful for you. I know you found a solution for that (I recommend you add the tab and return match also in there), but I wanted to clarify why cake's function didn't work in case someone else has a similar problem.
Inside an afterSave, what is the best way to get information about $this.
For example. If I debug($this->read()), I get everything I need to know about the current record I am working with (associated models, etc..).
array(
'Comment' => array(
'id' => '12',
'user_id' => '38'
'body' => 'test',
'created' => '2013-04-11 18:56:26',
'modified' => '2013-04-11 18:56:26'
),
'User' => array(
'password' => '*****',
'id' => '38',
'username' => 'example',
'created' => '2013-01-26 18:25:39',
'modified' => '2013-01-26 18:25:39',
'first_name' => '',
'last_name' => ''
)
)
But doesn't that mean I am querying the db again? Shouldn't $this already have all this information in it?
What is the proper way to get the results of $this->read(), or this is the correct way?
It is the proper way ($this->read), depending of what info you want about the record you just saved.
For example, if you're doing an insert, and your $data (used like Comment->save($data)) is:
array(
'Comment' => array(
'id' => '12',
'user_id' => '38'
'body' => 'test',
'created' => '2013-04-11 18:56:26',
'modified' => '2013-04-11 18:56:26'
),
'User' => array(
'password' => '*****',
'id' => '38',
'username' => 'example',
'created' => '2013-01-26 18:25:39',
'modified' => '2013-01-26 18:25:39',
'first_name' => '',
'last_name' => ''
)
)
and I mean exactly like that, then $this->data will still have that same info you just saved. $this->data is set to false only after afterSave.
However, if you do something like
$this->Comment->saveField('body', 'othertest');
the $this->data array in the afterSave will only contain something like
Array
(
[id] => 6
[body] => 'othertest'
[modified] => 2013-04-11 15:17:45
)
In other words, if you want to get all the information related to a model regardless of the data passed as parameter in save(), you'll have to do a $this->read() (or find()).
You should be able to access the data like so:
public function afterSave($var = null){
parent::afterSave($var);
echo '<pre>';
print_r($this->data);
echo '</pre>';
die();
}
Try that code and see look through the output. This will give you access to the data that was posted, which should match the record if the save was a success. Also what version of CakePHP are you using and what are you attempting to do?
Read is fine though.
I am creating a Wordpress theme that catalogs albums, and I have created the custom post type, created the custom fields, and have them successfully pulling in. I have several custom fields including; Artist, Album, Size, Label etc. I currently have the posts sorting alphabetically by the Artist name with this array:
$args=array(
'post_type' => 'albums',
'order' => 'ASC',
'meta_key' => 'custom_meta_artist',
'orderby' => 'meta_value',
'posts_per_page' => -1,
);
But I would also like the Albums, 'custom_meta_album', to sort alphabetically if it is the same Artist. Currently if a user enters in 10 albums by the same artist, the post will be alphabetized correctly by the Artist name, but the Albums have no order.
Is there a way to do some sort of second level sorting or primary and secondary sorting in Wordpress? I don't know if it's a IF statement that says "if artists value is equal then also sort albums ascending" or something along those lines. I figure there needs to be some way to tell Wordpress which field it should sort by first and then continue to the second level.
You may try this, hope this will work
// keep this function in your functions.php
function myCustomOrderby($orderby) {
return str_replace('menu_order', 'mt1.meta_value, mt2.meta_value', $orderby);
}
This is your args array
$args=array(
'post_type' => 'albums',
'orderby' => 'title',
'order' => 'ASC',
'posts_per_page' => -1,
'meta_query' => array(
array(
'key' => 'custom_meta_artist',
'value' => '',
'compare' => 'LIKE'
),
array(
'key' => 'custom_meta_album',
'value' => '',
'compare' => 'LIKE'
)
)
);
add_filter('posts_orderby','myCustomOrderby'); // Add filter before you call the WP_Query
$albums = new WP_Query($args);
remove_filter('posts_orderby','myCustomOrderby'); // Remove filter after you call the WP_Query
// Start your loop
while ( $albums->have_posts() ) : $albums->the_post();
//...
endwhile;
I have two models, Category and Point. The associations are defined as:
Category hasMany Point
Point belongsTo Category
I would like, when adding Points to my database, to be able to select the category it belongs to from a <select> box, along with the rest of the form data.
Where would I need to set the category list and how could I do it? And how would I produce the select box?
I assume it could be done with
$form->input('categorieslist',array('type'=>'select')); //categorieslist needs
//setting somewhere.
Also to generalize a bit:
In a View with access to the Form helper
<?php
echo $form->input( 'dataKey', array(
'type' => 'select',
'options' => array(
'key1' => 'val1',
'key2' => 'val2',
),
));
?>
The above will render a select input with two options. You can also place an empty option as the first item. Passing a value of true will simply append an empty option with a blank value to the beginning of the options rendered in the HTML.
<?php
echo $form->input( 'dataKey', array(
'type' => 'select',
'options' => array(
'key1' => 'val1',
'key2' => 'val2',
),
'empty' => true,
));
?>
You can pass a string to the 'empty' key to have it display custom text as the key field for the empty option.
<?php
echo $form->input( 'dataKey', array(
'type' => 'select',
'options' => array(
'California' => 'CA',
'Oregon' => 'OR',
),
'empty' => 'choose a state',
));
?>
One last example, you can also pre-select an option with the selected key. The value should match the value of one of the select options, not the key.
<?php
echo $form->input( 'dataKey', array(
'type' => 'select',
'options' => array(
'California' => 'CA',
'Oregon' => 'OR',
),
'empty' => 'choose a state',
'selected' => 'California',
));
?>
From the Model
Model->find( 'list', array( ... )); will always return an array formatted for use with select box options. If you pass data to your view stored in a variable with a lowercase plural model name, that is, ( $this->set( 'categories', $categories );, then you will automagically generate drop downs for related models by using the form helper in the view and passing it a data index of the same model name in singular form suffixed with "_id".
Aziz's answer at #2 is the example of that automagic kicking in.
CakePHP 1.3 Form Helper
CakePHP1.2 Form Helper
In the controller:
$categories = $this->Point->Category->find('list');
$this->set(compact('categories'));
In the view:
$form->input('category_id',array('type'=>'select'));