I have created the MVC directory structure and started with writing an "App" class.
Everything works well on the local machine using WAMP. But it fails when uploaded to the hosting server.
So, I compared PHP settings between host and local, all looks good, everything matches version etc. I checked paths etc.
Here is my PRIVATE directory structure:
This is the PUBLIC area
This is the index.php file:
<?php
require_once '../httpd.private/init.php';
require_once '../httpd.private/core/App.php';
$app = new App;
?>
Which loads the INIT.PHP variables:
<?php
// Define path constants
define("DS", DIRECTORY_SEPARATOR);
define("ROOT", getcwd() . DS);
define("APP_PATH", ROOT . '../httpd.private' . DS);
define("VIEW_PATH", ROOT . "views" . DS);
define("MODEL_PATH", APP_PATH . "models" . DS);
define("DATA", APP_PATH . "data" . DS);
define("CORE_PATH", APP_PATH . "core" . DS);
define("CONTROLLER_PATH", APP_PATH . "controllers" . DS);
define('SEC_PATH', APP_PATH . "sec" . DS);
define("UPLOAD_PATH", APP_PATH . "uploads" . DS);
define('FILE_ENCRYPTION_BLOCKS', 10000);
$modules = [ROOT, APP_PATH, VIEW_PATH, MODEL_PATH, DATA, CORE_PATH, CONTROLLER_PATH, SEC_PATH];
set_include_path(get_include_path(). PATH_SEPARATOR . implode(PATH_SEPARATOR,$modules));
spl_autoload_register('spl_autoload', false);
?>
After the init file the App.php kicks in:
<?php
class App
{
protected $controller = 'homeController';
protected $method = 'index';
protected $params = [];
public function __construct()
{
$this->parseUrl();
if (file_exists(CONTROLLER_PATH . $this->controller . '.php'))
{
$this->controller = new $this->controller;
if (method_exists($this->controller, $this->method))
{
call_user_func_array([$this->controller, $this->method], $this->params);
} else {
header("Location: /home/index");
}
} else {
header("Location: /home/index");
}
exit();
}
public function parseUrl()
{
if (isset($_GET['url'])){
$url = explode('/', filter_var(rtrim($_GET['url'], '/'), FILTER_SANITIZE_URL));
$this->controller = isset($url[0]) ? $url[0] . 'Controller' : 'homeController';
$this->method = isset($url[1]) ? $url[1] :'index';
unset($url[0], $url[1]);
$this->params = !empty($url) ? array_values($url) : [];
}
}
}
?>
The ERROR:
Fatal error: Uncaught Error: Class 'homeController' not found in
/customers/2/e/9/something.com/httpd.private/core/App.php:15
Stack trace: #0 /customers/2/e/9/something.com/httpd.www/index.php(5): App->__construct() #1 {main} thrown in /customers/2/e/9/something.com/httpd.private/core/App.php on line 15
This is line 15 that is mentioned in the error:
$this->controller = new $this->controller;
And here is the controller.php file:
<?php
class Controller
{
protected $view;
protected $model;
public function __construct()
{
/* echo "This is the Class: " . __CLASS__ . "<br>";
echo "And this is the Method: " . __METHOD__ . "<br>";
die(); */
}
public function view($viewName, $data = [])
{
$this->view = new View($viewName, $data);
return $this->view;
}
public function model($modelName, $data = [])
{
if (file_exists(MODEL_PATH . $modelName . 'Model' . '.php')){
require MODEL_PATH . $modelName . 'Model' . '.php';
$this->model = new $modelName;
}
}
}
?>
How can I correct the error and perhaps better improve the code?
I am aware that I could start with using composer and other frameworks, but that will not help my homework.
I don't see any line where you include your controller file.
Before the instantiation of your controller, you need to require the script.
(You have done that with your model)
Related
I have a problem creating an object from another class inside the constructor of my kernel class, it gives a fatal error which says can not find the class, anybody can help please? I do not know what is wrong?
namespace App\Http;
use App\Http\Config;
use App\Controllers;
class kernel{
protected $controller = "HomeController";
protected $action = "index";
protected $params=[];
public function __construct(){
$url = $this->ParseUrl();
$format_url = ucfirst($url[0]) . "Controller";
if (file_exists(Config::CONTROLLERS_PATH . $format_url . ".php")) {
$this->controller = $format_url;
}
// $path = Config::CONTROLLERS_PATH . $this->controller . ".php";
// echo "path: $path";// path is correct
require_once (Config::CONTROLLERS_PATH . $this->controller . ".php");
// $include_file = get_required_files();
// var_dump($include_file);//require_once is working
//here is the problem
$this->controller = new $this->controller;
}
public function ParseUrl(){
if (isset($_GET['url'])) {
return explode("/", rtrim($_GET['url'], "/"));
}
}
}
I try to create a parent class for all my "Model" classes.
I have a class in app/code/core/User/Model/User.php named User_Model_User it should inherit from a parent class in app/code/core/Core/Model.php
Attempt:
Parent:
class Model
{
public function testParent()
{
echo "123";
}
}
Child:
class User_Model_User extends Core\Model
{
private $con;
private $user_id;
public function __construct($con)
{
$this->con = $con;
}
public function loadByEmail($email)
{
$this->user_id = $this->getUserId($email);
return $this;
}
...
Error:
Fatal error: Class 'Core\Model' not found in
/var/www/property-rights/app/code/core/User/Model/User.php
How does it work?
Not sure if this is the best way, but I solved it like this:
Main: app/Main.php
Put <project_root>/app/code/core in include path, so that I don't have to use the full path when calling include, require etc.
if (!defined('DS')) define('DS', DIRECTORY_SEPARATOR);
if (!defined('PS')) define('PS', PATH_SEPARATOR);
if (!defined('BP')) define('BP', dirname(dirname(__FILE__)));
Main::register('original_include_path', get_include_path());
$paths = array();
$paths[] = BP . DS . 'app' . DS . 'code' . DS . 'core';
$paths[] = BP . DS . 'app' . DS . 'code' . DS . 'local';
$paths[] = BP . DS . 'lib';
$paths[] = BP . DS . 'inc';
$appPath = implode(PS, $paths);
set_include_path($appPath . PS . Main::registry('original_include_path'));
Parent:
namespace Core;
class Model
{
Child:
require_once("Core/Model.php");
class User_Model_User extends Core\Model
{
With below code i have set layout and view files path.
class DemoMet_IndexController extends Zend_Controller_Action
{
public function init()
{
/* Initialize action controller here */
}
public function indexAction()
{
$theme = 'metronic_v3';
$layout_name = 'default';
$layout = Zend_Layout::getMvcInstance();
$layoutPath = APPLICATION_PATH . DIRECTORY_SEPARATOR. 'themes'. DIRECTORY_SEPARATOR . $theme . DIRECTORY_SEPARATOR. 'layouts'. DIRECTORY_SEPARATOR. 'scripts'. DIRECTORY_SEPARATOR;
$layout->setLayoutPath($layoutPath);
$layout->setLayout($layout_name);
$viewPath = APPLICATION_PATH . DIRECTORY_SEPARATOR. 'themes'. DIRECTORY_SEPARATOR . $theme . DIRECTORY_SEPARATOR. 'views'. DIRECTORY_SEPARATOR;
$layout->getView()->setBasePath($viewPath);
}
}
but when I access the url "http://project.localhost/demoMet/index/" .
Error message
with message 'script 'index/index.phtml' not found in path
project/application/modules/demoMet/views/scripts/
Though the view files path is set but it searching in default script folder
Add a _init function to your main application Bootatrp.php file!
Bootstrap.php
protected function _initViewHelpers() {
//Bootstrap view
$this->bootstrap('view');
//get bootstrapped view
$view = $this->getResource('view');
$view->addScriptPath(APPLICATION_PATH."/templates/default/views/scripts");
//$view->addScriptPath($theme);
$view->addHelperPath(APPLICATION_PATH."/templates/default/views/helpers/", "Administration_View_Helper");
}
Maybe you can try this:
public function indexAction()
{
$theme = 'metronic_v3';
$layout_name = 'default';
// without the last DIRECTORY_SEPARATOR
$layoutPath = APPLICATION_PATH . DIRECTORY_SEPARATOR. 'themes'. DIRECTORY_SEPARATOR . $theme . DIRECTORY_SEPARATOR. 'layouts'. DIRECTORY_SEPARATOR. 'scripts';
$this->_helper->layout->setLayout($layout_name);
$this->_helper->layout->setLayoutPath($layoutPath);
// with add 'scripts' after the last DIRECTORY_SEPARATOR
$viewPath = APPLICATION_PATH . DIRECTORY_SEPARATOR. 'themes'. DIRECTORY_SEPARATOR . $theme . DIRECTORY_SEPARATOR. 'views'. DIRECTORY_SEPARATOR . 'scripts';
$this->view->setBasePath($viewPath);
}
In my application/core directory, I had class MY_Controller.
And now, I want to create two classes in two paths application/core/Frontent/Frontend_Controller.php and application/core/Backend/Backend_Controller.php. Then my modules controllers extend from Frontend_Controller and Backend_Controller class.
But CI always raises class not found error.
Edit March 20th 2014:
I used #manix's suggestion:
1. Write below script at the end of /application/config/config.php
function __autoload($class)
{
if (strpos($class, 'CI_') !== 0)
{
if (file_exists($file = APPPATH . 'core/Frontend/' . $class . EXT))
{
include $file;
}
if (file_exists($file = APPPATH . 'core/Backend/' . $class . EXT))
{
include $file;
}
}
}
Create /application/core/Backend/Backend_Controller.php like this:
(defined('BASEPATH')) OR exit('No direct script access allowed');
class Backend_Controller extends CORE_Controller {
}
I have a Menu class extends Backend_Controller. Then receive this error Fatal error: Class 'Backend_Controller' not found in codeigniter\application\widgets\menu\Controllers\menu.php on line 6. If I put the Backend_Controller.php at /application/core/Backend_Controller.php, it is OK. But I want to put it into a subfolder.
SOLUTION (update March 24th 2014)
Thank to manix. I edited from his code to load classes. Here is the code that works for me.
function __autoload($class) {
if (strpos($class, 'CI_') !== 0) {
if (file_exists($file = APPPATH . 'core/Frontent/' . $class . EXT)) {
include $file;
}
if (file_exists($file = APPPATH . 'core/Backend/' . $class . EXT)) {
include $file;
}
if (file_exists($file = APPPATH . 'core/' . $class . EXT)) {
include $file;
}
}
}
Try to call explicitly the __autoload funtionat the end of the config.php file that raised at application/config/ folder. Look the example above:
function __autoload($class)
{
if (strpos($class, 'CI_') !== 0)
{
if (file_exists($file = APPPATH . 'core/Frontent/' . $class . EXT))
{
include $file;
}
if (file_exists($file = APPPATH . 'core/Backend/' . $class . EXT))
{
include $file;
}
}
}
All,
I am reading the following article on a lightweight PHP dynamic front controller: http://www.w3style.co.uk/a-lightweight-and-flexible-front-controller-for-php-5
Here is the code:
index.php
<?php
define("PAGE_DIR", dirname(__FILE__) . "/pages");
require_once "FrontController.php";
FrontController::createInstance()->dispatch();
FrontController.php
<?php
class FrontController {
public static function createInstance() {
if (!defined("PAGE_DIR")) {
exit("Critical error: Cannot proceed without PAGE_DIR.");
}
$instance = new self();
return $instance;
}
public function dispatch() {
$page = !empty($_GET["page"]) ? $_GET["page"] : "home";
$action = !empty($_GET["action"]) ? $_GET["action"] : "index";
//e.g. HomeActions
$class = ucfirst($page) . "Actions";
//e.g. pages/home/HomeActions.php
$file = PAGE_DIR . "/" . $page . "/" . $class . ".php";
if (!is_file($file)) {
exit("Page not found");
}
require_once $file;
$actionMethod = "do" . ucfirst($action);
$controller = new $class(); // I DON'T UNDERSTAND WHAT THIS DOES...
if (!method_exists($controller, $actionMethod)) {
exit("Page not found");
}
//e.g. $controller->doIndex();
$controller->$actionMethod();
exit(0);
}
}
pages/guestbook/GuestbookActions.php
<?php
class GuestbookActions {
public function doIndex() {
echo "Index action called...";
}
public function doCreatePost() {
echo "CreatePost action called...";
}
}
In the front controller class, could someone explain to me what $controller = new $class(); does? I don't understand it. It seems to be creating a class on the fly? In the example above, $class is a string with a value like "HomeActions". So $controller would be a new instance of a class named "HomeActions", but those are not defined anywhere. I'm confused.
Many thanks,
JDelage
$controller = new $class();
That does indeed create a new object of the type contained in $class, so it is equivalent to $controller = new HomeActions() in your example. From the manual:
If a string containing the name of a class is used with new, a new instance of that class will be created
The classes are not all present initially. However, the necessary one is loaded dynamically:
$file = PAGE_DIR . "/" . $page . "/" . $class . ".php";
if (!is_file($file)) {
exit("Page not found");
}
require_once $file;
require_once loads the file which presumably contains the class definition, so you can create the object as shown above.
The example request in the article is to http://localhost/index.php?page=guestbook&action=index, so $class would be GuestbookActions, which is defined in the third code sample.