Render a view in PHP - php

I am writing my own MVC framework and has come to the view renderer. I am setting vars in my controller to a View object and then access vars by echo $this->myvar in the .phtml script.
In my default.phtml I call the method $this->content() to output the viewscript.
This is the way I do it now. Is this a proper way to do that?
class View extends Object {
protected $_front;
public function __construct(Front $front) {
$this->_front = $front;
}
public function render() {
ob_start();
require APPLICATION_PATH . '/layouts/default.phtml' ;
ob_end_flush();
}
public function content() {
require APPLICATION_PATH . '/views/' . $this->_front->getControllerName() . '/' . $this->_front->getActionName() . '.phtml' ;
}
}

Example of a simple view class. Really similar to yours and David Ericsson's.
<?php
/**
* View-specific wrapper.
* Limits the accessible scope available to templates.
*/
class View{
/**
* Template being rendered.
*/
protected $template = null;
/**
* Initialize a new view context.
*/
public function __construct($template) {
$this->template = $template;
}
/**
* Safely escape/encode the provided data.
*/
public function h($data) {
return htmlspecialchars((string) $data, ENT_QUOTES, 'UTF-8');
}
/**
* Render the template, returning it's content.
* #param array $data Data made available to the view.
* #return string The rendered template.
*/
public function render(Array $data) {
extract($data);
ob_start();
include( APP_PATH . DIRECTORY_SEPARATOR . $this->template);
$content = ob_get_contents();
ob_end_clean();
return $content;
}
}
?>
Functions defined in the class will be accessible within the view like this:
<?php echo $this->h('Hello World'); ?>

Here's an example of how i did it :
<?php
class View
{
private $data = array();
private $render = FALSE;
public function __construct($template)
{
try {
$file = ROOT . '/templates/' . strtolower($template) . '.php';
if (file_exists($file)) {
$this->render = $file;
} else {
throw new customException('Template ' . $template . ' not found!');
}
}
catch (customException $e) {
echo $e->errorMessage();
}
}
public function assign($variable, $value)
{
$this->data[$variable] = $value;
}
public function __destruct()
{
extract($this->data);
include($this->render);
}
}
?>
I use the assign function from out my controller to assign variables, and in the destructor i extract that array to make them local variables in the view.
Feel free to use this if you want, i hope it gives you an idea on how you can do it
Here's a full example :
class Something extends Controller
{
public function index ()
{
$view = new view('templatefile');
$view->assign('variablename', 'variable content');
}
}
And in your view file :
<?php echo $variablename; ?>

Related

How to create view data from model in basic PHP MVC System

I'm creating a simple PHP MVC system based on the "original" MVC principle, that is...
Controller instructs the model based on user input / queries and loads view
Model is a data layer is is unaware and independant from the controller or view
View creates own copy of data from Model for presentaion purposes
Everything I've done so far conforms to these principles, however, I've stumbled upon a problem as follows...
I set a default page title in the parent model
I inform the model to change its page title value using a model method based on the user page request in the correct controller method (index_controller/index)
I make a copy of models page title in the home view to b used on the template.
The problem is, the page title isnt updated because im setting the view variable in the index view constructor which happens before the model can be updated by the controller.
I can get the correct view variable by fetching and assigning it just before load the template, but the template loading is done in the parent view class which is an issue because different views require different variables.
Please let me know what I'm doing wrong! Any help is much appreciated!
It might help to see some of thecode in question...
lib/bootstrap.php
class Bootstrap {
function __construct() {
// Gets the request URL and seperate into array
$this->url = $this->getUrlArray();
// Generates the controller name based on URL array
$this->controller_name = $this->getControllerName();
// Loads controller file and creates new controller object
$this->controller = $this->getController();
// Calls requested methods based on URL array
$this->callMethods();
}
function getUrlArray() {
$url = isset($_GET['url']) ? rtrim($_GET['url'], '/') : 'index';
$url = explode('/', $url);
return $url;
}
function getControllerName() {
return $this->url[0] . '_controller';
}
function getController() {
$file = 'controllers/' . $this->controller_name . '.php';
if(file_exists($file)) {
require $file;
return new $this->controller_name($this->url[0]);
} else {
require 'controllers/error_controller.php';
return new Error_Controller('error');
}
}
function callMethods() {
if(!isset($this->url[1])) {
$this->controller->index();
} else {
$method_name = $this->url[1];
if(method_exists($this->controller, $method_name)) {
if(!isset($this->url[2])) {
$this->controller->$method_name();
} else {
$this->controller->$method_name($this->url[2]);
}
} else {
$this->controller->index();
}
}
}
}
lib/controller.php
class Controller {
protected $model;
public function __construct($name) {
$this->base_name = $name;
$this->model_name = $this->getModelName();
$this->model = $this->getModel();
$this->view_name = $this->getViewName();
$this->view = $this->getView();
//$this->creatView();
}
public function getModelName() {
return $this->base_name . '_model';
}
public function getViewName() {
return $this->base_name . '_view';
}
public function getModel() {
$file = 'models/' . $this->model_name . '.php';
if(file_exists($file)) {
require $file;
return new $this->model_name();
} else {
die('ERROR: This page is missing a model!');
}
}
public function getView() {
$file = 'views/' . $this->view_name . '.php';
if(file_exists($file)) {
require $file;
return new $this->view_name($this->model);
} else {
die('ERROR: This page is missing a view!');
}
}
}
lib/model.php
class Model {
public function __construct() {
$this->page_title = SITE_NAME;
}
public function setPageTitle($pre, $seperator) {
$this->page_title = $pre . ' ' . $seperator . ' ' . SITE_NAME;
}
}
lib/view.php
class View {
protected $model;
public function __construct(Model $model) {
$this->model = $model;
}
public function output($name, $noInclude = false) {
$file = 'templates/' . $name . '.php';
if(file_exists($file)) {
if($noInclude) {
require 'templates/' . $name . '.php';
} else {
require 'templates/header.php';
require 'templates/' . $name . '.php';
require 'templates/footer.php';
}
} else {
die('ERROR: This page is missing a template!');
}
}
}
controllers/index_controller.php
<?php
class Index_Controller extends Controller {
function __construct($name) {
parent::__construct($name);
}
function index() {
$this->model->setPageTitle('Home', '-');
var_dump($this);
$this->view->output('index/index');
}
function test($value = 'not set') {
echo 'You are in test and the value is ' . $value;
}
}
views/index_view.php
class Index_View extends View {
public function __construct(Model $model) {
parent::__construct($model);
$this->page_title = $this->model->page_title;
}
}
models/index_model.php
class Index_Model extends Model {
public function __construct() {
parent::__construct();
}
}
templates/header.php
<!DOCTYPE html>
<html>
<head>
<title><?php echo $this->page_title; ?></title>
</head>
<body>
<div id="header">
<!-- -->
</div>
<div id="content">
My var_dump in index_controller looks like this...
Cheers,
Tom

How to Integrate SEOStats with Codeigniter?

Hello I want to integrate the SEOStats Class with a project in codeigniter , is anyone provide me solution ?
I have tried to make the SEOstats class as a helper and load the helper in the specific controler , but a blank page is showing , I also try to include it via view but the same blank page i am seeing ,
I have included this code in my view file , the SEOstats directory also in the same views directory .
<?php
require_once 'SEOstats/bootstrap.php';
use \SEOstats\Services as SEOstats;
try {
$url = 'http://www.google.com/';
// Create a new SEOstats instance.
$seostats = new \SEOstats\SEOstats;
// Bind the URL to the current SEOstats instance.
if ($seostats->setUrl($url)) {
echo SEOstats\Alexa::getGlobalRank();
echo SEOstats\Google::getPageRank();
}
}
catch (SEOstatsException $e) {
die($e->getMessage());
}
i have also used it as library
<?php
namespace SEOstats;
use SEOstats\Common\SEOstatsException as E;
use SEOstats\Config as Config;
use SEOstats\Helper as Helper;
use SEOstats\Services as Service;
class SEOstats
{
const BUILD_NO = Config\Package::VERSION_CODE;
protected static $_url,
$_host,
$_lastHtml,
$_lastLoadedUrl
= false;
public function __construct($url = false)
{
if (false !== $url) {
self::setUrl($url);
}
}
public function Alexa()
{
return new Service\Alexa;
}
public function Google()
{
return new Service\Google;
}
public function OpenSiteExplorer()
{
return new Service\OpenSiteExplorer;
}
public function SEMRush()
{
return new Service\SemRush;
}
public function Sistrix()
{
return new Service\Sistrix;
}
public function Social()
{
return new Service\Social;
}
public static function getHost()
{
return self::$_host;
}
public static function getLastLoadedHtml()
{
return self::$_lastHtml;
}
public static function getLastLoadedUrl()
{
return self::$_lastLoadedUrl;
}
/**
* Ensure the URL is set, return default otherwise
* #return string
*/
public static function getUrl($url = false)
{
$url = false !== $url ? $url : self::$_url;
return $url;
}
public function setUrl($url)
{
if (false !== Helper\Url::isRfc($url)) {
self::$_url = $url;
self::$_host = Helper\Url::parseHost($url);
}
else {
throw new E('Invalid URL!');
exit();
}
return true;
}
/**
* #return DOMDocument
*/
protected static function _getDOMDocument($html) {
$doc = new \DOMDocument;
#$doc->loadHtml($html);
return $doc;
}
/**
* #return DOMXPath
*/
protected static function _getDOMXPath($doc) {
$xpath = new \DOMXPath($doc);
return $xpath;
}
/**
* #return HTML string
*/
protected static function _getPage($url) {
$url = self::getUrl($url);
if (self::getLastLoadedUrl() == $url) {
return self::getLastLoadedHtml();
}
$html = Helper\HttpRequest::sendRequest($url);
if ($html) {
self::$_lastLoadedUrl = $url;
self::_setHtml($html);
return $html;
}
else {
self::noDataDefaultValue();
}
}
protected static function _setHtml($str)
{
self::$_lastHtml = $str;
}
protected static function noDataDefaultValue()
{
return Config\DefaultSettings::DEFAULT_RETURN_NO_DATA;
}
}
and loaded the library as
$this->load->library('SEOstats');
I know this post is old. But I was looking for a solution as well recently and ended up writing my own and figured I would leave it here in case anyone else was looking for a solution in the future.
Place the following in a library file and autoload if you want.
if (!defined('BASEPATH'))
exit('No direct script access allowed');
class SEOstatistics {
private $seostats;
function __construct() {
require_once( APPPATH . 'third_party/seostats/bootstrap.php' );
$this->seostats = new \SEOstats\SEOstats;
}
private function alexa() {
return new \SEOstats\Services\Alexa;
}
private function google() {
return new \SEOstats\Services\Google;
}
private function moz() {
return new \SEOstats\Services\Mozscape();
}
private function openSiteExplorer() {
return new \SEOstats\Services\OpenSiteExplorer();
}
private function semRush() {
return new \SEOstats\Services\SemRush();
}
private function sistrix() {
return new \SEOstats\Services\Sistrix();
}
private function social() {
return new \SEOstats\Services\Social();
}
public function __call($method, $url) {
if (method_exists($this, $method)) {
if ($this->seostats->setUrl($url[0])) {
return call_user_func_array(array($this, $method),array());
}
return false;
}
}
}
And then an example of using it in a controller or model is:
$google = $this->seostatistics->google($url);
$rank = $google->getPageRank();
This is how I include SEOStats on my Codeigniter website
class Cron extends Frontend_Controller
{
public function get_google_page_rank() {
require_once (APPPATH . 'libraries/SEOstats/bootstrap.php');
try {
$url = 'http://www.google.com/';
// Get the Google PageRank for the given URL.
$pagerank = \SEOstats\Services\Google::getPageRank($url);
echo "The current Google PageRank for {$url} is {$pagerank}." . PHP_EOL;
}
catch(\Exception $e) {
echo 'Caught SEOstatsException: ' . $e->getMessage();
}
}
public function get_alexa_page_rank() {
require_once (APPPATH . 'libraries/SEOstats/bootstrap.php');
//use \SEOstats\Services\Alexa as Alexa;
try {
$url = 'https://www.google.com/';
// Create a new SEOstats instance.
$seostats = new \SEOstats\SEOstats;
// Bind the URL to the current SEOstats instance.
if ($seostats->setUrl($url)) {
/**
* Print HTML code for the 'daily traffic trend'-graph.
*/
echo \SEOstats\Services\Alexa::getTrafficGraph(1);
/**
* Print HTML code for the 'daily pageviews (percent)'-graph.
*/
echo \SEOstats\Services\Alexa::getTrafficGraph(2);
/**
* Print HTML code for the 'daily pageviews per user'-graph.
*/
echo \SEOstats\Services\Alexa::getTrafficGraph(3);
/**
* Print HTML code for the 'time on site (in minutes)'-graph.
*/
echo \SEOstats\Services\Alexa::getTrafficGraph(4);
/**
* Print HTML code for the 'bounce rate (percent)'-graph.
*/
echo \SEOstats\Services\Alexa::getTrafficGraph(5);
/**
* Print HTML code for the 'search visits'-graph, using
* specific graph dimensions of 320*240 px.
*/
echo \SEOstats\Services\Alexa::getTrafficGraph(6, false, 320, 240);
}
}
catch(\Exception $e) {
echo 'Caught SEOstatsException: ' . $e->getMessage();
}
}
}
Hope this helps
PS: Copy SEOstats folder in application/libraries folder

How to extending a class in another file

So I have been doing some OOP and I hit a snag. I'm trying to extend a class in another PHP file. The extended classes should load dynamically. I got it set up like this:
bootstrap.php file:
<?php
class bootstrap{
public $lang;
public $page;
public $action;
public $id;
public $message;
public function __construct() {
$this->buildPage();
}
public function buildPage() {
if($this->page == 'home'){
require_once CONTR . 'view.php';
new view($this->lang, $this->page, $this->action, $this->id, $this->message);
}
}
}
and the view.php file:
class view extends bootstrap{
public $lang;
public $page;
public $action;
public $id;
public $message;
public function __construct($lang, $page, $action, $id, $message) {
parent::__construct();
$this->lang = $lang;
$this->page = $page;
$this->action = $action;
$this->id = $id;
$this->message = $message;
$this->showPage();
}
public function showPage() {
require_once VIEW . 'header.php';
//echo VIEW . 'header.php';
//prepare SQL statements
$page = $this->page;
$name = "name_" . $this->lang;
//SQL statement
$selectdata = mysql_query("SELECT * FROM pages WHERE $name = '$page'");
$result = mysql_fetch_array($selectdata);
//Echo content
if($result["content_$this->lang"] == NULL){
echo "no content";
} else {
echo $result["content_$this->lang"];
}
//Debugging
echo '<br>' . $this->lang;
echo '<br>' . $this->page;
echo '<br>' . $name;
echo '<br>' . $page;
require_once VIEW . 'footer.php';
}
}
--> Index.php
require('front/config.php');
require('front/bootstrap.php');
$site = new bootstrap();
After doing this I tried to call the view class through the bootstrap class by using extends.
I have been trying lots of different things but I think I am quite close. Does anyone have an idea how to solve this one?
The showpage function does actually work when I put it in the bootstrap class, but when I put it in the view class, nothing works.
Thanks in advance!

extending class and protected data

im trying to create a class to manage widgets. I have problems with a protected data in parent class:
Widget.php
/** Parent class **/
class Widget{
protected $html =""; //formated html data
// method to load views in {system_path}/widgets/{widget_name}/views/
protected function LoadView($filename){
if(!empty($filename) && is_string($filename)){
$output = "";
$dir = WIDGET_PATH . "views" . DS . $filename;
ob_start();
include($dir);
$output = ob_get_contents();
ob_end_clean();
return $output;
}
return NULL;
}
//method to render formated html data
public function Render(){
if(isset($this->html) && !empty($this->html)){
return $this->html;
}
return NULL;
}
//static method to load a Widget
public static function Load($widgetName){
if(!empty($widgetName) && is_string($widgetName)){
$widgetName = strtolower($widgetName);
if(file_exists(WIDGET_PATH . $widgetName . DS . $widgetName . ".php")){
include_once(WIDGET_PATH . $widgetName . DS . $widgetName . ".php");
if(class_exists($widgetName."_Widget")){
$class = $widgetName."_Widget";
return new $class();
}
}
}
return FALSE;
}
}
/widgets/socialbar.php
/** SocialBar Widget **/
class Socialbar_Widget extends Widget
{
public function __construct(){
$this->html = "demo"; // test to see if it works
}
}
index.php
/*load class files, etc */
$Social = Widget::Load("socialbar"); //works, perfectly loads Socialbar_Widget()
var_dump($social); // works : object(Socialbar_Widget)[29] protected html = 'demo' ......
$Social->Render(); // throws Fatal error: Using $this when not in object context
To extend a variable inside parent class should i use "public"? Or what i mistake.
Thanks for help guys.
Your class name is class Socialbar_Widget,
Your are calling it in lower case
$Social = Widget::Load("socialbar")
and in load method you are doing strtolower($widgetName).
Check class file name.php. Load function may have returning false.

Sub views (layouts, templates) in Slim php framework

I'm trying out the Slim php framework
Is it possible to have layouts or sub views in Slim? I'd like to use a view file as a template with variables as placeholders for other views loaded separately.
How would I do that?
filename: myview.php
<?php
class myview extends Slim_View
{
static protected $_layout = NULL;
public static function set_layout($layout=NULL)
{
self::$_layout = $layout;
}
public function render( $template ) {
extract($this->data);
$templatePath = $this->getTemplatesDirectory() . '/' . ltrim($template, '/');
if ( !file_exists($templatePath) ) {
throw new RuntimeException('View cannot render template `' . $templatePath . '`. Template does not exist.');
}
ob_start();
require $templatePath;
$html = ob_get_clean();
return $this->_render_layout($html);
}
public function _render_layout($_html)
{
if(self::$_layout !== NULL)
{
$layout_path = $this->getTemplatesDirectory() . '/' . ltrim(self::$_layout, '/');
if ( !file_exists($layout_path) ) {
throw new RuntimeException('View cannot render layout `' . $layout_path . '`. Layout does not exist.');
}
ob_start();
require $layout_path;
$_html = ob_get_clean();
}
return $_html;
}
}
?>
example index.php:
<?php
require 'Slim/Slim.php';
require 'myview.php';
// instantiate my custom view
$myview = new myview();
// seems you need to specify during construction
$app = new Slim(array('view' => $myview));
// specify the a default layout
myview::set_layout('default_layout.php');
$app->get('/', function() use ($app) {
// you can override the layout for a particular route
// myview::set_layout('index_layout.php');
$app->render('index.php',array());
});
$app->run();
?>
default_layout.php:
<html>
<head>
<title>My Title</title>
</head>
<body>
<!-- $_html contains the output from the view -->
<?= $_html ?>
</body>
</html>
The slim framework makes use of other templating engines such as Twig or Smarty so as long as you choose a templating engine that allows subviews, then it'll work. For more info on view templating in Slim, check here.
I'm working with my View:
class View extends \Slim\View
{
protected $layout;
public function setLayout($layout)
{
$this->layout = $layout;
}
public function render($template)
{
if ($this->layout){
$content = parent::render($template);
$this->setData(array('content' => $content));
return parent::render($this->layout);
} else {
return parent::render($template);
}
}
}
You may add some method like setLayoutData(..) or appendLayoutData(..)
Few minutes ago:
class View extends \Slim\View
{
/** #var string */
protected $layout;
/** #var array */
protected $layoutData = array();
/**
* #param string $layout Pathname of layout script
*/
public function setLayout($layout)
{
$this->layout = $layout;
}
/**
* #param array $data
* #throws \InvalidArgumentException
*/
public function setLayoutData($data)
{
if (!is_array($data)) {
throw new \InvalidArgumentException('Cannot append view data. Expected array argument.');
}
$this->layoutData = $data;
}
/**
* #param array $data
* #throws \InvalidArgumentException
*/
public function appendLayoutData($data)
{
if (!is_array($data)) {
throw new \InvalidArgumentException('Cannot append view data. Expected array argument.');
}
$this->layoutData = array_merge($this->layoutData, $data);
}
/**
* Render template
*
* #param string $template Pathname of template file relative to templates directory
* #return string
*/
public function render($template)
{
if ($this->layout){
$content = parent::render($template);
$this->appendLayoutData(array('content' => $content));
$this->data = $this->layoutData;
$template = $this->layout;
$this->layout = null; // allows correct partial render in view, like "<?php echo $this->render('path to parial view script'); ?>"
return parent::render($template);;
} else {
return parent::render($template);
}
}
}
With Slim 3
namespace Slim;
use Psr\Http\Message\ResponseInterface;
class View extends Views\PhpRenderer
{
protected $layout;
public function setLayout($layout)
{
$this->layout = $layout;
}
public function render(ResponseInterface $response, $template, array $data = [])
{
if ($this->layout){
$viewOutput = $this->fetch($template, $data);
$layoutOutput = $this->fetch($this->layout, array('content' => $viewOutput));
$response->getBody()->write($layoutOutput);
} else {
$output = parent::render($response, $template, $data);
$response->getBody()->write($output);
}
return $response;
}
}
In layout:
<?=$data['content'];?>
You can use this in your parent view:
$app = \Slim\Slim::getInstance();
$app->render('subview.php');
If you want to capture the output in a variable, it's as easy as using the view's fetch() method:
//assuming $app is an instance of \Slim\Slim
$app->view()->fetch( 'my_template.php', array( 'key' => $value ) );
Yes it is possible. If you do not want to use any template engine like smarty or twig. If you want to use only .php view file. Follow these steps.
Step 1. Make a new directory in your project's root directory. e.g templates.
Step 2. Open dependencies.php and paste below code
$container = $sh_app->getContainer();
$container['view'] = function ($c) {
$view = new Slim\Views\PhpRenderer('src/templates/');
return $view;
};
Step 3. In your controller's method for rendering view code should be looking like this.
$this->container->view->render($response,'students/index.php',['students' => $data]);

Categories