how to combine two HABTM saves in one form in CakePHP? - 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)?

Related

Basic CakePHP: Unable to get the id (Edit Method)

This my database:
http://gyazo.com/c6a86127d6f91aae947cf45ee535cecd
Example:
http://gyazo.com/c23fec3fabb7e4504c42453980fbc372
When I press the edit button , they able to retrieve the data however the page show me empty field instead of the field that have old data.
Secondly, unable to undate because they keep send empty id_field back to controller.
p.s. add,edit,delete method work totally fine.
Below are my code:
Model
<?php
App::uses('AppModel', 'Model');
class EventDate extends AppModel {
public $useTable = 'eventdate';
public $primaryKey = 'eventDate_id';
public $validate = array(
'event_date' => array(
'rule' => array('date','ymd'),
'message' => 'Enter a valid date in YY-MM-DD format.',
'required' => true,
'allowEmpty' => false
)
);
}
Controller
public function edit($id = null) {
//Retrieve from database
$post = $this->EventDate->findByEventdateId($id);
$this->set('edate', $post) ;
// debug($post);
//Without Id
if (!$id) {
throw new NotFoundException(__('Invalid Event Date'));
}
//If Not Exist the id
if (!$post) {
throw new NotFoundException(__('Invalid Event Date'));
}
//After press the submit
if ($this->request->is(array('post','put'))) {
$this->EventDate->eventDate_id = $id;
debug($_POST);
if ($this->EventDate->save($this->request->data)) {
$this->Session->setFlash(__('The Event has been saved.'));
return $this->redirect(array('action' => 'index'));}
else
{$this->Session->setFlash(__('The Event could not be saved. Please, try again.'));}
}
//Set the data same as retrieved
if (!$this->request->data) { $this->request->data = $post;}
}
edit.ctp
<h2>Edit Event</h2>
<?php
echo $this->Form->create('eventdate');
//echo $this->Form->input('eventDate_id', array('type' => 'hidden'));
echo $this->Form->hidden('eventDate_id');
echo $this->Form->input('event_date',array(
'label' => 'Event Date',
'type' => 'text',
'id' => 'datepicker'));
echo $this->Form->end('Save Post');
?>
Below link is the debug($_Post) been shown:
http://gyazo.com/5e569e6cc6b3026fc8896c315197a938
Should be:
echo $this->Form->create('EventDate'); // notice the capital CamelCase
Side note: The info that displays in the fields will be out-of-date, since you 1) get the data from the DB and set to var, THEN do the save based on posted data.
Another side note: There are quite a few things that you're doing that are non-standard and not consistent w/ the recommended conventions. Cleaning that up will make it easier to work with AND easier to receive help.

How to write an approve action in cakephp

i want to create an simple application that will allow graduating students to register for graduation attendance. From the application form the student enter the details that's saved to the students table waiting for approval. The admin then approves the request and the record is inserted in the approved table and deleted from the students table. How can i write the approve action and how can i move the record to the approved table in cakephp 2.6.3.
thanks in advance
I would use one and same table to save this data. Use the table students. Add a approved column to the table where 0 = not approved, 1 = approved. When students are entering their data and saves it to students table, make sure approved = 0. Then admin can go change this value to 1 if student is approved.
// StudentsController.php
public function approve($id = null) {
if (!$this->Student->exists($id)) {
throw new NotFoundException(__('Invalid'));
}
if ($this->request->is(array('post', 'put'))) {
if ($this->Student->save($this->request->data)) {
$this->Session->setFlash(__('The student has been saved.'), 'default', array('class' => 'notice success'));
return $this->redirect(array('action' => 'index'));
} else {
$this->Session->setFlash(__('The student could not be saved. Please, try again.'), 'default', array('class' => 'notice error'));
}
} else {
$options = array('conditions' => array('Student.' . $this->Student->primaryKey => $id));
$this->request->data = $this->Student->find('first', $options);
}
}
app/View/Students/approve.ctp:
<h1><?php echo __('Approve student');?></h1>
<?php echo $this->Form->create('Student'); ?>
<?php
echo $this->Form->input('id');
echo $this->Form->input('approved', array('label' => __('Approve'), 'options' => array(
'0' => __('Not approved'),
'1' => __('Approved'),
)));
?>
<?php echo $this->Form->end(array('label' => __('Save'), 'class' => 'button')); ?>
Sorry for not answering your exact question, but I really think it is unnecessary to use two tables to identify who are not approved vs approved students.

Cakephp: combine input values to create hidden name input

I've searched high and low for a solution but can't seem to get this figured out. What I'm trying to do is upon adding a product, I want the name field to be populated from the inputs in the form. So the name would include the values the user selects for type_id,category_id and subcategory_id. Does anyone know of a way to accomplish this?
Add product View page
<fieldset>
<legend><?php echo __('Add Product'); ?></legend>
<?php
echo $this->Form->input('type_id');
echo $this->Form->input('category_id', array('label' => 'Vendor'));
echo $this->Form->input('subcategory_id', array('label' => 'Model'));
echo $this->Form->input('location', array('label' => 'Location'));
echo $this->Form->input('sku', array('label' => 'Asset Tag'));
echo $this->Form->input('mac');
echo $this->Form->input('description', array('label' => 'Notes'));
echo $this->Form->input('name', array( 'value' => ['type_id']['category_id'] , 'type' => 'hidden'));
//echo $this->Form->input('cost');
// echo $this->Form->input('Tag');
?>
</fieldset>
Product controller add function
public function add() {
if ($this->request->is('post')) {
$this->Product->create();
if ($this->Product->save($this->request->data)) {
$this->Session->setFlash(__('The product has been saved'));
$this->redirect(array('action' => 'index'));
} else {
$this->Session->setFlash(__('The product could not be saved. Please, try again.'));
}
}
$subcategories = $this->Product->Subcategory->find('list',array('order'=>'Subcategory.name asc'));
$categories = $this->Product->Category->find('list',array('order'=>'Category.name asc'));
$types = $this->Product->Type->find('list',array('order'=>'Type.name asc'));
$this->set(compact('subcategories', 'categories', 'types'));
}
In order to do it the way you are trying to do it, you would have to use client-side javascript to update the input value "on-the-fly", but that's not very safe and can easily be messed with. It would make much more sense to drop the name input altogether and just handle this in the beforeSave method of your Product model (or alternatively by defining the name value in your Controller just before saving).
public function beforeSave($options = array()) {
// Generate the name based on type and category
$this->data['Product']['name'] = $this->data['Product']['type_id'] .
$this->data['Product']['category_id'];
return true;
}
Update based on your comment.
In order to get the names, just find those names (assuming your models are associated) and define those:
public function beforeSave($options = array()) {
// Get the type name
$type = $this->Type->field('name', array(
// Set the condition for the field
'Type.id' => $this->data['Product']['type_id']
));
// Get the category name
$category = $this->Category->field('name', array(
// Set the condition for the field
'Category.id' => $this->data['Product']['category_id']
));
// Generate the name based on type and category
$this->data['Product']['name'] = $type . $category;
return true;
}

CakePHP - add item to 2 models

How can I add an item and insert it into 2 tables?
So I have a 'Type' table and 'SpecificType' table.
Type has fields 'id' and some other common fields.
SpecificType has fields 'id', 'type_id' and some other uncommon fields.
When I go to /specific_types/add and I submit, ideally I want to first add that to 'Type' then add it to 'SpecificType'.
This is what I have now.
In SpecificType Model
var $belongsTo = array(
'Type' => array(
'className' => 'Type',
'foreignKey' => 'type_id',
'conditions' => '',
'fields' => '',
'order' => ''
)
);
In SpecificType Controller
var $uses = ('Type', 'SpecificType');
function add() {
if (!empty($this->data)) {
$this->Type->create();
if ($this->Type->save($this->data)) {
$this->SpecificType->create();
if ($this->SpecificType->save($this->data)) {
$this->Session->setFlash(__('The SpecificType has been saved', true));
$this->redirect(array('action' => 'index'));
} else {
$this->Session->setFlash(__('The SpecificType could not be saved. Please, try again.', true));
}
} else {
$this->Session->setFlash(__('The Type could not be saved. Please, try again.', true));
}
}
}
In SpecificType add.ctp
echo $form->input('Type.data1');
echo $form->input('title');
So right now, it saves Type.data1 but title isn't getting saved.
What am I missing?
Thanks,
Tee
Additional Info:
The 2nd model isn't saving only when I turn on MeioUpload.
Make sure your view is setup to create a form for SpecificType:
<?php echo $this->Form->create('SpecificType', array('action' => 'add')); ?>
<?php echo $this->Form->input('data1'); ?>
<?php echo $this->Form->input('title'); ?>
<?php echo $this->Form->end(); ?>
This will put all of your form data into: $this->data['SpecificType']
Right before your code:
$this->Type->create();
You need to do this:
$this->data['Type'] = $this->date['SpecificType'];
Then process the save. As long as the view is setup correctly for the SpecificType controller, all of the data from the form will be stored in $this->data['SpecificType']. If you pr($this->data) and there is data you need to save outside of $this->data['SpecificType'], review and fix the view.
Side note: Your design sounds awfully sketchy. You should never need to save the data in two locations. I would recommend revisiting the design of your app. There is something fundamentally wrong with it if you need to save the same data into two tables.
Just copy the data over to a SpecificType index in the data array and use saveAll(). The models are related so Cake will automatically link them via the type_id. We're working off the Type alias, so make sure you also have var $hasMany = array('SpecificType'); in your Type model.
function add() {
if (!empty($this->data)) {
$this->Type->create();
$this->data['SpecificType'] = $this->data;
if ($this->Type->saveAll($this->data)) {
$this->Session->setFlash(__('The SpecificType has been saved', true));
$this->redirect(array('action' => 'index'));
} else {
$this->Session->setFlash(__('The SpecificType could not be saved. Please, try again.', true));
}
} else {
$this->Session->setFlash(__('The Type could not be saved. Please, try again.', true));
}
}
The code seems to be fine, use saveAll instead of save

Can't delete posts in forum. (CakePHP)

I'm using the Cupcake Forum plugin within CakePHP. There's a form for selecting the desired posts, and then submitting the form to delete the posts. The form data is apparently being sent to the 'moderate' function within the 'topics' controller using POST and GET methods simultaneously. The function first checks to see if the data sent in is POST. However, when the data is received, it shows that it's GET. A fellow programmer and I don't want to completely change someone else's internal code, but we can't figure out how the data is being sent by both methods and being received as GET. The code from the plugin is below:
--------------moderate.ctp (view)---------------------
<?php echo $form->create('Post', array('url' => array('controller' => 'topics', 'action' => 'moderate', $topic['Topic']['slug']))); ?>
-------------topics_controller.php (controller)-------
public function moderate($id) {
if ($this->RequestHandler->isGet()){
$this->log('Is GET!');
}
$user_id = $this->Auth->user('id');
$topic = $this->Topic->getTopicForViewing($id, $user_id, 'id');
// Access
$this->Toolbar->verifyAccess(array(
'exists' => $topic,
'permission' => $topic['ForumCategory']['accessRead'],
'moderate' => $topic['Topic']['forum_category_id']
));
$this->log('ID: '.$id.'\n');
if ($this->RequestHandler->isPost()){
$this->log('Is POST!');
}
if ($this->RequestHandler->isGet()){
$this->log('Is GET!');
}
$this->log($this->RequestHandler->getReferer());
$this->log(serialize($this->data));
// Processing
if ($this->RequestHandler->isPost()) {
$this->log('INSIDE POST!');
if (!empty($this->data['Post']['items'])) {
$items = $this->data['Post']['items'];
$action = $this->data['Post']['action'];
foreach ($items as $post_id) {
$this->log('Action: '.$action.'\n');
$this->log('PostID: '.$post_id.'\n');
if (is_numeric($post_id)) {
if ($action == 'delete') {
$this->Topic->Post->destroy($post_id);
$this->Session->setFlash(sprintf(__d('forum', 'A total of %d post(s) have been permanently deleted', true), count($items)));
}
}
}
}
}
We added the log checks, which show the result of 'Is GET!' in Cake's log file. Since the method is GET, the statement 'if ($this->RequestHandler->isPost())' is never true; therefore, the submitted posts aren't deleted. What are we missing?
Try changing moderate.ctp to
<?php
echo $form->create('Post', array(
'url' => array(
'controller' => 'topics',
'action' => 'moderate',
$topic['Topic']['slug'],
),
'type' => 'post',
));
?>

Resources