I have a very simple model User, and it's associated table users with fields 'id', 'username', 'password', 'role', 'created', 'modified'.
The view add.ctp contains:
<div class="users form">
<?= $this->Form->create('user'); ?>
<fieldset>
<legend><?= __('Add user');?></legend>
<?= $this->Form->input('user.username'); ?>
<?= $this->Form->input('password'); ?>
<?= $this->Form->input('role', array('options' => array('admin' => 'Admin', 'customer' => 'Customer'))); ?>
</fieldset>
<?= $this->Form->end(__('Submit')); ?>
</div>
The model is set up according to http://book.cakephp.org/2.0/en/tutorials-and-examples/blog-auth-example/auth.html:
class User extends AppModel {
public $validate = array(
'username' => array(
'required' => array(
'rule' => array('notEmpty'),
'message' => 'You must specify a username'
)
),
'password' => array(
'required' => array(
'rule' => array('notEmpty'),
'message' => 'You must specify a password'
)
),
'role' => array(
'valid' => array(
'rule' => array('inList', array('admin','customer')),
'message' => 'You must specify a valid role',
'allowEmpty'=> false
)
)
);
}
And lastly, the controller simply has:
public function add() {
if($this->request->is('post')) {
$this->User->create();
if ($this->User->save($this->request->data)) {
$this->set('stuff', $this->User->data);
$this->Session->setFlash(__('The user has been saved.'));
//return $this->redirect(array('action' => 'index'));
} else {
$this->Session->setFlash(__('The user could not be saved. Please try again.'));
}
}
}
I've commented out the redirect on success to be able to show the INSERT query on submit (if I allow the redirect, the only query being shown is SELECT's)
So, quite simple, the problem is, when the form is submitted, it generates this query:
INSERT INTO `mytable`.`users` (`modified`, `created`) VALUES ('2014-02-21 13:03:11', '2014-02-21 13:03:11')
How can I determine why it won't insert the submitted fields? And how can I make it?
use this <?= $this->Form->create('User'); ?> instead of <?= $this->Form->create('user'); ?>
and use this <?= $this->Form->input('User.username'); ?> instead of <?= $this->Form->input('user.username'); ?>
CakePHP is case sensitive model name must be in CamalCase
Related
I'm going through the CakePHP tutorial and trying to test basic login functionality. I'm making slight tweaks along the way to match how my database needs to look (email and token instead of username and password as columns in the users table), I believe that I have messed something up when it comes to using Blowfish hashing. Can someone take a look and see if anything apparent pops out? Right now I can add new users, but their password in the database look to be plaintext. The token column is of type VARCHAR(75), is that enough space for Blowfish to work?
I'm getting the error:
**Warning (512): Invalid salt: pass for blowfish **
and then "Invalid username or password," when putting in a correct user/pass combo. When I put in incorrect credentials I only get the invalid user/pass error, so it looks like it is still getting through somewhere along the line.
app/Model/User.php
App::uses('AppModel', 'Model');
App::uses('BlowfishPasswordHasher', 'Controller/Component/Auth');
class User extends AppModel {
public $validate = array(
'email' => array(
'required' => array(
'rule' => array('notEmpty'),
'message' => 'An email is required'
)
),
'token' => array(
'required' => array(
'rule' => array('notEmpty'),
'message' => 'A password is required'
)
),
'group' => array(
'valid' => array(
'rule' => array('inList', array('user', 'admin', 'manager')),
'message' => 'Please enter a valid group role',
'allowEmpty' => false
)
)
);
public function beforeSave($options = array()) {
if (isset($this->data[$this->alias]['token'])) {
$passwordHasher = new BlowfishPasswordHasher();
$this->data[$this->alias]['token'] = $passwordHasher->hash(
$this->data[$this->alias]['token']
);
}
return true;
}
}
app/Controller/AppController.php
class AppController extends Controller {
//...
public $components = array(
'Session',
'Auth' => array(
'loginRedirect' => array(
'controller' => 'posts',
'action' => 'index'
),
'logoutRedirect' => array(
'controller' => 'pages',
'action' => 'display',
'home'
),
'authenticate' => array(
'Form' => array(
'passwordHasher' => 'Blowfish',
'fields' => array('username' => 'email', 'password' => 'token')
)
)
)
);
public function beforeFilter() {
$this->Auth->allow('index', 'view');
}
//...
}
add.ctp
<div class="users form">
<?php echo $this->Form->create('User'); ?>
<fieldset>
<legend><?php echo __('Add User'); ?></legend>
<?php echo $this->Form->input('email');
echo $this->Form->input('token');
echo $this->Form->input('group', array(
'options' => array('admin' => 'Admin', 'manager' => 'Manager', 'user' => 'User')
));
?>
</fieldset>
<?php echo $this->Form->end(__('Submit')); ?>
</div>
login.ctp
<div class="users form">
<?php echo $this->Session->flash('auth'); ?>
<?php echo $this->Form->create('User'); ?>
<fieldset>
<legend>
<?php echo __('Please enter your username and password'); ?>
</legend>
<?php echo $this->Form->input('email');
echo $this->Form->input('token');
?>
</fieldset>
<?php echo $this->Form->end(__('Login')); ?>
</div>
Check the blowfish salt to make sure it has the correct number of characters, and use the add / edit form to set the password initally.
You should also set the token length in the db to 256 chars
I'm new to CakePHP and I'm trying to implement the Simple Acl Controlled Application tutorial, and I've reached the part where you try to add new users and groups..
I successfully added the groups but when i try and add new users I receive the "The user could not be saved. Please, try again." Part of the function.
public function add() {
if ($this->request->is('post')) {
$this->User->create();
if ($this->User->save($this->request->data)) {
$this->Session->setFlash(__('The user has been saved'));
$this->redirect(array('action' => 'index'));
} else {
$this->Session->setFlash(__('The user could not be saved. Please, try again.'));
}
}
}
I noticed that the form tries to create a drop down box of all the different groups that I created but the drop box is empty and I have created three different groups (Admin, Responder and Volunteer).
Here is a copy of the add user view..
<div class="users form">
<?php echo $this->Form->create('User'); ?>
<fieldset>
<legend><?php echo __('Add User'); ?></legend>
<?php
echo $this->Form->input('id');
echo $this->Form->input('username');
echo $this->Form->input('password');
echo $this->Form->input('group_id');
?>
</fieldset>
<?php echo $this->Form->end(__('Submit')); ?>
</div>
<div class="actions">
<h3><?php echo __('Actions'); ?></h3>
<ul>
<li><?php echo $this->Html->link(__('List Users'), array('action' => 'index')); ?></li>
</ul>
</div>
Model as requested:
<?php
App::uses('AppModel', 'Model');
App::uses('AuthComponent', 'Controller/Component');
class User extends AppModel {
public $belongsTo = array('Group');
public $actsAs = array('Acl' => array('type' => 'requester'));
public function parentNode() {
if (!$this->id && empty($this->data)) {
return null;
}
if (isset($this->data['User']['group_id'])) {
$groupId = $this->data['User']['group_id'];
} else {
$groupId = $this->field('group_id');
}
if (!$groupId) {
return null;
} else {
return array('Group' => array('id' => $groupId));
}
}
public $primaryKey = 'id';
public $validate = array(
'id' => array(
'numeric' => array(
'rule' => array('numeric'),
),
),
'username' => array(
'notempty' => array(
'rule' => array('notempty'),
),
),
'password' => array(
'notempty' => array(
'rule' => array('notempty'),
),
),
'group_id' => array(
'numeric' => array(
'rule' => array('numeric'),
),
),
);
//The Associations below have been created with all possible keys, those that are not needed can be removed
//old belongs to
// public $belongsTo = array(
// 'Group' => array(
// 'className' => 'Group',
// 'foreignKey' => 'group_id',
// 'conditions' => '',
// 'fields' => '',
// 'order' => ''
// )
// );
public $hasMany = array(
'Post' => array(
'className' => 'Post',
'foreignKey' => 'user_id',
'dependent' => false,
'conditions' => '',
'fields' => '',
'order' => '',
'limit' => '',
'offset' => '',
'exclusive' => '',
'finderQuery' => '',
'counterQuery' => ''
)
);
public function beforeSave($options = array()) {
$this->data['User']['password'] = AuthComponent::password($this->data['User']['password']);
return true;
}
}
Debug message:
array(
'User' => array(
'password' => '*****',
'id' => '',
'username' => 'iwanjones'
)
)
Any help would be appreciated.
Thanks
In the form within your view, you create the id field as an input field (although through Cake's automagic it should convert it to a hidden input). When creating a new user, there is no id yet. It will be determined upon saving (creating) the record. In most applications this will be done by the MySQL backend's AUTO_INCREMENT functionality, which picks the first available "free" id.
In case of adding a new user, the id field is therefor not necessary. You only need it when you want to edit an existing user and make sure Cake edits the proper user, by setting it's id.
At this moment you set the id field in your view, but it gets no value, since it's a new user. In your Model you have added a validation rule that requires the id field to be numeric. But, the value is actually empty. You should do two things to get this working:
Drop the echo $this->Form->input('id'); line from the add view.
Remove the validation rule for the id field from your model (it's pretty uncommon to validate your primary key field, as Cake already handles this the proper way).
This should allow for the user to be saved successfully.
I'm writing a contact form and want to add some simple validation routines. The action for this page looks like this:
public function contact() {
$this->loadModel('Contact');
$this->set('pageTitle', 'Contact me');
}
and the Contact model is this:
<?php
class Contact extends AppModel {
public $useTable = false;
public $validate = array(
'name' => array(
'between' => array(
'rule' => array('between', 1, 60),
'message' => 'Between 1 and 60 characters in length'
)
),
'email' => array(
'kosher' => array(
'rule' => 'email',
'message' => 'Please make sure your email is entered correctly'
),
),
'message' => array(
'between' => array(
'rule' => array('between', 1, 65000),
'message' => 'Between 1 and 65000 characters in length'
)
)
);
}
and finally my view page:
<?php echo $this->Form->create('Contact'); ?>
<?php echo $this->Form->input('name'); ?>
<?php echo $this->Form->input('email'); ?>
<?php echo $this->Form->input('message', array('type' => 'textarea')); ?>
<?php echo $this->Form->end(array('label' => 'Send', 'class' => 'btn btn-primary')); ?>
However, when I submit the form with incorrect values the validation routines aren't called and no error messages are shown.
How can I get Cake to validate the form?
In your contact action all you are doing is loading the Contact model. You have to explicitly call the relevant model method to perform validation. Read the manual properly for how to do that.
Look in the documentation for how to insert/update data from a form in the controller. You'll see something like this:
if ($this->request->is('post')) {
if ($this->Contact->save($this->request->data)) {
// handle the success.
} else {
$this->Session->setFlash(__('The Contact could not be saved. Please, try again.'));
}
}
I am new to CakePHP. When I am using Model Field Validations then it is showing error message infront of each required form field. I want to show it in a div at the top of the form. How I can implement it. Thanks in advance.
Here is my Code:
Model:
<?php
class User extends AppModel {
public $validate = array(
'username' => array(
'required' => array(
'rule' => array('notEmpty'),
'message' => 'A username is required'
),
array(
'rule' => array('minLength', 8),
'message' => 'Username must be at least 6 characters long'
)
),
'password' => array(
'required' => array(
'rule' => array('notEmpty'),
'message' => 'A password is required'
)
),
'city' => array(
'required' => array(
'rule' => array('notEmpty'),
'message' => 'A City is required'
)
),
'state' => array(
'required' => array(
'rule' => array('notEmpty'),
'message' => 'A State is required'
)
),
'role' => array(
'valid' => array(
'rule' => array('inList', array('admin', 'author')),
'message' => 'Please enter a valid role',
'allowEmpty' => false
)
)
);
}
UsersController.php
public function add() {
$this->set('states_options', $this->State->find('list', array('fields' =>array('id','name') )));
$this->set('cities_options', array());
if ($this->request->is('post')) {
$this->User->set($this->request->data);
if($this->User->validates())
{
$this->User->create();
if ($this->User->save($this->request->data)) {
$this->Session->setFlash(__('The user has been saved'));
$this->redirect(array('action' => 'index'));
} else {
$this->Session->setFlash(__('The user could not be saved. Please, try again.'));
}
}
else {
$errors = $this->User->validationErrors;
$this->set('ValidateAjay',$errors);
//pr($errors);die;
}
}
}
User View:
<!--<script src="http://code.jquery.com/jquery-1.7.2.js"></script>-->
<script>
$(document).ready(function(){
$('#UserState').change(function(){
var stateid=$(this).val();
$.ajax({
type: "POST",
url: "checkcity",
data:'stateid='+stateid+'&part=checkcity',
success: function(data) {
$("#city_div").html(data);
}
});
});
});
</script>
<div class="users form">
<?php
if(!empty($ValidateAjay)){
pr($ValidateAjay);
}
echo $this->Form->create('User'); ?>
<fieldset>
<legend><?php echo __('Add User'); ?></legend>
<?php
echo $this->Form->input('username');
echo $this->Form->input('password');
echo $this->Form->input('state', array('options' => $states_options , 'empty' => 'Select State' ));
?>
<div id="city_div">
<?php
echo $this->Form->input('city', array('options' => $cities_options, 'empty' => 'Select City' ));
?>
</div>
<?php
echo $this->Form->input('role', array(
'options' => array('admin' => 'Admin', 'author' => 'Author')
));
?>
</fieldset>
<?php echo $this->Form->end(__('Submit')); ?>
</div>
You can get all validation errors from the $this->validationErrors variable on the view. Then feel free to iterate through them and display as you like. They will be organized by model, like so:
array(
'User' => array(
'username' => 'This field cannot be empty.',
'password' => 'This field cannot be empty.'
)
);
Then you can iterate through them on the view and display them as such. This example displays them as an unordered list:
$errors = '';
foreach ($this->validationErrors['User'] as $validationError) {
$errors .= $this->Html->tag('li', $validationError);
}
echo $this->Html->tag('ul', $errors);
Lastly, you can hide the form helper's automatic error messages by hiding them with CSS or setting the FormHelper defaults to not show them.
CSS
.input.error {
display: none;
}
or
in the view
$this->Form->inputDefaults(array(
'error' => false
));
jeremyharris example makes a lot of sense, however if you don't want to manually set loop for every form field, you can try this:
$errors = '';
foreach($this->validationErrors as $assoc) {
foreach ($assoc as $k => $v) {
$errors .= $this->Html->tag('li', $v);
}
}
echo $this->Html->tag('ul', $errors);
So if your validation returns multiple errors, the output will looks like this:
- A username is required
- A password is required
Though this is a very old post, I'd like to answer my solution here as well.
To get Errors of Model Validations, just use the $model->getErrors();. This will return an array of errors with field key.
Example
$errors = $user->getErrors();
How do I show the messages when using the CakePHP validation? As I creating the input fields manually using input() instead using the shorthand form() helper.
e.g. Form:
<?php echo $this->Form->create('User', array('id' => 'loginform', 'type' => 'post',
'url' => array('controller' => 'users', 'action' => 'login'))); ?>
<fieldset id="login">
<ul class="clearfix">
<li id="li-username">
<?php echo $this->Form->input('email', array( 'label' => array('class' => 'placeholder', 'text' => 'Email address or username') )); ?>
</li>
<li id="li-password">
<?php echo $this->Form->input('password', array( 'type' => 'password', 'label' => array('class' => 'placeholder', 'text' => 'Password') )); ?>
<span id="iforgot"><?php echo $this->Html->link('?',
array('controller' => 'users', 'action' => 'forgotpassword'), array('title' => 'Forgot your password?')); ?></span>
</li>
<li id="li-submit">
<button type="submit" title="Log in">Log in ►</button>
</li>
</ul>
</fieldset>
<?php echo $this->Form->end(); ?>
and this is my validation in the user model:
public $validate = array(
'email' => array(
'valid' => array(
'rule' => 'email',
'message' => 'The email is not valid'
),
'required' => array(
'rule' => 'notEmpty',
'message' => 'Please enter an email'
)
)
);
However the validation error messages don't show?
EDIT:
I tested this on my register form at /users/add/ and it works so it seems that the auto validation does not work with the login method???? How do I add validation for the login form then :/
The validation is actually stored in the model object. I'm not entirely sure off-hand how to access the errors, but I think its in $this->User->validationErrors.
Have a look at the model api for more information.
For logging in, use the auth component. If you'd rather not, then just get the user from the db and display an error using $this->Session->SetFlash() if the user doesn't authenticate.
You can show your code login function?
I think in your code that have redirect in-case validate false
If you use $this->redirect() it'll not show validate messages :)
First you check your post data is going to validate function.you can simple check this in your else condition like this :
$this->{$this->modelClass}->set($this->data);
if($this->{$this->modelClass}->validates(){
//Save data in DB
}else{
pr($this->{$this->modelClass}->validationErrors); // This will show your error message
}
You can also show error in your view.ctp file like this
$errors = '';
foreach ($this->validationErrors[$model] as $key => $validationError) {
$errors .= $this->Html->tag('li', $validationError[0]);
}
echo $this->Html->tag('ul', $errors,array('class' => 'error'));