CakePHP drop down box from associated model - cakephp

I have a simple api that allows customers to book vehicles. In my reservations controller i have a function which is to add a reservation. Here is the code:
Controller
function add() {
if($this->request->is('post')) {
if($this->Reservation->save($this->data)) {
$this->Session->setFlash('The Reservation was successfully added!');
$this->redirect(array('action'=>'index'));
} else {
$this->Session->setFlash('The Reservation was not added.');
}
}
$this->set('title_for_layout','Add Reservation');
}
Here is what i have in my add view for a reservation.
View
<?php
echo $this->Form->create('Reservation', array('action'=>'add'));
echo $this->Form->input('customer_id', array( 'type' => 'text' ) );
echo $this->Form->input('vehicle_id', array( 'type' => 'text' ) );
echo $this->Form->input('date');
echo $this->Form->end('Add Reservation');
?>
But because i am adding a new reservation and i want a dropdown box for vehicle ids and one for customer ids how can i do this?
I think i have linked the models by putting this into the customers and vehicles models:
var $hasMany = array( 'Reservation' => array( 'className' => 'Reservation' ) );
Could anyone point me into the right direction so that a dropdown box would appear with a list of vehicle and customer IDs on the add reservation page.

In your add function in controller, use
$vehicle = $this->Reservation->Vehicle->find('list', array('fields' =>array('Vehicle.id','Vehicle.name')));
$this->set('vehicle', $vehicle);
In your view,use
<?php echo $this->Form->input('vehicle_id', array('type' => 'select',
'options' => $vehicle)); ?>
Use the same thing for customers also and you will get list of customers and vehicles in dropdown.

Related

CakePhp $hasAndBelongsToMany not saving multiple select items as expected

I have the following code setup (snipped for brevity)
class BasePackage extends AppModel {
public $name = 'BasePackage';
public $hasAndBelongsToMany = array('ProductSubtype', 'ProductType');
}
class ProductType extends AppModel {
public $name = 'ProductType';
}
class ProductSubtype extends AppModel {
public $name = 'ProductSubtype';
}
Above are the simple Model classes.
/* tables in database */
base_packages
product_types
product_subtypes
base_packages_product_types
base_packages_product_subtypes
The first table is the main package that users are creating with the form, the product_* tables are pre-loaded with appropriate types and subtypes (they don't change very often), the last two are the Join tables that CakePhp wants to have
/* in BasePackage/add.ctp */
// ...
<ul class="nwblock">
<li>
<?php
echo $this->Form->input('ProductType.product_type_id', array(
'label' => 'Choose Product Type',
'type' => 'select',
'class' => 'form-control',
'style' => 'width:300px; margin-bottom:20px;',
'options' => $protypes
));
?>
</li>
</ul>
<ul class="nwblock">
<li>
<?php
echo $this->Form->input('ProductSubtype.product_subtype_id', array(
'label' => 'Choose Subtype(s)',
'multiple' => 'multiple',
'type' => 'select',
'class' => 'form-control',
'style' => 'width:300px;height:390px;margin-bottom:20px;',
'options' => $subtypes
));
?>
</li>
</ul>
// ...
Above we see the two controls that are loaded from the product_* tables. The types are a single select dropdown and the subtypes are a multiple select list.
/* in BasePackageController.php */
public function add() {
$protypes = $this->BasePackage->ProductType->find('list',
array('fields' => array('ProductType.id', 'ProductType.display')));
$subtypes = $this->BasePackage->ProductSubtype->find('list',
array('fields' => array('ProductSubtype.id', 'ProductSubtype.display')));
$this->set('protypes', $protypes);
$this->set('subtypes', $subtypes);
if ($this->request->is('post')) {
$this->BasePackage->create();
if (!empty($this->request->data)) {
$this->BasePackage->saveAll($this->request->data, array('deep' => true));
}
}
}
The process is as follows, while the user creates a new BasePackage, they select a ProductType from a dropdown box and one to many ProductSubtypes from a multiple select list. When the $this->BasePackage->saveAll() call is made, the data to be inserted into base_packages and base_packages_product_types tables is inserted correctly. However, the base_packages_product_subtypes table remains untouched.
UPDATE:
If I remove the 'multiple' => 'multiple', from the form->input options, the code saves both the producttype and the productsubtype (as expected). This is obviously not sufficient, as I need to save 1-to-many. Anyone know how to activate the 'Many' part of the HABTM?
To me BasePackage <> ProductType looks more like it should be a many-to-one relation, ie BasePackage belongsTo ProductType?
Anyways... please follow the conventions as described in the Cookbook:
http://book.cakephp.org/2.0/en/models/saving-your-data.html#saving-related-model-data-habtm
The form helper should be fed with the model name, ie ProductSubtype, and the view var should be camel backed plural, ie productSubtypes, that way CakePHP will do the rest for you automatically.
public function add() {
// ...
$this->set('productSubtypes', $subtypes);
// ...
}
echo $this->Form->input('ProductSubtype', array(
'label' => 'Choose Subtype(s)',
'class' => 'form-control',
'style' => 'width:300px;height:390px;margin-bottom:20px;'
));
Can you try with BasePackage->saveAssociated ?
http://book.cakephp.org/2.0/en/models/saving-your-data.html#model-saveassociated-array-data-null-array-options-array

HABTM dropdown items not selected

I created a site for fun to learn CakePHP but for some reason I can't get a multiple select dropdown box to show my selected items. In this example 1 video game can have multiple difficulties (easy, normal, hard). On my Game edit page I have a multi select box to pick the difficulties. It shows all three difficulties and I can select them and it saves correctly. However when I return to the edit page the items I previously saved do not show highlighted as selected. I have verified that the records are saving correctly in the database.
Tables:
games
difficulties
difficulties_games
Models:
class Game extends AppModel {
public $actsAs = array('Containable');
public $hasAndBelongsToMany = array(
'Difficulty' =>
array(
'className' => 'Difficulty',
'joinTable' => 'difficulties_games',
'foreignKey' => 'game_id',
'associationForeignKey' => 'difficulty_id',
'unique' => 'true'
)
);
}
class Difficulty extends AppModel {
public $actsAs = array('Containable');
public $hasAndBelongsToMany = array(
'Game' =>
array(
'className' => 'Game',
'joinTable' => 'difficulties_games',
'foreignKey' => 'difficulty_id',
'associationForeignKey' => 'game_id',
'unique' => 'true'
)
);
}
Controller:
$game = $this->Game->findById($id);
$this->set('difficulties', $this->Game->Difficulty->find('list'));
View (edit.ctp):
echo $this->Form->input('Difficulty');
This has to be something simple I am missing but I've read through the book on HABTM and searched here and couldn't find much on multi-select boxes.
UPDATE:
Here is the entire edit function in the controller:
public function edit($id = null) {
if (!$id) {
throw new NotFoundException(__('Invalid post'));
}
$game = $this->Game->findById($id);
if (!$game) {
throw new NotFoundException(__('Invalid post'));
}
if ($this->request->is('post') || $this->request->is('put')) {
$this->Game->id = $id;
if ($this->Game->saveAll($this->request->data)) {
$this->Session->setFlash('Your game has been updated.');
$this->redirect(array('action' => 'index'));
} else {
$this->Session->setFlash($this->Game->invalidFields());
}
}
if (!$this->request->data) {
$this->request->data = $game;
}
$this->set('systems', $this->Game->System->find('list'));
$this->set('genres', $this->Game->Genre->find('list'));
$this->set('difficulties', $this->Game->Difficulty->find('list'));
}
Also here is some more on the View:
echo $this->Form->create('Game');
echo $this->Form->input('name');
echo $this->Form->input('system_id');
echo $this->Form->input('genre_id');
echo $this->Form->input('Difficulty');
echo $this->Form->input('id', array('type' => 'hidden'));
echo $this->Form->end('Save Game');
What CakePHP version are you using? Releases 2.2.6 and 2.3.0 have a bug related to showing existing habtm selected. So updated to 2.2.7 if using 2.2.6 or if using 2.3.0 use the master branch from github until the next bugfix release is done.
For everyone who sets public $recursive = -1; in his AppModel due to performance reasons, or changes the recursion in his controller:
The automagic won't work without recursive 1! Make sure you change it in the options when retreiving your data for the edit.
$options = array(
'recursive' => 1,
'conditions' => array('YourModel.' . $this->YourModel->primaryKey => $id)
);
$this->request->data = $this->YourModel->find('first', $options);

how to combine two HABTM saves in one form in CakePHP?

I have two models Business and User. They are related by a HABTM relationship.
Everything is working with the baked controllers, models and views.
Now I'm trying to combine the two models in one form so the user can enter a business name with is user info.
Here's the form :
Form->create('User'); ?>
Form->input('Business.name', array('label' => __('Business name')));
echo $this->Form->input('User.email');
echo $this->Form->input('User.firstname');
echo $this->Form->input('User.lastname');
echo $this->Form->input('User.password');
echo $this->Form->input('User.phone_cell', array('type' => 'text'));
echo $this->Form->input('User.phone_home', array('type' => 'text'));
echo $this->Form->input('User.phone_work', array('type' => 'text'));
?>
Form->end(__('Submit')); ?>
The only way I was able to make it work was to save the User first and then get the user id and save the business after by adding the user array with the new id.
if ($this->User->save($this->request->data)) {
$this->request->data['User'] = array('User' => array(0 => $this->User->id));
if ($this->User->Business->save($this->request->data)) {
// User saved
} else {
// User not saved
}
} else {
$this->Session->setFlash(__('The user could not be saved. Please, try again.'));
}
I tried the saveAll method without success. Is is possible to optimize this the CakePHP way for a single save ?
Thanks
I was able to get it to work myself with a couple models named User and Group. Here's some snips from my code to show how I did it:
UsersController.php
public function edit($id = null)
{
$this->User->id = $id;
if ($this->request->is('get')) {
//On page load load the user data
$this->request->data = $this->User->read();
} else {
//Saving
if ($this->User->save($this->data)) {
//....snipped...
} else {
$this->Session->setFlash('Unable to update the user.');
}
}
//Build $groups array for form
// Only admins can assign admin rights
if ($this->isMember('Admin')) {
$this->set('groups',$this->User->Group->find('list'));
} else {
$this->set('groups',$this->User->Group->find('list',array(
'conditions' => array(
'Group.name !=' => 'Admin'
)
)));
}
//...more snipping...
}
edit.ctp (View)
echo $this->Form->create('User', array('action' => 'edit'));
echo $this->Form->input('User.username');
echo $this->Form->input('Group',array(
'type' => 'select',
'multiple' => true,
'label' => "Group (Select multiple entries with CTRL)",
'size' => count($groups)
)
);
//More snipping
With that example to work from, how are you validating that the Business.name entered is valid and can be matched to the HABTM relation? Mine forces a selection list in this case. My Model is extremely simple so I didn't include that.
What are your outputs to debug($this->data); vs. debug($this->request->data)?

Cakephp habtm relation updating instead of saving

Hello my problem is i try to save a new relation between a shop and a payment method
the relation is habtm... shop and payment already exist. i want to ad more payment methods.
But always when i save ,the old payment realtion in the shop_payment table is only updated, not a second one saved....
i read a lot i set unique to false but nothing changes that.
Anyone got an idea?
Model
class Payment extends AppModel {
var $hasAndBelongsToMany = array(
'Mainshop'=>array('className'=>'Mainshop', 'unique'=>'false')
);
}
View
echo $this->Form->create('Mainshop');
echo $this->Form->input('name',array('default'=>$mainshop['Mainshop']['name']));
echo $this->Form->input('Payment.id', array(
'type' => 'select',
'options' => array($payments),
));
echo $this->Form->input('id', array('type'=>'hidden','value'=>$mainshop['Mainshop'] ['id']));
echo $this->Form->end('Edit Shop');?>
Controller
if (!empty($this->data)){
$this->Mainshop->save($this->data);
$this->redirect(array('action' => 'edit',$this->data['Mainshop']['id']));
}
My recommendation defines the relationship with all fields in model:
var $hasAndBelongsToMany = array(
'Mainshop'=>array(
'className'=>'Mainshop',
'unique'=>'false',
'joinTable' => 'shop_payments',
'foreignKey' => 'payments_id',
'associationForeignKey' => 'shop_id'
)
);
In the controller add create():
if (!empty($this->data)){
$this->Mainshop->create();
$this->Mainshop->save($this->data);
$this->redirect(array('action' => 'edit',$this->data['Mainshop']['id']));
}

Cakephp: BelongsTo Relationship

I want to model the following simple relationship:
One Passenger belongs to a Car; One Car has many Passengers.
The passenger table has an id and Car_id column, the Car table has one id column.
My models look like this:
<?php
class Passenger extends AppModel {
var $name = 'Passenger';
var $belongsTo = 'Car';
} ?>
and
<?php
class Car extends AppModel {
var $name = 'Car';
var $hasMany = array (
'Passenger' => array (
'className' => 'Passenger',
'foreignKey' => 'car_id'
)
);
}
?>
and my add Passenger .ctp looks like this:
<?php
echo $this->Form->create('Passenger');
echo $this->Form->input('car_id');
echo $this->Form->end('Save');
?>
BUt when I access the page to add a passenger, all I see is an empty drop down box. Is there an additional step I must take in order to populate the dropbox with all cars?
First off, you have forgotten to mention the belongsTo relation in your Passenger model:
<?php
class Passenger extends AppModel {
var $name = 'Passenger';
var $belongsTo = array('Car');
}
?>
Next, in the corresponding action of your controller, you will need to obtain a list of all the cars from the database, and set it to the plural form of the model's variable ($cars). You would do that like so:
$cars = $this->Passenger->Car->find('list');
$this->set(compact('cars'));
This will convert the car_id input field into a drop down list with the populated information.
HTH.
The Passenger will only know about the car with which it is associated - at this point, none.
In the add method in the passenger controller, do
$this->Car->find('list');
and pass the result into your view:
$this->set('cars',$cars);
In the view, give the $cars variable as the value for $options in the field declaration:
echo $this->Form->input('car_id', array('options' => $cars));
Alternatively, you can do something like:
echo $this->Form->input('Car.id', array('options' => $cars));
$this->CompanyCashback->bindModel(array('belongsTo' => array(
'CompanyBranch' => array('className' => 'CompanyBranch', 'foreignKey' => false, 'conditions' => array('CompanyCashback.publisher_id = CompanyBranch.publisher_id && CompanyBranch.branch_type = "online" ')),
'PersonalInformation' => array('className' => 'PersonalInformation', 'foreignKey' => false, 'conditions' => array('CompanyCashback.publisher_id = PersonalInformation.user_id')),
'Country' => array('className' => 'Country', 'foreignKey' => false, 'conditions' => array('PersonalInformation.country_id = Country.id')),
'User' => array('className' => 'User', 'foreignKey' => false, 'conditions' => array('PersonalInformation.user_id = User.id')))
));

Resources