For the setting up of a small home framework, I want to send variables to the view, but I have to date find no solutions that works.
The code in question:
src/Controller/Controller.php
<?php
namespace App\Controller;
use App\Network\Request;
class Controller {
protected $viewPath = ROOT . VIEW;
protected $template = ROOT . TEMPLATE;
protected $layout = "default";
public function __construct()
{
$request = new Request();
$this->render($request->controller().'/'. $request->action());
}
public function layout($template) {
if($template != $this->layout) {
require $this->template . $template . '.php';
}
}
public function render($view) {
ob_start();
require $this->viewPath . '/' . str_replace('.', '/', $view). '.php';
$content = ob_get_clean();
require $this->template .$this->layout . '.php';
}
public function set($varname) {
extract($varname);
return $varname;
}
}
?>
app/Controller/PostsController.php
<?php
namespace App\Controller;
class PostsController extends Controller {
public function index() {
$posts = [
"id" => "1",
"ids" => "2"
];
$this->set(compact('posts'));
}
}
?>
Using the $this->set function in PostsController returns me Undefined variable: posts after an echo.
I also try to put ob_start and ob_get_clean in the set function but do not work either.
Namely, I do not want to include the function set in render, since I handle the view of the view dynamically (see __construct ()).
Another question:
How do I associate a View class with my views and thus use $this->method ().
Thank you
Your variables are only limited to function set scope. So you cannot see it in render function
Why won't you send array of values into the render function like that
public function render($view, array $params = []){
extract($params, EXTR_OVERWRITE);
ob_start();
require $this->viewPath . '/' . str_replace('.', '/', $view). '.php';
$content = ob_get_clean();
require $this->template .$this->layout . '.php';
}
then you call it like this
$this->render('hello', [
'name' => 'Mikołaj',
'surname' => 'Woźniak'
]);
Related
I have this file root/core/Router.php
<?php
namespace Core;
class Router {
protected $url;
protected $controller;
private function parseURL() {
// threat the $this->url; for example ["r", "product"]
}
private function request() {
$this->controller = Controller::get($this->url[1]);
}
public function __construct() {
$this->parseURL();
$this->request();
}
}
?>
then file root/core/Controller.php
<?php
namespace Core;
class Controller {
public static function model($name, $params = []) {
$model = "\\Model\\$name";
return new $model($params);
}
public static function view($name, $params = []) {
require_once APP_DIR . "view/" . $name . ".php";
}
public static function get($name, $params = []) {
require_once APP_DIR . "controller/" . $name . ".php";
$name = "\\Controller\\$name";
return new $name($params);
}
}
?>
then root/controler/Product.php
<?php
namespace Controller;
use Core\Controller;
use Model\Product;
class Product {
public function get() {
$ret['state'] = 510;
$productModel = new Product;
$products = $productModel->getAll();
if(isset($products)) {
$ret['products'] = $products;
$ret['state'] = 200;
}
return $ret;
}
}
?>
then file root/model/Product.php
<?php
namespace Model;
class Product {
public function add($values) {
return Database::insert("product", $values);
}
}
?>
and root/core/Model.php
<?php
namespace Core;
class Model {
protected $table = null;
public function getAll() {
// some code to collect data
}
}
?>
What i want to achive is that every Controller in root/controller/*.php able to load any Model in root/model/*.php but class inside root/model/*.php must able to access (inheritance/extends) the Model class inside root/core/Model.php i firstly asked on chatGPT for some AI Generated answer, that the reason why i get this far.
Then i get this error, when the AI keep giving the same answer.
Fatal error: Cannot declare class Controller\Product because the name is already in use in C:\xampp\htdocs\app\shop\controller\Product.php on line 6
I actually realize that the simple way probably with naming the class so ther no conflict between it but i became aware how to properly using the namespace if its such features in php. Those files loaded without any autoloader, so i just require_once each file in root/init.php file.
I read few documentations but hard to implement in multiple files and directorys.
I Apreciate any feedback, thanks
The error is:
Class 'Controller\Index' not found
but in all my code at any time I call this class:
Test.php << Script Executor
include_once("index.engine.php");
Index::importController();
use Controller\User;
echo User::getWorld(); // The error happens here.
Index.engine.php << Indexer Includes
if (!defined('HOME')) define("HOME", __DIR__."/");
class Index{
public static function importModel(){
spl_autoload_register(function ($class) {
$nome = str_replace("\\", "/" , $class . '.model.php');
if( file_exists( HOME . $nome ) ){
include_once( HOME . $nome );
}
});
}
public static function importController(){
spl_autoload_register(function ($class) {
$nome = str_replace("\\", "/" , $class . '.controller.php');
if( file_exists( HOME . $nome ) ){
include_once( HOME . $nome );
}
});
}
public static function importPersistent(){
spl_autoload_register(function ($class) {
$nome = str_replace("\\", "/" , $class . '.persistent.php');
if( file_exists( HOME . $nome ) ){
include_once( HOME . $nome );
}
});
}
}
user.controller.php << Only an intermediary
namespace Controller{
include_once (__DIR__ ."/../index.engine.php");
Index::importPersistent();
use Persistent\Test;
class User{
public static function getWorld(){
$result = Test::getEngine();
return $result;
}
}
}
user.persistent.php << Function required
namespace Persistent{
class Test{
public static function getEngine(){
$engine = "Engine is on! \o/";
return $engine;
}
}
}
Thanks for help me.
use Controller\User; # this is used to call a namespace, in your code there is no declaration of the namespace
echo User::getWorld(); //
For this, one would be expected to have a file in this form
sample.php
namespace Controller;
class User {
public static function getWorld() {
...
}
}
user.controller.php
namespace Controller{
include_once (__DIR__ ."/../index.engine.php");
Index::importPersistent();
use Persistent\Test;
class User{
public static function getWorld(){
$result = Test::getEngine();
return $result;
}
}
}
I change to:
namespace Controller{
use Index;
use Persistent\Test;
Index::importPersistent();
class User{
public static function getWorld(){
$result = Test::getEngine();
return $result;
}
}
}
The error was in the include which was called more than once, then altered to call only once in the view.
I am seeing some weird error on my client website. It's code someone else made for him for his application. The error message is saying that $this when not in object context but the Class has been extended where from App.
Please help out.
Error
Fatal error: Using $this when not in object context in contactController.php on line 6
contactController.php
class contactController extends App{
public function index(){
$this->view('content'); //error mmessage is pointing here
}
}
app.php
class App{
public $controller;
public $method;
public $params = [];
public function view( $file ){
include( site_path() . '/views/' . $file . '.php' );
}
public function model( $file ){
require_once( site_path() . '/models/' . $file . '.php' );
}
public function engine(){
global $core_current_ControllerMethod, $core_current_controller, $core_current_method;
//Get the current controller and method from a helper function
$get_wc_cm = get_wc_cm();
//Assign it to the global variable
$core_current_ControllerView = $get_wc_cm;
//Seperate the controller and method
$cm = explode('#', $get_wc_cm);
$controller = !empty($cm[0])? $cm[0]: null; // This is the controller
$method = !empty($cm[1])? $cm[1]: null; // This is the method
//Assign it to the global varaible
$core_current_controller = $controller;
$core_current_method = $method;
//Assign it to the class variable
$this->controller = $controller;
$this->method = $method;
$ControllerFile = site_path(). '/controllers/' . $this->controller . '.php';
if( file_exists($ControllerFile) ){
require_once($ControllerFile);
new $this->controller;
$callback = is_callable(array($this->controller, $this->method), false);
if( $callback ){
call_user_func_array([$this->controller, $this->method], [$this->params]);
}
}
}
}
$app = (new App)->engine();
Try to change :
class contactController extends App{
public function index(){
$this->view('content'); //error mmessage is pointing here
}
}
To :
class contactController extends App{
public function index(){
parent::view('content'); //error mmessage is pointing here
}
}
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]); ?>
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; ?>