Bonfire
Bonfire copied to clipboard
How extend Users module
I'm trying to extend the users module like this: 'Funcionario' (employee in english) is a type of user who can log in. It has all 'user' attributes plus some others attributes. I could do it with custom fields but 'Funcionario' is just one example of many other users types I'll need. Have a table row for each attribute for each different user type would probably give performance problems (too many rows in the meta table). I thought about extending user module by changing the view to add additional fields, controller and model to CRUD the new attributes. However, on extending the 'Settings' controller of 'Users' module I see the following error message:
Unable to load the requested language file 'users' for current language 'english' AND for fallback to 'English'.
The code:
// Bonfire class, unmodified...
class Settings extends Admin_Controller {
private $siteSettings;
[...]
public function __construct() {
parent::__construct();
$this->auth->restrict($this->permissionView);
$this->lang->load('users');
$this->load->model('roles/role_model');
$this->siteSettings = $this->settings_lib->find_all();
if ($this->siteSettings['auth.password_show_labels'] == 1) {
Assets::add_module_js('users', 'password_strength.js');
Assets::add_module_js('users', 'jquery.strength.js');
}
Template::set_block('sub_nav', 'users/settings/_sub_nav');
}
[...]
}
My controller
require_once(APPPATH. '/modules/users/controllers/Settings.php');
class Content extends Settings {
public function __construct(){
parent::__construct();
$this->auth->restrict($this->permissionView);
$this->load->model('funcionario/funcionario_model');
$this->lang->load('funcionario');
Assets::add_css('flick/jquery-ui-1.8.13.custom.css');
Assets::add_js('jquery-ui-1.8.13.min.js');
$this->form_validation->set_error_delimiters("<span class='error'>", "</span>");
Template::set_block('sub_nav', 'content/_sub_nav');
Assets::add_module_js('funcionario', 'funcionario.js');
}
[...]
}
I believe the error is because the system is looking for the language file ($this->lang->load('users')) in the 'funcionario' module directory (Content class is in funcionario/controllers) instead of looking in the users module directory (Settings class is in users/controllers). If I comment the '$this->lang->load('users')' snippet, I see the folowing error:
Unable to load the requested file: user_fields.php
Probably for the same reason the other error. Am I in the wrong way? if not, how solve this types of issues.
I think you're extending the settings the wrong way. Have you checked the "System Events" or the "Extended Settings" on the documentation? It was provided there for this use case, if I understood your problem.
Can you expand more about what you are trying to do with the funcionario module? From what I understand, you just want to extend the settings to accommodate funcionario module model, am I right?
What I'm really trying to do is manage different types of extended users. In a scenario of a condominium, for example, would be the Doorkeeper and the Apartment owners. Doorkeeper attributes: all of users module plus 'salary' and 'hire date'. Apartment owner attributes: all of users module plus 'apartment number' and 'block' where he lives. These users can log into the system and have access to different parts of the system.
The "Extended Settings" you referred, create too many rows in meta table (when having many users types with many attributes), as I mentioned before. Beyond that, I can not create indexes to fields widely used to search in the table.
I just read about 'System events' but I dont know if I understood how to fit in my scenario. Assuming I was doing the Doorkeeper module, I would have a view with all the fields of 'user' (could in some manner load the fields used in the users module?) plus the fields salary and hire date. To save the information I would trigger an event calling the 'Settings' controller of users module passing the user data?
Some simple example about this? Thank you
It would be good to separate the attributes for different users for indexing purposes.
My suggestion here is to utilize the 'Role' in creating users.
You can create Doorkeeper and Appartment roles, this is also an advantage so that you can utilize Role-based access, and when you create a user using users module, suppose you select 'Doorkeeper' role. Now using System Events, save_user, which is called after a user is inserted or updated and meta data is saved, you can run your custom module to check the role of the newly created user, and based on that role, you can redirect it to a view which contains fields/attributes specific for 'Doorkeeper'.
For your specific problem above,
on the bonfire class settings: change this
$this->lang->load('users');
to this
$this->lang->load('users/users');
You just need to specify to search the users lang file under users module. That should work fine.
First of all, thank you for your attention.
What you're suggesting would look like this?
What I would like to do is create a custom user from a single form with all the fields as below ...
When save the information, the data would be saved in the tables: users, permissions/roles and Doorkeeper. Just to clarify my goal , in joomla framework, I would do something like this:
class DoorkeeperController {
[...]
public function create() {
$user = new stdClass;
$user->username = $db->getEscaped(JRequest::getVar('username'));
$user->name = $db->getEscaped(JRequest::getVar('name'));
$user->email = $db->getEscaped(JRequest::getVar('email'));
[...] // other user fields
$userId = UserUtilities::registerUser($user, 18, 'Registered'); // custom method to register a user, saving in the joomla users table, and defining the role 18...
$doorkeeper = new stdClass;
$doorkeeper ->salary = $db->getEscaped(JRequest::getVar('salary'));
$doorkeeper ->hire_date= $db->getEscaped(JRequest::getVar('hire_date'));
$doorkeeper->user_id = $userId; // foreign key
$modelDoorkeeper = $this->getModel('doorkeeper');
$modelDoorkeeper->insert($doorkeeper);
}
}
Could I use 'System Events' to get the same result? or should I do something similar to what I would do in joomla?
What you're suggesting would look like this?
Yes that's it.
What I would like to do is create a custom user from a single form with all the fields as below ... Try putting this in your Funcionario module view but make sure to specify the module as like this
<?php Template::block('users/views/user_fields', 'user_fields', $fieldData); ?> // render your other fields here...
Then on your Funcionario module controller:
public function create(){
[...]
// when you submit the form above, it will call the register method in Users register.
Modules::run('users/users/register');
[...]
}
I'm not on my PC so I haven't tested it. I'm just giving you idea on where you can proceed.
Hi, when using this
This error appears
Unable to load the requested file: user_fields.php
I tried then place the fields directly in the funcionario view and added this in the funcionario controller, as you suggested
Modules::run('users/users/register');
But this way the form of the funcionario view is not displayed, only the form of the users view. Any other suggestions on how to extend the users module?
Sorry, I missed this earlier, but in your quoted Template::block()
call, the first two arguments are reversed, which is why you get the error message about being unable to load the requested file. It should probably be:
Template::block('user_fields', 'users/user_fields', $fieldData);
The first argument to Template::block()
is the name of the block, the second is the name/path of the view. I also changed one of the arguments from 'users/views/user_fields'
to 'users/user_fields'
. The system will attempt to find the view either in the module's views directory (where the module is the part before the first slash) or in the active theme. So, it would look for /modules/users/views/user_fields.php
or /themes/{active_theme}/users/user_fields.php
.
rob1000 you could make it work ? I have the same situation, where I need to assign a employee to a company, but the data not inserted in DB:
Error Number: 1364
Field 'codEmpresa' doesn't have a default value
INSERT INTO bf_users
(role_id
, email
, username
, display_name
, language
, timezone
, active
, password_hash
, created_on
) VALUES ('4', '[email protected]', '[email protected]', 'Contato', 'portuguese_br', 'UM8', 1, '$2a$08jy6aORF2XeP0pEvN7e.OxhFFlgjx04.ZzffFl47sveMo3iW68KG', '2016-03-10 14:28:08')
Filename: C:/xampp/htdocs/bonfire/core/BF_Model.php
Line Number: 480
thanks for the reply mwhitneysdsu. I'm currently developing other modules, I will continue the module discussed here later. If your suggestion works I comment here.
Hi Jojr, I'm currently developing other modules, I will continue the module discussed here later, I still have not tested the latest suggestion of mwhitneysdsu... what I had thought to do was use the bonfire event system as follows (not tested):
application/modules/funcionario/controller/Content.php
class Content extends Admin_Controller{
public function create()
{
$this->auth->restrict($this->permissionCreate);
if (isset($_POST['save'])) {
Events::trigger('need_create_user', null); // <<< Custom event
}
}
public function userCreated($user_id){
if ($insert_id = $this->save_funcionario()) {
log_activity($this->auth->user_id(), lang('funcionario_act_create_record') . ': ' . $insert_id . ' : ' . $this->input->ip_address(), 'funcionario');
Template::set_message(lang('funcionario_create_success'), 'success');
redirect(SITE_AREA . '/content/funcionario');
}
// Not validation error
if ( ! empty($this->funcionario_model->error)) {
Template::set_message(lang('funcionario_create_failure') . $this->funcionario_model->error, 'error');
}
redirect(SITE_AREA . '/content/funcionario');
}
}
application/config/events.php
$config['need_create_user'][] = array(
'module' => 'users',
'filepath' => 'controllers',
'filename' => 'Settings.php',
'class' => 'Settings',
'method' => 'customCreate'
);
$config['user_created'][] = array(
'module' => 'funcionario',
'filepath' => 'controllers',
'filename' => 'Content.php',
'class' => 'Content',
'method' => 'userCreated'
);
application/modules/users/controller/Settings.php
class Settings extends Admin_Controller{
public function customCreate() {
$id = $this->saveUser('insert', null, array());
Events::trigger('user_created', $id); // <<< Custom event
}
}
See if that helps you, let me know if it works or another way that you have used to solve. Specifically about the error that you mention, I think your 'codEmpresa' is a primary key and you did not set it as auto increment ... Otherwise, you can Indicate the 'codEmpresa' in every insertion, taking care to set a different value every time.
Thanks a lot! I will try to do this.
Hi @rob1000 I could add the custom fields in the table "bf_users" this way:
I have inserted two new fields into the bf_users table, named codGrupo and codEmpresa. (that are the parameters I need to distinguish the user's company).
So I did what @JbalTero said:
Path: users/views/settings/user_form.php
Template::block('user_fields', 'user_fields', $fieldData);
// render your other fields here...
Template::block('user_company','user_company', $fieldData); //my custom fields
That's my custom user_company fields: (I'll fill the select field with ajax)
<div id="result"></div> </div> <div id="div_empresa" class="form-group" style="display: none;"> <label for="company_id" class="col-sm-2 control-label"><?php echo lang('nome_empresa'); ?></label> <div class="col-sm-10"> <select name="codEmpresa" id="codEmpresa" class="select2-container <?php echo $controlClass; ?> form-control" required=""> <option selected="" />Carregando...</option> </select> <span class="help-inline"><?php echo form_error('empresa'); ?></span> </div> <div id="result"></div> </div>
In users/models/settings/User_model.php I put these parameters at the end of prep_data function:
public function prep_data($post_data) { ... //Passing the parameters $data['codEmpresa'] = $post_data['codEmpresa']; //custom field $data['codGrupo'] = $post_data['codGrupo']; //custom field return $data; }
Now I can save the custom fields into the bf_users table.
I'm glad this approach worked for you. In my case I'll need different types of "Extended users" so I can't modify directly the users table, but thanks for sharing your solution :)
Hi @rob1000 , what did you do finally for extend users? Maybe create a new table with user_id FK?
Hi @Romerski , I had changed from CodeIgniter to another framework.
@rob1000 Unlucky, I had extended Users module creating different tables with user_id as FK. Just wanted to know your stuff. Out of curiosity, to which framework did you changed?
@Romerski to Yii2.