Welcome Guest, Not a member yet? Register   Sign In
form validation question
#1

[eluser]rsmarsha[/eluser]
When submitting a form and running the rules, do I just access the posted variables with $_POST ? I guess what I'm asking is do the validation rules such as xss_clean work on the posted variables?

So $_POST['content'] with an xss_clean validation rule on it, would mean the rule is run and the returned value put back in $_POST['content'] ?

Here is my first effort at handling a form for writing a blog post.

Code:
public function write () {
        $results = $this->blog_model->get_categories();
        $categories = array();
        foreach ($results AS $result) {
            $categories[$result->id] = $result->name;
        }
        $data = array(
            'categories' => $categories
        );

        $this->form_validation->set_rules('title', 'Title', 'required|xss_clean');
        $this->form_validation->set_rules('content', 'Content', 'required|xss_clean');
        if ($this->form_validation->run() === FALSE)
        {
            $this->_view('admin/blog_write_post', $data);
        }
        else
        {
            $post_data = array(
                'title' => ,
                'content' => '',
                'user_id' => '',
                'posted' => '',
                'category' => ''
            );
            $this->blog_model->insert_post($post_data);
            $this->_view('admin/blog_post_submitted', $data);
        }
    }

the post data array is empty at the moment while I check I have the right idea. Does the write method above look ok? I did have a submit and a write method but I figured the above idea should work better. I could be wrong, just thought I'd see what you all thought.
#2

[eluser]dj_voc[/eluser]
I'm just wonder why u leave empty the $post_data array value?

if u want insert some data to db, u should insert the post data to the array value

Code:
$post_data = array(
                'title' => $this->input->post('title'),
                'content' => $this->input->post('content'),
                'user_id' => $some_user_id,
                'posted' => $some_posted,
                'category' => $some_category
            );
#3

[eluser]SitesByJoe[/eluser]
Your structure looks pretty good.

You're correct with the way things work, of everything passes validation, the post data should be safe to add to the database.

Things to improve it would be to move your rule declarations into a form_validation config file (see userguide) and moving some of your database calls inside your if() conditional since you only need them when calling your form, not when processing your post data.

Another thing I like to do is to set a success message and then redirect after running the database sequence. Something like:

Code:
// set a temporary success message
$this->session->set_flashdata('message', 'Post added successfully');

// redirect to a new screen based on our new id
redirect('controller/method/' . $this->db->insert_id());

I then run a conditional check on my view template that pops up if the flashdata message has been set.
#4

[eluser]cideveloper[/eluser]
Another thing to deal with.

Say for example a user goes to admin/blog_write_post. They fill out the content and choose a category but forget to fill out the title. They hit submit. form validation fails and they are now redirected back to admin/blog_write_post probably with the validation error telling them title is required. With your code as it is they now have to re-select the category. It gets annoying as a user if they have to fill out stuff twice if they didn't make a mistake with that field.

Also to make your code a bit cleaner You should move this

Code:
$categories = array();
        foreach ($results AS $result) {
            $categories[$result->id] = $result->name;
        }

to the model. Then you can just do this

Code:
$data = array(
            'categories' => $this->blog_model->get_categories()
        );
#5

[eluser]rsmarsha[/eluser]
@djvoc It's not finished yet which is why I left that bit out.

@SitesByJoe Thanks for the tips, not sure I follow the redirect bit though. Your redirect directs to the insert method in your model? Does the model then redirect to a view? Oh and I moved the validation into a config file.

@cideveloper Thanks for the advice, I've moved the categories now. I do have code in place to remember the fields, as you can see from the view.

Maybe you can all look at the new code?

Controller
Code:
public function write () {
        if ($this->form_validation->run('write_blog_post') === FALSE)
        {
            $data = array(
                'categories' => $this->blog_model->get_categories()
            );
            $this->_view('admin/blog_write_post', $data);
        }
        else
        {
            $this->blog_model->insert_post();            
            $this->_view('admin/blog_post_submitted', $data);
        }
    }

Model
Code:
public function get_categories() {
        $this->db->select("id, name", FALSE);
        $this->db->order_by("name asc");
        $query = $this->db->get('blog_categories');
        if ($query->num_rows() > 0)
        {
            $categories = array();
            foreach ($query->result() AS $result) {
                $categories[$result->id] = $result->name;
            }
            return $categories;
        }
        else
        {
            return FALSE;
        }
    }
    
    public function insert_post() {
        $data = array(
            'title'        => $this->input->post('title'),
            'content'    => $this->input->post('content'),
            'user_id'    => '1',
            'posted'    => date('Y-m-d H:i:s'),
            'category'    => $this->input->post('category')
        );
        $this->db->insert('blog_posts', $data);
    }

View
Code:
<h3>Write a blog post</h3>
&lt;?php echo validation_errors(); ?&gt;
&lt;?php
$data = array(
    'id' => 'write_post'
);
echo form_open('admin/blog/write', $data);
$data = array(
    'name' => 'title',
    'placeholder' => 'Title',
    'value' => set_value('title')
);
echo form_input($data);
$data = array(
    'name' => 'content',
    'placeholder' => 'Content',
    'value' => set_value('content')
);
echo form_textarea($data);
echo form_label('Category', 'category');
echo form_dropdown('category', $categories, set_value('category'));
echo form_submit('submit', 'Submit Post');
?&gt;

The view looks a bit messy and I'm sure there's a much cleaner way of doing it so any tips/advice welcome. One idea I had was to move the $data arrays used to create the form fields into one large array built in the controller and then just access them in the view when echo'ing the create form code.

I can't seem to get the order by clause in the get_categories method in the model, to work right. At the moment it's just ordering by name but I setup a default field in the table with 0 or 1 allowed and 1 sets the default category.

I want to order like
Code:
$this->db->order_by("default desc, name asc");

But if I do that the num_rows bit below it throws errors as a none object.

Also I am not sure if I'm running the insert method from the model right. I moved the data array from the controller into the model and as it's post data I don't need any parameters. If I'm getting it right that is.

Very new to CI so all the advice is much appreciated, just be patient if I'm doing something stupid. Wink
#6

[eluser]cideveloper[/eluser]
Your view looks fine. Nothing messy about it.

Where did you move the validation rules to now? A config file? That is a good way to do it. Cleans up the controller. However if you dont validate the dropdown then it wont re-populate the dropdown on validation error. even if you just do a 'trim|required'.

What SitesByJoe is saying is that it is common practice to redirect after a post submit. That way the user cannot hit refresh or F5 and then be prompted to submit the form again and then do a double submit. Redirect the user to the page that was before the page that they write the blog post. On that page put a notification bar at the top with

Code:
&lt;?=$this->session->flashdata('message');?&gt;

Controller

Code:
public function write () {
        if ($this->form_validation->run('write_blog_post') === FALSE)
        {
        $data = array(
            'categories' => $this->blog_model->get_categories(),
            'message' => (validation_errors()) ? validation_errors() : $this->session->flashdata('message')
        );
        $this->_view('admin/blog_write_post', $data);
        }
        else
        {
        $result_id = $this->blog_model->insert_post()
        if ($result_id){
            $this->session->set_flashdata('message', 'Blog Entry Submitted');        
            redirect('admin/previous_page');
        } else {
            $this->session->set_flashdata('message', 'An Error Occured Submitting the Post');
            redirect('admin/blog/write');
        }
        }
    }

Model
Code:
public function insert_post() {
        $data = array(
            'title'        => $this->input->post('title'),
            'content'    => $this->input->post('content'),
            'user_id'    => '1',
            'posted'    => date('Y-m-d H:i:s'),
            'category'    => $this->input->post('category')
        );
        $this->db->insert('blog_posts', $data);
        if ($this->db->affected_rows()>0){
            return TRUE;
        } else {
            return FALSE;
        }
    }

View
Code:
<h3>Write a blog post</h3>
&lt;?php echo $message;?&gt;
&lt;?php
$data = array(
    'id' => 'write_post'
);
echo form_open('admin/blog/write', $data);
$data = array(
    'name' => 'title',
    'placeholder' => 'Title',
    'value' => set_value('title')
);
echo form_input($data);
$data = array(
    'name' => 'content',
    'placeholder' => 'Content',
    'value' => set_value('content')
);
echo form_textarea($data);
echo form_label('Category', 'category');
echo form_dropdown('category', $categories, set_value('category'));
echo form_submit('submit', 'Submit Post');
?&gt;

This is very subjective but I find once you have the pages set up properly it simplifies coding a lot

and for you order_by try this

Code:
$this->db->order_by("default", "desc");
$this->db->order_by("name", "asc");

P.S. Nothing is "stupid" We are all always learning and finding better ways to do things
#7

[eluser]rsmarsha[/eluser]
I moved the validation to a config file as suggested earlier in the post which as you said does make it tidier.

Code:
&lt;?php
$config = array(
    'write_blog_post' => array(
        array(
            'field' => 'title',
            'rules' => 'required|xss_clean'
        ),
        array(
            'field' => 'content',
            'rules' => 'required|xss_clean'
        ),
        array(
            'field' => 'category',
            'rules' => 'is_natural_no_zero'
        )
    )                        
);

I made the changes you suggested though as this is an admin form I just have the submitted message show on the write page in case the user wants to write another post.

So : -

Code:
public function write () {
        if ($this->form_validation->run('write_blog_post') === FALSE)
        {
            $data = array(
                'categories' => $this->blog_model->get_categories(),
                'message' => (validation_errors()) ? validation_errors() : $this->session->flashdata('message')
            );
            $this->_view('admin/blog_write_post', $data);
        }
        else
        {
            $result = $this->blog_model->insert_post();
            if ($result){
                $this->session->set_flashdata('message', 'Blog Entry Submitted');        
            }
            else
                {
                $this->session->set_flashdata('message', 'An Error Occured Submitting the Post');
                
            }
            redirect('admin/blog/write');
        }
    }

I tried the order_by method you suggested and I get the same error. I've checked the fields and can't work it out, it's as if the order by breaks the query.
#8

[eluser]cideveloper[/eluser]
in your controller add

Code:
$this->output->enable_profiler(TRUE);

It will give you a lot of information about the page loading including the SQL statements being generated. Post the SQL generated so we can see whats going wrong.
#9

[eluser]moazzemeee05[/eluser]
controller

$this->load->view('a123');
#10

[eluser]rsmarsha[/eluser]
@cideveloper Thanks, I have tried that and it errors out the page before it can display the profiler output. Maybe if I turn off php errors I might be able to see it, I'll try that.

@moazzemeee05 Sorry I don't follow what your getting at there.




Theme © iAndrew 2016 - Forum software by © MyBB