Handling contact form submissions Codeigniter - php

I've inherited a website built using Codeigniter (v2.1.4). The client has asked for a change, and I'm not sure of the best way to achieve it.
I have the following method in the Main controller that powers a new vans page.
public function new_vans($slug = null){
$this->load->view('inc/header_view');
if($slug === NULL){
//If no slug is provided, show all new vans
$this->load->view('new_vans_view');
}else{
//If there is a slug, just show the selected van, or redirect if nothing returned
$data['new_van'] = $this->Database->getSingle('new_vans', array('slug' => $slug));
if(!empty($data['new_van'])){
$this->load->view('new_van_details_view',$data);
}else{
redirect('/new-vans');
}
}
$this->load->view('inc/footer_view');
}
The client has asked for a contact form to be added to a couple of pages including this one, and my question is, should I create a new method that just handles the contact form submissions? If so, how would I handle sending validation errors back to the page? The contact forms will all have the same fields, so I would guess creating a new method is the way to go?

Partial Views(forms)
Partial views are good for forms, they can be re-used
like your client has requested.
Returning views as data
There is a third optional parameter lets you change the behavior
of the function so that it returns data as a
string rather than sending it to your browser.
This can be useful if you want to process the data in some way.
If you set the parameter to true (boolean) it will return data.
The default behavior is false, which sends it to your browser.
Remember to assign it to a variable if you want the data returned:
$string = $this->load->view('myfile', '', true);
Master layouts
To create a Master layout so you can wrap your views
create a new file inside your views directory
views/master/layout.php
<body>
<?php $this->load->view($view); ?>
</body>
Controller
class someController extends CI_Controller
{
public function __construct()
{
parent::__construct();
$this->template = 'master/layout';
}
public function index()
{
return $this->load->view($this->template, array(
'view' => 'somecontrollerview',
'contact_form' => $this->load->view('partials/forms/contact', array(), true)
));
}
}
somecontrollerview
Echo out the contact form(string)
<?php echo $contact_form; ?>
Contact Controller
Create a new Controller to handle your form validation

The client has asked for a contact form to be added to a couple of pages including this one, and my question is, should I create a new method that just handles the contact form submissions?
create a new controller and new methods
If so, how would I handle sending validation errors back to the page?
look through the codeigniter documentation for form validation. basically if they have an error you are going to show them a view with the form again. it does not matter which page they came "from".
The contact forms will all have the same fields, so I would guess creating a new method is the way to go?
you need to validate the form fields, hopefully capture the contact info to a database, send an email confirmation to the customer, and send an email to the sales person unless its being done directly from the database, and then show a view with a thank you.
each one of those steps is a separate method.
optionally you can show the email address on the thank you page saying 'we have sent you a copy to the email address: something#gmail.com -- that way if the customer messed up the email address they can go back and correct it.

Related

CakePHP - Controller or No Controller?

I am currently building a web app which has two models, Donor and Donation Models respectively. It has multiple user roles. When the staff user first registers a donor, I want him to be redirected to another form which allows him to fill in the Donation details(the donor is registered once the first donation is successful).
Firs of all, should I create a donation controller, from which I would redirect the user using:
return $this->redirect(array('controller'=>'donations','action'=>'add'));
For the above to work, it requires me to save the newly registered donor's id in a session like so :
$this->Session->write('id', $this->Donor->id);
So the user is redirected to 'donations/add' in the url, and this works fine.. However I think this has some flaws. I was wandering whether I should create another action inside the Donor controller called 'add_donation', which will have its respective 'View'. The idea is to be able to form a url of the sort : 'donors/add_donation/4' (4 being the donor_id ! )
This URL follows this construct: 'controller/action/id'
If anyone could shed some light on best practices, or describe any caveats to my solution(the former, using session etc.) , please do help a brother out! Ill be deeply indebted to you! Thanks in advance!
After you saved the data you can do this in the DonorsController:
$this->redirect(array(
'controller' => 'donations',
'action' => 'add',
$this->Donor->getLastInsertId()
));
There is no need to return a redirect, it's useless because you get redirected. Notice that we pass the last inserted record id as get param in the redirect. The redirect method of the controller calls by default _stop() which calls exit().
CakePHP3: There is a discussion about changing that default behavior in 3.0. Looks like in CakePHP 3.0 the redirect() won't exit() by default any more.
DonationsController:
public function add($donorId = null) {
// Get the donor to display it if you like to
if ($this->request->is('post')) {
$this->request->data['Donation']['donor_id'] = $donorId;
// Save code here
}
}
I would not use the session here, specially not by saving it to a totally meaningless and generic value named "id". If at all I would use always meaningful names and namespaces, for example Donor.lastInsertId as session key.
It's not always clear where to put things if they're related but the rule of thumb goes that things should go into the domain they belong to, which is pretty clear in this case IMHO.
Edit:
Leaving this edit here just if someone else needs it - it does not comply with the usage scenario of the asker.
If you have the user logged in at this stage, modify the add function to check if the userId passed is the same as the one logged in:
DonationsController:
public function add($donorId = null) {
// Get the donor to display it if you like to
if ($this->request->is('post')) {
if ($this->Auth->user('id') != $donorId) {
throw new InvalidArgumentException();
}
$this->request->data['Donation']['donor_id'] = $donorId;
// Save code here
}
}
You can use also the same controller using more models with uses.
Or you can also to ask to another controller with Ajax and morover to get response with Json.

Prestashop Add extra fields to registration form

I am building a prestashop site
The corporate buyers cannot register for an account to view the products unless they can enter a valid EIN number or a valid Duns & Brandstreet number in registration.
How to make it possible?
Also any other e-commerce software that can help me solve this by switching to it?
All you really need to do is add the field to the template and then override the AuthController with additional code to handle you new field. e.g.
<?php
class AuthController extends AuthControllerCore
{
public function preProcess()
{
// Additional pre-processing for the new form field
if (Tools::isSubmit('submitAccount'))
{
if (!MyDBNumberValidationClass::verifyvalidnumber(Tools::getValue('db_number_field', 0)))
$this->errors[] = Tools::displayError('The Dun and Bradstreet number you entered is invalid.');
}
parent::preProcess();
}
}
I'm assuming that you're doing complex verification of the number which is why the static call to MyDBNumberValidationClass::verifyvalidnumber() is in the above, but it could equally by any simple test or an additional function in your AuthController override class definition above that validates. If you add two fields (i.e. the EIN number too) then just alter the logic to handle generating an error only if both are invalid; success of the form validation is based on $this->errors being empty.
This is only part of a general solution since it only handles validating the extra fields. If you need to actually do something with the data entered then the best way is to write a little handler module that installs itself on hookCreateAccount e.g.
public function hookCreateAccount($params)
{
// Get the field data entered on the form
$DB_number = $params['_POST']['db_number_field'];
// Your custom processing...
}
Note that there's no way to back out of the account creation from here so you will want to add code to email the store owner should there be a problem.

Best practise for handling form submission in controllers

Lets say for example I am creating a an online shop. I have a controller called products and within that controller I have a function called create_product. Create_product calls a view that displays a form where users get to enter new products into the database.
When the user fills in the form to create a product, should I send the action back to the create_product controller and handle it with an IF statement? or offload to another function?
Example
<form method="post" action="www.example.dev/products/create_product/add">
//the above form would post back to the original controller
function create_product()
{
if(uri->segment(3) == "add")
{
//call a model to do all the database stuff
}
load->view->create_product_form;
}
Is this the best way to handle this or should I be passing it off to another function?
Don't cram a ton of stuff in one function using the URI segment to filter it. createProduct() can list the products available for creation (in a CRUD format, I assume), and the submission of the form should ping another controller with the POSTed data. Perhaps insertProduct(), where the data is sanitized and sent to the model for insertion to the database.
Separation of concerns! Keep the functions as separate as possible with good descriptors for the names of the functions.
I (personally) would have a function that set the form parameters and "launch" the view with that form, and another function used to validate and call the model to put the values of that form into the database. I believe that is really up to you, but the code would be cleaner if you divide the controller with several functions depending on what they actually do.
I like the way symfony deals with forms & form submission. It is in one function (action)
simplified code:
executeCreate() {
$this->form = new Form()
if($r->isMethod('POST')) {
//handle submission
bind();
save();
}

CakePHP form validation before sending post to the requested controller function

My validation is working as it stands, but I want to display the validation error prior to the search controller. I understand this might not be possible within the CakePHP framework.
I have a model plan.php. And in the plans_controller.php, I have a function called search().
My form calls search() as expected (because there is no search model):
echo $this->Form->create('Plan', array('action' => 'search'));
As it stands, when I submit my search, the errors are displayed and the url changes to .../search, so no results are displayed ("There are 0 results for that search criteria", but the correct validation errors are displayed below required form fields.
I do not want the .../search url to be displayed. I want the form to "halt" and just display the validation errors w/out changing the url to the search function.
I am calling the search form within an element because the search form displays on several different pages.
To sum this up: The search form should validate w/out changing the url path to the controller action name of the search. Of course, the validation is done IN the search() and plan.php model, so I just don't know how to work around this and wondering if its even possible.
You can use the validates() method of the model to check whether it validates and then redirect back.
Assuming your model is called Plan, this would be your controller
$errors = array();
if (!$this->Plan->validates($this->data)) {
//errors occured
$errors = $this->Plan->invalidFields();
$this->Session->save('Plan.errors', $errors);
$this->redirect('/plans');
}
And in your view.
if ($this->Session->check('Plan.errors')) {
$errors = $this->Session->read('Plan.errors');
$this->Session->delete('Plan.errors'); //don't want it again
}
In both cases, make sure Session helper/component is actually assigned to your view and controller
OK. Cracked out a working solution w/ implode, but now my errors are only displayed in the default layout and no longer under the form fields where that belong.. So now I need to know how to get the errors back below the form fields..
Working code:
...else {
$errors = $this->Plan->invalidFields();
$error_messages = implode(' ',$errors);
$this->Session->setFlash($error_messages);
$this->redirect('/');
}...

PHP advice please. (Kohana experience a plus)

I've been working with PHP for about a year, but I do it as a hobby. I dont have anybody I can go to as a teacher or a mentor to give me advice on what I may be doing completely wrong, or what I could do better. I've done quite a few different things within that year, so I wouldnt consider myself a complete noob.
Anyways, I have just started using a framework (Kohana), and there really arent that many tutorials out there, so I'm not entirely sure if I'm doing things in a good way.
I have a few code snippets that I would like to post to get some feedback pertaining to what I just said.
For Starters
User Controller
class User_Controller extends Template_Controller{
public function register()
{
// logged in users cant register
if($this->logged_in)
{
url::redirect('user/profile');
}
// initially show an empty form
$form = $errors = array
(
'username' => '',
'email' => '',
'password' => '',
'gender' => '',
'dob_month' => '',
'dob_day' => '',
'dob_year' => '',
'date_of_birth' => '',
'captcha' => '',
'registration' => ''
);
// check for a form submission
if($this->input->post('register'))
{
// get the form
$post = $this->input->post();
// prepare the data for validation
$post['date_of_birth'] = "{$post['dob_year']}-{$post['dob_month']}-{$post['dob_day']}";
// create a new user
$user = ORM::factory('user');
// validate and register the user.
if($user->register($post, TRUE))
{
// SEND EMAIL
// login using the collected data
if(Auth::instance()->login($post->username, $post->password, TRUE))
{
// redirect the user to the profile page
//url::redirect("user/profile/{$user->id}");
}
}
// get validation errors and repopulate the form
$form = arr::overwrite($form, $post->as_array());
$errors = arr::overwrite($errors, $post->errors('registration_errors'));
}
// template variables
$this->template->title = 'Sign Up';
$this->template->body = new View('layout_1');
// layout variables
$this->template->body->left = new View('user/registration_form');
$this->template->body->right = 'Right Side Content';
// registration form variables
$this->template->body->left->form = $form;
$this->template->body->left->errors = $errors;
$this->template->body->left->captcha = new Captcha('register');
}
}
Register Function within User_Model
class User_Model extends ORM{
public function register(array& $user, $save = FALSE)
{
$user = new Validation($user);
// logged in users cant register
if(Auth::instance()->logged_in())
{
$user->add_error('registration', 'logged_in');
return FALSE;
}
// trim everything
$user->pre_filter('trim')
// everything is required
->add_rules('*', 'required')
// username must be 5 - 30 alphanumeric characters and available
->add_rules('username', 'length[5,30]', 'valid::alpha_numeric', array($this, 'username_available'))
// email must be valid format and available
->add_rules('email', 'valid::email', array($this, 'email_available'))
// password must be 5 - 15 characters and alpha dash
->add_rules('password', 'length[5,15]', 'valid::alpha_dash')
// gender must be either male or female. capitalize first letter
->add_rules('gender', array($this, 'valid_gender'))
->post_filter('ucfirst', 'gender')
// dob must be a valid date, and user must be old enough.
->add_callbacks('date_of_birth', array($this, 'check_dob'))
// captcha must be entered correctly.
->add_rules('captcha', 'Captcha::valid');
// add the registration date
$this->registration_date = date::unix2mysql(); // helper function transforms the current unix to mysql datetime format
// validate the information. an ORM function.
$result = parent::validate($user, $save);
// was the user info valid?
if($result === TRUE)
{
// was the user saved?
if($save === TRUE)
{
// add a login role
$this->add(ORM::factory('role', 'login'));
$this->save();
}
}
else
{
$user->add_error('registration', 'failed');
}
return $result;
}
}
Mostly all my models follow the same format when validating info.
I have some other things I would appreciate feedback on as well, but I dont want to overwhelm anybody.
Thanks a lot for your time
EDIT: I'm sorry, I should've posted both the user controller and model. I've been reading alot about how models should be fat, and controllers should be skinny. Thats why I created a register function in the model to validate the info instead of doing so within the controller. The register function takes an array, but turns that array into a validation object so that I can retrieve the user input, and the errors. I've seen a few tutorials on Kohana where it was done this way.
First, I would not put the register() method into the User model. A model should be a representation of the object in the database and generally only contains your "CRUD" methods (create, retrieve, update, delete), getter and setter methods, and maybe some static helper methods related to the model. By putting your register() method into the model, you're making the model do presentation logic that should really be done by a User controller, since this is a response to a user action. A controller handles user actions, validates those user actions, then updates the model if the validation is successful.
In your example, the user is attempting to create a new account. He fills out a form and clicks submit. The form's POST action should point to a controller's method, like /user/register, and that method will use the Validation library to validate the form data sent by the user. Only if that data validates successfully should you create a User model instance, set the properties of that model to what the user input, and then use the model's save() method to save to the database. If the validation fails, you report the error to the user and you don't create a User model at all since you don't have a valid data set to create a model with yet.
Next, you are checking to see if the user is logged in. Again, this should be in the controller, not the model. Besides that, the user should not be able to get to this register process in the first place if he is already logged in. The controller method that creates the user registration form view should check to see if the user's logged in, and if he is, then he should be redirected to another page. Even if the user is playing tricks and manages to submit the form (maybe he logged in via another window while having the form open in an old window), your register method should check for that first and not create a $user Validation object yet.
I can see in your code that there are some confusing items based on your model set up. For example, you're passing the $user array into the method, which I presume is the form data. But you're using the "pass by reference" operator (&) which is unnecessary in PHP5 since all objects are now passed by reference. But after that you're recasting $user as a Validation object. Are you using the $user Validation object elsewhere and require it to be passed by reference? If so, that's another flaw in the logic as all of this processing needs to be in the controller and the $_POST values can be used directly in the controller instead of having to pass around a Validation object.
Later on, you're validating the user information with parent::validate($user, $save). Why is the validate() method being called on parent as a static method? If this is a model, it should be extending Kohana's core Model class, and "parent" references the Model class. Is your model extending the Validation class? Also, why are you passing in the $user Validation object to the validation() method? Doing that is required if you need to do recursion (to validate elements again after making changes from previous filters), but it looks like you're not doing anything to require recursion. You should be calling validate() on the $user Validation object:
$user->validate();
without any arguments. The validation errors will become part of the $user object, so you can check for errors using
$user->errors();
Finally, while Kohana allows you to use method chaining, I would not use one long chain to set up the rules and other items for the validation. It's confusing and may cause debugging to be difficult. Put each of those on its own line and perform each directly on the $user object.
I dont know Kohanna so im not sure what the lay of the land is on their MVC separation but typically i would make register an action on a controller. The main thing i disagee with in your code is that the Model is coupled to the Authentication system internally. The authentication check should be made outside the class and the control flow decision should be made outside as well, OR the result of the authentication check should be passed in to the Model for use in its internal operation.
Typically i might do something like the following pseudo code:
// in my controller class for User or whatever
public function registerAction()
{
// get the form data from the request if its POST, ortherwise a blank array
$userData = $this->getRequest('user', array(), 'POST');
// create a user
$user = new User($userData);
if(Auth::instance()->logged_in())
{
// we are logged in add an error to the user object for use by the view
$user->getValidator()->add_error('registration', 'logged_in');
}
elseif($user->is_valid())
{
// user data is valid, set the view with the success message
$user->save();
$this->setView('register_success');
}
/**
* render the designated view, by default this would be the one containing the
* registration form which displays errors if they exist - however if we success-
* fully registered then the view with the success message we set above will be
* displayed.
*/
$this->render();
}

Categories