Using common functions (controllers) in code igniter - php

I am using Code Igniter as the framework for a project I am working on. I am a little new to the MVC world but learning as I go.
In my project, I have a front end controller and a back end admin controller.
On the front end, I have a registration form that has about 5 drop down's that are populated by a database call. In the admin side of things, I show the user submitted record along with pre-selecting the option in the dropdown that was chosen.
In order to do this, I had to also populate the dropdowns in the admin controller.
This is where my question comes into play. In a scenario like that, I essentially have 3 identical functions in the front end controller and the admin controller.
How can I go about creating a common or controller that both of these controllers have access to?
Here is an example of a shared function:
public function fetchSites($org = null)
{
if (!$org) {
if (null !== $this->input->post('org')) {
$sites = $this->support_model->getSites($this->input->post('org'));
header('Content-Type: application/json');
echo json_encode($sites);
}
} else {
$sites = $this->support_model->getSites($org);
return $sites;
}
}
Both the front end and backend share the same model, just different controllers.
I looked into creating a controller in the application/core but I couldn't figure out how to access the data from that controller.

You can easily create a helper and call it from both controllers, that way you wont be repeating code.
Something along with this in your helper file:
function sharedFunctionality($org = null)
{
$CI = & get_instance();
$CI->load->model('path/to/support_model');
if (!$org){
$sites = $CI->support_model->getSites($CI->input->post('org'));
header('Content-Type: application/json');
echo json_encode($sites);
} else {
$sites = $CI->support_model->getSites($org);
return $sites;
}
}
In both your controllers you will only need to call the helper and then the function:
$this->load->helper('nameOfHelper');
$sites = sharedFunctionality($this->input->post('field'));
More information to create a helper file:
https://ellislab.com/codeigniter/user-guide/general/helpers.html

Related

Passing database results into header file in PHP-MVC

I'm starting a new project using the http://www.php-mvc.net framework but have never had to include database results in the header file before and not sure how to go about it. I need to pull a list of current categories and there ID's from the database and use them to populate a menu.
The header.php file is in /views/_templates. The normal way of passing database results to the view is to run the query in the relevant model, get the data in the controller, pass the data from the controller to the view, then loop over the data with a foreach loop in the view. The problem being the _template files don't have any kind of controller for them.
The best I can come up with is to use include and include a view file from the home controller, using that controller to get the results and pass them to a menu.php in the views/home folder.
/views/_templates/header.php
<li class="dropdown">
<?php include 'views/home/menu.php'; ?>
</li>
/views/home/menu.php
foreach ($links as $link){
<li><?php echo $link->name; ?></li>
}
the above code has been shortened its more for principle than a working example.
The method I have come up with works but I wanted to know if there's a more elegant way of doing things?
As I commented:
No need to store in session you could use a Twig global so its available in all templates and you could make sure that your base controller runs a preExceute to pull all the data together and then add that global.
That might look something like this:
abstract class MyBaseController extends Controller
{
private $view = null;
private prepareView()
{
$twig_loader = new Twig_Loader_Filesystem(PATH_VIEWS);
return new Twig_Environment($twig_loader);
}
public function getView()
{
if ($this->view === null) {
$this->view = $this->prepareView();
}
return $this->view;
}
protected function preRender()
{
// whatever logic you need to prepare the menu data as $links
$this->getView()->addGlobal('links', $links);
}
public function render($view, $data_array = array())
{
$this->preRender();
// render a view while passing the to-be-rendered data
echo $this->getView()->render($view . PATH_VIEW_FILE_TYPE, $data_array);
}
}
Now depending on what data you need to build your stuff for $links you may or may not need to get a bit more elaborate. Especially given how the URL params are handled in the Application class. I really hope you're only doing this as a learning experience because this "framework" you've found isn't really good for much other than learning how you might implement MVC.

CakePHP: how to do sub-actions with sub-views

Apologies if I'm using the wrong terminology to describe what I'm trying to do...
I have a model/controller called Report which users can view like so:
example.com/reports/view/123
Each report hasAndBelongsToMany File objects. I need to make those files accessible like so:
example.com/reports/view/123/file/456
Or
example.com/reports/view/123/456
^ ^
| |
report file
I'm intentionally NOT creating a separate action for files (example.com/files/view...) because access to the file is relative to the report.
What is the correct way to do this in CakePHP?
My first guess is to add logic inside of ReportsController::view that checks for the existence of the second parameter (file) and manually render() a different view (for the file) conditionally. But I'm not sure if this is "the CakePHP way".
You are in the right path, modify your action to accept an optional parameter.
public function view($file = null) {
$somethingElse = null;
if (isset($file)) {
//your logic
$somethingElse = $this->Foo->bar();
}
$this->set(compact('somethingElse'));
}
Regarding to the view, I don't know your requirements, but I think you don't need to create a different view, you can either put a conditional in your view to show something, or (my favourite approach) create an element that will be displayed only if $somethingElse contains something. That is:
//View code
if (!empty($somethingElse)) {
echo $this->element('yourAwesomeElement', compact('somethingElse'))
}
Then in yourAwesomeElement
foreach ($somethingElse as $something) {
echo $something;
}
The good thing is that your element will be reusable for future views that could need this.

cakephp - callback function for every controller action to set available navigation links

I'm trying to achieve something so basic in my cakephp-app, that I'm quite surprised I didn't easily find a solution to it...
What I just want to do is to set available links for my app's main navigation depending on the user being logged in or not and if he is, depending on his role (which is stored in the users-table).
So basically a function like this:
if(!$this->request->is('ajax')) {
if(_user_is_not_logged_in_) {
$availableNavItems = array('login','help');
}
else {
if($this->Auth->User('role') == 'user') {
$availableNavItems = array('something','something else','whatever','help','logout');
}
elseif($this->Auth->User('role') == 'admin') {
$availableNavItems = array('something','something else','whatever','admin-tool','user management','help','logout');
}
}
// set available pages for layout
$this->set('availableNavItems',$availableNavItems);
}
In my layout of course I would create a navbar with links to those available pages.
The only question I have - where would I put code like the above? Is there any callback-function I could put in AppController which cakephp calls on every request?
And, what would be a good way to check what I wrote as pseudo-code "_user_is_not_logged_in_" above?
Thanks in advance for any help!
if(_user_is_not_logged_in_) {
could be written as
if(!$this->Auth->user('id')){
And you could put the function in your beforeRender method of your AppController, which executes on every request, right before the view is rendered.
Also of note is the beforeFilter method, which gets called early, before the controller logic executes. You shouldn't need it in this case, but it's worth knowing about.

MVC in PHP - How does the controller know the view?

I'm new to MVC in PHP and I was just wondering what the best way to do this is?
At the moment I've got a simple setup like this:
Model
User.php
Controller
controller.php
View
login.php
register.php
my_account.php
The model has all the database functionality for logging in and registering, and the view files have the relevant working forms.
My main question is, what is the best way to have the controller call pages? Currently, it looks something like:
public function show_page()
{
if ($_GET['p'] == "login")
{
include('View/login.php');
if (isset($_POST['username']))
{
$this->user->login($_POST['username'], $_['pass']
}
}
if ($_GET['p'] == "register") { include('View/register.php'); }
if ($_GET['p'] == "my_account") { include('View/my_account.php'); }
}
This doesn't seem logical, am I doing it wrong?
I think that the best way is to use some kind of routing system so you have a map somewhere with the possible url pattern / page to show combinations and after deciding which controller to call you can load the appropriate view in your controller.
What you presented here seems somewhat blurred to me. I think that you should check out implementations out there like Pure mvc or symfony so you can get a grip on the concept quickly. I believe that you (or anyone else for that matter) shouldn't reinvent the wheel but study, understand and improve what you can get.
If you are going to create your own MVC framework then you should check out the basic MVC concepts and plan your software before trying to write it.
Most PHP based MVC frameworks that I've used utilize a front controller. The .htaccess file directs all traffic to a single (usually index.php) file (usually) in the root of the project.
This file is responsible for determining which application controller to load. That controller is then responsible for any and all application level logic.
in a framework I wrote, in my front controller I do this
$page = tgsf_parse_url();
require resolve_controller( $page );
The tgsf_parse_url function in the above code parses $_SERVER['REDIRECT_URL'] to determine what variables are being passed.
the resolve_controller in the above code handles plugin hooks and 404 conditions, but the bottom line is that it always returns a path to send to include/require so that variable scoping doesn't become an issue (including in a function limits variable scope)
Any variables that are set in the controller are automatically available in a view when you include a view like this:
// this is an application level controller file
$name = 'Mr. Example';
include view( 'example' );
Then in the view file:
<h2><? echo $name; ?></h2>
What you have is not dynamic at all.
This is how I do it in my MVC:
private function loadView(){
//Bring the variables to the global scope
extract($this->getAll()); //load all variables into local scope
if(Config::get('view')){
$template_file = 'view/' . Config::get('view') . '/' . Config::get('method') . '.stp';
if(is_file($template_file)){
include $template_file;
}
else {
include 'view/missingview.stp'; //no such view error
}
}
else {
Config::set('template', 'blank');
include 'view/missingfunction.stp'; //no such function error
}
}
Have something set the view somewhere in the code.
This is how I set the view in the controller:
public function __construct(SessionManager $SESSION) {
$this->pageOn = Config::get('page');
$this->session = $SESSION;
$model_name = $this->name;
if(class_exists($model_name) && is_subclass_of($model_name, 'AppModel')){
/**
* #var AppModel $model_name
*/
$this->$model_name = new $model_name();
}
else {
//default model (no database table chosen)
$this->$model_name = new AppModel();
}
/* Get all posts */
$this->posts = $this->$model_name->getPosts();
Config::set('view', strtolower($model_name)); //<<RIGHT HERE!
if(!$this->session->get(strtolower($model_name))){
$this->session->set(strtolower($model_name), array());
}
}

What is an example of MVC in PHP?

I'm trying to understand the MVC pattern. Here's what I think MV is:
Model:
<?php
if($a == 2){
$variable = 'two';
}
else{
$variable = 'not two';
}
$this->output->addContent($variable);
$this->output->displayContent();
?>
View:
<?php
class output{
private $content;
public function addContent($var){
$this->content = 'The variable is '.$var;
}
public function displayContent(){
include 'header.php';
echo $content;
include 'footer.php';
}
}
?>
Is this right? If so, what is the controller?
The controller is your logic, the model is your data, and the view is your output.
So, this is the controller:
$model = new UserDB();
$user = $model->getUser("Chacha102");
$view = new UserPage($user->getName(), $user->getEmail());
echo $view->getHTML();
The model is the UserDB class which will give me my data. The view is the UserPage that I give the data from the model to, and it will then output that page.
As you can see, the controller doesn't do much in this example, because you are simply getting user data and displaying it. That is the beauty of MVC. The controller doesn't have to deal with the User SQL or HTML stuff, it just grabs the data and passes it to the view.
Also, the view doesn't know anything about the model, and the model doesn't know anything about the view. Therefore, you can chance the implementation of either, and it won't affect the other.
Relating more to your example, you have the view correct, but you have mixed your controller and model.
You could relieve this by:
Controller:
$model = new NumberToWord();
$word = $model->getWord($a);
$this->output->addContent($word);
$this->output->displayContent();
Model:
class NumberToWord{
public function getWord($number)
{
if($number == 2){
return 'two';
}
else{
return 'not two';
}
}
}
And keep your same output
Controllers receive user requests - usually there is some kind of router that takes a URL and routes the request to the appropriate controller method.
Models are used by a controller to query data to/from a database (or other data source).
Views are called from a controller to render the actual HTML output.
If all you want to do is create a simple template system, you might aswell go with:
$content = 'blaba';
$tpl = file_get_contents('tpl.html');
echo str_replace('{content}',$content,$tpl);
With a template file like:
<html>
<head><title>Whatever</title></head>
<body>{content}</body>
</html>
In your example, it's more like you've split a Controller into a Model and a View.
Model: Business logic / rules and typically some sort of database to object relational mapping
Controller: Responds to url requests by pulling together the appropriate Model(s) and View(s) to build an output.
View: The visual structure the output will take. Typically a "dumb" component.
It can be confusing when you first encounter MVC architecture for a web app, mainly because most web frameworks are not MVC at all, but bear a much closer resemblance to PAC. In other words, the Model and View don't talk, but are two elements pulled together by the context the Controller understands from the given request. Check out Larry Garfield's excellent commentary on the subject for more information:
http://www.garfieldtech.com/blog/mvc-vs-pac
Also, if you are interested in the MVC pattern of development, I suggest you download one of the many frameworks and run through a tutorial or two. Kohana, CodeIgnitor, CakePHP, and Zend should be enough to kick-start a Google-a-thon!
Zend Framework: Surviving The Deep End has some good sections explaining MVC. Check out the MCV Intro and especially this seciton on the model.
There are numerous interpretations of the Model but for many programmers the Model is equated with data access, a misconception most frameworks inadvertently promote by not obviously acknowledging that they do not provide full Models. In our buzzword inundated community, many frameworks leave the definition of the Model unclear and obscured in their documentation.
To answer "where's the controller":
Controllers must define application behaviour only in the sense that they map input from the UI onto calls in Models and handle client interaction, but beyond that role it should be clear all other application logic is contained within the Model. Controllers are lowly creatures with minimal code who just set the stage and let things work in an organised fashion for the environment the application operates in.
I think you'll fine it (and his references of other articles and books) a good read.
Here is a very simple example of MVC using PHP. One thing missing is THE router. It selects one of the controller to do the job. We have only one controller, the customer.
If we compare it with 3 tiers
Model: The database
View: Client
Server:Controller
Router:It selects a controller
When you select something from an application on web browser, the request goes to router, from router it goes to controller. Controller asks from model and make a view. View is rendered to you.
Only model can talk to controller back and forth.
1- Model.php
<?php
class Model
{
private $con=null;
private $r=null;
function connect()
{
$host="localhost";
$db="mis";
$user="root";
$pass="";
$this->con=mysqli_connect($host,$user,$pass) or die(mysqli_error());
if(!$this->con){
echo die(mysqli_error());
}
else mysqli_select_db($this->con,$db);
}
function select_all()
{
$this->connect();
$sql="select * from customers";
$this->r=mysqli_query($this->con,$sql) or die(mysqli_error());
return $this->r;
}
function display_all()
{
$i=0;
echo "aaaaaaaaaa";
$this->r=$this->select_all();
while($q=mysqli_fetch_array($this->r))
{
$i++;
echo $i."-Id:".$q['id']."</br>";
echo $i."-Name:".$q['name']."</br>";
echo $i."-Phone:".$q['phone']."</br></br>";
}
}
}
?>
2. Controller: There may may be many controllers.
<?php
class Customers extends Model
{
function select_all1()
{
//echo "aaaaaaa";
$this->display_all();
}
}
?>
3. View: There may be many views
<?php
include("model.php");
include("customers.php");
?>
<html>
<head><title>Customers</title></head>
<body>
<?php
$c=new Customers();
echo $c->select_all1();
?>
</body>
</html>

Categories