Loading view from root of Codeigniter - php

This question is related to this question
Loading view outside view folder with CodeIgniter
But the problem it is very old, and nobody looks it any more :(
This is problem i have, i have created function based on #SpYk3HH answer like this
MY_Loader.php
<?php
class MY_Loader extends CI_Loader {
public function base_view($view, $vars = array(), $get = FALSE) {
// ensures leading /
if ($view[0] != '/') $view = '/' . $view;
// ensures extension
$view .= ((strpos($view, ".", strlen($view)-5) === FALSE) ? '.php' : '');
// replaces \'s with /'s
$view = str_replace('\\', '/', $view);
if (!is_file($view)) if (is_file($_SERVER['DOCUMENT_ROOT'].$view)) $view = ($_SERVER['DOCUMENT_ROOT'].$view);
if (is_file($view)) {
if (!empty($vars)) extract($vars);
ob_start();
include($view);
$return = ob_get_clean();
if (!$get) echo($return);
return $return;
}
return show_404($view);
}
}
In controller I have used it like this
Welcome.php
class Welcome extends CI_Controller {
function __construct()
{
parent::__construct();
// Load globals
}
/**
* Index Page for this controller
*/
public function index()
{
$data['lang'] = '1';
$data['body_render']='mypages/home.php';
$this->load->view("/layouts/view_layout", $data);
}
view_layout.php
<?php $this->load->base_view($body_render); ?>
home.php
<?php echo $lang; ?>
But i got error, like i can not pass $lang to that partial inside partial?
Message: Undefined variable: lang
I modified all my contollers and views to very simple that somebody can understand.

As far as I can see in your codes, you didn't pass any variable to MY_Loader::base_view() when you are calling it
in your view_layout.php you need to pass variables you need
for example:
<?php $this->load->base_view($body_render, ['lang'=> $lang]); ?>

Related

php shortest version of calling a class

i saw a lot of ways that you can use to call a class inside another one in PHP and i want your opinion about the shortest version of calling a class.
lets say we have a class name view,
and another class name controller
class View
{
private $data = array();
private $render = FALSE;
public function __construct($template , $datas = null)
{
try {
$file = strtolower($template) . '.php';
if (file_exists($file)) {
if($datas > 0) {
foreach($datas as $data) {
array_push($this->data, $data);
}
}
$this->render = $file;
} else {
die('Template ' . $template . ' not found!');
}
}
catch (customException $e) {
echo $e->errorMessage();
}
}
public function __destruct()
{
extract($this->data);
include($this->render);
}
}
and
require_once "system/autoload.php";
class Controller {
function index() {
$view = new View('something');
}
i know that i can use
$view = new View('something');
or use OOP and extent and call a function from view inside controller like
$this->viewFunction();
but is there any way that i can call view class inside controller like this
View('something)
i want to make it shortest version possible
if it is not possible or i have to make change inside compiler well just give me the shortest version
thank you all
You can surely do this in PHP. Have a look at magic methods, especially __invoke()
class View
{
public function __invoke(string $template)
{
return $template;
}
}
You can simply invoke it by doing
$view = new View();
$view('my template');

MVC bad url error handling

I´m making a tiny MVC framework for learning purpose.
I have a file and a class called load which is in my model folder. It reads the requested file name and checks if the file is in the views folder and returns the correct file.
The problem I´m having is that I´m trying to make a handling for bad urls so that if the requested file/url does not excist you are directed to the index.php page in the views folder...
I have an if statement inside the function that checks if the file exists and I thought I could just write an else statement requiring the index.php file incase the file was not found...
But this doesn´t work. All I´m getting is a white blank page when I type in an non existing page even I´f I try echo something in the else statement...
Does anyone know what´s missing or what I´m doing wrong?
UPDATE:
Added mainController class
This is what the hole load class looks like:
<?php
/* model/load.php
*/
class load
{
/* This function takes parameter
* $file_name and match with file in views.
*/
function view($file_name, $data = null)
{
if (is_readable('views/' . $file_name)) {
if (is_array($data)) {
extract($data);
}
require 'views/' . $file_name;
} else {
//This is where I thought I could require the index.php file...
}
}
}
And in my controller folder I have a mainController class sending the files to the load file.
This is what the mainController class looks like:
<?php
/* controller/main.php
*
*/
class mainController
{
public $load;
public $urlValues;
public function __construct()
{
$url = parse_url($_SERVER['REQUEST_URI']);
$url = explode('/', trim($url['path'], '/'));
$this->urlValues = array('controller' => $url[1]);
//Index page
if ($this->urlValues['controller'] == "index.php") {
$key = array("key" => "");
$this->load = new load();
$this->load->view('index.php', $key);
}
//Register page
if ($this->urlValues['controller'] == "register.php") {
$this->load = new load();
$this->load->view('register.php');
}
//Home page
if ($this->urlValues['controller'] == "home.php") {
$this->load = new load();
$this->load->view('home.php');
}
}
}
It looks as though you are only calling the view method when the controller matches, and therefore it never gets executed. Try something like this, and work from there:
<?php
/* controller/main.php
*
*/
class mainController
{
public $load;
public $urlValues;
public function __construct()
{
$url = parse_url($_SERVER['REQUEST_URI']);
$url = explode('/', trim($url['path'], '/'));
$this->urlValues = array('controller' => $url[1]);
// ifs go here
$this->load = new load();
$this->load->view($this->urlValues['controller']);
}
}

how to pass data to view using $this_render->view("pagename",$renderData) in codeigniter?

Here is my code.
public function usertype($renderData='')
{
$this->grocery_crud->set_table('usertype');
$output = $this->grocery_crud->render();
$this->_example_output($output,$renderData='');
}
function _example_output($output = null,$renderData='')
{
// $this->load->view('pages/our_template',$output);
//echo $output;
// $this->output=$output;
$this->_render('pages/our_template',$renderData);
}
I want to use $this->_render('pages/our_template',$renderData); instead of $this->load->view('pages/our_template',$output); But I need to pass $output to the view page. Please help me to find a way to pass $output to my view page using $renderData.
And in my view page I want to get the the data
like
echo $output;
hi you can to do with view like this
$output = $this->load->view('pages/our_template',$data,TRUE); // this will return view output to variable
echo $output
Edited New Answer
First of all sorry for wrong answer
if you want to use $this->_render method then you have to take advantage of OOP create a MY_Controller under application/core directory and add _render method in it, extends your all controllers with MY_Controller like this
class MY_Controller extends CI_Controller{
function __construct(){
parent::__construct();
}
function _render($view = '', $data = array(), $return = FALSE){
if($return){
return $this->load->view($view,$data,$return);
}
$this->load->view($view,$data);
}
}
Example Page Controller
class PageController extends MY_Controller{
function __construct(){
parent::__construct();
}
function index(){
$data['title'] = 'Page title';
$data['body'] = 'Page body';
$this->_render('page_view',$data);
}
}
if you are using a layout for your project which has header,footer, sidebars then you can make render method little bit advance
function _render($view = '', $data = array(), $return = FALSE){
$output = $this->load->view($view,$data,TRUE);
if($return){
return $output;
}
$layout_data['header'] = $this->load->view('header_view',$data,TRUE);
$layout_data['footer'] = $this->load->view('footer_view',$data,TRUE);
$layout_data['sidebar'] = $this->load->view('sidebar_view',$data,TRUE);
$layout_data['body'] = $output;
$this->load->view('layout',$layout_data);
}
if you like answer accept and up it.

Kostache - before() method

Well, is there something like before() method in kostache module? For example, if I have a couple of PHP lines inside of the view file, I'd like to execute them separately inside of the view class, without echoing anything in the template itself. How can I handle that?
You can put this type of code in the constructor of your View class. When the view is instantiated, the code will run.
Here is a (slightly modified) example from a working application. This example illustrates a ViewModel that lets you change which mustache file is being used as the site's main layout. In the constructor, it chooses a default layout, which you can override if needed.
Controller:
class Controller_Pages extends Controller
{
public function action_show()
{
$current_page = Model_Page::factory($this->request->param('name'));
if ($current_page == NULL) {
throw new HTTP_Exception_404('Page not found: :page',
array(':page' => $this->request->param('name')));
}
$view = new View_Page;
$view->page_content = $current_page->Content;
$view->title = $current_page->Title;
if (isset($current_page->Layout) && $current_page->Layout !== 'default') {
$view->setLayout($current_page->Layout);
}
$this->response->body($view->render());
}
}
ViewModel:
class View_Page
{
public $title;
public $page_content;
public static $default_layout = 'mytemplate';
private $_layout;
public function __construct()
{
$this->_layout = self::$default_layout;
}
public function setLayout($layout)
{
$this->_layout = $layout;
}
public function render($template = null)
{
if ($this->_layout != null)
{
$renderer = Kostache_Layout::factory($this->_layout);
$this->template_init();
}
else
{
$renderer = Kostache::factory();
}
return $renderer->render($this, $template);
}
}

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