Multiple Models Across A Layout in CakePHP - php

What is the best way to achieve the following in CakePHP?
I have a layout which like many others has 3 major sections, a header, a footer and the main content. The header and footer aren't completely static and are implemented as Elements, it has hit counts and some other dynamic stuff. This dynamic stuff isn't related to the main content in any way but is more related to the overall site.
For this I think the footer needs to have a model of its own, can I have the footer run on a different controller/action than the main content? Else, I guess I would need to put the footer model in the main view's model and than pass to the footer element, which doesn't seem the neatest way.
To put it in different words, the header, the footer, the main content and possibly a few more sidebars are totally independent of each other, but are rendered from the same layout. The model that is passed from the controller to the view/layout would need to have the models needed for the header/footer/content/sidebars?
I explored and found that requestAction might be a way, but did not convinced if that's the best way. May be I haven't looked at the right places yet.

Just add what you need inside the beforeRender method of your AppController:
class AppController extends Controller {
public function beforeRender () {
$this->set('number_of_visists', /* ... */) ;
}
} ;
So you'll get the value on each page, then you can either put everything inside your layout file or split it in multiple element but you'll have access to $number_of_visits everywhere.
Edit: Little edit to answer your comment. This is one way of doing what you want, may be not the most "correct" but the first which came to my mind. I didn't test this so it may contains some mistakes...
You could use components: Let's say you have three component, one for the header, one for the footer and one for the menu.
In your AppController:
class AppController extends Controller {
public $components = array('Header', 'Menu', 'Footer');
} ;
Then your components (I'll show only one example):
class FooterComponent extends Component {
public function beforeRender(Controller $controller) {
$visitModel = ClassRegistry::init('VisitCounter');
$controller->set('number_of_visits', $visitModel->getNumberOfVisits()) ;
}
}
Then in your layout you just use elements:"
<html>
<!-- Whatever you want... -->
<?php echo $this->element('footer') ; ?>
</html>
Every developper can work on his own component (and the associated models) and his own element without disturbing the other ones.

Related

Code Igniter - Best Practice for views to not violate DRY

Trying to determine the best way to handle views in codeigniter. Right now anything I consider seems too messy.
Currently I have 3 relevent views:
1) Header
2) Content
3) footer
Every single controller has something like this. Some controllers even have this several times (different functions in the same controller):
$this->load->view('head', $data);
$this->load->view('volunteers/add_profile.php',$content_data);
$this->load->view('foot');
It seems pretty silly to have to load header and footer on EVERY single page. However, each page will have slightly different data in the header (meta tags, style sheets, loaded scripts, etc).
Is there a cleaner way for me to do this?
Thanks!
I like to create a parent controller with a method like renderPage('content_view', $data). That method can include the header, menu, footer, ... That way, all the view loading stuff is kept in the controller and I don't have to bother with header, menu or footer on every action or view. It's also flexible as your child controllers can redefine the renderPage() method to fit their purposes.
If you need to load multiple content views, you could create a renderPage() method that takes in an array of string instead of a string.
Yes - have a template view. In your controller:
$data['header'] = xxx;
$data['content'] = xxx;
$this->load->view('my_template', $data);
Then in your my_template.php view file:
$this->load->view('head', $header);
$this->load->view('volunteers/add_profile.php',$content);
$this->load->view('foot');
Either what #TheShiftExchange suggested, or, if your application allows it, you can call header and footer views from each content view (which is the only view called from the controller then).
I've created my own controller where I create MY_Controller extends CI_Controller class then in MY_Controller I use access modifier $data and $loadviewArray.
public $data = array();
public $loadviewArray = array();
after this I create function in MY_Controller
public function loadview() {
foreach ($this->loadviewArray as $key => $val) {
$this->load->view($val, $this->data);
}
}
then I create controller Admin and extends MY_Controller like this Admin extends MY_Controller in Admin controller create function index.
public function index() {
$this->data["page_title"] = "Login";
$this->data["records"] = $data; // You can pass data
$this->loadviewArray = array("admin/header", "admin/login", "admin/footer");
$this->loadview();
}
In $data access modifier array I pass data at views and in $loadviewArray load views then call a function for loading views you can do like this also its very helpful for me now. And create header and footer views seperate...
please check https://github.com/alzalabany/codeigniter-base-controller/tree/master
So you can always use a templating lib. yet i dont like them for some reason !
codeigniter allow you to extend its core; if you go to link mentioned above u can see a small example
in this example every controller that will extend MY_controller will start with these defauls
protected $body='base/body',
$title='Codeigniter Z master',//txt
$js=array(),//filename
$inline_js='',//script
$css=array(),
$inline_css='',//style
$breadcrumb=FALSE,//<li><a>
$content=array(),//html
$noEcho = FALSE;
so if u chose to change them in MY_controller its effect will be default, otherwise use $this->title = 'Codeigniter - welcome page'; in ur controller constructor for example;
loading assist is a very easy job just call $this->_assets() and location of asset (edit MY_controller.php default location to you assets folder); if its an inline_js/css just call
$this->_assets('alert("hi");','js');
if you want to load a view into a page section use $this->outv(view_path,view_data,section_name);
and if you want to just load html into a variable u can use
$this->out('Footer','footer');
at end just call ->_flush();
some other options i use like
$noEcho ; if set it will clear all buffer to remove any echo's before it send your view content to browser;
you can also set functions like log-out or log-in inside MY_controller and it will be accessible by any of ur controllers http://localhost/ci/welcome/logout
any way :) i hope that answers your question !

Creating a database-generated menu on every page in CodeIgniter?

I'm using CodeIgniter and have a menu on the site that needs to read a list of cities from the database. This is simple to do if it's just on one or two pages - I load the model and call a function from the controller, and pass the data into the view.
But if I want it on every page, that means I have to keep copying the same code to every single controller function and pass the data into the view. (Note, I'm using a separate "header" view that contains the menu.)
What's the best way to automatically load some data on every page load and have it available to my view?
Create a new root controller class like MY_Controller.
You can read how here: https://www.codeigniter.com/user_guide/general/core_classes.html
Then make all your controllers extend that class.
Add a function in MY_Controller like this:
function show_view_with_menu($view_name, $data) {
$menu_data = $this->menu_model->get_menu(); // load your menu data from the db
$this->load->view('header', $menu_data); // display your header by giving it the menu
$this->load->view($view_name, $data); // the actual view you wanna load
$this->load->view('footer'); // footer, if you have one
}
Whenever you normally do load a view, instead do this:
$this->show_view_with_menu('view_for_this_controller', $data);
You define your own Application_Controller, which extends CI_Controller. All of your own controllers then extend your Application_Controller rather than the CI_Controller.
In the __construct() of your Application_Controller you'll introduce the code you've been copying and pasting everywhere previously.
My solution was just to create a display class that handles these things. A simplified version:
class Display
{
public function load_pages($name, $data = array()) {
$CI =& get_instance();
// Top and header templates
$CI->load->view('header.php', $data);
// Default to loading the one template file
$CI->load->view($name, $data);
// Footer template
$CI->load->view('footer.php');
}
}
I have it doing fancier stuff, such as setting default values (page title, meta tags) and loading js/css, etc. It works just like a shortcut to having to copy/paste the regular templates that I load but also allows me to define a custom template setup if I need to, unlike if you have it do so automatically be extending your controller class.
I haven't had the need to but you can also specify different functions within this class to load different sections of the site, such as load_admin_pages() or some such. In my case I handle that just by setting a prefix parameter that gets prepended to the file paths and that's gotten what I need for my current project.

Php, If I have a menu class, how to display it? (MVC logic)

I have got a menu class:
addMenuItem ($parent)
modifyLinkTarget ($item)
etc. Now I will show it with a show() method, which should produces HTML output. But its not a good way, because what if I have several templates while it produces one HTML. CSS wont help standalone :) so how to display it not to hurt MVC and being flexible?
The menu class contains your items, links etc. and is your model. As you correctly said, the model does not output anything, it is the task of the view. So you have to pass the model (menu class object) to your view, where you can output it. For this, your menu class might need some additional methods like getAllMenuItems(int $parentItem) or something like that. In your view, you can do something like this:
<ul>
<?php foreach($menuClass->getAllMenuItems(2) as $item) { ?>
<li>$item['text']</li>
<?php } ?>
</ul>
As you can see, you might have to extend your menu model with a menuItem class, to follow the OOP way. Your menu class organizes several menuItem objects.
Overall, you have to following situation:
header('some html utf8 http header stuff');
echo viewObject->generateHTML('template.tpl', $contentData, $menuObject);

Pagination in PHP MVC

I've written a small MVC in PHP5 and desire a pagination module to be added to some files in my views section/folder..
I was wondering.. would the Pagination class be included in the Controller or Models section/folder?
Currently i've included it in the Models folder and called the function when needed..
The way I see it, pagination is a control, allowing user to tell your database (model), which portion of data he or she wants to see.
So I would go with the Controllers module.
Well, I think a better approach would be to make a helpers folder and then load them into your application like this :
function use_helper()
{
static $helpers = array();
foreach (func_get_args() as $helper)
{
if (in_array($helper, $helpers)) continue;
$helper_file = HELPER_PATH.DIRECTORY_SEPARATOR.$helper.'.php';
if (!file_exists($helper_file))
throw new Exception("Helper file '{$helper}' not found!");
include $helper_file;
$helpers[] = $helper;
}
}
Then all you have to do is build a pagination.php file with your Pagination class.
When you need it, you call the function
use_helper('pagination');
From here of course it depends on you Pagination class.
Hope this helps.
i guess the best approach is to call the pagination from the view, referring to this MVC
A view queries the model in order to generate an appropriate user interface
(for example the view lists the shopping cart's contents).
The view gets its own data from the model.
In some implementations, the controller may issue a general instruction to the view to render itself.
In others, the view is automatically notified by the model of changes in state (Observer) that require a screen update.
and because you will be using this class almost in every view, you should make a helper and include this class inside that helper so that all the views can share its methods

redundant implementation in CI controller

I wanna ask you best practices about blog front page.
I wanna build blog application using CodeIgniter framework. I have 2 type of page (front page, and admin page)
Supposed I have several controller in my front page (home, post, page, and link). By default I have include viewer of for all of these controller: header.php, footer.php, sidebar.php.
In the sidebar, I always display categories, recent comment, recent post, links, and archived.So .., In all of my front page controller I must implement select of categories, recent comment, recent post, links, and archived. Supposed I implement in all controller's constructor.
__construct () {
//data['categories'] = CategoryModel->getlist
//data['recent_posts] = PostModel->get_recent_post
//etc
can you suggest me, where I must place this method so I mustn't implement this method in all controller.
Thanks
You can write a base controller which the other ones inherit from
class AppStartup extends Controller {
function __construct() {
// whatever you need
}
}
then
class Home extends AppStartup {
// ....
}
Also you could start accepting some of the answer given to you, or people won't be so happy to help you.
The best way to do this is to create a MY_Controller and use $this->data instead of $data. That means all your controllers will run from MY_Controller (as long as you explicitley tell your controllers to inherit from it).
http://codeigniter.com/wiki/MY_Controller_-_how_to_extend_the_CI_Controller/

Categories