Anonymous user form submission drupal 7 - drupal-7

I have a situation where after doing the basic registration the user is redirected to a page where he needs to fill a small form.
i aim at implementing the hook_user_insert and hook_menu to do something like this
function registration_user_insert(&$edit, $account, $category){
drupal_goto('splan/'.$edit['uid']);
}
function registration_menu() {
$items['splan/%'] = array(
'title' => 'Select a Plan',
'page callback' => 'drupal_get_form',
'page arguments' => array('selectplan_form'),
'access callback' => TRUE,
'type' => MENU_CALLBACK
);
return $items;
}
In selectplan_form i will define my new form and then using the uid i would save data into user table.
Now what is happening is after the basic user registration form is being submitted the redirection to splan/uid is happening but i also get the following error.
You are not authorized to access this page.
Now i have changed permissions to allow anony. users to create and edit webform but still the problem exists.
Please help!!!!!!!!

Try removing 'access callback' => TRUE, and add 'access arguments' => array('access content'), instead.
Perhaps you forgot to clear the cache?

Is it imperative that the form you refer to be filled out AFTER a user registers? If so, its a somewhat tricky situation. Either way, putting a drupal_goto in the user_insert hook will interrupt the registration process. If your form doesn't require the user to be registered first, you should simply alter the registration form to include whatever extra fields you have on your form. To do this, you need to implement a hook_from_alter():
http://api.drupal.org/api/drupal/modules--system--system.api.php/function/hook_form_alter/7

Related

CakePHP 3.5 Auth use multiple tables

I have an Auth process which works fine with one userModel. But not only because of my DB schema I need to have one login method/action which works with multiple models.
So far I've tried everything I was able to think of or find online - for example editing this Cake 1.3 solution into Cake 3 and a few more hints I was able to find.
However, I'm not able to figure it out.
Thank you for any answer.
My AppController component load:
$this->loadComponent('ExtendedAuth', [
'authenticate' => [
'Form' => [
//'userModel' => 'Admins',
'fields' => [
'username' => 'email',
'password' => 'password'
]
]
],
'loginAction' => [
'controller' => 'Admins',
'action' => 'login'
],
// If unauthorized, return them to page they were just on
'unauthorizedRedirect' => $this->referer(),
]);
My ExtendedAuthComponent:
class ExtendedAuthComponent extends AuthComponent
{
function identify($user = null, $conditions = null) {
$models = array('Admins', 'Users');
foreach ($models as $model) {
//$this->userModel = $model; // switch model
parent::setConfig('authenticate', [
AuthComponent::ALL => [
'userModel' => $model
]
]);
$result = parent::identify(); // let cake do its thing
if ($result) {
return $result; // login success
}
}
return null; // login failure
}
}
EDIT1: Description of situation
I have two separate tables (Admins, Users). I need just one login action which tries to use Admins table prior to Users. Because of the application logic I can't combine them to one table with something like 'is_admin' flag. So basically what I need is instead of one specific userModel set in Auth config, I need a set of models. Sounds simple and yet I'm not able to achieve it.
EDIT2: Chosen solution
Based on the answer below, I decided to update my schema. Auth users table is just simplified table with login credentials and role and other role-specific fields are then in separate tables which are used as a connection for other role-specific tables. Even though the answer is not exactly a solution for the asked question, it made me think more about any possible changes of the schema and I found this solution because of it so I'm marking it as a solution. I appreciate all comments as well.
As Mark already said in a comment: Don't use two users tables. Add a type field or role or whatever else and associated data in separate tables if it's different like admin_profiles and user_profiles.
Don't extend the Auth component. I wouldn't recommend to use it anymore any way because it's going to get deprecated in the upcoming 3.7 / 4.0 release. Use the new official authentication and authorization plugins instead.
If you insist on the rocky path and want to make your life harder, well go for it but then you should still not extend the auth component but instead write a custom authentication adapter. This is the right place to implement your custom 2-table-weirdness. Read this section of the manual on how to do it.

How to pull data for and display an Association as a multiple-select checkbox in CakePHP 3?

I'm setting up a user access model with Roles in a separate table, and linked to Users by a UserRoles table.
I currently have the following in Model/Table/UsersTable.php:
$this->belongsToMany('Roles', [
'through' => 'UserRoles'
]);
and the following in Model/Table/RolesTable.php:
$this->belongsToMany('Users', [
'through' => 'UserRoles'
]);
and the following in Model/Table/UserRolesTable.php:
$this->belongsTo('Users', [
'foreignKey' => 'user_id'
]);
$this->belongsTo('Roles', [
'foreignKey' => 'role_id'
]);
I have 3 different roles created, 'viewer', 'creator', and 'administrator'. I've successfully set privileges based on user types. Where I am getting stuck is adding roles to a user via an association form.
Right now I have given Administrator users the ability to edit user information. This works for basic information that I have in the Users table, but I can't figure out how to set up the form field for the associated Role. I would like it to be a checkbox where the Administrator can select each privilege for the user.
I'm currently doing this, which is not giving me what I want:
echo $this->Form->input('Users.role', ['type' => 'checkbox']);
This is giving me a single checkbox with the label "Role". I want to pull each row from my Roles table and list them all as options.
I have a few questions relating to this:
1) This seems really elementary but I'm just not finding it clearly stated. What code do I need in my UsersController to pull the list of all Roles? (not just those associated with the current User, but all objects in the Roles table.)
2) What form input code do I need to display checkboxes with all possible Roles, and show the current user privileges (in my UserRoles table) as already checked off? I think I need something like this in my form:
echo $this->Form->select('User.Role', $options, ['multiple' => 'checkbox']);
...but I can't tell what $options should be, and how to set already-selected values.
I am currently pulling Roles with my User object to be edited:
$user = $this->Users->get($id, [
'contain' => ['Roles'],
'Users.id' => $this->Auth->user('id')
]);
...but I'm having trouble converting it into a checkbox form selection.
Thanks so much.
In order to create a list of checkbox out of some options, you first need to send the options from the controller:
$this->set('roles', $this->Users->Roles->find('list'));
Then, in your template add a multiple => checkbox input:
echo $this->Form->input('roles', ['multiple' => 'checkbox', 'options' => $roles]);
It is not necessary to prefix your input names with User. just name your inputs as the properties of a User entity.

CakePHP validation on => 'create', on => 'update'

I'm hoping you cakephp experts can answer this re Cake 2.1 and data validation in the model.
Cake gives you an "on" key for use in the validate array. I understand what the docs say about this but my question is, what's the point of these two items.
Let's say I have a validation rule for when a record is created. The validation passes and the record is created.
Then the user goes and edits that record and changes it to something that no longer passes that particular validation. But since I've got my validation set to run on create only, the validation passes and the record is updated with invalid data. It seems to me like this would apply to any on create / on update rules. If a user wanted to bypass validation, just create a valid record, then go and edit it so it's now invalid.
Can someone perhaps help me understand when it might make sense to use on update and on create?
This is most useful in conduction with the required rule. You should set certain fields that are minimally required to be required 'on' => 'create'. This makes the rule fail if those fields don't exist in the data set and the record cannot be created, but allows you to update existing records without having to pass that field each and every time.
For example:
'email' => array(
'required' => array(
'on' => 'create',
'rule' => 'notEmpty',
'message' => 'Enter your email address',
'required' => true,
'last' => true
),
'notempty' => array(
'rule' => 'notEmpty',
'message' => 'Enter your email address',
'allowEmpty' => false,
'last' => true
),
'email' => array(
'rule' => 'email',
'message' => 'Not a valid email address',
'last' => true
)
)
I found it really useful in cooperation with profile pictures. You need one to be uploaded on create (if it is needed), but on update i can remain empty => no update to picture will be done.
'on' => null will do the job
EDIT :
Ok, let's say you have a Profile model.
If you have a Date of Birth field, you would probably use a rule that would be enforced for both addition and edition.
You might also add a delete_picture checkbox in your form that a user should select in order to delete their profile picture. When adding, you have no profile picture so this field is only relevant at edition time and you would then use on => update.
Let's say you also have a group field that is set when you create the object but that is meant to never be changed. You would then use on => create.

Having trouble with the CakePHP data validation

i'm currently having some issues by using the cakePHP data validation.
I've tried to use the rule with the argument 'on' => 'created' but it didn't seems to work.
My objective is to check during the creation of the user, to check if the mail is not already existing in my database.
But when it's a edit, i don't want to check this, i mean, if the user don't change the mail, obviously this mail is already existing in the database, but it's just the same then before...
So i don't want to check if the mail, have not been changed.
'mail' => array(
'valid_mail' => array(
'rule' => array('email', true),
'message' => 'Veuillez insérer un email valide.'
),
'isUnique_mail' => array(
'rule' => 'isUnique',
'on' => 'create',
'message' => 'Ce mail est déjà utilisé.'
)
)
Hope you guys understand my problem.
Part of your problem might be that you're not specifying the ID of the record that needs to be saved using $this->Model->id = $id so when you call the save (or saveAll) function, it's trying to insert a record.
The isUnique validation function actually will filter out the ID of the current record when updating if it's been set using $this->Model->id. You can see this at the bottom of the function (line 2446).
Personally, I'd leave the isUnique validation on all the time to prevent users from changing their emails to one that already exists once they've registered.

CakePHP AutoComplete Question

I am working on a book review application and I am using autoComplete to search for titles in when creating a review. The review model has an associated book_id field and the relationship is setup as the review hasOne book and a book hasMany reviews.
I am trying to pass the Book.id (into the book_id field), but I want to display Book.name for the user to select from. With the default setup (accomplished via CakePHP's tutorial), I can only pass Book.name. Is it possible to display the name and pass the id?
Also, I am passing it via the following code in the create() action of the review controller:
$this->data['Review']['book_id'] = $this->data['Book']['id'];
Is that the proper way to do it in CakePHP? I know in Ruby on Rails, it is automatic, but I can't seem to make it work automagically in CakePHP. Finally, I am not using the generator because it is not available in my shared hosting environment... so if this is the wrong way, what do I need other than associates in my models to make it happen automatically?
Thanks for the help and I promise this is my question for awhile...
UPDATE- I tried the following, but it is not working. Any ideas why?
function autoComplete() {
$this->set('books', $this->Book->find('all', array(
'conditions' => array(
'Book.name LIKE' => $this->data['Book']['name'].'%'
),
'fields' => array('id','name')
)));
$this->layout = 'ajax';
}
The problem is that when I use the code above in the controller, the form submits, but it doesn't save the record... No errors are also thrown, which is weird.
UPDATE2:
I have determine that the reason this isn't working is because the array types are different and you can't change the array type with the autoComplete helper. As a workaround, I tried the follow, but it isn't working. Can anyone offer guidance why?
function create() {
if($this->Review->create($this->data) && $this->Review->validates()) {
$this->data['Review']['user_id'] = $this->Session->read('Auth.User.id');
$this->Book->find('first', array('fields' => array('Book.id'), 'conditions' => array('Book.name' => $this->data['Book']['name'])));
$this->data['Review']['book_id'] = $this->Book->id;
$this->Review->save($this->data);
$this->redirect(array('action' => 'index'));
} else {
$errors = $this->Review->invalidFields();
}
}
FINAL UPDATE:
Ok, I found that the helper only takes the find(all) type or array and that the "id" field wasn't passing because it only applied to the autoComplete's LI list being generated. So, I used the observeField to obtain the information and then do a database lookup and tried to create a hidden field on the fly with the ID, but that didn't work. Finally, the observeField would only take the characters that I put in instead of what I clicked, due to an apparent Scriptaculous limitation. So, I ended up going to a dropdown box solution for now and may eventually look into something else. Thanks for all of the help anyway!
First of all, $this->data will only contain ['Book']['id'] if the field exists in the form (even if it's hidden).
To select something by name and return the id, use the list variant of the find method, viz:
$selectList = $this->Book->find('list', array(
'fields' => array(
'id',
'name'
)));
$this->set('selectList', $selectList);
In the view, you can now use $selectList for the options in the select element:
echo $form->input('Book.id', array('type' => 'hidden'));
echo $form->input('template_id', array(
'options' => $selectList,
'type' => 'select'
));

Resources