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.
Related
I am trying to save associated data in Cakephp 2.0, in the database I have two tables, table entities (id, main_name) and adresses(id, entity_id, city)
In the Entities model I made the association:
public $hasMany = array(
'Address' => array(
'className' => 'Address',
'foreignKey' => 'entity_id'
)
);
In the AdressesController I saved with the following data:
public function add() {
if ($this->request->is('post')) {
if($this->Entity->save($this->request->data)) {
$this->Flash->success('Entity successfully registered!');
$this->redirect(array('action' => 'add'));
} else {
$this->Flash->error(Oops, we could not register this entity!
Make sure it already exists.');
}
}
}
And in the view, my form looks like this:
<?php
echo $this->Form->input(
'Entity.main_name',
array(
'type' => 'text',
'class' => 'form-control',
'label' => false
)
);
?>
<?php
echo $this->Form->input(
'Address.city',
array(
'type' => 'text',
'class' => 'form-control',
'label' => false
)
);
?>
The data of the entity normally saved in the database, but does not relate the entity_id and does not save the city in the adresses table, do I have to do anything else in the controller?
There are several ways of solving your problem. Like described in CakeBook: Saving your data you can use saveAssociated() or Save each Model step by step.
Saving using saveAssociated()
In your Controller/EntitiesController.php:
public function add() {
if ($this->request->is('post')) {
$this->Entity->create();
// Use saveAssociated() instead of save() here
if ($this->Entity->saveAssociated($this->request->data)) {
$this->Flash->success(__('The entity has been saved.'));
return $this->redirect(array('action' => 'index'));
} else {
$this->Flash->error(__('The entity could not be saved. Please, try again.'));
}
}
$addresses = $this->Entity->Address->find('all');
$this->set($addresses);
}
In your View/Entities/add.ctp:
<?php
echo $this->Form->input('main_name', array(
'type' => 'text',
'class' => 'form-control',
'label' => false
));
// Make sure you use Address.0.city
echo $this->Form->input('Address.0.city', array(
'type' => 'text',
'class' => 'form-control',
'label' => false
));
?>
Since you use a hasMany Association a Entity can have several Addresses. For this reason you have to set the 0 in Address.0.city. This will result in a data array like this:
array(
'Entity' => array(
'main_name' => 'Fancy Name'
),
'Address' => array(
(int) 0 => array(
'city' => 'Cool City'
)
)
)
Saving Models step by step
Another approach would be to save the Entity and then save the Address with the entity_id like described in CakeBook:
In your Controller/EntitiesController.php:
public function add() {
if (!empty($this->request->data)) {
// save Entity
$entity = $this->Entity->save($this->request->data);
if (!empty($entity)) {
// Set the EntityId to the data array and save the Address with the EntityId
$this->request->data['Address']['entity_id'] = $this->Entity->id;
$this->Entity->Address->save($this->request->data);
}
}
}
In this case your View/Entities/add.ctp Address form would look like:
echo $this->Form->input('Address.city', array(
'type' => 'text',
'class' => 'form-control',
'label' => false
));
Best, variables
So, I'm trying to make an authentication in CakePHP that is using email instead of username, which field I don't even have in my users table in database. first i was trying to google that, and i already have tried these:
Cakephp 2.0 Authentication using email instead of username
Using email instead of username in CakePHP Auth Component
and few others, but nothing seems to work - still i get the "incorrect data" error. below is my code
AppController.php
class AppController extends Controller {
public $components = array(
'Session',
'Auth' => array(
'userModel' => 'User',
'loginRedirect' => array(
'controller' => 'pages',
'action' => 'display'
),
'logoutRedirect' => array(
'controller' => 'pages',
'action' => 'display',
'home'
),
'authenticate' => array(
'Form' => array(
'fields' => array(
'username' => 'email',
'password' => 'password'
),
'passwordHasher' => 'Blowfish'
)
)
)
);
public function beforeFilter(){
$this->Auth->allow('index', 'view');
}
UsersController.php
public function add() {
if ($this->request->is('post')) {
$this->User->create();
$this->request->data['User']['role'] = "user";
if(strcmp($this->request->data['User']['password'], $this->request->data['User']['repeat']) == 0){
if ($this->User->save($this->request->data)) {
$this->Session->setFlash(__('Użytkownik zarejestrowany.'));
return $this->redirect(array('controller' => 'Pages', 'action' => 'display'));
}
else $this->Session->setFlash(__('Wystąpił błąd, spróbuj ponownie.'));
}
else $this->Session->setFlash(__('Wpisane hasła się nie zgadzają'));
}
}
public function login(){
if($this->request->is('post')){
if($this->Auth->login()){
return $this->redirect($this->Auth->redirectUrl());
}
$this->Session->setFlash(__('Nieprawidłowe dane, spróbuj ponownie'.$this->Auth->login()));
}
}
login.ctp
<div class="users form">
<?php echo $this->Session->flash('auth'); ?>
<?php echo $this->Form->create('User'); ?>
<fieldset>
<legend>
<?php echo __('Zaloguj się'); ?>
</legend>
<?php
echo $this->Form->input('email' /*I also tried with username instead of email here*/, array('label' => 'Email'));
echo $this->Form->input('password', array('label' => 'Hasło'));
?>
</fieldset>
<?php echo $this->Form->end(__('Zaloguj')); ?>
</div>
EDIT: Here is 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' => 'Email jest wymagany'
)
),
'password' => array(
'required' => array(
'rule' => array('notEmpty'),
'message' => 'Hasło jest wymagane'
)
),
'repeat' => array(
'required' => array(
'rule' => array('notEmpty'),
'message' => 'Powtórz hasło'
)
),
'identicalFieldValues' => array(
'rule' => 'identicalFieldValues',
'message' => 'Wpisane hasła się nie zgadzają'
)
);
public function identicalFieldValues(){
return $this->data['User']['password'] === $this->data['User']['repeat'];
}
public function beforeSave($options = array()){
if(isset($this->data[$this->alias]['password'])){
$passwordHasher = new BlowfishPasswordHasher();
$this->data[$this->alias]['password'] = $passwordHasher->hash(
$this->data[$this->alias]['password']
);
}
return true;
}
}
2nd EDIT: I read that the problem can be in size of the varchar in sql, so I changed it from 50 to 130, deleted users, made a new one, but still I cannot log in.
3rd EDIT: I made a completly new, clean cake project, without password hashing, but still with login via email and still im getting "incorrect data" -.-
I cant seem to figure out why my form is not applying validation defined in my model. Any assistance?
\app\View\Enquiries\view.ctp:
<?php
echo $this->Form->create('Enquiry', array('action'=>'email','novalidate' => true));
echo $this->Form->input('message', array ('type' => 'textarea', 'class'=>'form-control'));
echo $this->Form->hidden('email', array ('value'=> $enquiry['Enquiry']['email']));
?>
\app\Model\Enquiry.php
<?php
App::uses('AppModel', 'Model');
class Enquiry extends AppModel {
public $actsAs = array('Acl' => array('type' => 'requester'));
public function parentNode() {
return null;
}
public $validate = array(
'message' => array(
'notEmpty' => array(
'rule' => array('notEmpty'),
'message' => 'Please enter your enquiry',
'allowEmpty' => false,
)
),
);
public $belongsTo = array(
'User' => array(
'className' => 'User',
'foreignKey' => 'user_id',
'conditions' => '',
'fields' => '',
'order' => ''
)
);
}
\app\Controller\EnquiriesController.php
<?php
App::uses('AppController', 'Controller', 'Network/Email');
class EnquiriesController extends AppController {
public $helpers = array('GoogleMap','Html','Form','Session'); //Adding the helper
public $components = array('Paginator','Email','Session');
public function email($id, $dest=null){
if ($this->request->data) {
//Admin reply enquiry email
$Email = new CakeEmail('default');
$Email->config('default');
$Email->template('replyenq');
$Email->from(array('xxxx#gmail' => 'xxxx'))
->to($this->request->data['Enquiry']['email'])
->subject('xxxx has sent you a reply!')
->send();
//after sending, display a notification
$this->Session->setFlash(__('Reply enquiry has been successful.' , true), 'alert-box', array('class'=>'alert-success'));
//Redirect after email has been successful
return $this->redirect(array('action' => '../enquiries'));
}
else {
$this->Session->setFlash(__('Message was empty. Please ensure you enter a message'), 'alert-box', array('class'=>'alert-warning'));
return $this->redirect(array('action' => '../enquiries/view/'.$id));
}
}
}
Data is only normally validated when calling the save() method of a model. Your controller takes the submitted data and puts it straight into an e-mail so there is no interaction with the Enquiry model.
You will need to manually call $this->Enquiry->validates() from the controller and add logic to deal with the result.
See also: Validating Data from the Controller
I am making a PHP forum with CakePHP I am troubles with getting an array of all the members then echoing them in a view, here is my code.
<?php
App::uses('AppModel', 'Model');
class Member extends AppModel {
public $validate = array(
'username' => array(
'notEmpty' => array(
'rule' => array('notEmpty')
),
),
'password' => array(
'notEmpty' => array(
'rule' => array('notEmpty')
),
),
'email' => array(
'email' => array(
'rule' => array('email')
),
),
);
public $hasMany = array(
'Post' => array(
'className' => 'Post',
'foreignKey' => 'user_id',
'dependent' => false,
'conditions' => '',
'fields' => '',
'order' => '',
'limit' => '',
'offset' => '',
'exclusive' => '',
'finderQuery' => '',
'counterQuery' => ''
),
'Topic' => array(
'className' => 'Topic',
'foreignKey' => 'user_id',
'dependent' => false,
'conditions' => '',
'fields' => '',
'order' => '',
'limit' => '',
'offset' => '',
'exclusive' => '',
'finderQuery' => '',
'counterQuery' => ''
)
);
}
That is my member model here is my MembersController
<?php
App::uses('Controller', 'AppController');
class MembersController extends AppController {
public $components = array('Paginator');
public function beforeFilter() {
parent::beforeFilter();
$this->Auth->allow('profile','login');
}
public function index(){
$this->Paginator->settings['contain'] = array('Member');
$this->set('members', $this->Paginator->paginate());
}
public function profile($id=null) {}
public function login() {
if($this->request->is('post')) {
if ($this->Auth->login()) {
$this->redirect($this->Auth->redirect());
} else {
$this->Session->setFlash(__('Invalid username or password'));
}
}
}
public function logout() {
$this->redirect($this->Auth->logout());
}
}
And here is my Index view
<div class="row">
<?php foreach ($members as $member): ?>
<?php echo $user[name]; ?>
<?php endforeach; ?>
</div>
When I access example.com/members I get an error saying Model "Member" is not associated with model "Member" [CORE/Cake/Model/Behavior/ContainableBehavior.php, line 342]
Before you ask I have made AppModels actas Containable
class AppModel extends Model {
public $actsAs = array('Containable');
}
Remove that line:
$this->Paginator->settings['contain'] = array('Member');
You're causing a self-join by using this and you haven't defined that in your members model and you dont want that.
This is wrong as well plus your php has a syntax error - missing ' around the name.
<?php foreach ($members as $member): ?>
<?php echo $user[name]; ?>
<?php endforeach; ?>
It should be:
<?php foreach ($members as $member): ?>
<?php echo $member['Member']['name']; ?>
<?php endforeach; ?>
You're struggling with the very basics, I would recommend you to do the blog tutorial or at least read about how data is passed to the view and how model associations work. You can find everything in the book.
Your problem is here:
public function index(){
$this->Paginator->settings['contain'] = array('Member');
$this->set('members', $this->Paginator->paginate());
}
Since paginate is being called from the members controller, it will by default try to paginate Member. Your contain setting is indicating the Member data should also contain the associated model, also named Member. You have no association between Member and itself, hence the error. I'm going to assume that contain setting was a mistake, so simply remove the line $this->Paginator->settings['contain'] = array('Member');
$this->Paginator->settings['contain'] = array('Member'); is your problem. Since the setting are going to be passed as options to find() call on Member model you are effectively asking Member to contain itself. Set 'contain' to array() to prevent any associated records from being fetched.
Though the recommended way it to set property $recursive to -1 in AppModel so that by default no associated records are fetched. Containable is then used to fetch associated records as required.
WHen i have an input field with the multiple options concerning 'customer_id' the data request generated is
$request->data containing array(CompanysCustomer => array('id' => '1', 'uid' => 'fhs32hrqwr8wfsdiof', 'customer_id' => array('0' => '5', '1' => '8', '2' => '9')).
I dont undestand how to use or make use of this array. It Works well when i dont use multiple, because then i dont get array at 'customer_id'. I have an idea to manipulate the array and list them out ond do the save pr foreach, but that seems unefficient, it has to be some other way?
And im having trouble saving this to the db. I managed to make it when i have one single record to save. I cant make it save many records at once.
Version 2.4.1
public function add($id) {
if ($this->request->is('post')) {
$this->CompanysCustomer->create();
if ($this->CompanysCustomer->save($this->request->data)){
$this->Session->setFlash(__('The Companys Customer has been saved.'));
return $this->redirect(array('action' => 'index'));
}
else{
$this->Session->setFlash(__('The Companys Customer could not be saved. Please, try again.'));}
}
$customers = $this->CompanysCustomer->Customer->find('list');
$this->set(compact('customers'));
}
Model CompanysCustomer
<?php
App::uses('AppModel', 'Model');
/**
* CompanysCustomer Model
*/
class CompanysCustomer extends AppModel {
//The Associations below have been created with all possible keys, those that are not needed can be removed
/**
* belongsTo associations
*
* #var array
*/
public $belongsTo = array(
'Company' => array(
'className' => 'Company',
'foreignKey' => 'company_id',
'conditions' => '',
'fields' => '',
'order' => ''
),
'Customer' => array(
'className' => 'Customer',
'foreignKey' => 'customer_id',
'conditions' => '',
'fields' => '',
'order' => ''
)
);
}
View: CompanyCustomer\add.ctp
<div class="companysCustomers form">
<?php echo $this->Form->create('CompanysCustomer'); ?>
<fieldset>
<legend><?php echo __('Add Companys Customer'); ?></legend>
<?php
$company_id = $id;
echo $this->Form->input('company_id', array(
'type' => 'hidden',
'value' => $id,
));
$uid = uniqid("", $more_entropy = true);
echo $this->Form->input('uid', array(
'type' => 'hidden',
'value' => $uid,
));
//echo $this->Form->input('company_id');
echo $this->Form->input('customer_id',array('type' => 'select', 'multiple' => 'checkbox','size' => '20'));
?>
</fieldset>
<?php echo $this->Form->end(__('Submit')); ?>
</div>
Reading the documentation helps
http://book.cakephp.org/2.0/en/core-libraries/helpers/form.html#FormHelper::select
'multiple' => true
for example.
For saving use
saveMany()