I am trying to load (include file) the GetRiskSummaryCommandHandler.php (GetRiskSummary\CommandHandler) at runtime dynamically, while resolving Route api/risks to HandleCommand (of class CommandHandler) method.
How can I do this? If not can I modify any taken approach including modifying autoloader?
My api class snippet looks like this:
API.php
<?php
abstract class API
{
public function processRequest()
{
$id1 = $this->requestObj->id1;
//$id2 = $this->requestObj->id2;
$endpoint1 = $this->requestObj->endpoint1;
$endpoint2 = $this->requestObj->endpoint2;
$isDestination = in_array($id1, ['first', 'prev', 'next', 'last']);
$numSetEndpoints = (int)isset($endpoint1) + (int)isset($endpoint2);
switch($numSetEndpoints)
{
case 0:
if ($isDestination)
return json_decode($this->_response("No Endpoint: ", $endpoint1));
return json_decode($this->_response("ProjectAIM API"));
case 1:
$className = $endpoint1.'Controller';
break;
case 2:
$className = $endpoint2.'Controller';
break;
}
$class = "GetRiskSummaryCommandHandler";
$method = "HandleCommand";
if (class_exists($class))
{
if (method_exists($class, $method))
{
$response = (new $class($this->requestObj))->{$method}($this->requestObj);
if ($response['Succeeded'] == false)
{
return $response['Result'];
}
else if ($response['Succeeded'] == true)
{
header("Content-Type: application/json");
return $this->_response($response);
}
else if ($response['Result'])
{
header("Content-Type: text/html");
return $this->_response($response);
}
}
}
}
**Command Handler Snippet, uses a Route Attiribute
GetRiskSummaryCommandHandler.php
<?php
namespace GetRiskSummary;
use Infrastructure\CommandHandler;
class GetRiskSummaryCommandHandler extends CommandHandler
{
#[Route("/api/risks", methods: ["GET"])]
public function HandleCommand()
{
$qb = $this->getEntityManager()
->createQueryBuilder();
$qb->select('*')
->from('Risks', 'Risks')
->orderBy('RiskID', 'DESC');
$query = $qb->getQuery();
return $query->getResult();
}
}
Autoloader.php
<?php
namespace Autoloader;
class Autoloader
{
private static function rglob($pattern, $flags = 0) {
$files = glob($pattern, $flags);
foreach (glob(dirname($pattern).'/*', GLOB_ONLYDIR|GLOB_NOSORT) as $dir) {
$files = array_merge($files, self::rglob($dir.'/'.basename($pattern), $flags));
}
return $files;
}
public static function ClassLoader($path)
{
$pathParts = explode("\\", $path);
$path = $pathParts[array_key_last($pathParts)];
$matches = self::rglob("*/$path*");
foreach ($matches as $name)
{
$filePath = realpath($name);
if (file_exists($filePath))
include $filePath;
}
}
}
spl_autoload_register("AutoLoader\AutoLoader::ClassLoader");
I think the biggest missing feature of PHP Attributes would be that as far as I'm aware PHP Attributes are static and aren't evaluated at runtime. They are just glorified comments.
If it was true, we could do some truly amazing things like non-intrusively attaching pre/post-processing functions, just like what you wrote.
They work just like in symfony or doctrine. You can't use variables in them and you must write your own code to search your php class tree for attributes in the code and use php reflection to obtain the information and run the attributes.
To be honest it's pretty disappointing, although maybe it's just the first step that will be fixed in later versions of PHP.
But for now, I think what you're asking for is impossible. Because they are not running dynamically like you appear to be asking.
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');
I have coded my own PHP auto class loader but I receive the following error when I try to use the class functions with the class
Fatal error: Call to a member function Test() on a non-object
I would also like to know if this approach is the best approach available and if anyone suggests a better way of coding this then I will appreciate it.
$class = array();
foreach (scandir(include_dir) as $filename)
{
if (is_file(include_dir . '/' . $filename))
{
//its a php file, lets do this!
if (substr($filename, -4) == '.php')
{
$page = preg_replace('/\.php$/','',$filename);
$class[$page] = GetClass($page);
}
}
}
$class['Blue']->Test2();
$class['Blue2']->Test();
Iat seems that this error only occurs when there is numbers in the filename / class
And here is class loader file that i include in my index the class Blue works but Blue2 doesn't and throws that error.
function GetClass($class)
{
if (CheckAllOkay($class))
{
include('/blue/' . $class . '.php');
if (ClassCanBeAutoLoaded($class))
{
$newclass = new $class;
return $newclass;
}
}
}
function ClassCanBeAutoLoaded($class)
{
return class_exists($class);
}
function CheckAllOkay($class)
{
return file_exists($class);
}
Here is the class Blue2
<?php
class Blue2
{
function __construct()
{
echo '[LOADED]';
}
public function Test()
{
echo '[TEST CALLED]';
}
}
?>
Class Blue is the same is just echos a diffrent text and has a diffrent class name
I have been trying to figure out a way to load models from different directory other than "application/models" directory.
I want to load my model from "application/modules".
I have tried the instructions by extending CI_Loader by following instructions provided in
http://ellislab.com/forums/viewthread/103276/#
but it is giving me error "Unable to locate the specified class: Model.php" whereas my core "Model.php" is there under "system/core" folder.
Even ,I have also tried to load model using
$this->load->model (APPPATH.'modules/mymodel.php');
but no success.
UPDATE:
I want my model loader to behave like this :
$this->load->module('mymodel')
and
$this->mymodel->mymodelmethod() !!
NOT like: $this->load->models('mymodel')
Is there any way i could load models from outside the "application/modules" folder ?
Please advise .Thanks
The problem is that the code you reference is for an older version of codeigniter. In older versions of codeigniter the CI_Model class was named Model. As the class Model doesn't exist in the latest version of php you are getting the error:
Unable to locate the specified class: Model.php
The part of the code where this is happening is towards the end (line 114):
if ( ! class_exists('Model'))
{
load_class('Model', FALSE);
}
If you check your system/core/Loader.php you will see that in the version of codeigniter you are using this has been replaced with:
if ( ! class_exists('CI_Model'))
{
load_class('Model', 'core');
}
You need to re-write the MY_Loader.php to make it compatible with the version of codeigniter you are using, presumably 2.1.
The best way to do this would be to grab the Codeigniter 2.1 version of the core Loader.php and use the model() method from it as a base for re-writing your MY_Loader.php.
Something to bare in mind when re-writing your MY_Loader.php is that constructors also changed in later versions of codeigniter, so your MY_Loader class should look something like this:
class MY_Loader extends CI_Loader {
function __construct()
{
parent::__construct();
}
public function model($model, $name = '', $db_conn = FALSE)
{
...
}
}
More details on extending core classes can be found in the Codeigniter Documentation
UPDATE
I noticed you changed your functionality, so I updated the answer. You can create a whole new loader and base it off the core CI_Model class, although it seems like a lot of effort when you could just extend the model loader and be done.
class MY_Loader extends CI_Loader {
protected $_ci_module_paths = array();
protected $_ci_modules = array();
function __construct()
{
parent::__construct();
$this->_ci_module_paths = array(APPPATH);
}
public function initialize()
{
$this->_ci_classes = array();
$this->_ci_loaded_files = array();
$this->_ci_models = array();
$this->_ci_modules = array();
$this->_base_classes =& is_loaded();
$this->_ci_autoloader();
return $this;
}
public function module($module, $name = '', $db_conn = FALSE)
{
if (is_array($module))
{
foreach ($module as $babe)
{
$this->$module($babe);
}
return;
}
if ($module == '')
{
return;
}
$path = '';
// Is the $module in a sub-folder? If so, parse out the filename and path.
if (($last_slash = strrpos($module, '/')) !== FALSE)
{
// The path is in front of the last slash
$path = substr($module, 0, $last_slash + 1);
// And the module name behind it
$module = substr($module, $last_slash + 1);
}
if ($name == '')
{
$name = $module;
}
if (in_array($name, $this->_ci_modules, TRUE))
{
return;
}
$CI =& get_instance();
if (isset($CI->$name))
{
show_error('The module name you are loading is the name of a resource that is already being used: '.$name);
}
$module = strtolower($module);
foreach ($this->_ci_module_paths as $mod_path)
{
if ( ! file_exists($mod_path.'modules/'.$path.$module.'.php'))
{
continue;
}
if ($db_conn !== FALSE AND ! class_exists('CI_DB'))
{
if ($db_conn === TRUE)
{
$db_conn = '';
}
$CI->load->database($db_conn, FALSE, TRUE);
}
if ( ! class_exists('CI_Model'))
{
load_class('Model', 'core');
}
require_once($mod_path.'modules/'.$path.$module.'.php');
$module = ucfirst($module);
$CI->$name = new $module();
$this->_ci_modules[] = $name;
return;
}
// couldn't find the model
show_error('Unable to locate the module you have specified: '.$module);
}
public function add_package_path($path, $view_cascade=TRUE)
{
$path = rtrim($path, '/').'/';
array_unshift($this->_ci_library_paths, $path);
array_unshift($this->_ci_model_paths, $path);
array_unshift($this->_ci_module_paths, $path);
array_unshift($this->_ci_helper_paths, $path);
$this->_ci_view_paths = array($path.'views/' => $view_cascade) + $this->_ci_view_paths;
// Add config file path
$config =& $this->_ci_get_component('config');
array_unshift($config->_config_paths, $path);
}
public function remove_package_path($path = '', $remove_config_path = TRUE)
{
$config =& $this->_ci_get_component('config');
if ($path == '')
{
$void = array_shift($this->_ci_library_paths);
$void = array_shift($this->_ci_model_paths);
$void = array_shift($this->_ci_module_paths);
$void = array_shift($this->_ci_helper_paths);
$void = array_shift($this->_ci_view_paths);
$void = array_shift($config->_config_paths);
}
else
{
$path = rtrim($path, '/').'/';
foreach (array('_ci_library_paths', '_ci_model_paths', '_ci_module_paths', '_ci_helper_paths') as $var)
{
if (($key = array_search($path, $this->{$var})) !== FALSE)
{
unset($this->{$var}[$key]);
}
}
if (isset($this->_ci_view_paths[$path.'views/']))
{
unset($this->_ci_view_paths[$path.'views/']);
}
if (($key = array_search($path, $config->_config_paths)) !== FALSE)
{
unset($config->_config_paths[$key]);
}
}
// make sure the application default paths are still in the array
$this->_ci_library_paths = array_unique(array_merge($this->_ci_library_paths, array(APPPATH, BASEPATH)));
$this->_ci_helper_paths = array_unique(array_merge($this->_ci_helper_paths, array(APPPATH, BASEPATH)));
$this->_ci_model_paths = array_unique(array_merge($this->_ci_model_paths, array(APPPATH)));
$this->_ci_module_paths = array_unique(array_merge($this->_ci_module_paths, array(APPPATH)));
$this->_ci_view_paths = array_merge($this->_ci_view_paths, array(APPPATH.'views/' => TRUE));
$config->_config_paths = array_unique(array_merge($config->_config_paths, array(APPPATH)));
}
private function _ci_autoloader()
{
if (defined('ENVIRONMENT') AND file_exists(APPPATH.'config/'.ENVIRONMENT.'/autoload.php'))
{
include(APPPATH.'config/'.ENVIRONMENT.'/autoload.php');
}
else
{
include(APPPATH.'config/autoload.php');
}
if ( ! isset($autoload))
{
return FALSE;
}
// Autoload packages
if (isset($autoload['packages']))
{
foreach ($autoload['packages'] as $package_path)
{
$this->add_package_path($package_path);
}
}
// Load any custom config file
if (count($autoload['config']) > 0)
{
$CI =& get_instance();
foreach ($autoload['config'] as $key => $val)
{
$CI->config->load($val);
}
}
// Autoload helpers and languages
foreach (array('helper', 'language') as $type)
{
if (isset($autoload[$type]) AND count($autoload[$type]) > 0)
{
$this->$type($autoload[$type]);
}
}
// A little tweak to remain backward compatible
// The $autoload['core'] item was deprecated
if ( ! isset($autoload['libraries']) AND isset($autoload['core']))
{
$autoload['libraries'] = $autoload['core'];
}
// Load libraries
if (isset($autoload['libraries']) AND count($autoload['libraries']) > 0)
{
// Load the database driver.
if (in_array('database', $autoload['libraries']))
{
$this->database();
$autoload['libraries'] = array_diff($autoload['libraries'], array('database'));
}
// Load all other libraries
foreach ($autoload['libraries'] as $item)
{
$this->library($item);
}
}
// Autoload models
if (isset($autoload['model']))
{
$this->model($autoload['model']);
}
// Autoload modules
if (isset($autoload['module']))
{
$this->module($autoload['module']);
}
}
}
You can use the above in your controller via:
$this->load->module('test_module');
$this->test_module->method();
If i am getting your problem correctly , you have to initialize the instance of CI.
Example :-
In your external file do this :-
class modules
{
var $CI;
function __construct()
{
$this->CI =& get_instance();
}
function retrieve_data()
{
// Load Model
$this->CI->load->model('YOUR MODEL NAME'); // Give the name of your model that you want to laod
}
}
Hope it helps you :)
As far as i understand your question the answer lies here.
Moduler Extension
download it and install according to the instructions. then you can simply access any thing with these steps.
In your controller load the module like this.
$this->load->module('pages');
Make sure you have a directory Modules under application. And your Module pages should exist there. Pages module can have controller , models , views , helpers , config and libraries etc.
Now you need to call model. Here is how you can do it.
$this->pages->model->test_model->get_test_data();
Also you should note that loading module loads all the resources.
If nothing works, try this
public function setPackagePaths($path, $view_cascade=TRUE, $model_cascade=TRUE, $library_cascade=TRUE, $helper_cascade=TRUE) {
$path = rtrim($path, '/').'/';
///$this->_ci_view_paths = $this->_ci_library_paths = $this->_ci_model_paths = array();
$this->_ci_library_paths = array($path.'libraries/' => $library_cascade) + $this->_ci_library_paths ;
$this->_ci_helper_paths = array($path.'helpers/' => $helper_cascade) + $this->_ci_helper_paths ;
$this->_ci_model_paths = array($path.'models/' => $model_cascade) + $this->_ci_model_paths ;
$this->_ci_view_paths = array($path.'views/' => $view_cascade) + $this->_ci_view_paths;
// Add config file path
$config =& $this->_ci_get_component('config');
array_unshift($config->_config_paths, $path);
}
Its a hardcore way to update this function to Loader Class. But works fine.
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.