I'm in the middle of cleaning up a web app written in CodeIgniter. Each main view has a sidebar that displays some common database driven data - recent updates, news, etc. I have the queries cached to help speed things up a bit but I'm also looking for a better way to make this happen.
Right now each controller loads the model, loads up the $data array and passes it to the view.
I've extended the main CI controller class and am not loading up the data in the constructor which has simplified the code a bit but I'm still left feeling like there should be a better way. Any suggestions?
not sure if that's what you're asking , but you can have a extra parent/base controller to load repetitive data like news , updates , etc...
class baseController extends CI_Controller {
public function __construct(){
parent::__construct();
}
function viwe($view = 'defualt' , $data = array()){
$data['updates'] = $this->db->get('updates');
$data['news'] = $this->db->get('news');
$this->load->view($view , $data );
}
}
another controller :
include "baseController.php";
class another extends baseController {
public function __construct(){
parent::__construct();
}
function index()
{
$data['thisData'] = $this->db->get('thisdata');
$this->view('thisView' , $data );
}
}
Related
I am trying to create Main site navigation, Sidebar Navigation and Footer navigation in Fat Free environment. I am just starting to work with frameworks especially with MVC type.
My problem, since my navigation will be almost on every page of the website, I was thinking about creating separate controller and model to handle all this staff, but not sure how it would work without making routing?
Also, I am not sure how to handle join in the model, I could not find any information about this online at all.
Here is my current Category Controller
class Categories extends DB\SQL\Mapper
{
public function __construct(DB\SQL $db)
{
parent::__construct($db, 'categories');
}
public function all()
{
$this->load();
return $this->query;
}
public function getByID($id)
{
$this->load(array('id=?', $id));
return $this->query;
}
public function getBySlug($category_slug)
{
$this->load(array('category_slug=?', $category_slug));
return $this->query;
}
public function add()
{
$this->copyfrom('POST');
$this->save();
}
public function edit($id)
{
$this->load(array('id=?', $id));
$this->copyfrom('POST');
$this->update();
}
public function delete($id)
{
$this->load(array('id=?', $id));
$this->erase();
}
}
any ideas or pointers will help me to go a long way.
Thanks in advance
I don't know if understood what your issue is, but if you want to make the categories available for all methods in a Controller, you could use the beforeRoute() method:
class TestController extends MainController {
// runs before routing
// if another controller extends TestController and also has a
// beforeRoute, this will be overriden
function beforeRoute() {
// Load Categories
$categories = new Categories($this->db);
// Assiging ->all() to variable makes the method return an array of all results
$categoriesArray = $categories->all();
// Set an array in the hive for template use
$this->f3->set('categories', $categoriesArray );
// Clear the instance
$categories->reset();
}
function renderPage() {
// the 'categories' hive variable is available because beforeRoute has been run
// Set the page title from the dictionary file
$this->f3->set('pageTitle', $this->f3->get('DICT_'.'page_whatever') );
// Render the View
$this->f3->set('view','page.whatever.htm');
$template=\Template::instance();
echo $template->render('layout.sidebar.htm');
}
// End of Controller
}
And of course, in the template:
<repeat group="#categories" value="#category">
<li>
{{ #category.label }}
</li>
</repeat>
ps: You might be using $f3 instead of $this->f3 (and the same for $db)
I'm building an application in Codigniter with HMVC. In it I call a module inside another controller. The problem I've run into is trying to pass/retrieve the data loaded into module. Specifically, I'm loading some javascript files that I would then like to pass to the calling controller.
Here is a simplified code:
public function module()
{
...
$this->data['js'] = $this->js_assets;
...
return $this->load->view('module_view', $this->data, true);
}
public function controller()
{
...
$this->load->module('module/module');
$this->data['module'] = $this->module->module();
...
}
I know that I can retrieve data['js'] in module_view as $js, but I wonder if I can just pass the data directly to the controller.
What I'd like to do is get data from the module to the calling controller
Yes, you can do that with HMVC.
In the calling module you can organise code like this (pseudocode):
class Someclass extends CI_Controller {
...
public function show_page()
{
$this->load->module("module");
$js_files = $this->module->get_js_files();
$this->load->view("header", array("js_files" => $js_files));
}
...
}
In the callee module you would write something along these lines:
class Module extends CI_Controller {
...
public function get_js_files()
{
$scripts = $this->frontend_model->get_scripts();
return $scripts;
}
....
}
(Although in this fantasy case it would be wiser to get data from model in the first place)
Another technique is, like #wolfgang1983 correctly mentioned, to call another module like this:
Modules::run('modulename/controller/function', $data);
and in order to get data from that controller you just have to assign returned data to a variable:
$data_received = Modules::run('modulename/controller/function', $data);
But in this case you can't get variables, only buffered output (like loaded and processed view files or echoed statements).
Assume i have controller with the class name "google" and it contains some data example
// application/controller/google.php
$data = array(
'target' => 'earth',
'percentage' => 70
);
and its view file is 'google_view.php' // application/view/google_view.php
and in second controler with the calss name "msn" here i want to get the "google" controller data .. or i just want to include "google_view" file without passing the $data variable again
I heard to use of setflash .. but the problem is what if user visit msn page without visiting google
so is there any way to get google controller data?
i also checked opencart cms & its an MVC framework in its controller we can call another controller like below.. in below code we can call header controller.
$this->children = array(
'common/column_left',
'common/column_right',
'common/content_top',
'common/content_bottom',
'common/footer',
'common/header'
);
You're looking for HMVC features, which CodeIgniter doesn't really do. Take a look at this library which implements it in CI : https://bitbucket.org/wiredesignz/codeigniter-modular-extensions-hmvc. There's lots of resources on the net which explain HMVC vs MVC in more detail.
If you're doing this sort of thing on any sort of scale, CodeIgniter might not be the best framework for your application - it would be worth looking at a few others. I'm using a lot of Laravel at the minute, which would work perfectly fine if you're just wanting to fetch the output of another controller (eg. in Laravel you just go $second_controller_output = Route::forward('GET','other/controller');).
Hope that helps!
Mmm ... I don't think you do that in CI but I'll suggest one idea ...
Extend the Controller core class, then be sure to extend your new class in your application controller’s constructors. E.g.
class MY_Controller extends CI_Controller {
public function __construct() {
parent::__construct();
$this->default_data_google = array(
'target' => 'earth',
'percentage' => 70
);
}
}
class Google extends MY_Controller {
public function __construct() {
parent::__construct();
}
public function index() {
$data = $this->default_data_google;
$this->load->view('google_view', $data);
}
}
//
..
class Msn extends MY_Controller {
public function __construct() {
parent::__construct();
}
public function index() {
$data = $this->default_data_google;
$this->load->view('google_view', $data);
}
}
I have this thing that I need in multiple places:
public function init()
{
$fbLogin = new Zend_Session_Namespace('fbLogin'); #Get Facebook Session
if(!$fbLogin->user) $this->_redirect('/'); #Logout the user
}
These two lines:
$fbLogin = new Zend_Session_Namespace('fbLogin'); #Get Facebook Session
if(!$fbLogin->user) $this->_redirect('/'); #Logout the user
Whats the best way to do it in ZendFramework?To create a plugin or? I mean I want to execute it in multiple places but If I need to edit it I want to edit it in one place.
Here is an example of an Action Helper that you can call from your controllers easily.
<?php
class My_Helper_CheckFbLogin extends Zend_Controller_Action_Helper_Abstract
{
public function direct(array $params = array())
{
// you could pass in $params as an array and use any of its values if needed
$request = $this->getRequest();
$view = $this->getActionController()->view;
$fbLogin = new Zend_Session_Namespace('fbLogin'); #Get Facebook Session
if(!$fbLogin->user) {
$this->getActionController()
->getHelper('redirector')
->gotoUrl('/'); #Logout the user
}
return true;
}
}
In order to use it, you have to tell the helper broker where it will live. Here is an example code you can put in the bootstrap to do so:
// Make sure the path to My_ is in your path, i.e. in the library folder
Zend_Loader_Autoloader::getInstance()->registerNamespace('My_');
Zend_Controller_Action_HelperBroker::addPrefix('My_Helper');
Then to use it in your controller:
public function preDispatch()
{
$this->_helper->CheckFbLogin(); // redirects if not logged in
}
It doesn't go into much detail, but Writing Your Own Helpers is helpful as well.
If you need this check in every Controller you could even set up a baseController from which you extend instead of the default one:
class My_Base_Controller extends Zend_Controller_Action
{
public function init()
{ ...
class IndexController extends My_Base_Controller
{ ...
Shift your init() into the base controller and you don't need to repeat yourself in every specific controller.
Need a varying init() in a specific controller?
class FooController extends My_Base_Controller
{
public function init()
{
parent::init();
...
I generate a menu from a database table using a function, and I've placed this in an extended base controller class:
<?php
class MY_Controller extends Controller {
public function __construct()
{
parent::Controller();
}
public function category_menu()
{
$this->load->model('category_model', 'category');
$categories = $this->category->get_categories();
$menu ="<ul class=\"menu_body\" id=\"nav_categories\">\n";
foreach($categories->result() as $row)
{
$menu .= "\t<li>" . anchor('listing/view' . $row->url, $row->name) . "</li>\n";
}
$menu .= "</ul>\n";
return $menu;
}
}
then naturally my controller looks like ~
<?php
class Site extends MY_Controller {
function __construct()
{
parent::__construct();
}
function index()
{
$data['menu'] = $this->category_menu();
$this->load->view('view', $data);
}
}
this does work, but it seems inefficient to have to do this for ~every~ page/view?
Or is this just a limitation of CI/MVC and there's no other way of doing it.
thanks for any insight
The better way of doing this is rendering content in views. You can have partial templates, you don't need to do string appending in the controller:
$categories = $this->category->get_categories();
$data['menu'] = $this->load->view('menu', array('data'=>$categories), TRUE);
$this->load->view('view', $data);
The TRUE in the call to view tell the function to return the rendered content and not put it into the buffer. You can then pass it to 'view'. You can also get the categories and pass them into the view 'view' and load the partial template from there.
If your menu entries won't be changing much you can probably cache the resulting array (serialized to file, to memcache, wherever) and use that to build your menu instead of querying the database on every pageload. Then you'll query the database only if the cache is not valid.
This way you should either expire the cache every few minutes so you get fresh data from the database, or make sure that whenever you update the menu structure from elsewhere (say, a CMS), you invalidate the cache (delete file, delete memcache key etc) so that next time you call category_menu() you get fresh data.
As a sidenote, Ken Struys raises a very valid point as well and you should consider it. The whole point of Controllers and Views is so that you can separate your code from your html.