I'm actually creating websites for fun and some of my friends told me that I could be more efficient if I could create the output of the page with a php class that would represent the whole page.
I was wondering how you people would do it.
Thanks
I am not a OO programmer .. but, as a proof of concept, and as per your question, you can do/try something like this.
class Page {
public $meta_title;
public $meta_keywords;
public $html_body;
public function displayPage() {
$page ='
<html>
<head>
<title>'.$this->meta_title.'</title>
<meta name="keywords" content="'.$this->meta_keywords.'" />
</head>
<body>
'.$this->html_body.'
</body>
</html>
';
echo $page;
}
}
Then you just use this Page class as ..
$page = new Page();
$page->meta_title ="Hello world!";
$page->meta_keywords = "some text keywords";
$page->body = '<h1>Contact Us </h1>
<p>you can contact us at blah ... blah .. etc.</p>
<address>Dummy Address </address>
';
$page->displayPage();
Please note that you can add so many things into to it like .. class variables (type array) to define stylesheets, javascripts files .. then you just loop over it to define these files dynamically for individual pages.
You can amend the display page function so that it accomodate left, right, or top navigation bar. Then you can also have variables like $show_right_bar, $show_left_bar to control which pages display which side navigation bar. So you can amend and extend to whatever your requirements are.
Alternatively, you can try some php frameworks, which are much more evolved solutions, but that really depends on your programming skills and your requirements.
Hope this helps.
I'd suggest looking into some PHP frameworks, such as Cake which is good for beginners, or Symfony or Zend Framework if you're more skilled. Those will streamline your PHP development a lot.
What you could do is have all the tags in the page stored as a multi-dimensional array. PHP is mushy enough to do this. As such, every tag would be stored in an element of the array.
Then, you can use control statements to print different parts of the page at different times depending on certain conditions.
It would kinda look like what you get when you convert an XML file to an array.
Here's what I'm thinking.
$page['html']['title'] = "Page's Title";
$page['body']['p'][1] = "1st Paragraph";
$page['body']['p'][2] = "2nd Paragraph";
And then you could use your own functions to print these out as HTML fields.
I would suggest using some of the MVC (Model, View, Controller) frameworks out there like KohanaPHP. It is essentially this. You're working in a strictly Object-Oriented environment. A simple page in Kohana, build entirely from a class would look like this:
class Home_Controller extends Controller
{
public function index()
{
echo "Hello World";
}
}
You would then access that page by visiting youur url, the class name, and the method name:
http://www.mysite.com/home/ (index() can be called after home/, but it's implicit)
When you start wanting to bring in database-activity, you'll start working with another Class called a Model. This will contain methods to interact with your database, like the following:
class Users_Model extends Model
{
public function count_users()
{
return $this->db->count_records('users');
}
}
Note here that I didn't write my own query. Kohana comes with an intuitive Query Builder.
That method would be called from within your Controller, the first class that we mentioned at the beginning of this solution. That would look like this:
class Home_Controller extends Controller
{
public function index()
{
$usersModel = new Users_Model;
$userCount = $usersModel->count_users();
echo "We have " . $userCount . " users!";
}
}
Eventually, you'll want more complicated layouts, which will involve HTML/CSS/Javascript. At this point, you would introduce the "Views," which are just presentation layers. Rather than calling echo or print from within the Controller, you would load up a view (an HTML page, essentially) and pass it some variables:
class Home_Controller extends Controller
{
public function index()
{
$myView = new View("index");
$usersModel = new Users_Model;
$userCount = $usersModel->count_users();
$myView->userCount = $userCount;
$myView->render(TRUE);
}
}
Which would load the following "View"
<p>We have <?php print $userCount; ?> users!</p>
That should be enough to get you started. Using the MVC-style is really clean, and very fun to work with.
So many ways to do this, indeed.
When I make a simple personal site, I typically have a banner at the top and a menu on one side. To prevent myself from having to copy'n'paste everything, my index.php checks a get variable, and based on that get variable loads the appropriate content in the middle. By way of example, my index.php. My menu actually loads the content with a function, but this is not necessary/recommended:
<?php
$page = strtolower($_GET['page']);
if(!isset($page) || $page === '')
{
$page="home";
}
switch($page)
{
case "loomis":
require_once("loomis.php");
break;
case "home":
default:
$page = "home";
require_once("home.php");
break;
}
include "menu.php";
?>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<HTML>
<HEAD>
<TITLE>Nebulous - <?php getTitle($page) ?></TITLE>
<link href="style.css" rel="stylesheet" type="text/css" />
</HEAD>
<body>
<?php displayMenu() ?>
</body>
</html>
Classes are really only useful as representations of data or functionality, not really to render pages.
OOP can be useful in page rendering if you have something that is static throughout your pages. (e.g. Header, Footer)
$index = new Page();
$index->displayHeader();
// php/html per needs
$index->displayFooter();
This isn't all that intuitive but as the others said, the possibilities are vast. I would suggest picking up a book on the subject.
The best way to achieve your aim is to start with an html class. Its purpose is to write any HTML tags and indent them properly. It is not a simple task as I have hardly ever found one such html class on the web written properly. Hint: you will need a stack for managing the automatic closure of HTML tags and a working buffer for the current tag that rolls into a bigger holding buffer.
Using the services of the html class, you can build a webpage class that will create pages from settings. The trick here is to remain flexible and not hard-code too much inside your class. You need a setter for basic settings such as title, author, keywords etc. holding them into an array. Then webpage->header() should output the top of your page automatically. Then you should use functions such as webpage->heading($string,$size) to create a heading, webpage->paragraph($text), webpage->image() and so on. At the end you just need webpage->footer().
To make the webpage class worthwhile, make it create the css as well. For example if you want to use bootstrap, you can have the class include the css and style your code. Note that you can also make the webpage class create advanced objects such as webpage->breadcrumbs() or webspage->pagination()
I had exactly the same thought and could not find any modern OO PHP library to do what I wanted. I also wanted to use the Foundation CSS framework, so I wrote my own PHP library and have been using it for years. Very easy to make pages once you set up your base page and menus. Check it out on Packagist.org. I also wrote a PHP documentor library because I did not like any of the existing static generation packages out there with their complex setup. Take a look at PHPFUI.com for an example of the library in use. Run the HTML through an HTML validator if you want. Very clean because no HTML was touched by human hands in the construction of the site.
Related
It's really convenient how MVC patterns allow you to define view a and then load variables into it via the controller. For the sake of argument let us take CodeIgniter as an example:
Controller:
Class Example extends CI_controller(){
function show_page(){
$data = array('msg'=>'Hello World');
echo $this->load->view('hello',$data);
}
}
View (hello.php):
<h1><?php echo $msg; ?></h1>
I have taken over an old project written years ago where there are redundant html code everywhere. It has no pattern whatsoever just straight up poorly structured code.
I wanted to create a class that has a function that will fetch all HTML code from a file in one folder, feed variables to them and show the result. Like so:
Folder structure:
View_folder
- hello.php
Class
- view_class.php`
Main:
<?php
$data['msg'] = 'Hello World!';
echo $view_class->get_view('hello.php',$data);
?>
Is it possible to achieve this? Can someone give an example function on how to do this. Thanks.
Sure thing, that's what the frameworks are doing. Here's a really basic overview of how I'd expect that to work:
function view($template, $data){
extract($data); // this pulls all of the first-level array keys out as their own separate variables
ob_start(); // this turns on **output buffering** which is the method we'll use to "capture" the contents of the view (there are surely other ways)
require $template; // you should prepend some sort of fixed path to this where all of your templates will reside
echo ob_get_flush(); // turns off output buffering, returning the buffered content as a string which we then send to the browser.
}
I'm trying to understand MVC, and learning CI framework. I've some questions about MVC and some basic questions about CI.
1)Views are visual part of application as i read from tutorials, my question is: e.g There is a button "Login" but if user already logged in button will be "Logout". Where will that login check be? On controller or on view? i mean
//this is view//
<?php if($_SESSION('logged') == true):?>
Logout
<?php else: ?>
login
<?php endif; ?>
or
//this is controller//
if($_SESSION('logged') == true)
$buttonVal = 'logout';
else
$buttonVal = 'login';
//and we pass these value to view like
$this->view->load('header',$someData);
//this time view is like
<?=$somedata['buttonVal']?>
i just write theese codes as an example i know they wont work, they are imaginary codes, but i guess you got what i mean. Login check should be on controller or on view?
2)Should models contain only codes about data and return them to controller? For example there is a math, we get 2 value from database and multiply them and display them. Model will multiply or controller will do it?
here we load data with model and do math on controller:
//model
$db->query(....);
$vars=$db->fetchAll();
return $vars;
//controller
$multi = $vars[0] * $vars[1];
$this-load->view('bla.php',$mutli);
here we load data with model and do math on model too, controller just passes data from model to view:
//model
$db->query(....);
$vars=$db->fetchAll();
$multi = $vars[0] * $vars[1];
return $multi;
//controller
$multi = $this->model->multiply();
$this-load->view('bla.php',$mutli);
i mean with that, models should do only database works and pass data to controllers, controller do rest of work and send view to render? Or models do work, controllers get them and send them to view?
3)This is about codeigniter, i have a header which has to be in every page, but it has javascripts,css depending to page i'm using
<?php foreach ($styles as $style): ?>
<link id="stil" href="<?= base_url() ?>/css/<?= $style ?>.css" rel="stylesheet" type="text/css" />
<?php endforeach; ?>
this will be on every page, so in every controller i have
$data['styles'] = array('css1','css2');
$this->load->view('header', $headers);
i'm thinking to make a main controller, write this in it, and all my others controllers will extend this, i see something MY_Controller on CI wiki, is this MY_Controller same with what i'm doing? Are there any other ways to do this?
Sorry for bad English and dummy questions. Thanks for answers.
This is absolutely view logic, the correct way to do it in my opinion:
<?php if($logged_in):?>
Logout
<?php else: ?>
login
<?php endif; ?>
The value of $logged_in would probably be retrieved from a call to a library method:
<?php if ($this->auth->logged_in()): ?>
Authentication is one of those things you'll want access to globally, so you may be calling $this->auth->logged_in() in controller or views for different reasons (but probably not in models).
In every controller i have
$data['styles'] = array('css1','css2');
$this->load->view('header', $headers);
Yes you could extend the controller class with MY_Controller, but you're better off keeping this in the view/presentation layer. I usually create a master template:
<html>
<head><!-- load assets --></head>
<body id="my_page">
<header />
<?php $this->load->view($view); ?>
<footer />
</body>
</html>
And write a little wrapper class for loading templates:
class Template {
function load($view_file, $data) {
$CI = &get_instance();
$view = $CI->load->view($view_file, $data, TRUE);
$CI->load->view('master', array('view' => $view));
}
}
Usage in a controller:
$this->template->load('my_view', $some_data);
This saves you from loading header/footer repeatedly. In my opinion, presentation logic like which CSS file to load or what the page title should be belongs in the view whenever possible.
As far as models go, you want them to be reusable - so make them do what you need and keep it strictly related to data manipulation (usually just your database). Let your controller decide what to do with the data.
Not related to MVC, but in general you want to write as little code as possible. Redundancy is a sign that you could probably find a better solution. These are broad tips (as is your question) but hopefully it helps.
1) View logic should be simple and mostly if-then statements, if needed. In your example, either case would work but use the logic in the view. However, if you were checking for login and redirecting if not logged in, then that would occur in a controller (or a library).
2) Think of Codeigniter models as ways to access database functions - Create, Retrieve, Update, Delete. My (loose) rule of thumb is for Codeigniter models is to return results from update, delete or insert queries or a result set from a fetch query. Any applicable math can then occur in the controller. If this is a math operation that occurs EVERY time, consider adding it to a library function. See below...
3) Extending the controller is the proper and best way to accomplish this.
*) Not to add more to your plate, but also be sure to learn about Codeigniter Libraries. For example, in your controller you could load your library. You then call your library function from your controller. The library function calls a model which retrieves your database result. The library function then performs math on that function and returns the result to the controller. The controller is left with little code but a lot is accomplished due to the library and model.
The user lo-gin check should be in the controller.
This should be the first function that need to be invoked in the constructor.
Below i have given the sample code which redirects the user to the login page if he is not logged in, hope this would give you some idea,
<?php
class Summary extends Controller {
function Summary() {
parent::Controller();
$this->is_logged_in();
}
function is_logged_in() {
$logged_in = $this->session->userdata('logged_in');
if (!isset($logged_in) || $logged_in != true) {
$url = base_url() . 'index.php';
redirect($url);
exit();
}
}
?>
The button change can be implemented in the view by checking the session variable in view and making decisions accordingly.
Please take look at this link
I am currently involved in the development of a larger webapplication written in PHP and based upon a MVC-framework sharing a wide range of similarities with the Zend Framework in terms of architecture.
When the user has logged in I have a place that is supposed to display the balance of the current users virtual points. This display needs to be on every page across every single controller.
Where do you put code for fetching sidewide modeldata, that isn't controller specific but needs to go in the sitewide layout on every pageview, independently of the current controller? How would the MVC or ZF-heads do this? And how about the rest of you?
I thought about loading the balance when the user logs in and storing it in the session, but as the balance is frequently altered this doesn't seem right - it needs to be checked and updated pretty much on every page load. I also thought about doing it by adding the fetching routine to every controller, but that didn't seem right either as it would result in code-duplication.
Well, you're right, having routines to every controller would be a code-duplication and wouldn't make your code reusable.
Unlike suggested in your question comments, I wouldn't go for a a base controller, since base controllers aren't a good practice (in most cases) and Zend Framework implements Action Helpers in order to to avoid them.
If your partial view is site-wide, why don't you just write your own custom View Helper and fetch the data in your model from your view helper? Then you could call this view helper directly from your layout. In my opinion, fetching data through a model from the view doesn't break the MVC design pattern at all, as long as you don't update/edit these data.
You can add your view helpers in /view/helpers/ or in your library (then you would have to register your view helper path too):
class Zend_View_Helper_Balance extends Zend_View_Helper_Abstract
{
public function balance()
{
$html = '';
if (Zend_Auth::getInstance()->hasIdentity()) {
// pull data from your model
$html .= ...;
}
return $html;
}
}
Note that you view helper could also call a partial view (render(), partial(), partialLoop()) if you need to format your code in a specific way.
This is a pretty simple example, but to me it's enough is your case. If you want to have more control on these data and be able to modify it (or not) depending on a particular view (or controller), then I recommend you to take a look on Placeholders. Zend has a really good example about them here on the online documentation.
More information about custom view helpers here.
When you perform such a task, consider using the Zend_Cache component too, so you won't have to query the database after each request but let's say, every minute (depending on your needs).
What you are looking for is Zend_Registry. This is the component you should use when you think you need some form of global variable. If you need this on EVERY page, then you are best adding it to your bootstrap, if you only need it in certain places add it in init method of relavent controllers.
application/Bootstrap.php
public _initUserBalance()
{
$userId = Zend_Auth::getInstance()->getIdentity()->userId;
$user = UserService::getUser($userId);
Zend_Registry::set('balance', $user->getBalance());
}
application/layouts/default.phtml
echo 'Balance = ' . Zend_Registry::get('balance');
That wee snippet should give you the right idea!
In this case, I usually go with a front controller plugin with a dispatchLoopShutdown() hook that performs the required data access and adds the data to the view/layout. The layout script then renders that data.
More details available on request.
[UPDATE]
Suppose you wanted to display inside your layout the last X news items from your db (or web service or an RSS feed), independent of which controller was requested.
Your front-controller plugin could look something like this in application/plugins/SidebarNews.php:
class My_Plugin_SidebarNews
{
public function dispatchLoopShutdown()
{
$front = Zend_Controller_Front::getInstance();
$view = $front->getParam('bootstrap')->getResource('view');
$view->sidebarNews = $this->getNewsItems();
}
protected function getNewsItems()
{
// Access your datasource (db, web service, RSS feed, etc)
// and return an iterable collection of news items
}
}
Make sure you register your plugin with the front controller, typically in application/configs/application.ini:
resource.frontController.plugins.sidebarNews = "My_Plugin_SidebarNews"
Then in your layout, just render as usual, perhaps in application/layouts/scripts/layout.phtml:
<?php if (isset($this->sidebarNews) && is_array($this->sidebarNews) && count($this->sidebarNews) > 0): ?>
<div id="sidebarNews">
<?php foreach ($this->sidebarNews as $newsItem): ?>
<div class="sidebarNewsItem">
<h3><?= $this->escape($newsItem['headline']) ?></h3>
<p><?= $this->escape($newsItem['blurb']) ?></p>
</div>
<?php endforeach; ?>
</div>
<?php endif; ?>
See what I mean?
I'm loading javascript files in the bootstrap as usual, but there's a file that I want to have included only if it's a page that has a form
->appendFile('http://myurl.com/js/formscript.js');
Is there a way to detect the page being loaded, from the bootstrap so I can decide whether or not to include this file?
I thought about passing a variable from the Form to the view, and then checking for that variable in the bootstrap, but it's not working.
This would be in my form
$layout = new Zend_Layout();
$view = $layout->getView();
$view->formscript = true;
and this would be in my bootstrap
if ($view->formscript)
but var_dump($view->formscript) give me null, so any other ideas to activate js files only in specific conditions?
To include javascript files in a particular pages alone, add the following code in those pages(I mean view scripts - *.phtml).
<?php
$this->headScript()->appendFile('http://myurl.com/js/formscript.js');
?>
Similarly, to add CSS files to a particular page, do the following.
<?php
$this->headLink()->appendStylesheet('http://myurl.com/styles.css');
?>
It is possible, but you do not need your bootstrap. You can just access the variable from your layout:
//form
$view = Zend_Layout::getMvcInstance()->getView();
$view->formscript = TRUE;
//layout
if($this->formscript)
{
$this->headScript()->appendFile('http://myurl.com/js/formscript.js');
}
echo $this->headScript();
Do not use getView() in your form as it will return the view object for the form, not for your application. This has tripped me up more than a couple of times >.>
Your idea to set a flag - something like $view->hasForm - in your view seems like a pretty reasonable approach. But as others have noted, it shouldn't be the form itself that attempts to set the flag since it doesn't really have access to view object until rendering time.
Instead, wherever you place a form into your view - probably in a controller, perhaps even in a front controller plugin - simply set your flag there.
Then your view script or layout can call $this->headScript()->appendFile() if the flag has been set.
Why not move over appendFile() to your form class (of course if you use Zend_Form), you would be sure that your JS line will be created only in the same time as your form. The place for this line is good in init() as well as in render()
class Your_Form extends Zend_Form {
public init(){
$this->getView()->appendFile('http://myurl.com/js/formscript.js');
[...]
}
}
Hey guys, I am new to CodeIgniter and need some help. I have a controller that formats the content area of a post. The problem is that I also need to create a sidebar that contains dynamic groups, and a right column that contains recent posts. This isn't hard, the problem I'm running into is that I want the sidebar, and right column on every page, and I don't want to recode the same bits to get the data in every controller.
What would be the best way to do this without copy/paste?
There are a lot of ways to do this.
1) Templating: This is my preference for most cases (because my templates are complex), I render my view into a variable using something like:
$content = $this->load->view('myview', $page_data, true);
Then I load it into the template parser (fyi you could load it into another view too) like this:
$this->load->library('parser');
$data = array(
'page_title' => 'My Page Title',
'page_content' => $content,
'side_bar' => side_bar(), // function which generates your side bar
'right_col' => right_col() // function which generates your right column
);
$this->parser->parse('my_template', $data);
Then your template is like:
<html>
<head>
<title>{page_title}</title>
</head>
<body>
<div>{side_bar}</div>
<div>{page_content}</div>
<div>{right_col}</div>
</body>
</html>
2) Load another view in your view: (assumes you menu is a view not a controller) Something like this:
<?php $this->load->view('menu_view'); ?>
3) PHP Includes: exactly how you would do it in plain PHP (just include a url which points to a controller which returns a menu), Something like this:
<?php include("/common/sidebar"); ?>
Codeigniter will render that page and then include it.
4) AJAX.. i use this if the content in the "template" content is less important, like banners, suggested related item lists and such.
Use PHP to generate a static HTML page, such as side_bar.html...
Then you can include it on other pages.
You could look into HMVC. It's especially suited for "widget"-type areas like you are talking about.
Essentially what you will do is create two full MVC structures - one for your sidebar and right column, including a controller, a model(if required), and a partial view. Then, you can call this controller directly from the main view to pull the required content in to the page.
To actually call it from within a view, just place the following in the markup wherever you want the sidebar to appear:
<?php echo modules::run('module/sidebar/index'); ?>
The index isn't required, but I put it there to demonstrate that you can call different methods using modules::run(). You can also pass an unlimited number of parameters to modules::run().
In code igniter, there is an optional third parameter to $this->load->view that lets you return a rendered view as a string, which can in turn be used for assignment. What you can do is create a master template, that has all the common parts, as a very simplified example:
<html>
<head>
</head>
<body>
<?php echo $sidebar; ?>
<?php echo $content; ?>
<?php echo $right_column; ?>
</body>
</html>
Then you can create a private function in your controller to populate the dynamic content of your common parts, and combine them with your content and master template:
private function BuildTemplate($view, $data) {
// Generate sidebar content
$sidebar_data['...'] = 'blah blah';
$master_data['sidebar'] = $this->load->view('sidebar', $sidebar_data, true);
// Generate right column data
$right_data['...'] = 'blah blah';
$master_data['right_column'] = $this->load->view('right_column', $right_data, true);
// Now load your content
$master_data['content'] = $this->load->view($view, $data, true);
// Merge it into the master template and return it
return $this->load->view('master' $master_data, true);
}
Then in your appropriate controller method:
public function index() {
$data['...'] = 'blah';
echo $this->BuildTemplate('index', $data);
}
Which will pull everything together for you. You can optionally add extra arguments to BuildTemplate if you want to add things like page specific titles or scripts.
I'm not sure if your problem is in the view, or in the (dynamic) data to be shown in the (common parts of) that view.
If it's the later (as seems to suggest the phrase 'I don't want to recode the same bits to get the data in every controller'), then you have several options. For example.
Put the logic to get the 'common' data in some function outside the controller, as a helper or inside some model, and call it from your controllers.
Make your controllers inherit your own custom controller, that implements that data gathering function.
Refactor your two controllers into a single controller, with different functions for each scenario.
1-Create a custom library class in library folder with the below code
if (!defined('BASEPATH')) exit('No direct script access allowed');
class LoadView{
function __construct(){
$this->CI =& get_instance();
}
function load_view($page){
$this->CI->load->view('header');
$this->CI->load->view('sidebar');
$this->CI->load->view($page);
$this->CI->load->view('footer');
}
}
2-Now load this library in your controller like this
$this->load->library('loadview');
3-Now call the library method and simply insert your page name and you don't have to include header,sidebar and footer again and again as they will be dynamically included by your library.
$this->loadview->load_view('about.php');