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

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.

Related

CakePHP Model validation not working properly

I am new to CakePHP and have created a normal form to submit first name.
My table name is "registers. I have created a controller named RegistersController (RegistersController.php) and a model named Register (Register.php) . Each time i submit after entering first name, it still displays error (First name is must) which it should only if i submit it without entering anything. Next i added validation for having minimum 6 characters. That validation is also not working. I mean, cakephp is not validating that rule. Could anyone please tell me where i have done anything wrong?
Model:-
class Register extends AppModel {
//put your code here
//public $useTable = "registers";
public $validate = array(
'first'=>array(
'minLength' => array(
'rule' => array('minlength','6'),
'field' => 'first',
'message' => 'Minimum 6 characters required'
),
'required' => array(
'rule'=>array('notEmpty'),
'required' => true,
'message' => array('First name is must')
)
)
);
}
Controller:-
class RegistersController extends AppController {
public $uses = array("Register");
//put your code here
public function index() {
if($this->request->is('post')){
//echo "Data";
if($this->Register->validates()){
//$this->Register->create();
//echo "Data validated";
print_r($this->Register->validationErrors);
}else{
//echo "Data not validated";
print_r($this->Register->validationErrors);
}
}
}
My view is as follows:-
<?php
echo $this->Form->create('Register');
echo $this->Form->input('first');
echo $this->Form->end("Submit");
?>
You are missing this line
$this->Register->set($this->request->data);
Put it before the validation call, i.e.
$this->Register->validates()

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;
}

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);

cakephp file notempty validation - bug?

How to get an input type file to validate for notempty in cake?
When you submit the form without adding a file the validation says it is empty even though $this->request->data shows the file.
// Model/Product.php
class Product extends AppModel {
public $validate = array(
'name' => array(
'rule' => 'notEmpty'
),
);
}
// Controller/ProductController.php
public function add() {
if ($this->request->is('post')) {
$this->Product->create();
if ($this->Product->save($this->request->data)) {
$this->Session->setFlash('Your product has been saved.');
} else {
$this->Session->setFlash('Unable to add your product.');
debug($this->request->data);
debug($this->Product->validationErrors);
}
}
}
// View/Products/add.ctp
echo $this->Form->create('Product', array('type' => 'file'));
echo $this->Form->input('name', array('type' => 'file'));
echo $this->Form->end('Save Post');
I don't think that you can actually use notEmpty on the -somewhat special- file field. The file field is handled differently than any other input field, as it returns the superglobal $_FILES as a result. As such, you should check it a little bit differently. There is actually quite a good example in the CakePHP Documentation.
Now this is for actually uploaded files, but you can easily change it by checking if the name key is not empty and actually set. Something like this as a custom validation rule in your Model should do the trick:
public function fileSelected($file) {
return (is_array($file) && array_key_exists('name', $file) && !empty($file['name']));
}
And then just set this as validation rule for your file field:
public $validate = array(
'name' => array(
'rule' => 'fileSelected'
),
);

CakePHP password validation in edit form

I'm using a simple registration form for CakePHP.
This is my edit view:
<h2>Add User</h2>
<?php echo $form->create('User');
echo $form->input('first_name');
echo $form->input('last_name');
echo $form->input('email');
echo $form->input('address');
echo $form->input('phone');
echo $form->end('Edit');?>
These are my validation rules in User.php
class User extends AppModel {
var $name = 'User';
var $validate = array(
(... more rules here ...)
'password' => array('rule' => array('confirmPassword', 'password'),
'message' => 'Passwords do not match'),
'password_confirm' => array('rule' => 'alphanumeric',
'required' => true)
);
It's a stupid question, but when I use the edit form, the saving of the data fails, because I require a password input in the last rule. That rule was added for the register page, of course.
I've found billions of ways to bypass this problem (disable validation on saving, selecting which fields to save, ...), but I wonder what the "correct" CakePHP way of doing this is? Seems like such a simple problem, but I can't find any documentation on how it has to be done the clean way.
To make my question more clear: I don't want an edit user page where passwords can be changed.
the Cake way is to simply set the validation rule to apply only on create, allowing you to freely edit your data without having to validate the field again.
var $validate = array(
'fieldName' => array(
'rule' => 'ruleName'
'required' => true,
'allowEmpty' => false,
'on' => 'create', // or update <-- here
'message' => 'Your Error Message'
)
);
And of course, if you don't want the password field edited here, just remove the appropriate input
I use multiple validation sets:
In your model, or app_model, override the validates function with this:
function validates($options = array()) {
// copy the data over from a custom var, otherwise
$actionSet = 'validate' . Inflector::camelize(Router::getParam('action'));
if (isset($this->validationSet)) {
$temp = $this->validate;
$param = 'validate' . $this->validationSet;
$this->validate = $this->{$param};
} elseif (isset($this->{$actionSet})) {
$temp = $this->validate;
$param = $actionSet;
$this->validate = $this->{$param};
}
$errors = $this->invalidFields($options);
// copy it back
if (isset($temp)) {
$this->validate = $temp;
unset($this->validationSet);
}
if (is_array($errors)) {
return count($errors) === 0;
}
return $errors;
}
In your controller:
class UsersController extends AppController {
function forgot() {
$this->User->set($this->data);
$this->User->validationSet = 'forgotpassword';
if ($this->User->validates()) {
// send email to reset password and show success message
}
}
}
And finally back in your model, build a validation array, you can have your default validation array, then add a supplemental array such as
class User extends AppModel {
var $validate = array( ... );
var $validateForgotpassword = array( ... );
}
More details here:
http://snook.ca/archives/cakephp/multiple_validation_sets_cakephp
(note the code sample in the article has a bug in it, so be sure to change $param = 'validate' . $validationSet; to $param = 'validate' . $this->validationSet;)
remove your 'required' => true, it is not doing what you think its doing.
'required' => true means that the field should be present in any data that is saved. you are not passing it.

Resources