How should this function be achieved using MVC

#1
[eluser]Lone[/eluser]
Ive got one question that has been bugging me for a while on how to properly achieve it in CodeIgniter. I have actually hit this issue a few times before for different applications but this time it is a bit easier to explain.


The Requirement
Sending of the same type of email from 3 different functions in a controller. In this email there are fields required as well.


The problem
I don't want to repeat the same email message sending process in 3 functions in the controller so what to have it in a 'common' location.


My first solution -which I don't like for having to use get_instance()
Make a library with a function that sends the email using given variables eg. name and email.

Controller
Code:
function sample_name {
  $name = "John";
  $email = "john@sample.com";
  $this->load->library('misc');
  $this->misc->send_test_email($name,$email);
  $data['message'] = "Success";
  $this->load->view('controller/sample_name',$data);
}

function another_sample_name {
  $name = "John";
  $email = "john@sample.com";
  $this->load->library('misc');
  $this->misc->send_test_email($name,$email);
  $data['message'] = "Success";
  $this->load->view('controller/another_sample_name',$data);
}

Library
Code:
function send_test_email($name,$email) {
  $CI =& get_instance();
  $CI->load->library('email');
  $CI->email->from('the@website.com');
  $CI->email->to($email);
  $CI->email->subject('Test Email');
  $CI->email->message('Wowzers, you just sent a test email!');
  $CI->email->send();
}


How to improve?
It is a hard one to explain, but hopefully you get what I mean, Im trying not to repeat myself in my code (DRY) and trying to see how to achieve it without having to use the get_instance() as I feel it is a bit of a last resort thing to do.

#2
[eluser]thurting[/eluser]
I'm not really sure what you are trying to accomplish, but your description sounds like it could be solved by creating a super class from which the relevant controllers inherit from. Just remember to call the parent constructor throughout the chain so Controller::Controller() is eventually called.
Code:
//This is the superclass all controllers must inherit from - core class
class Controller {}

//This should probably be an abstract class
abstract class EmailController extends Controller {
  public function __construct() {
    parent::Controller();
  }

  private function _mail() {
     //your function here
  }
}

//This is your action controller
class ActionController extends EmailController {
  public function __construct() {
    parent::__construct();
  }

  public function action() {
    //This is an action - I can call the _mail function from here
    $this->_mail();
  }
}

#3
[eluser]Lone[/eluser]
Thanks for the suggestion thurting - I think that your code might not be so ideal for what I am trying to achieve but damn I can see some good uses for it elsewhere though Smile

I think I might have worked out the answer to my solution - private functions. But the reason I thought the use of them would not be correct in a controller under MVC is because my understanding of the controller functions to be used strictly for http://www.domain.com/controller/function - not private functions?

Or is this an ok practice to do and I could achieve the answer to my solution the correct MVC way by the following:

Controller
Code:
function _send_email($name,$email) {
  $this->load->library('email');
  $this->email->from('the@website.com');
  $this->email->to($email);
  $this->email->subject('Test Email');
  $this->email->message('Wowzers, you just sent a test email!');
  $this->email->send();
}

function sample_name {
  $name = "John";
  $email = "john@sample.com";
  $this->_send_email($name,$email);
  $data['message'] = "Success";
  $this->load->view('controller/sample_name',$data);
}

function another_sample_name {
  $name = "John";
  $email = "john@sample.com";
  $this->_send_email($name,$email);
  $data['message'] = "Success";
  $this->load->view('controller/another_sample_name',$data);
}

#4
[eluser]wiredesignz[/eluser]
Use a Model, autoload it if you have CI 1.6.0

And don't listen to those that say a Model is for database interaction only. Models are for any data, business logic, or processing.

And you never know, later on you may wish to store your emails in a database, the Model then is the perfect place as you can alter it without changing anything else.

#5
[eluser]thurting[/eluser]
If you don't need the function in other controllers then just use a private function. Just remember to use the underscore naming convention (_name). Not only is this a good practice, but it prevents the function from being called through the HTTP request - at least using the default set up.

#6
[eluser]Lone[/eluser]
I too considered a Model and see it as the most ideal location - but as you said it is quite often commented in codeigniter as for 'database interaction only'. But I can see so many other uses for it as well like this.

#7
[eluser]wiredesignz[/eluser]
If you really need someone elses confirmation that Models are really for any business logic, and not just database, read this page:
http://www.phpwact.org/pattern/model_view_controller

#8
[eluser]wiredesignz[/eluser]
Or this from wikipedia:

Model

The domain-specific representation of the information on which the application operates. Domain logic adds meaning to raw data (e.g., calculating if today is the user's birthday, or the totals, taxes and shipping charges for shopping cart items).

Many applications use a persistent storage mechanism (such as a database) to store data. MVC does not specifically mention the data access layer because it is understood to be underneath or encapsulated by the Model.

An MVC model component is intended for domain logic, not data access. The description says very clearly that the data access layer is understood to be underneath or encapsulated by the model.

#9
[eluser]Lone[/eluser]
Thanks for that link - I have seen similar descriptions of models like that as well which go against what I keep hearing for the use of them in CI. Im interested into why it is always said in CI by EllisLabs for database only?

The other advantages I see to putting it into the model is that any db related functions in the model can be called by a straight '$this->' instead of '$this->model'. Also, the fact that then the function doesn't become controller dependant as being in the model means the model can be loaded in any controller and use the function from the model as required.

#10
[eluser]wiredesignz[/eluser]
The Ellislab/CI guys probably won't commit to any particular use of a Model, it's up to the individual to decide, thats why CI is better than other PHP frameworks. You are free to do whatever works for you.

However, following good MVC practice means seperation of concerns, a Controller is not the place for email processing.

Use a Library, Model, Plugin or even a helper. The choice is yours.


Digg   Delicious   Reddit   Facebook   Twitter   StumbleUpon  


  Theme © 2014 iAndrew  
Powered By MyBB, © 2002-2020 MyBB Group.