I'm trying to build MVC pattern using OOP PHP. Please read the rest of the post to understand what I want exactly.
This is the homepage controller which extends the main controller
class Home extends Controller {
function __construct () {
parent::__construct();
}
public function index () {
$this->load->model("test");
$this->test->get_all();
$data = array (
'name' => "Amr",
'age' =>24
);
$this->load->view("home_view",$data);
}
}
The Main Controller looks like this and extends loader class:
class Controller extends Loader {
public $load;
function __construct(){
parent::__construct();
$this->load = new Loader();
}
}
The Loader class which has the problem looks like this
class Loader {
public $Error;
function __construct(){
$this->Error = new Error();
}
public function model($Modelname){
$this->$Modelname = $Modelname;
if (file_exists("models/".$Modelname.".php")){
require_once $Modelname . ".php";
$this->$Modelname = new $Modelname;
}else{
$this->Error->Not_found();
}
}
public function view($Viewname,$data=NULL){
if(is_array($data)){
extract($data);
}
if (file_exists("views/".$Viewname.".php")){
require_once $Viewname . ".php";
}else{
$this->Error->Not_found();
}
}
public function helper($helper) {
if (file_exists("helpers/".$helper.".php")){
require_once $helper . ".php";
$this->$helper = new $helper;
}else{
$this->Error->Not_found();
}
}
}
What I need to do is to be able FROM HOMEPAGE Controller to do something like this:
$this->load->model("someModel"); // model name is test
$this->someModel->someMethodInModel(); // the model method is get_all()
// and the same for helper
$this->load->helper("someHelper");
$this->someHelper->someMethodInHelper();
Can anyone help me?
EDIT: The error that I'm getting when doing this is:
Notice: Undefined property: Home::$test
Fatal error: Call to a member function get_all() on a non-object
NOTE: the model name is test and the model method is get_all()
public function model($Modelname){
$this->$Modelname = $Modelname;
if (file_exists("models/".$Modelname.".php")){
require_once $Modelname . ".php";
$this->$Modelname = new $Modelname;
What do you need help with? With your current code you can do
$this->load->model("someModel");
$this->someModel->someMethodInModel();
// and the same for helper
$this->load->helper("someHelper");
$this->someHelper->someMethodInHelper();
in your Home controller. I just tried it out myself. What errors do you get? What's not working properly?
If I were you, I would put a "load()" method into my controller which would call the "loader" class and store the new model/helper/view into a variable.
I think the problem you're having is, your loader creates an instance of a model as a member of the Loader class, and not your controller class.
if your base controller extends Loader then there is no reason use it like property
class Controller extends Loader {
public $load;
function __construct(){
parent::__construct();
$this->load = new Loader();
}
}
change it to
class Controller extends Loader {
}
another way is to use magic method hook http://php.net/manual/en/language.oop5.overloading.php#object.get
class Controller {
public $load;
function __construct(){
parent::__construct();
$this->load = new Loader();
}
function __get($modelName){
return $this->load->$modelName;
}
}
Related
I have view class like this:
class View {
public function __construct() {
}
public static function render($name) {
require 'views/user/header.php';
require 'views/user/'.$name.'.php';
require 'views/user/footer.php';
}
}
and I call the view class in controller like this:
class Controller {
function __construct() {
$this->view = new View();
}
}
and then I set the view property from controller child class, like this:
class Index extends Controller {
function __construct() {
parent::__construct();
$this->view->js = "test";
}
public function index() {
$this->view->render('index/index');
}
}
But when I want to get $this->js from "header.php" which is set at render function on view class, I always get this error message:
Fatal error: Uncaught Error: Using $this when not in object context
I was tried to check, Am I in the right class? using this methods in "header.php" file:
echo get_class(); // and this method return "View";
that means I was on the view class, right?
Can anyone please help me?
Thanks in advance
You have defined render() as a static method, but you are calling it as it was not static.
I would probably benefit from reading this: http://chadminick.com/articles/simple-php-template-engine.html
P.S. What you call "view" is just a template.
Suppose that I've this class:
class Loader
{
function library($name)
{
require $name . '.php';
}
}
and now I include the class foo ($name) inside my controller, like this:
class Controller
{
function __construct()
{
$this->load = new Loader();
}
}
class Child_Controller extends Controller
{
function __construct()
{
parent::__construct();
$this->load->library('foo');
init();
}
}
is possible, for example, access to the included class inside $this? Like:
class Child_Controller extends Controller
{
//..construct above..
function init()
{
$this->print('some text');
}
}
where print is a method of foo, the class included:
class Foo
{
function print($message)
{
echo "your message: " . $message;
}
}
So, summing, I want include in the child controller, in $this, all the method of the included class by the Loader class extended by the base controller. Is this possible?
Or another idea would be create dynamically in the Child_Controller, a property that take the name of the included class, so, for call the method of foo I can do something like:
$this->Foo->print('some text');
No, you can't do that however you can do something similar in storing Foo in a generic property like this:
class Child_Controller
{
private $lib;
function __construct()
{
parent::__construct();
$this->lib = $this->load->library('Foo');
$this->init();
}
function init()
{
$this->lib->print('Hello World!');
}
}
If you want to instantiate multiple libraries then rather than using a dynamic name for the variable you should use an array with the library name as the key, like this:
class Child_Controller
{
private $libs = [];
function __construct()
{
parent::__construct();
$this->libs['Foo'] = $this->load->library('Foo');
$this->init();
}
function init()
{
$this->libs['Foo']->print('Hello World!');
}
}
If you can't use an array and absolutely must use a variable name you can do that like this:
class Child_Controller
{
function __construct()
{
$var = 'Foo';
$this->{$var} = $this->load->library($var);
$this->init();
}
function init()
{
$this->Foo('Hello World!');
}
}
I have a simple php code and I want to split it into model,view,helper. Model should access some methods from helper class and helper class should access some methods from model class.
I am not sure if the below pattern is correct. I guess it is not because in this example model,view,helper will be initialized multiple times. Which is the most simple way to accomplish something like I am trying to do with the below code?
lib/main.php
require_once('lib/model.php');
require_once('lib/helper.php');
require_once('lib/view.php');
$action = isset($_REQUEST['action']) ? $_REQUEST['action'] : 'show';
switch($action){
case "show":
$class->showAction();
break;
case "another":
$class->anotherAction();
break;
}
class main extends abstract{
public function showAction(){
if($this->helper->getParam('browse')){
//something
}else{
$profiles= $this->model->getProfiles();
}
echo $this->view->toHtml($profiles);
}
}
lib/abstract.php
class abstract{
public function __construct(){
$this->model = new model();
$this->view = new view();
$this->helper = new helper();
}
}
lib/model.php
class model extends abstract{
public function getProfiles(){
if($this->helper->someMethod(){
//some code
}
//some code
return $profiles;
}
}
lib/helper.php
class helper extends abstract{
public function someHelperMethod(){
if($this->model->someAnotherMethod(){
//some code
}
//some code
return $profiles;
}
}
First problem is that you are nesting your classes like russian dolls. You shouldn't have your Abstract class both contain model/view/helper, and be the parent of model/view/helper.
I'd caution against using extension just to ensure a class is in-scope.
Generally you can think of it this way: use extension when your class has shared behaviors or properties as it's parent, but it either needs additional functionality, or modifications to existing functionality.
The "abstract" class you defined shares no attributes or methods between Model/View/Helper, so Model/View/Helper should not probably extend from it.
If however you want a "container" class that contains instances of each of these class types, just make it a standalone class, don't extend it, for example:
class Container{
public $model;
public $view;
public $helper;
public function __construct(){
$this->model = new model();
$this->view = new view();
$this->helper = new helper();
}
public function showAction(){
if($this->helper->getParam('browse')){
//something
}else{
$profiles= $this->model->getProfiles();
}
echo $this->view->toHtml($profiles);
}
Then instantiate it only once at the start someplace:
$action = isset($_REQUEST['action']) ? $_REQUEST['action'] : 'show';
$class = new Container();
Then, if you want to call something from Model inside Helper, this can be done a number of ways.
One option, pass a reference to this class and keep it inside Helper:
// Inside Container
public function __construct(){
$this->model = new model();
$this->view = new view();
$this->helper = new helper($model);
}
The Helper class would look like:
class Helper{
protected $model;
public function __construct($model){
$this->model = $model;
}
public function someHelperMethod(){
if($this->model->someAnotherMethod()){
//some code
}
//some code
return $profiles;
}
}
I need to call a function someFunction() how do I refer to it when it is in the following class structures?
abstract class A
{
protected $session;
protected $model;
public function __construct()
{
$session = new classSession;
$model = new classModel;
}
}
class classModel
{
$this->session->someFunction();
}
I've tried using $this->session->someFunction() but it does not work!
Firstly, you need to put it within the context of a function - code cannot exist on its own within a class body. Secondly, for anything in classModel to access $session, classModel has to extend class A. You end up with something like this:
class classModel extends A
{
public function foo()
{
$this->session->someFunction();
}
}
So for $this->session->someFunction(); to execute, you'd do this:
$model = new classModel();
$model->foo();
I have a big problem. How to get called subclass method from a superclass. Please execute below code.
class Model {
public function render(){
echo '<br />class: '.get_class($this).' -- function: '.__FUNCTION__;
}
}
class Product extends Model {
public function show(){
$this->render();
}
}
class User extends Model {
public function index(){
$this->render();
}
}
$p = new Product();
$u = new User();
echo $p->show();
echo $u->index();
result :
class: Product -- function: render
class: User -- function: render
How to get subclass method name instead of render?
Thanks.
You can get that information using debug_backtrace().
I am curious as to why you want this - it could indicate a flaw with your design if you need this for anything other than debugging.
The __FUNCTION__ thingie is replaced at compile-time by the name of the function it is in. So no matter how your object model is structured, you'll get the function where __FUNCTION__ is met by PHP's preprocessor.
The best you can do here, if you want to know the name of the method being called, is to add it as a parameter to the method render() :
class Model {
public function render($methodName){
echo '<br />class: '.get_class($this).' -- function: '. $methodName;
}
}
And add the name in the method calls :
class Product extends Model {
public function show(){
$this->render(__FUNCTION__);
}
}
class User extends Model {
public function index(){
$this->render(__FUNCTION__);
}
}
Could you go into detail as to why you need this?
I'm not sure what you are trying to do, but especially when you are developing a PHP framework you should restrict yourself to the basic rules of inheritance.
Maybe you could illustrate a little better what you're trying to achieve with this.
Couldn't you simply change it to the following?
class Model {
protected $_type='unspecified';
public function render(){
echo '<br />class: '.$this->_type.' -- function: '.__FUNCTION__;
}
}
class Product extends Model {
public function __construct(){
$this->_type = 'product';
}
public function show(){
$this->render();
}
}
class User extends Model {
public function __construct(){
$this->_type = 'user';
}
public function index(){
$this->render();
}
}
Or is there any reason why that doesn't work for you?
You could move the logic which works out what you are rendering into the superclass, e.g.:
class Model {
public function render($type){
echo '<br />class: '.get_class($this).' -- function: '.$type;
}
public function show() {
$this->render('show');
}
public function index() {
$this->render('index');
}
}
class Product extends Model {
public function show(){
//some stuff
parent::show();
}
}
class User extends Model {
public function index(){
parent::index();
}
}
I don't really recommend this to you, but what you could do is throw an exception and catch it right away.
Then you can use the stack trace of this exception to find out which function called your render method.
I know that it works, but both performancewise and codingwise this is not a good option.
UPDATE:
<?php
class bla {
function test1() {
$this->test2();
}
function test2() {
$method = "";
try {
throw new Exception("bla");
} catch(Exception $e) {
$trace = $e->getTrace();
$method = $trace[1]['function']);
}
echo $method; //will echo test1
}
}
$blub = new bla();
$blub->test1();
Hope you get what I'm trying to illustrate.