Best way to construct a website application in code igniter - php

How do people construct websites with cake/CI ect... for easy maintenance on the html?
I can put each of the sections in its own view file and make the website that way:
<div id="header"></div> <!-- header_view.php -->
<div id="content"> <!-- header_view.php -->
<div id="left_column"></div> <!-- page_x_view.php -->
<div id="center_column"></div> <!-- page_x_view.php -->
</div>
<div id="footer"></div> <!-- footer_view.php -->
But each page_x_view.php file would contain
<div id="left_column"><!-- Content --></div>
<div id="center_column"><!-- Content --></div>
And I'm duplicating these items through each of the files, so if I need to change the column structure then it is not easy.
Hopefully I am clear.

I have a controller caled MY_Controller which has a method that renders the complete page. I extend all my controllers from this main controller. HOw this helps? My main controllers takes a view and embedds it in the main content area of page and assembles a complete page. This controller takes header, footer, sidebar views and does all the mambo jumbo. Its very easy to develop such a system in CI. Some this call two step or multiple views. So if some random day I have to change layout of my page I just need to look at MY_Controller.
Cake on the other side uses layouts. I have done just one project in CakePHP so am not that expert but you can achieve the same effect in any framework. Here is how I do it in CI
<?php if (!defined('BASEPATH')) exit('No direct script access allowed');
class MY_Controller extends CI_Controller
{
public function __construct()
{
parent::__construct();
log_message('debug', 'Controller Library '.__CLASS__ . ' ('. __FILE__ .') loaded.');
$this->properties['viewPath'] = $this->config->item('viewPath');
$this->setPageMetaData();
$this->setFavIcon();
}
public function render($viewData = null, $data=null)
{
$data = array(
'headerLayout' => $this->printHeaderLayout(array_merge($this->properties, (isset($data['headerLayout'])?$data['headerLayout']:array()))),
'leftLayout' => $this->printLeftLayout(array_merge($this->properties, (isset($data['leftLayout'])?$data['leftLayout']:array()))),
'rightLayout' => $this->printRightLayout(array_merge($this->properties, (isset($data['rightLayout'])?$data['rightLayout']:array()))),
'footerLayout' => $this->printFooterLayout(array_merge($this->properties, (isset($data['footerLayout'])?$data['footerLayout']:array()))),
'containerLayout' => $viewData,
);
this->load->view($this->properties['viewPath'].'layout/layout.php', $data);
}
public function setPageMetaData($pageMetaData=null)
{
$this->properties['pageTitle'] = isset($pageMetaData['pageTitle'])? $pageMetaData['pageTitle'] : $this->config->item('pageTitle');
$this->properties['pageKeywords'] = isset($pageMetaData['pageKeywords'])? $pageMetaData['pageKeywords'] : $this->config->item('pageKeywords');
$this->properties['pageDescription'] = isset($pageMetaData['pageDescription'])? $pageMetaData['pageDescription'] : $this->config->item('pageDescription');
}
public function setFavIcon($favIcon=null)
{
$this->properties['favIcon'] = (null !== $favIcon) ? $favIcon : $this->config->item('favIcon');
}
public function printHeaderLayout($data=null)
{
return ($this->load->view($this->properties['viewPath'].'layout/header', $data, true));
}
public function printFooterLayout($data=null)
{
return( $this->load->view($this->properties['viewPath'].'layout/footer', $data, true));
}
public function printLeftLayout($data=null)
{
return($this->load->view($this->properties['viewPath'].'layout/left', $data, true));
}
public function printRightLayout($data=null)
{
return($this->load->view($this->properties['viewPath'].'layout/right', $data, true));
}
}
Do note that this is not the exact code. I had to modify it for you, so do not blindly user it. If you know CI you will understand that I have setup paths to view in a config file. This helps me in setting up two totally different themes and use same controller. I can also add authentication layer which will based on user authentication/cookies can show a login or logout link in header. This is a template which I keep change and I extend all my controllers from MY_Controller and use in my controllers I simply do
$viewDataForForm = $this->load->view($this->properties['viewPath'].'homepage/some-form', array(), true);
$viewDataForContent = $this->load->view($this->properties['viewPath'].'homepage/some-content', array(), true);
$this->render($viewDataForForm.$viewDataForContent);
HTH!

Codeigniter and CakePHP take advantage of the Model View Controller configuration. They separate the database queries and data processing from the views. This provides an easy to use and easy to maintain way of coding. Multiply controllers can use the same view which helps cut down on the amount of code written and the complexity. Methods in the models can be reused which reduces bugs and amount of code written. And controllers provide and easy to follow way of reading and writing code. I am not sure if I answered your question but comment on my answer if you need and more explanation.

Related

Using Smarty 3.1 with Kohana 3.3

KSmarty is a Kohana module meant to integrate Smarty with Kohana. I'm trying to migrate my current project (already using Smarty) to using Kohana.
I'm trying to get KSmarty set up, but I'm having difficulties getting the templates to work. This is the "hello world" example from KSmarty:
application/classes/Controller/Welcome.php
<?php defined('SYSPATH') or die('No direct script access.');
class Controller_Welcome extends Controller_Template
{
public $template = 'welcome';
public function action_index()
{
// Assign a value to the variable 'intro'
$this->template->intro = 'Hello world!';
// Create a nested view by loading a different template
$this->template->content = View::factory('content');
}
}
// End Welcome
application/views/welcome.tpl
<html>
<body>
<h1>{$intro}</h1>
<p>
{$content}
</p>
</body>
</html>
application/views/content.tpl
Yes, this works!
However, for me, the controller/view combo does not work as expected. Here are the variants of action_index() that I've tried:
public function action_index()
{
echo 'foo';
}
// Output: foo
public function action_index()
{
// Assign a value to the variable 'intro'
$this->template->intro = 'Hello world!';
// Create a nested view by loading a different template
$this->template->content = View::factory('content');
}
// No output
// No error in apache log, php log, or kohana log
public function action_index()
{
Ksmarty::instance()->assign(array(
'intro' => 'Hello world!',
'content' => APPPATH.'/views/content.tpl'
// Note: also changed {$content} in template to {include $content}
));
Ksmarty::instance()->display(APPPATH.'/views/welcome.tpl');
}
// Expected HTML output
I could simply use Ksmarty::instance() like this and get my website working, but this isn't how the Kohana Views system was designed, and it feels like a kludge, especially since the KSmarty example matches up with Kohana's use of Views.
I'm pulling my hair out trying to pin this one down, which is impressive considering the amount of hair-pulling Kohana gave me on the initial install. What am I doing wrong?
Oh, I have make two changes to KSmarty to reach this point:
All instances of Kohana::config('smarty') replaced with Kohana::$config->load('smarty'); as far as I can tell, this is a matter of a version change in Kohana.
Commented out $s->security = Kohana::$config->load('smarty')->security;; as far as I can tell, this is a matter of a version change in Smarty, and KSmarty is configured to FALSE anyway.
Adding echo $this->template; to the end of the view works. It's not in the Kohana nor the KSmarty documentation/examples, but it's close enough to satisfy me. If anyone else ever comes up with an answer that solves the problem without echo, I'll mark that answer as accepted, but until that time, I have a solution.
<?php defined('SYSPATH') or die('No direct script access');
class Controller_Welcome extends Controller_Template
{
public $template = 'welcome';
public function action_index()
{
// Assign a value to the variable 'intro'
$this->template->intro = 'Hello world!';
// Create a nested view by loading a different template
$this->template->content = View::factory('content');
// Output the view
echo $this->template;
}
}
// End Welcome

Zend Framework 2: Composing web page of several parts

I need to compose a web page of several view templates (the view template rendering page content and a view template rendering sidebar). In my layout.phtml, I have two variable placeholders: $content and $sidebar:
......
<?php echo $this->sidebar; ?>
......
<?php echo $this->content; ?>
......
In my controller's action, I pass the data to these view templates through the ViewModels chained in a tree:
public function indexAction() {
// Preparing my data
// $form = ...
// $menuItems =
// $activeItem =
// Create sidebar view model
$sidebarViewModel = new ViewModel(array('menuItems'=>$menuItems, 'activeItem'=>$activeItem));
// Add it as a child to layout view model
$this->layout()->addChild($sidebarViewModel, 'sidebar');
// Page content view model
$viewModel = new ViewModel(array('form'=>$form));
return $viewModel;
}
But, because I have the sidebar on every page, I will have to copy and paste this code for every action of every controller. Is there any recommended way of reusing the code that populates the ViewModel for sidebar?
One approach would be to achieve this with a controller plugin.
Assuming you have wired it up with appropriate config, and you're in the Application module.
In module/Application/src/Application/Controller/Plugin/AddSidebar.php:
namespace Application\Controller\Plugin;
use Zend\Mvc\Controller\Plugin\AbstractPlugin;
class addSidebar extends AbstractPlugin {
public function __invoke($menu, $active) {
// create new view model
$sidebarVM = new ViewModel(array(
'menuItems' => $menu,
'activeItem' => $active
));
// add it to the layout
$this->getController()->layout()->addChild($sidebarVM, 'sidebar');
}
}
Then in each of your controllers:
$this->addSidebar($menuItems, $activeItem);
Another (probably better) option would be to hook into the render MvcEvent and add the sidebar there. You'd have to work out how to generate $menuItems and $activeItem in that context however.

Best way for scripts in codeigniter

In CodeIgniter I often have many scripts inherent to my project, for instance:
<?php
// Load many things
$this->load->model('news_model');
$this->load->helper('utility_helper');
$news = $this->news_model->get_basic_news();
// For moment no news
$view_datas['news']['check'] = false;
if ($news) {
$view_datas['news'] = array(
'check' => true,
'news' => _humanize_news($news)
);
}
?>
This script is used in different controllers, at the moment I create a scripts folder and I import it like that: include(APPPATH . 'scripts/last_news.php'); I'm quite sure it's not the best way to handle this problem. Any thoughts on that?
Update:
A solution given in the answers is to use a helper or a library.
Let's imagine a rewrite of my previous code:
class Scripts {
public function last_news() {
// Load many things to use
$CI =& get_instance();
$CI->load->model('news_model');
$CI->load->model('utility_helper');
$news = $CI->news_model->get_basic_news();
// Avoid the rest of code
}
}
Just create a new library and load that library whereever you require?
e.g.
<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed');
class Newclass {
public function get_news($limit)
{
//return news
}
}
/* End of file Newsclass.php */
In your controllers
$this->load->library('newsclass');
$this->newsclass->get_news($limit);
Or another idea is to create helper functions.

Zend - refactoring to include a form globally on site

I currently have a search form in the search controller, so the only way I can get to it is through /search/. I have to refactor my code so that this search form appears not only in the Search Controller but also globally throughout the site.
( The code isnt exact as I had to retype some of it )
My class that extends Zend_Form is located in application/forms/forms/SearchForm.php:
class Form_SearchForm extends Zend_Form {
public function init() {};
}
My search controller is something like..
class SearchController extends Zend_Controller_Action
{
public function search() {
$searchForm = new Form_SearchForm();
$this->view->form = $searchForm;
}
}
In my Bootstrap.php I have an autoloader for models:
protected function _initAutoload() {
$autoLoader = Zend_Loader_Autoloader::getInstance();
$resourceLoader = new Zend_Loader_Autoloader_Resource(
array(
'basePath' => APPLICATION_PATH,
'namespace' => '',
'resourceTypes' => array(
'form' => array(
'path' => 'forms',
'namespace' => 'Form_',
),
'model' => array(
'path' => 'models/',
'namespace' => 'Model_',
),
),
)
);
return $autoLoader;
}
I'm wondering where I can store my code so that globally the search form is generated in the view.
My global layout file is located in application/layouts/scripts/layout.phtml and currently spits out a dynamic content area:
<div id="main">
<?php echo $this->layout()->content;?>
</div>
Should I just add the form to this layout.phtml or is there some generic controller I should use?
Edit: Sorry for not specifying this too, but what if for example I wanted to not include it for 1-2 special pages ( maybe an admin section ).. if I hardcoded it into layout.phtml it would still appear.. or should I serve a different layout file to say, an admin area?
Creating a searchAction() is not good for performance because it requires a brand new dispatch cycle. If, and only if, you have very complex logic that justifies a separate action, you could create a Controller Plugin and add searchAction() to the ActionStack. If you are only instantiating/assigning the form or if you don't need the search form for every request, it's not an optimal solution.
Another possibility would be to instantiate and assign the form in the bootstrap. This kind-of breaks separation of concerns, but provides better performance.
protected function _initSearchForm()
{
$this->bootstrap('view');
$view = $this->getResource('view');
$searchForm = new Form_SearchForm();
$view->searchForm = $searchForm;
return $searchForm;
}
Finally, my preferred solution would be a custom view helper:
<?php
class My_View_Helper_SearchForm extends Zend_View_Helper_Abstract
{
public function searchForm()
{
$searchForm = new Form_SearchForm();
return $searchForm;
}
}
For either of these solutions, you'd ideally output the form in your layout file to minimise duplication.
layout.phtml:
<?php echo $this->searchForm() ?>
And create an alternate layout admin.phtml for admin area pages. This gives you the flexibility to change the admin pages significantly when new requirements pop up.
You can create your Form in a Controller Plugin and add it to view vars somehow (by Zend_Controller_Front?), which are accessible in layout, too. But it's too complicated in current ZF version (or I'm too dumb)
You can make Form_SearchForm a singleton
class Form_SearchForm ... {
static function getInstance() {
static $instance;
if (!$instance)
$instance = new Form_SearchForm();
return $instance;
}
}
Now instead of creating new Form_SearchForm() just get it as
$form = Form_SearchForm::getInstance();
You can put an instance of Form_SearchForm to the registry
I probably have missed a very cool a simple way :)
I would split it into a partial and a place holder.
in layout.phtml:
<?php if($searchForm = $this->placeHolder('searchForm'): ?>
<?php echo $searchForm; ?>
<?php endif; ?>
then in your views you can call:
<?php $this->placeHolder('searchForm')->set($this->partial('search-from.phtml', 'search')); ?>
IF you wanted you could even make a search view helper that basically does the place holder call.
The Controller plugin would be better if you have more pages that dont need it than d though. I would still probably use placeholder though to accomplish it. That way you can easily override or append to it later on a view-by-view basis without calling anything on the front controller.

Modular web site with zend framework, stack of actions

How to build modular web site with Zend framework. I have pages in db, every page is represented as url. Every page has 1toN contents. Every content has controller, action and position (+other now not important columns). So, one request is one page and multiple contents (multiple actions). How can I build all actions before the output? I would like to have layout design like example bellow, where contents are put in there containers (actions are run before layout print-out).
<div id="left">
<?= $this->layout()->left_container ?>
</div>
<div id="center">
<?= $this->layout()->center_container ?>
</div>
<div id="right">
<?= $this->layout()->right_container ?>
</div>
Until now I called actions from layout view, but I do not like this approach:
foreach ($contents as $item) {
echo $this->action($item['action'], $item['controller'], null, array('content' => $item));
}
Thanks.
p.s.
adepretis's code is similar to my, views of my actions are run inside layout, which means that when error occurres it is printed in layout where the action is called. Is there no whey that actions are build before layout output? Another bad thing is that in every action I must run ...->setResponseSegment, I would like this to be automated.
p.s. #2
I have found answer, it is listed bellow as answer. If there is a whey I can do this easier please write it down.
You can use the ActionStack helper. For example:
class MyController_Action extends Zend_Controller_Action {
function init() {
/** you might not want to add to the stack if it's a XmlHttpRequest */
if(!$this->getRequest()->isXmlHttpRequest()) {
$this->_helper->actionStack('left', 'somecontroller', 'somemodule');
$this->_helper->actionStack('center', 'somecontroller', 'somemodule');
$this->_helper->actionStack('right', 'somecontroller', 'somemodule');
}
}
class MyController extends MyController_Action {
function indexAction() {
// do something
}
}
class SomecontrollerController extends MyController_Action {
function leftAction() {
// do something
$this->_helper->viewRenderer->setResponseSegment('left_container');
}
function centerAction() {
// do something
$this->_helper->viewRenderer->setResponseSegment('center_container');
}
function rightAction() {
// do something
$this->_helper->viewRenderer->setResponseSegment('right_container');
}
}
A request for /somemodule/my/index results in executing /somemodule/somecontroller/left. /somemodule/somecontroller/right, /somemodule/somecontroller/center which end up in the correspondig layout segments.
I found my answer on other forum. Here is the asnwer:
MyPlugin
class MyPlugin extends Zend_Controller_Plugin_Abstract
{
public function routeStartup(Zend_Controller_Request_Abstract $request)
{
$action_stack = new Zend_Controller_Action_Helper_ActionStack();
// here I will read actions from db and run it in loop, but for example few are staticly added bellow
$action_stack->actionToStack('index', 'content', 'default', array('position' => 'left'));
$action_stack->actionToStack('index', 'content', 'default', array('position' => 'center'));
$action_stack->actionToStack('index', 'edo', 'default', array('position' => 'center'));
$action_stack->actionToStack('left', 'edo', 'default', array('position' => 'left'));
$action_stack->actionToStack('right', 'edo', 'default', array('position' => 'right'));
}
}
BaseController, that every controller extends
class BaseController extends Zend_Controller_Action
{
public function preDispatch()
{
$position = $this->_request->getParam('position', false);
if ($position) {
$this->_helper->viewRenderer->setResponseSegment($position);
}
}
}
Layout.phtml
<div>
<h2><u>LEFT:</u></h2>
<?=$this->layout()->left?>
</div>
<div>
<h2><u>CENTER:</u></h2>
<?=$this->layout()->center?>
</div>
<div>
<h2><u>RIGHT:</u></h2>
<?=$this->layout()->right?>
</div>
This is what I wanted, if anyone has a better solution please answer the question and I will accept his answer.
hi i also encounter the same problem. The solution you suggest work fine. But my baseController is in module base .The code work smooth with baseController but when i extended with controllers in another module error occure as base Controller cannot identify in other controller
For eg:
modules/ base/Controller/baseController
modules/ user/Controller/userController
Any Solutions ?

Categories