[eluser]simplepixie[/eluser]
I am trying to keep my code as clean as possible rather than having to repeat the following code throughout each insert and update function in all my models, I wonder if I can use it globally (I have tried various ways but can't seem to get it to work unless it is used in the actual add/update function).
Code: function insert_udpate()
{
$keys = array_keys($_POST);
foreach($keys as $key) {
if(in_array($key,$this->mainfields)) {
$data[$key] = $this->input->post($key,TRUE);
}
}
}
The var $mainfields is set in the model and works fine when calling the foreach loop from within the model's insert and update functions but I don't want to have to keep repeating the same code through all models (have tried putting in My-Model and extending but still doesn't seem to work) - can this be called from one function and if so how?
I tried calling it like this so maybe this is where I have gone wrong:
Code: $this->db->update('table_name', insert_update(), array('id' => $id));
[eluser]richthegeek[/eluser]
You can do this but there are potentially security implications - you'd be wise to at least add a blacklist (better yet, a whitelist) of fields that are protected/writeable, so that user's cannot write any field at will.
The best option for something like this is to provide it as a parent model (MY_model) method and call it within a per-model insert_update class that vets the data.
Code: class user extends MY_model
{
...
function create()
{
// some whitelist/blacklist logic so that only valid fields are written to
$this->db->insert( "users", $this->insert_update() );
}
}
If you don't apply some sort of validation then you are leaving yourself open to major flaws even with XSS filtering.
[eluser]simplepixie[/eluser]
I still can't get this working (I already had the function insert_update in MY_Model and am extending it and calling the function as suggested in the relevant model I am trying to sort at the moment). Ignoring trimming and escaping characters etc (for the time being as I know how to implement this, I just haven't done so yet) can anyone tell me why this won't work.
I have this in MY_Model:
Code: class MY_Model extends Model
{
function __construct()
{
parent::__construct();
}
// Used to filter and create insert and update data/fields from form posts
function insert_udpate()
{
$keys = array_keys($_POST);
foreach($keys as $key) {
if(in_array($key,$this->mainfields)) {
$data[$key] = $this->input->post($key,TRUE);
}
}
}
}
Then I have this in my accounts_model:
Code: class Accounts_model extends MY_Model {
public $mainfields = array(
'firstname',
'surname',
'add1',
'add2',
'add3',
'town',
'county',
'postcode',
'landline',
'mobile',
'email'
);
function __construct()
{
parent::__construct();
}
// Some other code here
function update($id)
{
$this->db->update('accounts', $this->insert_update, array('id' => $id));
}
}
However, if I run the foreah in the accounts_model function it works fine:
Code: class Accounts_model extends MY_Model {
public $mainfields = array(
'firstname',
'surname',
'add1',
'add2',
'add3',
'town',
'county',
'postcode',
'landline',
'mobile',
'email'
);
function __construct()
{
parent::__construct();
}
// Some other code here
function update($id)
{
$keys = array_keys($_POST);
foreach($keys as $key) {
if(in_array($key,$this->mainfields)) {
$data[$key] = $this->input->post($key,TRUE);
}
}
$this->db->update('accounts', $data, array('id' => $id));
}
}
Any ideas please???
[eluser]Mat-Moo[/eluser]
Insert_update doesn't return anything... not going to help Maybe add return $data
[eluser]simplepixie[/eluser]
I did wonder that - should it be $this->insert_update($data)?
[eluser]Mat-Moo[/eluser]
Either setup a private var $data in my_model and call $this->inset_update() before the update, then reference $this->data in the update statement. Or just return $data in the insert_update function.
[eluser]simplepixie[/eluser]
Thank you - I will give it a go
[eluser]Rodrigo Ferreira[/eluser]
This is how I do this:
1. users_m extends MY_Model: http://bitbucket.org/jamierumbelow/codei...base-model
2. the 'fieldset' property contains arrays of areas related to the model and their respective fields (ex: for a 'users' model it would have the address area, contact area etc). Something like this:
Code: class Users_m extends MY_Model {
public $fieldset = array(
'identification' => array(
array(
'field' => 'firstname', // field used in the form
'dbfield' => 'firstname', // field in the DB. The 'field' above could be used,
but this way I can change the DB structure, if needed, without having to touch the views and controllers.
'label' => 'First Name', // label in the form
'rules' => 'trim|required|xss_clean', // rules
'type' => 'text' // type (could be text, textarea, dropdown etc). This is used to define how the field will be displayed in the form view.
),
array(
'field' => 'surname',
'dbfield' => 'surname',
'label' => 'Surname',
'rules' => 'trim|required|xss_clean',
'type' => 'text'
)
)
(...)
'address' => array(
array(
'field' => 'landline',
'dbfield' => 'phone', // just for the demonstration, you may have different dbfields names, usefull if you share a table etc.
'label' => 'Landline',
'rules' => 'trim|xss_clean',
'type' => 'text'
),
array(
'field' => 'cel',
'dbfield' => 'cel',
'label' => 'Cel Phone',
'rules' => 'trim|required|xss_clean',
'type' => 'text'
)
)
(...)
)
Note we have an array for identification, other for address etc. This is useful for adjust display or to split data in pages (in long forms).
In the controller:
Code: // Let's say there's a specific area to update the address:
$area = 'address'; // In a real case this would be dinamically set.
$data['area'] = $area;
// the View must know what fields should be displayed:
$data['forms'] = $this->users_m->fieldset[$area];
// set the validation rules for those fields as defined in the model (the set_validation function sets the validate property in MY_Model):
$this->users_m->set_validation($data['forms']);
// we limit the insert fields to those indicated in the fieldset[area] array:
foreach ($data['forms'] as $field)
$insert_array[$field['dbfield']] = $this->input->post($field['field']);
// the model handles validation and inserts data. The same logic may be used for updates. Note we do NOT use the $_POST array.
$insert_id = $this->users_m->update($id, $insert_array);
In the View ($user has the current user data):
Code: <?foreach($forms as $form):?>
<label for="<?=$form['field']?>"><?=$form['label']?></label>
<?if ($form['type'] == 'text'):?>
<input id="<?=$form['field']?>" name="<?=$form['field']?>" type="<?=$form['type']?>" size="64" value="<?=set_value($form['field'], $user->$form['dbfield'])?>" />
<?elseif ($form['type'] == 'textarea'):?>
<textarea id="<?=$form['field']?>" name="<?=$form['field']?>" cols="64" rows="5"><?=set_value($form['field'], $user->$form['dbfield'])?></textarea>
//(...code for dropdowns, bool etc etc etc)
<?endif?>
<?endforeach?>
EDIT: fixed some typos and added information on set_validation
[eluser]simplepixie[/eluser]
That is great, thank you for your reply - it is a great way to set things out and I makes things easier for me to manipulate if required etc.
I will reply with the outcome in case anyone else needs this.
[eluser]simplepixie[/eluser]
OK, I now have My_Model in use and updating is working fine, however I can't get the validation to work.
If I use (in my controller):
Code: function do_update()
{
$data['forms'] = $this->accounts_model->fieldset['info'];
$this->accounts_model->set_validation($data['forms']);
foreach ($data['forms'] as $field)
$insert_array[$field['dbfield']] = $this->input->post($field['field']);
$this->accounts_model->update($this->session->userdata('account_id'), $insert_array);
redirect('memberarea');
}
I end up with a blank page (stuck at accounts/do_update).
However if I remove the validation (which I thought would run anyway if using MY_Model as it seems to be run unless I set it to be skipped):
Code: function do_update()
{
$data['forms'] = $this->accounts_model->fieldset['info'];
foreach ($data['forms'] as $field)
$insert_array[$field['dbfield']] = $this->input->post($field['field']);
$this->accounts_model->update($this->session->userdata('account_id'), $insert_array);
redirect('memberarea');
}
The update works fine but no validation occurs (for example I have set the email field to required but it updates without an email address).
Should I be loading the CI form_validation file as well?
Or otherwise what am I doing wrong?
My Model fieldset is such:
Code: class Accounts_model extends MY_Model {
public $fieldset = array(
'info' => array (
array(
'field' => 'firstname',
'dbfield' => 'firstname',
'label' => 'Name',
'rules' => 'trim|strtoupper|xss_clean',
'type' => 'text'
),
array(
'field' => 'surname',
'dbfield' => 'surname',
'label' => 'Surname',
'rules' => 'trim|strtoupper|xss_clean',
'type' => 'text'
),
array(
'field' => 'add1',
'dbfield' => 'add1',
'label' => 'Address',
'rules' => 'trim|strtoupper|xss_clean',
'type' => 'text'
),
array(
'field' => 'add2',
'dbfield' => 'add2',
'label' => ' ',
'rules' => 'trim|strtoupper|xss_clean',
'type' => 'text'
),
array(
'field' => 'add3',
'dbfield' => 'add3',
'label' => ' ',
'rules' => 'trim|strtoupper|xss_clean',
'type' => 'text'
),
array(
'field' => 'town',
'dbfield' => 'town',
'label' => 'Town',
'rules' => 'trim|strtoupper|xss_clean',
'type' => 'text'
),
array(
'field' => 'county',
'dbfield' => 'county',
'label' => 'County',
'rules' => 'trim|strtoupper|xss_clean',
'type' => 'text'
),
array(
'field' => 'postcode',
'dbfield' => 'postcode',
'label' => 'Postcode',
'rules' => 'trim|strtoupper|xss_clean',
'type' => 'text'
),
array(
'field' => 'landline',
'dbfield' => 'landline',
'label' => 'Landline',
'rules' => 'trim|xss_clean',
'type' => 'text'
),
array(
'field' => 'mobile',
'dbfield' => 'mobile',
'label' => 'Mobile',
'rules' => 'trim|xss_clean',
'type' => 'text'
),
array(
'field' => 'email',
'dbfield' => 'email',
'label' => 'Email',
'rules' => 'trim|required|xss_clean',
'type' => 'text'
)
),
'added' => array(
array(
'dbfield' => 'created'
),
array(
'dbfield' => 'createdby'
)
),
'updated' => array(
array(
'dbfield' => 'modified'
),
array(
'dbfield' => 'modifiedby'
)
)
);
function __construct()
{
parent::__construct();
$this->_table = 'accounts';
}
}
/* End of file accounts_model.php */
/* Location: .application/modules/accounts/models/accounts_model.php */
This isn't complete yet - not sure if I can use strtoupper in the rules or not and am only testing on one required field for the moment until I get things working.
Please help as I have been looking for a solution to this since implementing the MY_Model yesterday.
|