how to save specific field in Cakephp - cakephp

here is my code
public function settings(){
$this->loadModel('Userinfo');
$helpers = array('TimeZoneHelper');
if($this->request->is('post')) {
$id = $this->Auth->User('idUser');
$data = $this->request->data['Userinfo']['timezone'];
$this->Userinfo->save($data,array(
'conditions' => array('Userinfo.User_id' => $id))));
}
i have a field name timezone in my userinfo table .. which i want to update .. i dont know how can i specifically update the single field in Cakephp as i am new in Cakephp ..i am doing this but dont know why it isn't working ...well when i debug the $data .. the data is coming fine ..
in database the datatype of timezone is "time"

Set you models id:
$this->Userinfo->id = $id;
Then, use the savefield function to save a specific field:
$this->Userinfo->saveField('timezone', 'UTC');
Good luck further on cakePhp!

Related

how to validate country name in cakephp

I have two tables, profiles and regions.
in regions table I have list of all countries name. and in profiles table I have profile for my users and one of the field in that table in 'country'
Previously I was giving users an input box to enter country name but recently I noticed that few people are entering wrong information there. One guy entered 'jupiter' as his country name.
now what I wanna do is in my Profile model is something like this:
'country must exist' => array(
'rule' => 'countryValidation',
'message' => 'There is no such country'
)
public function countryValidation($check) {
$country = strtolower($this->data['Profile']['country']);
$countries = array();
$regions = $this-Region->find('all');
foreach($regions as $region){
array_push($countries, strtolower($region['Region']['country']));
}
return in_array($country,$countries);
}
and I am sure that the problem here is with
$regions = $this-Region->find('all');
What's the correct way to validate country?
BTW, I can't give a drop down list of country because it mess up with my layout/website design.
What you're looking to do is a bad idea, as you can't guarantee that end users will spell the names of the countries correctly etc.......
At any rate, create a custom function in your model
public function myFunction($countryName){
return in_array($countryName,$countriesList);
}
where $countriesList is an array of country names.
In the model validation you can do the following
public $validate = array(
'country' => array(
'rule' => 'myFunction',
'message' => 'Insert custom message here'
)
);
EDIT:
Then I would create a custom find function in the Region model, and call it from the current model to retrieve an array of results for validation. Something like:
$countriesList = $this->Region->customFunction();
or $countriesList = $this->Region->find('list);
Check this to use a model in another model
App::uses('Model', 'Region');
$Region = new Region();
$regions = $Region->find('all');

What is the wrong here on associaction cake php

I am working on cake php and I have an association with users and user_details table, When I sign up then its working fine. Its post data on both the tables but when I redirect to profile page then it throws an error of userDetail array. When I printed that info array I got only one array instead of two arrays one is User and another one is UserDetail. Its working fine on my local machine but not working on server, But when I used recursive=>1 than its works. Please let me know what wrong here.
Query
$userInfo = $this->User->find('first',array('conditions'=>array('User.id'=>$userId)));
when I pass recursive than it works
$userInfo = $this->User->find('first',array('recursive'=>1,'conditions'=>array('User.id'=>$userId)));
Thanks
Shiv
Please use Containable behavior. It's more intuitive and clean then recursive variable. You can do this adding in your AppModel (or specific models if you don't want this behavior in all of them):
public $actsAs = array('Containable');
Then, in your find:
$userInfo = $this->User->find('first',array(
'conditions'=>array(
'User.id'=> $userId
),
'contain' => array('UserDetail')
));
If you have declared your association, you will retrieve your User along any UserDetail for that User
If you always want UserDetail to be fetched when you do a find on User, add the $recursive property to your User model:
public $recursive = 1;
However, the above is not recommended as usually, $recursive should be set to -1 in your AppModel. This is because Model::find() should normally only fetch data from a single model and not ALL related models. E.g. if your User model is related to say UserDetail and UserRole model, data from all of them will be fetched if $recursive is not equal to -1. This slows down your app.
When you do require related model data like in your question, use the containable behavior like this:
$userInfo = $this->User->find('first', array(
'conditions' => array('User.id'=>$userId),
'contain' => array('UserDetail')
));

CakePHP find query across multiple datasources

I am tring to do the following:
My 'Company' Models are being stored in a 'default' datasource. In to
model I set the var $useDbConfig = 'default';
My 'User' Models are being stored in another datasource called
'users_db'. In this model I set the var $useDbConfig = 'users_db';
There is a 'belongsTo' relationship between 'Company' and 'User' models.
I want to do a recursive find query that brings back all users for each company in one go. I have the feeling that I cannot do this with Cake as it currently is.
When I try the following:
$res2 = $this->Company->find('all', array(
'conditions' => array('Company.id' => 1),
'recursive'=>2
));
I get a message that it cannot find the users table(its looking in the default source):
Error: Table user_groups for model User was not found in datasource default.
Is there any way I can do this?
Many thanks for any help you can provide.....
kSeudo.
Why not replace the your original statement by this:
$this->loadModel('User');
$res2 = $this->User->find('all',
array( 'conditions' => array( 'User.company_id' => 1 ) ));
This will produce the results you want.
Otherwise, if you wanted something tidier, you could add a fetch_users() function to your Company class that implemented a similar logic.
Ok, problem solved. Once I set the datasource in the model correctly everything seems to work fine.
Thanks guys

CakePHP: Retrieve specific table field in controller

I am new to Cake and tried to find the best solution to retrieve a specific field belonging to an $id:
This is my view function in my Post controller
function view($id = null) {
if (!$id) {
$this->Session->setFlash(__('Invalid post', true));
$this->redirect(array('action' => 'index'));
}
$this->set('post', $this->Post->read(null, $id));
}
In the post table, there is a user_id foreign key. I need to retrieve this specific field belonging to this Post $id.
I read about functions as find('All), read() or just drop an unconventional session in the view through:
$session->write('example') = $post['Post']['user_id];
What is the best way to do this, my preference is to retrieve the field in the controller. Thanks!
CakePHP has a field function which should do just that.
$this->Post->id = $id;
$user_id = $this->Post->field('user_id');
For more information on using field, see: http://book.cakephp.org/2.0/en/models/retrieving-your-data.html#model-field
A second option is to use the find function and returning only a few fields if you do not want the entire Post object. Also shown below is using a condition instead of setting the current Post.
$this->Post->find('first', array(
'conditions'=>array('id'=>$id),
'fields'=>array('user_id')
));
More information on find is available at: http://book.cakephp.org/2.0/en/models/retrieving-your-data.html
$this->Post->id = $id;
$this->Session->write('example',$this->Post->field('user_id'));
In CakePHP 3, you can use $this->Model->get() to get the Entity, and then reference the required field directly.
$fieldValue = $this->ModelName->get($id)->fieldName;
Try this one, since I don't know which field(s) you need I provide an example field array set using Magic Find Types:
$fields = ['title', 'body', 'created'];
$record = $this->Post->findById($id, $fields);
or multiple records
$recordSet = $this->Post->findAllByTitle('The title', $fields);
*Note the the second example doesn't make a lot of sense unless there are multiple titles with the name 'The title' in the the posts.title column.

HABTM form validation in CakePHP

I have a Projects table and a Users table which are linked by a HABTM relation. In the "add" new Project page I have a multiple checkbox section to select Users for the new project. I want to have at least one User for the Project. What's the best way to approach this in CakePHP ?
Try this:
// app/models/project.php
/**
* An additional validation check to ensure at least one User is
* selected. Spoofs Cake into thinking that there are validation
* errors on the Project model by invalidating a non-existent field
* on the Project model, then also invalidates the habtm field as
* well, so when the form is re-displayed, the error is displayed
* on the User field.
**/
function beforeValidate() {
if (!isset($this->data['User']['User'])
|| empty($this->data['User']['User'])) {
$this->invalidate('non_existent_field'); // fake validation error on Project
$this->User->invalidate('User', 'Please select at least one user');
}
return true;
}
I stumbled on the same issue, but now - 3 years later - with CakePHP 2.3.
To be clear; Group has and belongs to User. I've had a form like this:
// View/Groups/add.ctp
echo $this->Form->input('name');
echo $this->Form->input('User');
With the validation rule like in user448164's answer:
// Model/Group.php
public $validate = array(
'User' => array(
'rule' => array('multiple', array('min' => 1)),
'message' => 'Please select one or more users'
)
);
That didn't work, after Googling for it, I found this question which couldn't still be the best solution. Then I tried several things, and discovered this to work just fine:
// View/Groups/add.ctp
echo $this->Form->input('name');
echo $this->Form->input('Group.User');
Way too easy solution, but had to dig into it to find out it works this way.
Hopefully it helps somebody one day.
Update for CakePHP 2.4.x (possibly 2.3.x as well)
When I wrote this answer, I was using CakePHP 2.3.x. Back then it worked perfectly for both validating and saving the data. Now when applying the same code on a new project, using CakePHP 2.4.x, it didn't work anymore.
I created a test case, using the following code:
$data = array(
'User' => array(
'Client' => array(8)
),
);
$this->User->create();
$this->User->saveAll($data);
My first thought was: Saving all means saving all "root" models, what actually makes sense to me. To save deeper than just the "root" ones, you'll have to add the deep option. So I ended up with the following code:
$data = array(
'User' => array(
'Client' => array(8)
),
);
$this->User->create();
$this->User->saveAll($data, array('deep' => true));
Works like a charm! Happy coding. :)
Update (2014/03/06)
Struggling with the same problem again, in this case with hasMany instead of habtm. Seems like it behaves the same way. But I found myself looking for this answer again, and got confused.
I'd like to make clear that it's key to use Group.User instead of User in your input. Else it won't use the User model validation.
I've just been looking at his problem myself on a project and came across a slightly more elegant solution, as long as you're only dealing with a habtm relationship and you need to ensure that at least one checkbox is selected.
so for example you're editing a Project and you want it to be associated with at least one user
Add this to beforeValidate()
// check habtm model and add to data
foreach($this->hasAndBelongsToMany as $k=>$v) {
if(isset($this->data[$k][$k]))
{
$this->data[$this->alias][$k] = $this->data[$k][$k];
}
}
In the validation rules add the following:
'User' => array(
'rule' => array('multiple', array('min' => 1)),
'message' => 'Please select one or more users'
)
teknoid's blog has a pretty in depth solution to your issue here. The most Cakey way of doing this would be to add custom validation to your model, as you mention in your comment above. Check out http://teknoid.wordpress.com/2008/10/16/how-to-validate-habtm-data/
From the article, where Tag HABTM Post (:: Project HABTM Users):
First, we validate the Tag model, by
using the data from the form to ensure
that at least one Tag was selected. If
so, we save the Post and the relevant
Tags.
2016 update for CakePhp 2.7
Full answer here : HABTM form validation with CakePHP 2.x
TL;DR;
AppModel.php
public function beforeValidate($options = array()){
foreach (array_keys($this->hasAndBelongsToMany) as $model){
if(isset($this->data[$model][$model]))
$this->data[$this->name][$model] = $this->data[$model][$model];
}
return true;
}
public function afterValidate($options = array()){
foreach (array_keys($this->hasAndBelongsToMany) as $model){
unset($this->data[$this->name][$model]);
if(isset($this->validationErrors[$model]))
$this->$model->validationErrors[$model] = $this->validationErrors[$model];
}
return true;
}
In the main model of your HABTM :
public $validate = array(
'Tag' => array(
'rule' => array('multiple', array('min' => 1)),
'required' => true,
'message' => 'Please select at least one Tag for this Post.'
)
);
If you are using CakePHP 2.3.x, you may need to add this code to your model in addition to the code that GuidoH provided, otherwise your HABTM model data may not save:
public function beforeSave($options = array()){
foreach (array_keys($this->hasAndBelongsToMany) as $model){
if(isset($this->data[$this->name][$model])){
$this->data[$model][$model] = $this->data[$this->name][$model];
unset($this->data[$this->name][$model]);
}
}
return true;
}
As per my comment on Guido's answer above, I use Guido's answer exactly, however I modify the data with the beforeSave callback before it saves to the database.
I have this issue on Cake 2.4.5+
public function beforeSave($options = array()) {
$temp = $this->data['Group']['User'];
unset($this->data['Group']['User']);
$this->data['User']['User'] = $temp;
return true;
}

Resources