Responded to a Stack question so I thought I would post here as well for continuity. If you have a better way, please share
There are many conversation on this topic and several ways you can implement this. Some have expanded the
users table, some the
auth_identities table. I chose to create a seperate
user_details table. Either method is fine and purely based on your development style and application needs.
Here is my table, it has a lot more than this, but you get the idea:
I set a Key to the
auth_identities table in case the user is removed.
PHP Code:
CREATE TABLE `user_details` (
`id` INT(11) UNSIGNED NOT NULL AUTO_INCREMENT,
`user_id` INT(11) UNSIGNED NOT NULL,
`firstname` VARCHAR(255) NOT NULL COLLATE 'utf8_general_ci',
`middlename` VARCHAR(50) NULL DEFAULT NULL COLLATE 'utf8_general_ci',
`lastname` VARCHAR(255) NOT NULL COLLATE 'utf8_general_ci',
`phone` VARCHAR(255) NOT NULL COLLATE 'utf8_general_ci',
`address1` VARCHAR(255) NOT NULL COLLATE 'utf8_general_ci',
`address2` VARCHAR(255) NULL DEFAULT NULL COLLATE 'utf8_general_ci',
`city` VARCHAR(255) NOT NULL COLLATE 'utf8_general_ci',
`state` VARCHAR(255) NOT NULL COLLATE 'utf8_general_ci',
`zip` INT(11) NULL DEFAULT '0',
`updated_at` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (`id`) USING BTREE,
INDEX `user_id` (`user_id`) USING BTREE,
CONSTRAINT `auth_identities_user_id_fk2` FOREIGN KEY (`user_id`) REFERENCES `users` (`id`) ON UPDATE RESTRICT ON DELETE CASCADE
)
COLLATE='utf8_general_ci'
ENGINE=InnoDB
AUTO_INCREMENT=1;
https://codeigniter4.github.io/shield/qu...ing-a-user
The below taken from the documentation above, Make sure you are using the right Model before your class name:
PHP Code:
use CodeIgniter\Shield\Models\UserModel;
protected $usersModel;
public function __construct() {
$this->usersModel = new UserModel();
}
In my Controller, I have the following as a view for the user, (I use an Ajax Modal Window):
PHP Code:
public function view() {
checkAjax();
if (!$this->user->hasPermission('users.read')) {
$response['success'] = false;
$response['messages'] = lang("App.invalid_permission");
return $this->response->setJSON($response);
}
$id = $this->request->getPost('id');
$user = $this->usersModel->findById($id);
$permission = $user->getPermissions();
$identity = $user->getEmailIdentity();
$data = [
'title' => 'View Users',
'user' => $user,
'details' => $this->detailsModel->where('user_id', $id)->first(),
'group' => (!empty($user->groups) ? $user->groups[0] : 'Unassigned'),,
'pTable' => buildPermissionsTable($permission),
'identity' => $identity->secret
];
return view('users/view', $data);
}
The "
buildPermissionsTable" is in a
array_helper file as I only give one role to the users where Shield allows multiple. I assign each user permissions based on Controller.Method IE: users.create or users.update or users.delete. This helps me to prevent group overlap or creating several different groups when I only need to assign a specific level of access.
Updating the user is the same as above, sort the data from the posted user form in the controller and insert into the appropriate table. You can find more on that using the link above:
You put everything in the users and
auth_identities tables first, then the rest in the
user_details table, basic example below:
Example to modify the data in users and
auth_identities tables slightly modified from the above documentation link (obviously the method below is not complete):
PHP Code:
public function edit() {
checkAjax();
if (!$this->user->hasPermission('users.update')) {
$response['success'] = false;
$response['messages'] = lang("App.invalid_permission");
return $this->response->setJSON($response);
}
$id = $this->request->getPost('id');
$originalDate = Time::now('America/Chicago', 'en_US');
$newDateString = $originalDate->format('Y-m-d H:i:s');
// Add all of your post value here...
// $authFields are for Shield
// $detailFields are for user_details table
$authFields['username'] = $this->request->getPost('username');
$authFields['email'] = $this->request->getPost('email');
$authFields['updated_at'] = $newDateString;
// Snip...
$detailFields['firstname'] = $this->request->getPost('firstname');
$detailFields['lastname'] = $this->request->getPost('lastname');
$detailFields['phone'] = $this->request->getPost('phone');
// Snip... You get the idea from here...
$this->validation->setRules([
'username' => ['label' => 'Username', 'rules' => 'required|max_length[20]|min_length[6]|alpha_dash|is_unique[users.username,id,'.$id.']'],
'email' => ['label' => 'Email Address', 'rules' => 'required|valid_email|is_unique[auth_identities.secret,user_id,'.$id.']'],
'password' => ['label' => 'Password', 'rules' => 'permit_empty|min_length[8]'],
'confirm_password' => ['label' => 'Confirm Password', 'rules' => 'permit_empty|min_length[8]|matches[password]'],
'group' => ['label' => 'User Group', 'rules' => 'required'],
]);
$response = array();
if ($this->validation->run($fields) == FALSE) {
$response['success'] = false;
$response['messages'] = $this->validation->getErrors(); //Show Error in Input Form
} else {
$users = $this->_usersModel;
$user = $users->findById($id);
$user->fill($fields);
if ($users->save($user)) {
$user->syncGroups($fields['group']);
// reset rules to check user details data
$this->validation->reset();
// Validation for Rules are in UserDetailsModel
if ($this->detailsModel->save($detailFields) == TRUE) {
$response['success'] = true;
$response['messages'] = lang("App.update-success");
} else {
$response['success'] = false;
$response['messages'] = $this->_detailsModel->errors();
}
} else {
$response['success'] = false;
$response['messages'] = lang("App.update-error");
}
}
return $this->response->setJSON($response);
}
Hope this helps!
If you see a mistake or if your way is better, post it below!
- Dean