I create a new object $Manager in my index.php($Manager = new Manager()). After that I do some routing etc. to eventually end up in a controller. That controller includes the view of choice.
Now; I'd like to use $Manager in that view, without having to assign a global $Manager in the method that includes it.
My controller looks like this:(stripped all the other methods)
<?php
Class PostController extends Controller {
public function home () {
$items = $this->getItems();
require_once(ROOT . 'application/items/post/home.view.php');
}
}
?>
In that home.view.php file I include view.view.php in a loop and do:
<?= $Manager->currentPageItem(); ?>
but it gives the error:
<b>Notice</b>: Undefined variable: Manager in <b>C:\xampp\htdocs\blurp\application\items\post\view.view.php</b> on line <b>4</b><br />
I've tried making $Manager a global in the index.php, to no avail. adding global $Manager to the home method works; but is not my solution of choice(Since every method would need that than)
How can I get includes from functions to keep using global variables like my $Manager?
Instead of using globals use dependency injection
//Your controller
class PostController extends Controller {
public function home() {
$items = $this->getItems();
require_once(ROOT . 'application/items/post/home.view.php');
}
}
//Somewhere in low end part of code
class Controller extends BaseClass {
}
abstract class BaseClass {
public $manager;
/**
* Passing dependencies
*/
public function init(Manager $manager) {
$this->manager = $manager;
}
}
//Index, router, whatever
$controller = new PostController;
$controller->init(new Manager);
$controller->home();
//View
echo $this->manager->currentPageItem();
Related
I am a newbie php coder. I have this main controller:
namespace App\Core;
class Controller
{
/** #var View View The view object */
public $View;
public $templates;
/**
* Construct the (base) controller. This happens when a real controller is constructed, like in
*/
public function __construct()
{
}
public function loadModel() {
$this->model = new \App\Front\Model\IndexModel(); //error line
}
}
In IndexController I have:
namespace App\Front\Controller;
use App\Front\Model\IndexModel;
class IndexController extends \App\Core\Controller {
public function index(){
$this->loadModel->test();
}
}
In IndexModel I have:
namespace App\Front\Model;
class IndexModel
{
public function test(){
echo 'test print';
}
}
In Action I get this error:
Notice: Undefined property: App\Front\Controller\IndexController::$loadModel in /Applications/xampp/htdocs/cmstest/application/Front/Controller/IndexController.php on line 13
I load all classes using composer and PDR-4 method.
What is the problem and how do I fix it? Thanks
Notice that in your loadModel method you just assign the new model to this but you not returning anything -> so you cannot can function test() on null.
In order to fix it use:
class IndexController extends \App\Core\Controller {
public function index(){
$this->loadModel();
$this->model->test();
}
}
If you insist on doing in index only one function you can modify your loadModel function to:
public function loadModel() {
if (!$this->model) // that way you load the Model only once. If you want to reload every time just remove the if
$this->model = new \App\Front\Model\IndexModel();
return $this->model;
}
And then you can do:
public function index(){
$this->loadModel()->test();
}
I have a problem with the following code. When I use $this when not in object content.
dashboardController.php
<?php
class dashboardController extends BaseController{
public function index($name=''){
$this->view->loadView('dashboard/index');
}
}
baseController.php
<?php
class BaseController{
public function loadView($viewName){
$this->view = new View($viewName);
}
}
view.php
<?php
class View{
public function __construct($viewName);{ echo " i am form view to render
}
}
I am getting the error using $this when not in object content but in another folder the login went success without.
Try this:
dashboardController
<?php
class dashboardController extends BaseController
{
public function index($name = '')
{
// Call loadView(), because this controller doesn't have a method
// called loadView() it'll fall back to loadView() in the BaseController
$this->loadView('dashboard/index');
// Get the viewName from the view, will be 'dashboard/index'
echo $this->view->getViewName();
}
}
BaseController
<?php
class BaseController
{
// The view, protected so it can be accessed by children via $this->view
protected $view;
// Load a view, protected so it can only be accessed by children
// or within this controller
protected function loadView($viewName)
{
// Create a new view instance
$this->view = new View($viewName);
}
}
View
<?php
class View
{
// The loaded view, private so it can't be changed by an external class
private $viewName;
public function __construct($viewName)
{
$this->viewName = $viewName;
}
// Retrieve the view name, public so anything can access it
public function getViewName()
{
return $this->viewName;
}
}
I have a base controller that looks something like this:
<?php
namespace framework;
class BaseController
{
public $model;
public $view;
function __construct()
{
$this->model = new ModelFactory();
$this->view = new View($this->model->data);
}
}
This controller is never called directly, but only through extends:
<?php
namespace framework\controllers;
use framework\BaseController,
framework\Router;
class IndexController extends BaseController
{
}
What I'd like to do, and hopefully this makes sense, is insert data or extra functionality into the base controller between $this->model and $this->view in such a way that it's anonymous or decoupled, rather than hard-coded. As an example, the application may or may not require user data. The following is how I could hard code it although this is exactly what I'm trying to avoid:
<?php
namespace framework;
class BaseController
{
public $model;
public $view;
function __construct()
{
$this->model = new ModelFactory();
// get user data
$this->model->data['user_roles'] = array();
if ($user = $this->isLoggedIn()) {
$this->model->data['user_roles'] = $user->roles;
}
$this->view = new View($this->model->data);
}
// check if a user is logged in and return a user object or false
public function isLoggedIn() {}
}
And the following is pseudo code of what my brain thinks I'd like to accomplish:
// anonymous function in my bootstrap or global configuration file
$user_roles = function () {};
<?php
namespace framework;
class BaseController
{
public $model;
public $view;
function __construct($name, $value) // not sure how these are passed in
{
$this->model = new ModelFactory();
// get extra data
$this->model->data[$name] = $value($this->model);
$this->view = new View($this->model->data);
}
}
Not sure if I need a specific pattern or if I'm even heading in the right direction. How can I accomplish something along these lines? I open to any recommended alternative approaches.
What you're looking for are PHP traits.
Traits are a way to extract/isolate behavior which you can then "inject" in any class.
When you declare a trait:
trait ControllerQueryable
{
public function magicQuery()
{ // $this is the class that's using this trait.
$this->orm->fetch(str_replace(get_class($this), 'Controller', ''), $this->params['id']);
}
}
It's made available for any class to use:
class BlogController extends BaseController
{
use ControllerQueryable;
public function showAction()
{
$model = $this->magicQuery();
// yada yada yada
}
}
Contrarily to extends, you can use as many traits as you want.
I have my application within Zend Framework 1. I'm using Zend_Auth to manage sessions. Below is how I check authentication within the IndexController class:
class IndexController extends Zend_Controller_Action
{
public function init()
{
$auth = Zend_Auth::getInstance();
if ($auth->hasIdentity()) {
$this->view->user = $auth->getIdentity();
}
}
public function indexAction()
{
}
}
Basically it just sets a view variable of user to whatever is in the auth object. Within my view I can check if the user variable is set and act appropriately (e.g. Display "Welcome Tom!" and a logout link)
However, this functionality is not available yet in my other controllers. Rather than duplicate the same code within each init() method, how can I do this? I'm not so sure where to put the code for this.
UPDATE:
I tried to do something like this in the bootstrap file:
class Bootstrap extends Zend_Application_Bootstrap_Bootstrap
{
protected function _initView() {
$auth = Zend_Auth::getInstance();
if ($auth->hasIdentity()) {
$this->view->user = $auth->getIdentity();
}
}
}
..but I get the following error: Notice: Indirect modification of overloaded property Bootstrap::$view has no effect in /var/www/budgetz/application/Bootstrap.php on line 9 Warning: Creating default object from empty value in /var/www/budgetz/application/Bootstrap.php on line 9.
You can use an abstract class inheriting from Zend_Controller_Action like this:
abstract Class Yourlibrary_Controller_ControllerAbstract extends Zend_Controller_Action
{
public function preDispatch()
{
$auth = Zend_Auth::getInstance();
if ($auth->hasIdentity()) {
$this->view->user = $auth->getIdentity();
}
}
}
And yours Controllers inherit Yourlibrary_Controller_ControllerAbstract not Zend_Controller_Action
I am trying to build an abstract base controller that will extend all other controllers. So far I have something like:
abstract class BaseController {
protected $view;
protected $user;
public function __construct() {
$this->view = new View; //So a view is accessible to subclasses via $this->view->set();
$this->user = new User; //So I can check $this->user->hasPermission('is_admin');
}
abstract function index();
}
class UserController extends BaseController {
public function index() {}
public function login() {
if($this->user->isLoggedin()) {
redirect to my account
}
else {
$this->view->set('page_title', "User Login");
$this->view->set('sidebar', $sidebar); //contains sidebar HTML
$this->view->set('content', $content); //build main page HTML
$this->view->render();
}
}
}
The problem i get is I get errors like this:
Call to a member function set() on a non-object in C:\xampp\htdocs\program\core\controllers\admin.controller.php on line 44
If I put the $user and $views properties in the main controller (ie UserController), everything works fine. But I only want to set up these objects once (in the base controller) and not have to add $this->view = new View; in all my controllers.
FIXED: I overrode my constructors and I thought you couldn't call parent::__construct() on abstract classes.
What you are trying to do should work. Make sure you aren't covering up your constructor in UserController. (i.e., if it has a constructor, it needs to call its parent constructor.)
Otherwise, do some debugging to see where $this->view is being reset.
Your code works for me. You are either overriding your __construct() method in UserController, or you are overridding the view field with something other than a View object.
What you have in this form would work.