How to create a lookup in CakePHP - cakephp

I'm in the process of converting a 10 year old PHP application. After my boss hired a php consultant, he has set up a CakePHP application environment and we are learning as we go. (fun, I know). Also, I come from a javascript/sharepoint background and have not had a lot of php experience.
As a test, I created a basic address table with these fields: firstname, lastname, state, phonenumber. I've been using justice league members as names and other test data to populate my table. Baked it just fine, default bootstrap pages are working.
I decided I wanted to add a dropdown field called current status, and for now just to keep it simple I wanted the choices: alive, dead.I created the column in my address table.
I created a second table called statuses and pointed the status column in my first table to the status table, using the status id as the foriegn key.
Baked my new table and rebaked my old one.
The status drop down does not give my choices of dead or alive, If I click in the field I get an up or down arrow, and based on which one you click, it either increments or decrements by 1. So the first time I click it inserts a 0. If I go up or down, it adds or takes away one.
I'm not sure what I'm doing wrong, I'm guessing there is some additional code I need to add to the MVC?

ok, if this works, then a lot is working :-). Now to the following: set in the Status Model a query like this:
public function getStatus()
{
$opt = $this->Status->find('list', array(...));
return $opt;
}
Then get the list over to the Adress Controller like this:
$this->loadModel('Status');
$opt => $this->Status->getStatus();
$this->set('opt', $opt);
Now you are able to access the $opt in the view file.
Just delete this line in the view:
$opts = array('0' => __('dead'), '1' => __('alive'));
And it should work.

Keep it simple. Ad to your table this row (only to understand how it works): 'status' as typ "tinyint(1)". Then set this in your view file:
$opts = array('0' => __('dead'), '1' => __('alive'));
When you create the inputfield, do it like that:
echo $this->Form->input('Address.status', array('options' => $opts, 'label'
=> __('Status')));
This should work.

Related

Can't populate a Select options with related model info - CakePHP

Puling my hair out with this, I know its something very simple but I've been struggling to resolve it. For the record I'm using cakePHP 2.2.
I'm trying to populate a select input with related model data.
Basically I have users and user_statuses. The user model belongsTo the UserStatus model. Within the user/add() function I want to have a drop down select box populated with the data from the UserStatus model.
Heres the code:
UsersController/Add()
$groups = $this->User->Group->find('list');
$UserStatus = $this->User->UserStatus->find('list');
$this->set(compact('groups', 'UserStatus'));
View/Users/add.ctp
echo $this->Form->input('user_status_id', array('class' => 'span9'));
The field in the users table making the relationship is user_status_id which links to the id in the user_statuses table.
Based on the above the select box will NOT populate with the statuses from the user_statuses table. Interestingly enough, it will if I change the view code to just :
echo $this->Form->input('user_status_id', array('class' => 'span9'));
However, when I do this is will NOT write to the database.
Any help will be gratefully received.
Thanks in advance.
The options param should solve the problems for display and as long as there is a user_status_id in your User table, the below code should save the value in your User model on save.
echo $this->Form->input('User.user_status_id', array('options'=>$UserStatus,'class' => 'span9'));
Should be:
$userStatus = $this->User->UserStatus->find('list');
(note the lowercase 'u')

MVCGrid w/Expander (parent) invoking an MVC Form(child) and loading child record - UPDATED

My multi-level MVCGrid/MVCForm/MVCGrid saga continues....
I am using nested MVCGrids with expander buttons that invoke MVCForms to perform different data operations. ALL mySQL tables in this process have an "id" data element and that is the primary key for each table. Each mySQL table also has a point to its parent when necessary using _id naming convention. All of the foreign-keys have been setup in mySQL to work this way as well.
The model for the parent is like this:
class Model_uidcontrol extends Model_Table {
public $entity_code='uidcontrol';
public $table_alias='uc';
function init(){
parent::init();
The model for the child is like this:
class Model_uiddetails extends Model_Table {
public $entity_code='uiddetails';
public $table_alias='ud';
function init(){
parent::init();
Each model has its own "id" and a pointer to its parent.
The expander column in the MVCGrid (parent) invokes this child function:
$um=$this->add('MVCForm');
$um->setModel('uiddetails')
->loadData(($_GET['uidcontrol_id']));
I have tried this in the child model:
$this->addRelatedEntity('uc','uidcontrol','uidcontrol_ID');
and this as well:
$this->addField('uidcontrol_id')
->refModel('Model_uidcontrol')
->caption('System Info')
->visible(true);
I've tried each technique separately and together to get child records to be coordinated with the proper parent.
debug() shows this
where
ud.id = '121'
ud.uidcontrol_id = '121'
OK, I understand the $GET and how it works and how that relates to dsql - at least I think I do.
What I can't figure out is how to tell MVCForm to use "ud.uidcontrol_id = '121 " that come
via the $GET when building the dsql for data loading and not use 'ud.id'
In the above example, there is a parent record "uidcontrol" with that id. I forced the 'id' of the child record to be 121 to see if it would pull data and display it in the form. OK, data displays as it should.
When I try this parent whose 'id' = 10, debug() produces this
ud.id = '10'
ud.uidcontrol_id = '10'
and no data is returned. There is a uidcontrol record with id = 10 but the dsql is trying to match to ud.id = 10 as well.
I can post more of what I am working to clarify what I am trying to do if that helps.
Ideally, I would like to tell MVCForm "Hey! Don't use the 'id' data element when building the dsql, use the one I am supplying instead. Problem is, I can't figure out how to do that... but I've learned a bunch along the way. Me thinks that I am probably "over thinking" something here.
Thanks for any suggestions!
Monday Feb 6th Notes:
var_dump($_GET); says:
'id' => string '10' (length=2) <=== uidcontrol.id
'uidcontrol_id' => string '10' (length=2) <=== uidcontrol.id
I write this:
$um->setModel('uiddetails')
->addCondition('uidcontrol_id',($_GET['id']))
->loadData(($_GET['id']));
And the SQL debug shows this being built:
where
ud.id = '10'
ud.uidcontrol_id = '10'
The issue is that I want ONLY " ud.uidcontrol_id = '10' ". Table uiddetails has its own id of 125 and a uidcontrol_id value of 10. As a result of that, the query doesn't return a record.
The loadData method only loads records by their id. To link the "child" model through his referenced record you must use setMasterField or addCondition to instruct the model to filter on the relationship.

how to display the data returned by get_by_user_id() in DataMapper Code Igniter?

I am new to code igniter data mapper. I have a table called user, and I am trying to retrieve data from the database table and show them to the user.
Here is what I have in the model:
$u=new User();
$results=$u->get_by_user_id($id);
//$results here will be set to huge bunch of none sense data( which also includes the row that I am looking for as well)
if ($u->exists())
{
foreach ($results->all as $row){
$data['user']['first_name']=($row->user_first); //this where I am stuck ..
$data['user']['last_name']=($row->user_last);//this is also where I am stuck..
}
I don't know how to treat results to get a required fields I am looking for and store them in the $data I am passing to the user to view.
Thanks!
When you call get_by_x() on the model, the fields will be populated with data and you can access them like this:
$u = new User();
$u->get_by_user_id($id);
if($u->exists())
{
// you can access the table columns as object fields
$data['user']['first'] = $u->first;
$data['user']['last'] = $u->last;
}
else
{
$data['error'] = 'No such user!';
}
Have a look at the documentation which is really helpful: see Get and Get By.
Also, DataMapper expects all tables to have an id column: see Table Naming Rules. If your column is named id you should then call $u->get_by_id($id) instead of $u->get_by_user_id($id).

CakePHP user session not updating but database yes

I'm developing with cakePhP and I have the following problem:
When a user logs in with his name and password to the account system that I've created, he can save items (images) as favorites. This is saved in a text field into the database. What is saved is the image ID.
The saving process works perfectly, the user clicks on the images and they're added to that field (it actually saves all the IDs as a text array that I process later).
The problem comes when removing images. When the user does it (I'll post the code below), the images is removed correctly from the database (I go to PHP MyAdmin and I see it). This means that the array that holds the favorite images IDs is updated instantly. However, when I reload that array from the website, it hasn't been updated. It's like it's stored in the caché or something. Then, if the user logs out and logs in again, then he can see the correct one. The thing is that I have other things in my website that work in a similar way and they all get updated instantly, so I can't see why this doesn't.
This is the code that I use to remove the ID from the database:
function remove_favorite($pictureID) {
$this->User->id = $this->Auth->User('id'); //We get the ID of the current user
$favoritesArray = $this->User->deleteFavoritePicture($this->User->id, $pictureID); //This function retrieves the array (string) of pictures from the user's table, and deletes all the images with the ID passed as parameter, returning the updated array (string)
$fields = array('images_favorites' => $favoritesArray, 'modified' => true); //We indicate the field that we're going to update in the users table
//We save the new string that doesn't contain the deleted image anymore
if($this->User->save($fields, false, array('images_favorites'))) {
$this->Session->setFlash(__('The image has been removed from your favorites', true));
} else {
$this->Session->setFlash(__('Error removing image from favorites, please try again', true));
}
$this->redirect(array('action' => 'manage_favorites',$this->User->id));
}
This is how the deleteFavoritePicture function looks like:
function deleteFavoritePicture($userID, $pictureID) {
$userInfo = $this->find("id = $userID");
$favoritePicturesString = $userInfo['User']['images_favorites'];
$favoritePicturesArray = explode(",", $favoritePicturesString); //Array
$i = 0;
while ($i < count($favoritePicturesArray)) {
//We remove from the array the images which ID is the one we receive to delete
if ($favoritePicturesArray[$i] == $pictureID) unset($favoritePicturesArray[$i]);
$i++;
}
$favoritePicturesString = implode(",", $favoritePicturesArray); //String
return ($favoritePicturesString);
}
That's it. Does anyone now what can be going on? Thanks so much in advance for any clue!
EDIT
Ok, I think I found something that may give a clue of what's going on here:
This is the code for the manage_favorites action:
function manage_favorites($id) {
//$user = $this->User->find("id = $id");
$user = $this->Auth->user();
$this->set('user', $user);
}
That is the action that is called for the page when a user wants to modify his favorites. The same action is called once the user removes a favorite. Here's the thing:
If I use the $id parameter in the manage_favorites function and the $user = $this->User->find("id = $id"); line (the one quoted now), then the problem does not exist! This is how I used to have it. HOWEVER, I had to change it because it was a big security flaw, since the user id ($id) was a visible parameter who anyone could change, and then access other users accounts. What I did was changing the way I obtain the user array of favorite images, using the following line: $user = $this->Auth->user();. This is how I have it now (well, and also without the $id parameter in the function header), so the user information (including the favorites array) comes from the Auth component, instead directly from the database.
So, the problem is clear: when the user deletes a favorite, it's doing it on the array in the database. WHen I show the result of that operation, the array I'm retrieving is not the one in the DB, it's the one in the session. That's why it's not showing the changes.
How can I avoid this without using a non-secure method like the one I had before?
When you save, the array passed to the save method of the model should look like this:
[User] => array(
[field] => value,
[field2] => value2,
...
)
In your example, you clearly haven't added the [User] key.
Also, is your modified field actually the default Cake modified field? That is, the DATETIME field which changes to the current time when the row is updated?
Lastly, maybe you have debugging set to 2 in config.php. try changing this to 0 (as in production) and see if caching persists.
Hope some of the points I have mentioned above will solve your problem. Please let me know!
There could be two things wrong with this.
What does your deleteFavoritePicture method look like? There could be something being done wrong there.
You're passing false as the second parameter to the User::save method, which means that you don't want to validate. Unless there is a SQL error, then this will return true even if it doesn't validate properly, I believe. Try changing this false to true and see if your results differ.

What is the equivalent to getLastInsertId() in Cakephp?

If I do getLastInsertId() immediately after a save(), it works, but otherwise it does not. This is demonstrated in my controller:
function designpage() {
//to create a form Untitled
$this->Form->saveField('name','Untitled Form');
echo $this->Form->getLastInsertId(); //here it works
}
function insertformname() {
echo $this->Form->getLastInsertId(); //this doesnt echo at all
}
Please suggest a way to get the functionality I want.
CakePHP has two methods for getting the last inserted id: Model::getLastInsertID() and Model::getInsertID().
Actually these methods are identical so it really doesn't matter which method you use.
echo $this->ModelName->getInsertID();
echo $this->ModelName->getLastInsertID();
This methods can be found in cake/libs/model/model.php on line 2768
Just use:
$this->Model->id;
In Cake, the last insert id is automatically saved in the id property of the model. So if you just inserted a user via the User model, the last insert id could be accessed via $User->id
id - Value of the primary key ID of
the record that this model is
currently pointing to. Automatically
set after database insertions.
Read more about model properties in the CakePHP API Docs: http://api.cakephp.org/2.5/class-AppModel.html
Edit: I just realized that Model::getLastInsertID() is essentially the same thing as Model->id
After looking at your code more closely, it's hard to tell exactly what you're doing with the different functions and where they exist in the grand scheme of things. This may actually be more of a scope issue. Are you trying to access the last insert id in two different requests?
Can you explain the flow of your application and how it relates to your problem?
You'll need to do an insert (or update, I believe) in order for getLastInsertId() to return a value. Could you paste more code?
If you're calling that function from another controller function, you might also be able to use $this->Form->id to get the value that you want.
Try using this code in your model class (perhaps in AppModel):
function get_sql_insert_id() {
$db =& ConnectionManager::getDataSource($this->useDbConfig);
return $db->lastInsertId();
}
Caveat emptor: MySql's LAST_INSERT_ID() function only works on tables with an AUTO_INCREMENT field (otherwise it only returns 0). If your primary key does not have the AUTO_INCREMENT attribute, that might be the cause of your problems.
this is best way to find out last inserted id.
$this->ModelName->getInsertID();
other way is using
$this->ModelName->find('first',array('order'=>'id DESC'))
There are several methods to get last inserted primary key id while using save method
$this->loadModel('Model');
$this->Model->save($this->data);
This will return last inserted id of the model current model
$this->Model->getLastInsertId();
$this->Model-> getInsertID();
This will return last inserted id of model with given model name
$this->Model->id;
This will return last inserted id of last loaded model
$this->id;
Try to use this code. try to set it to a variable so you can use it in other functions. :)
$variable = $this->ModelName->getLastInsertId();
in PHP native, try this.
$variable = mysqli_insert_id();
This will return last inserted id of last loaded model
$this->id;
This will return last inserted id of model with given model name
$this->Model->id;
This will return last inserted id of the model current model
CakePHP has two methods for getting the last inserted id:
Model::getLastInsertID() and Model::getInsertID().
echo $this->ModelName->getInsertID();
echo $this->ModelName->getLastInsertID();
Below are the options:
echo $this->Registration->id;
echo $this->Registration->getInsertID();
echo $this->Registration->getLastInsertId();
Here, you can replace Registration with your model name.
Thanks
Use this one
function designpage() {
//to create a form Untitled
$this->Form->saveField('name','Untitled Form');
echo $this->Form->id; //here it works
}
You can get last inseted id with many ways.Like Model name is User so best way to fetch the last inserted id is
$this->User->id; // For User Model
You can also use Model function but below code will return last inserted id of model with given model name for this example it will return User model data
$this->User->getLastInsertId();
$this->User->getInsertID();
When you use save(), the last insert ID is set to the model’s $id property. So:
if ($this->Model->save()) {
printf('Last insert ID was %s', $this->Model->id);
}
Each time a save method is called on a model, cake internally calls Model::getLastInsertId() and stores the result into model class attribute id, so after calling save() it is not necessary to call Model::getLastInsertId() or inserId(), as tha value can be directly accessed like this
$id = $this->id;// within a model
$id = $this->{$this->modelName}->id;// in a controller
After insertion of data, we can use following code to get recently added record's id:
$last_insert_id=$this->Model->id;
each time you perform an insert operation on any model, cake internally fetchesthe last insert Id and Sets to Model->id attribute.
so one can access it directly by $Model->id;,
no need to query again for lastInsertId.
I think it works with getLastInsertId() if you use InnoDB Tables in your MySQL Database. You also can use $this->Model->id
$Machinedispatch =
$this->Machinedispatch->find('first',array('order'=>array('Machinedispatch.id DESC')));
Simplest way of finding last inserted row. For me getLastInsertId() this not works.
Actually you are using the getLastInsertId or getInsertId in a wrong manner.
getLastInsertId() is meant to work only after save() method.
It will even not work after a manual insert, as cake engine is storing the mysql_insert_id under $this->_insertID inside the save method which can be retrieved via the getLastInsertId or getInsertId.
Now in your case
$this->Model->id
OR
$this->Model->find('first',array('order'=>'id DESC'))
Will do.
This is interesting, I also stumbled upon this issue. What you asked perhaps how to get the last ID of a certain model regardless of it's state, whether it's just been inserted or not. To further understand what getInsertID does, we need to take a look at the source:
Link 1: http://api20.cakephp.org/view_source/model#line-3375
public function getInsertID() {
return $this->_insertID
}
Yup, that's the only piece of code inside that function. It means that cakephp caches any last inserted ID, instead of retrieve it from the database. That's why you get nothing if you use that function when you haven't done any record creation on the model.
I made a small function to get the last ID of a certain table, but please note that this should not be used as a replacement of getLastID() or getLastInsertID(), since it has an entirely different purpose.
Add the function lastID() to the AppModel as shown below so that it can be used system wide. It has it's limit, which can't be used on model with composite primary key.
class AppModel extends Model {
public function lastID() {
$data = $this->find('first',
array(
'order' => array($this->primaryKey . ' DESC'),
'fields' => array($this->primaryKey)
)
);
return $data[$this->name][$this->primaryKey];
}
}
Original Source : Class Model
In CakePHP you can get it by:
Model::getInsertID() //Returns the ID of the last record this model inserted.
Model::getLastInsertID() //Alias to getInsertID().
$this->Model->field('id', null, 'id DESC')

Resources