MVC Approach, is this still going the right way? - php

About a week ago i started experimenting with CodeIngiter, because i want to learn OOP. I thought i was on the right track, but now i begin to doubt that. The reason is, i have a controller for Members, which is becoming quite a large file. This is because i want my urls to be like members/login , members/register etc.
Here is my controller:
<?php
class Members extends CI_Controller
{
public function __construct()
{
parent::__construct();
$this->load->model('users');
}
public function index()
{
}
public function register()
{
$this->load->helper(array(
'form',
'recaptcha'
));
$this->load->library('form_validation');
$data['title'] = "Register a free account - Become an Author";
$data['titlesucces'] = "Thanks for registering";
$this->form_validation->set_rules('fname', 'First name', 'required');
$this->form_validation->set_rules('lname', 'Last name', 'required');
$this->form_validation->set_rules('password', 'Password', 'required');
$this->form_validation->set_rules('passwordconf', 'Password Confirmation', 'required');
$this->form_validation->set_rules('email', 'Emailaddress', 'required|is_unique[users.email]|valid_email');
$this->form_validation->set_rules('recaptcha_challenge_field', 'Captcha', 'required|recaptcha_matches');
if (!$this->form_validation->run()) {
$this->load->view('header', $data);
$this->load->view('register', $data);
} else {
$this->users->register_new_member();
$this->load->view('register_succes', $data);
}
}
public function login()
{
$data['title'] = "Login";
$data['fail'] = "";
$this->load->helper('form');
$this->load->library('form_validation');
$this->form_validation->set_rules('email', 'Emailaddres', 'required');
$this->form_validation->set_rules('password', 'Password', 'required');
if (!$this->form_validation->run()) {
$this->load->view('login', $data);
} else {
if ($this->users->do_login($this->input->post('email'), $this->input->post('password'))) {
$this->load->view('login', $data);
} else {
$data['fail'] = "Emailaddress or password is incorrect";
$this->load->view('login', $data);
}
}
}
public function logout()
{
$this->session->sess_destroy();
redirect('/members/login/', 'refresh');
}
public function addarticle()
{
if ($this->users->logged_in()) {
$this->load->helper('form');
$this->load->library('form_validation');
$this->form_validation->set_rules('title', 'Title', 'required|max_length[200]|min_length[10]');
$this->form_validation->set_rules('intro', 'Intro', 'required|min_length[40]|max_length[50]');
$this->form_validation->set_rules('cat', 'Category', 'required');
$this->form_validation->set_rules('body', 'Article', 'required|min_length[3000]|link_check');
$this->load->model('categories');
$data['title'] = "Add a new article";
$data['cats'] = $this->categories->get_all_categories();
if (!$this->form_validation->run()) {
$this->load->view('addarticle', $data);
} else {
$this->load->model('articles');
$this->articles->add_new_article();
$this->load->view('welcome');
}
} else {
redirect('/members/login/', 'refresh');
}
}
}
?>
As you can see its quite a big file already, but it will only get bigger. Now my question to you guys is: is this still the right MVC way or am i doing something wrong?
Thanks!

I have created a few critical high availability systems in CodeIgniter, and found it wonderfully powerful and greatly flexible for my particular projects. It does not have the large baggage that comes with other "enterprise" frameworks like ZF (Not to be saying ZF doesn't have its own advantages).
Like zeusakm said, your controller is not that huge. However it all depends also, on which side of the fat controller-lean model/lean controller-fat model debate you stand at (along with the other zillion variations/styles that are out there). Personally, I prefer to keep my controller as lean as possible. If I feel my controller is doing too many things, and becoming bloated sometimes I move some of those functionalities into helpers (instead of models), mainly because I like to have my models reflect business objects. Also, when some of these tasks can be coupled together into a more well formed entity, sometimes I merge them into libraries (my own or third party)
I guess the main idea is that there is no silver-bullet right way for MVC - what works for one project might not be a good idea for another. There are many factors to weigh in. End of the day, if your code is easily maintainable, if a person can read and understand the way it is laid out without too much hassle, if people with different roles/responsiblites like Programmers/Frontend HTML designers/ Backend database coders can all work together using the framework easily without stepping (too much) on each others toes, then yes I would say your MVC is doing its job.
Also keep in mind that how URLS map out into the MVC is only one aspect of the system. This can be handled in a myriad of different ways, from mock controllers which map into a detailed model, htaccess rewrites, sometimes even MVC routers help you configure how you want URLs to resolve..

You are doing completelly right things, and this file isn't big anough yet, and I doubt it will be. I've programmed on CodeIgniter - great and light-weight FW, and there is a cool MVC model/pattern workarounds. So just keep going.
Another thing while Your file/controller didn't achive 1000-1500 lines of code do not bother Your-self with this question.
The MVC is not actually what Your controller contains, rather than whole bunch of things Models(DB Queries, Herlper Functions), Views(Templates/GUI) and Controller(Logic) - keep that in mind and do not worry about anything at this point.

Related

valid_email not working along with callback function in codeigniter

Hello all i was using form_validation Library in codeigniter inside my application. I am making a password retrieving function. I have made a submit form of the email . Now, on the email input field i want to apply these validations.
required
valid_email
check email exist or not.
For the 3rd one i am using call back function to check the database and it worked fine. But with the call back function valid_email is not functioning. This is my controller functions.
public function password_retrieve()
{
if ($_SERVER['REQUEST_METHOD'] == 'POST')
{
$this->form_validation->set_rules('email', 'Email', 'trim|required|valid_email|callback__email_exists');
if ($this->form_validation->run() == false) {
$this->load->view('login_header');
$this->load->view('password_retrieve');
$this->load->view('login_footer');
} else {
}
} else {
$this->load->view('login_header');
$this->load->view('password_retrieve');
$this->load->view('login_footer');
}
}
function _email_exists($email)
{
$this->load->model('users_model');
$result = $result = $this->users_model->check_email_is_exist($email);
if (!$result) {
$this->form_validation->set_message(__FUNCTION__, 'This %s address does not exist!');
return false;
} else {
return true;
}
}
It should checked the valid_email rather than the going to the callback function.
In other mean i want to know what is the order of the rules. Is callback rule runs before the valid_email?
Try to remove "trim" and for check if email exist don't use another function. But use "is_unique[table_name.email]".
$this->form_validation->set_rules('email', 'Email', 'required|valid_email|is_unique[table_name.email]');
By Searching the official documentation and git repository i have found out that there is not a particular order in which a function will run in codeigniter. This means $this->form_validation->set_rules('email', 'Email', 'trim|required|valid_email|callback__email_exists');
In this case valid_email will run after the callback__email_exists. There is not a order in which first trim, then required and then valid_email will run.
So what i have done is to make a new function in my callback function which runs after the required but before the check_email.
Answering this question so that in future people can get the benefit from it. Cheers!

Unable to find custom callback validation rule (CodeIgniter 3 HMVC)

EDIT2: Scroll down for most up-to-date information!
In CodeIgniter 3, I recently moved callback rules across all of my controllers to application/libraries/MY_Form_validation.php to prevent code repetition etc., and to clean up.
Right now, they don't seem to be working anymore.
MY_Form_validation.php starts like this:
<?php if (!defined('BASEPATH')) exit('No direct script access allowed');
class MY_Form_validation extends CI_Form_validation
{
public $CI;
function run($module = '', $group = '')
{
log_message('debug',"Now running the MY_Form_validation");
(is_object($module)) AND $this->CI = &$module;
return parent::run($group);
}
Then a whole list of callback function follows, all defined as public function callback_name(){}.
I also have one (in the same class) which checks if the provided user login information is correct (and thus, if the user can login etc.), but the form validation can't find the rule.
The error log looks like this:
INFO - 2016-06-23 13:33:18 --> Form Validation Class Initialized
DEBUG - 2016-06-23 13:33:18 --> Now running the MY_Form_validation
INFO - 2016-06-23 13:33:18 --> Language file loaded: language/english/form_validation_lang.php
DEBUG - 2016-06-23 13:33:18 --> Unable to find callback validation rule: check_database
The first DEBUG message indicates that MY_Form_validation is loaded (as its overwritten run() method is used, hence the debug logging), but it somehow can't find the callback functions clearly defined below.
I also included language file application/language/english/form_validation_lang.php with the following line:
$lang['form_validation_check_database'] = 'The password does not match the username. Try again.';, which it catches correctly (i.e. this message is displayed when performing the form validation), but it somehow cannot find the callback function itself.
EDIT: I checked to see if methods weren't inherited correctly:
public function __construct($rules = array())
{
$this->CI =& get_instance();
var_dump(get_class_methods($this));
The var_dump() does output the correct, full array of methods, both my own custom callbacks and the built-in ones.
EDIT2:
I read the system/libraries/Form_validation.php and investigated where the debug message occurs, which can be seen in this code sample (line 734-749) :
// Call the function that corresponds to the rule
if ($callback OR $callable !== FALSE)
{
if ($callback)
{
if ( ! method_exists($this->CI, $rule))
{
log_message('debug', 'Unable to find callback validation rule: '.$rule);
$result = FALSE;
}
else
{
// Run the function and grab the result
$result = $this->CI->$rule($postdata, $param);
}
}
It seems as though callbacks are only looked for in the main CI object, but not in the form validation library itself. I could add some hacky exceptions that would pick the library callbacks, but I doubt that that's the best thing to do and I guess I'm overlooking something simple...
If any additional info is required, please let me know.
Alright, I found out...
Apparently, as soon as you move callback functions to MY_Form_validation.php, they are actually built-in validation rules, and no longer act as callbacks.
When setting form rules, I still had the callback_ prefix applied, which makes the Form_validation library look for the rule in the normal CI object (i.e. in the controller) rather than the (MY_)Form_validation class.
The fix for me was to simply remove this prefix from the applied validation rule settings. Now it finds the 'callback' functions correctly.
Please Try This
<?php
class Form extends CI_Controller {
public function index()
{
$this->load->helper(array('form', 'url'));
$this->load->library('form_validation');
$this->form_validation->set_rules('username', 'Username', 'callback_username_check');
$this->form_validation->set_rules('password', 'Password', 'required');
$this->form_validation->set_rules('passconf', 'Password Confirmation', 'required');
$this->form_validation->set_rules('email', 'Email', 'required|is_unique[users.email]');
if ($this->form_validation->run() == FALSE)
{
$this->load->view('myform');
}
else
{
$this->load->view('formsuccess');
}
}
public function username_check($str)
{
if ($str == 'test')
{
$this->form_validation->set_message('username_check', 'The {field} field can not be the word "test"');
return FALSE;
}
else
{
return TRUE;
}
}
}
?>

Where in my MVC PHP app do I put this build function?

I'm trying to convert my PHP app into more of an MVC app. I don't have much experience with MVC and I don't fully understand some of/all of the concepts or how to do it with PHP, so I need some help understanding where a particular function goes.
This function returns some HTML depending on if the user is logged in.
public function buildLoggedInMessage() {
if ($this->User->isLoggedIn()) {
return ' You are logged in as <strong>'.$this->User->getUsername().'</strong> (logout)';
} else {
return ' Login';
}
}
My initial thought was to place this function in my "controller" because it asks the User model if they are logged in (which checks the database record), however it "builds" some HTML, so maybe it should be in the view. Should I move it?
I will eventually move the HTML from the function into a template, so ignore the inline HTML.
Would the function be more suitable in the view if it was like this:
public function buildLoggedInMessage() {
if ($this->Controller->isLoggedIn()) {
return ' You are logged in as <strong>'.$this->User->getUsername().'</strong> (logout)';
} else {
return ' Login';
}
}
and the controller asks the model if the user is logged in?
Thanks.
I think view should not contain any business logic. Views should focus on presenting stuff, so your second solution is bad practice.
More than that, since views focus on the presentation and models handle most of the business logic, controllers should do only the necessary things to link views and models, which means fetch data from model and just insert the data into the view.
so this line of code make no sense because it means you implement business logic in controller:
$this->Controller->isLoggedIn()
Now let's see your first solution.
public function buildLoggedInMessage() {
if ($this->User->isLoggedIn()) {
return ' You are logged in as <strong>'.$this->User->getUsername().'</strong> (logout)';
} else {
return ' Login';
}
}
This function 'return' htmls rather than 'echo' htmls. So who is calling this function? and who will 'echo' the string from this function? I would say this is not a complete controller.
In modern web MVC, there's always some kind of 'router' handle the http requests and execute some instructions related to that. Since you wanna implement MVC pattern, you need to implement that 'router' first.
For example, you can create a 'Member' class which has a 'check' method to achieve the functionality you want.
class Member{
public function check() {
if ($this->User->isLoggedIn()) {
echo ' You are logged in as <strong>'.$this->User->getUsername().'</strong> (logout)';
} else {
echo ' Login';
}
}
}
And you need to implement the router class to handle http requests like 'http://myweb.com/member/check'.
The router code would be something like this:
$url_segments = explode('/', $_SERVER['REQUEST_URI']);
if (count($url_segments) == 4){
$controller_name = $url_segments[2];
$method_name = $url_segments[3];
}
else if (count($url_segments) == 3){
$controller_name = $url_segments[2];
$method_name = $this->default_method;
}
else if (count($url_segments) == 2){
$controller_name = $this->default_controller;
$method_name = $this->default_method;
}
$this->current_controller = $controller_name;
$this->current_method = $method_name;
require BASEPATH . '/controller/' . $controller_name . '.php';
$class_name = ucfirst($controller_name);
$controller = new $class_name($method_name);
call_user_func( array( $controller, $method_name ) );
Create a MVC framework is not an easy work.
I create a simple MVC framework for educational purpose.
https://github.com/howtomakeaturn/PigFramework
Check the index.php file, and you will know what I mean router and controller.
I don't think that the point of MVC is to put HTML in a controller, if I were you I'd send some data back and make an if else statement in my view based on the send data. To make good use of an MVC you first need to understand what it is or does, so I'd recommend searching for a tutorial.
put this function in the controller from where you are calling a login function after if a user authenticated then it will set the session or flash data i.e $this->session->set_flashdata('success', 'you are loged in as $username');
else
redirect('login');

CodeIgniter getting form field value to lowercase

I have just started on learning how to use CodeIgniter and have never use any framework before so I only know a bit of how is the flow. Right now I have 1 issue that I want to set the input username to lowercase and I do not have any idea how to write the function for the convert_lowercase().
Below is my code:
public function signup_validation()
{
$this ->load->library('form_validation');
$this->form_validation->set_rules('username', 'Username', 'required|trim|is_unique[userinfo.username]|convert_lowercase');
$this->form_validation->set_rules('password', 'Password', 'required|trim');
$this->form_validation->set_rules('cpassword', 'Confirm Password', 'required|trim|matches[password]');
$this->form_validation->set_message('is_unique', 'That Username Already Exists.');
if($this->form_validation->run()){
}else{
$this->load->view('signup');
}
}
public function convert_lowercase()
{
strtolower($this->input->post('username'));
}
I am not sure am I doing the right way.
And is it best to just put the strtolower in the set_rules parameter? Or it is best to put in a function?
And if separate it, how should it be done and how do I get the final username data to insert into database?
Any kind souls out there can help me on this?
Thanks in advance.
You can provide php native functions for form validation to CodeIgniter. Here is how your code should be
public function signup_validation()
{
$this ->load->library('form_validation');
$this->form_validation->set_rules('username', 'Username', 'required|trim|is_unique[userinfo.username]|strtolower');
$this->form_validation->set_rules('password', 'Password', 'required|trim');
$this->form_validation->set_rules('cpassword', 'Confirm Password', 'required|trim|matches[password]');
$this->form_validation->set_message('is_unique', 'That Username Already Exists.');
if($this->form_validation->run()){
}else{
$this->load->view('signup');
}
}
You should check their documentation on form validation: http://ellislab.com/codeigniter%20/user-guide/libraries/form_validation.html
add callback_ to the rules.
$this->form_validation->set_rules('username', 'Username', 'required|trim|is_unique[userinfo.username]|callback_convert_lowercase');
and the callback function should return some value.
public function convert_lowercase() {
return strtolower($this->input->post('username'));
}
I will try to explain the best I can! Have you set up your database config file correctly? Have you set up the database correctly? Make sure that is all good before you do this..
Here is a bit of what is going on
if($this->form_validation->run()){
//Right here is what happens if the form passes your test!
$this->insert_user();
}else{
$this->load->view('signup');
}
if($this->form_validation->run()) takes the rules you gave it and if it returns "true" it runs in that if statement otherwise it will return you to the signup page
Here is the function that I set an example for
public function insert_user()
{
$data = array(
'username' => strtolower($this->input->post('username')),
'password' => $this->input->post('password'),
);
$this->db->insert('users', $data);
}
I also suggest you look into encrypting your passwords and other CI documentation, it is fantastic
Regarding Codeigniter 4 it is no longer possible to modify data during validation.
They add this information in official documentation :
"You can also use any native PHP functions that return boolean and permit at least one parameter, the field data to validate. The Validation library never alters the data to validate."

Codeigniter Ocular and Form Validation

New to CodeIgniter and new to Ocular so bear with me.
I used to code in the following way when running form validation (where the index() method contains the form loading code):
if ($this->form_validation->run() == FALSE)
{
$this->index();
}
else
{
$this->load->view('view_name', $data);
}
However I'm now trying to use the Ocular Template Library and the above code no longer works see example below:
if ($this->form_validation->run() == FALSE)
{
$this->index();
}
else
{
$this->template->set($data);
$this->template->render();
}
The above code does not run through the index method as it used to without Ocular and I was wondering what the best practice is to correct this or even if my previous code was best practice?
Regards,
Numan1617
Sometimes it's hard to determine best practice with Codeigniter because it's convention-less nature, so all I can really tell you is how I've found best in my experience...
I assume you're form view is being served up via index() and then you're submitting your form to this (seperate) controller function that validates and processes the form data, and re-displays the view with errors if there was a problem...
I would clean this up by consolidating it all into a single function...
public function form()
{
//if this is a post request
if ($_POST)
{
//check the validation
if ($this->form_validation->run())
{
//process it
//and then redirect if you want to send to a "success" page
redirect('uri/to/success');
}
else
{
//load up $data values to re-display form
}
}
//load up any $data values needed for standard view
$this->load->view('view', $data);
// or $this->template stuff...
}
It always seemed to me to be a bad route to go down calling controller functions internally, ex. $this->index()

Categories