Basically, I would like to have multiple versions of the same page, some which accept params, some which do not.
For example,
public function index()
{
require_once(APPPATH . 'views/sessiondata.inc.php');//sets up variables from session data
require_once(APPPATH . 'views/header.inc.php');//header
include(APPPATH . 'views/breadcrumbs.inc.php');//top breadcrumbs
echo ' <h1>Let\'s sell an item, '.$username.',</h1>';
//print_r($this->session->all_userdata());
include(APPPATH . 'views/breadcrumbs.inc.php');//bottom breadcrumbs
require_once(APPPATH . 'views/footer.inc.php');//footer
}
This is a default function for controller x.php, hypothetically. Can I also use:
public function index($item)
{
require_once(APPPATH . 'views/sessiondata.inc.php');//sets up variables from session data
require_once(APPPATH . 'views/header.inc.php');//header
include(APPPATH . 'views/breadcrumbs.inc.php');//top breadcrumbs
echo ' <h1>Let\'s sell an item, '.$username.',</h1>';
//DO SOMETHING WITH THE $item VARIABLE.
//print_r($this->session->all_userdata());
include(APPPATH . 'views/breadcrumbs.inc.php');//bottom breadcrumbs
require_once(APPPATH . 'views/footer.inc.php');//footer
}
Will the system automatically know which version to use? Is there something similar to Java's #OVERRIDE that I need to use?
No. PHP doesn't allow you to overload functions in this manner. That said, you can achieve similar functionality by overloading the __call method:
public function __call ( string $name , array $arguments )
{
if( $name === 'index' && sizeof($arguments) === 1 ) {
// do index($item) stuff
} else {
// do index() stuff
}
}
But to be honest, using __call in this manner is of no real value, and adds unnecessary performance overhead, and complexity. In PHP, if you want to reuse code, simply decompose your functions into smaller discrete functions and reuse them as needed.
You cannot have two separate functions (because PHP does not allow function overloading) but you can use a default parameter which CodeIgniter will honor when choosing controller functions. So instead of having two functions, do the following:
public function index($item=null)
{
require_once(APPPATH . 'views/sessiondata.inc.php');//sets up variables from session data
require_once(APPPATH . 'views/header.inc.php');//header
include(APPPATH . 'views/breadcrumbs.inc.php');//top breadcrumbs
echo ' <h1>Let\'s sell an item, '.$username.',</h1>';
if ($item !== null) {
//DO SOMETHING WITH THE $item VARIABLE.
}
//print_r($this->session->all_userdata());
include(APPPATH . 'views/breadcrumbs.inc.php');//bottom breadcrumbs
require_once(APPPATH . 'views/footer.inc.php');//footer
}
Related
I have a custom module, and now want to call the add() function from checkout/cart. How do I call the controller and function?
I have tried $this->load->controller('checkout/cart'); but this returns a fatal exception.
I am using OpenCart v 1.5.6.4
In OpenCart 1.5.*, getChild is used to load other controllers. Specifically, it is running a route to the desired controller and function. For example, common/home would load the home controller from the common group/folder. By adding a third option we specify a function. In this case, 'add' - checkout/cart/add.
class ControllerModuleModule1 extends Controller {
protected function index() {
ob_start();
$this->getChild('checkout/cart/add');
$this->response->output();
$response = ob_get_clean();
}
}
Most controllers don't return or echo anything, but specify what to output in the $this->response object. To get what is being rendered you need to call $this->response->output();. In the above code $response is the json string that checkout/cart/add echos.
To solve the same issue, I use $this->load->controller("checkout/cart/add").
If I use getChild, this exception get thrown : "Call to undefined method Loader::getChild()".
What is the difference between the 2 methods? Is getChild better?
The problem with getChild() is it only works if the controller calls $this->response->setOutput() or echo at the end - producing actual output. If on the other hand, you want to call a controller method that returns a variable response, it isn't going to work. There is also no way to pass more than one argument since getChild() accepts only one argument to pass, $args.
My solution was to add this bit in 1.5.6.4 to system/engine/loader.php which allows you to load a controller and call it's methods in the same way as you would a model:
public function controller($controller) {
$file = DIR_APPLICATION . 'controller/' . $controller . '.php';
$class = 'controller' . preg_replace('/[^a-zA-Z0-9]/', '', $controller);
if (file_exists($file)) {
include_once($file);
$this->registry->set('controller_' . str_replace('/', '_', $controller), new $class($this->registry));
} else {
trigger_error('Error: Could not load controller ' . $controller . '!');
exit();
}
}
Now you can do this:
$this->load->controller('catalog/example');
$result = $this->controller_catalog_example->myMethod($var1, $var2, $var3);
I have the follow code snippet and works well:
<?php
require_once(FOLDER_ROOT . "/lib/transaction/RetornoBanco.php");
require_once(FOLDER_ROOT . "/lib/transaction/RetornoFactory.php");
$fileName = 'test.txt';
function rowProcess($self, $numLn, $vrow) {
print ($numLn . ' - ' . $vrow);
}
$test = RetornoFactory::getRetorno($fileName, 'rowProcess');
$retorno = new RetornoBanco($test);
$retorno->process();
The getRetorno function uses 'rowProcess' as a handler function.
But now I'm trying do it in my custom controller (on my own Magento Extension, looks like Zend Controllers).
For each line of my file (test.txt), rowProcess runs.
But now, in my controller, rowProcess has a class.
My controller:
class MY_CLASS_HERE extends Mage_Adminhtml_Controller_Action
{
public function uploadAction()
{
//just to simplify, this uploaded file exists
$fileName = '/home/user/public_html/app/files/file.RET';
$test = RetornoFactory::getRetorno($fileName, "rowProcess");
$retorno = new RetornoBanco($test);
$retorno->process();
echo 'My Controller Here';
}
public function rowProcess($self, $numLn, $vrow)
{
print ($numLn . ' - ' . $vrow);
//I'm creating log to prevent it is not a problem for standard output
Mage::log($numLn . ' - ' . $vrow);
//This function log is default in Magento and works without problems.
}
}
My controller works well but now the handler doesn't print nothing!
I think it's wrong because now my function handler inside a class and getRetorno function can not use it. What could I do to fix this?
How about using like this? Can you try it?
$test = RetornoFactory::getRetorno($fileName, $this->rowProcess);
Currently, I have a pretty average php auto loader loading in my classes. I've come to a point in development where I will need to override a class with another class based on a variable. I'm running a custom SaaS application, and we have the occasional organization that will demand some weird change to the way the system functions. In the past, we've filled up our code with garbage by massive IF statements for orgs, such as
if(ORGID == 'ABCD'){
//do this insane thing
}else{
//Normal code here.
}
So, I've been toying with the idea of a dynamic auto loader. ORGID is one of the very first defines in the application. The entire application is running under a fixed namespace of COMPANY\PRODUCT; Here's a code sample of what I was thinking I could do.
class MyLoader {
static public function load($name) {
$temp = explode('\\',$name);
$class = array_pop($temp);
$name = str_replace('_',DIRECTORY_SEPARATOR,$class);
if(file_exists(ROOT.'includes/_classes/' . $name . '.php')){
include(ROOT.'includes/_classes/' . $name . '.php');
}
}
}
spl_autoload_register(__NAMESPACE__ .'\MyLoader::load');
Since ROOT and ORGID are defined before the autoloader comes into play, I thought about doing this
class MyLoader {
static public function load($name) {
$temp = explode('\\',$name);
$class = array_pop($temp);
$name = str_replace('_',DIRECTORY_SEPARATOR,$class);
if(file_exists(ROOT.'includes/_classes/' . ORGID . '/' . $name . '.php')){
include(ROOT.'includes/_classes/' . ORGID . '/' . $name . '.php');
}elseif(file_exists(ROOT.'includes/_classes/' . $name . '.php')){
include(ROOT.'includes/_classes/' . $name . '.php');
}
}
}
spl_autoload_register(__NAMESPACE__ .'\MyLoader::load');
While this works, I have to copy/paste my entire class into the org specific class file, then make changes. I can't extend the primary class, because the classes share the same name. The only option I've been able to come up with that would allow me to extend my classes in such a way is to never load the base class.
Instead of
$myObj = new myClass();
I call
$myObj = new customMyClass();
and I have a file called customMyClass(); which simply extends myClass without making any changes to it. This way, the auto loader will load customMyClass and then load myClass. If an organization has their own customMyClass in their organization folder, then it will load in that class, which will then properly load in myClass.
While this works, we have hundreds of class files, which would double if we had a custom file for each.
I've seen a couple of examples that use eval to handle similar situations. Is that really the only way to do this type of thing?
UPDATE:
Just so I'm clear, the end goal is so that the thousands of places we've called $myObj = new myClass(); doesn't need to be rewritten.
I'm building a script that got a static class used to load few things including files and views.
class load
{
public static function view($file_path, $area)
{
debug::log('getting view <b>' . $area . $file_path . '</b>.');
ob_start();
self::file($file_path, 'areas/' . $area . '/views');
debug::log('flushing view <b>' . $area . $file_path . '</b>.');
eturn ob_get_clean();
}
public static function file($file, $folder)
{
if(is_file($file_path = ROOT . '/' . $folder . '/' . $file))
{
if(require_once $file_path)
{
debug::log('file <b>' . $file_path . '</b> included.');
return true;
}
}
else
debug::kill('requested file <b>' . $file_path . '</b> does not exist.');
}
}
In the controller Im calling the view method to get a view:
$html = load::view('public', 'path/to/view/file.php');
Obviously, Im not able to access the variables from the controller at the view file using this practice, so I did a small modification on the view class to capture the vars:
public static function view($file_path, $area, $vars = array())
And added the following lines of codes to get the keys into vars:
while(list($n_list_var,$v_list_var)=each($vars))
$$n_list_var = $v_list_var;
But again I can't access the vars since Im using a method to load a file.
I have a method to load the files because I wanna test and log each file include attempt and not repeat the code every time I need include a file. And I have the loader view inside the loader class so I have all the methods of this kind together. Should I give up on using a class to load files? Should I use the loader view method on a extendable class from my controller?
Instead of going ahead and modify my entire script I would like to hear some opinions ... what would be the best practice to go? Or is there a way to solve my problem? Maybe using __set and __get magic methods?
Thanks,
Why not just pass a $vars argument to load::file() and extract( $vars ) (possibly moving the vars you use inside file() into class variables to prevent them from being overwritten)?
I'm suggesting using extract() instead of:
while(list($n_list_var,$v_list_var)=each($vars))
$$n_list_var = $v_list_var;
By the way, it would be a good idea to name your class Load.
For MVC reasons, I want to be able to trigger a function to find when the function has been called, since Codeigniter has functions around their core, I want to hook a function such as setcookie and create a file when it's been called (from the triggered function) for example:
function call_me()
{
$file = fopen('setcookie.txt', 'a+');
fwrite($file, 'Called at ' . __CLASS__);
fclose();
}
So when setcookie is called, it should trigger the call_me function. Is there any specific function or method to do this? I know about debug_backtrace but that's not the purpose I want.
What you basically need to have a look at is Observers.
The observer pattern (aka. Dependents, publish/subscribe) is a
software design pattern in which an object, called the subject,
maintains a list of its dependents, called observers, and notifies
them automatically of any state changes, usually by calling one of
their methods. It is mainly used to implement distributed event
handling systems. Observer is also a key part in the familiar MVC
architectural pattern. In fact the observer pattern was first
implemented in Smalltalk's MVC based user interface framework.1
Why don't you try what is described here :
http://devzone.zend.com/1384/observer-pattern-in-php/
I know about debug_backtrace but that's not the purpose I want.
I see that you insist not to use backtrack function, but still I believe that when you want to log when a function is called backtrack can come in handy.
The idea is that you have a predifined piece pf code stored in a constant, whenever you want to debug an if condition evaluates this code.
If you are under prouction the if statement will prevent from evaluating anything so your code's speed is not affected. If it works for you you can modify it to your needs, to track down even more levels.
To make my point this is a full example, if I have not understood right and this is not what you're looking for, my apologies!
To check the example you have a file: test.php
<?php
define ('__SITE_PATH',realpath(dirname(__FILE__)).'/');
ini_set('log_errors', 1);
ini_set('error_log', __SITE_PATH.'my_error_log.log');
include 'test1.php';
include 'test2.php';
define (__DEBUG_EVAL, '
$dbt = debug_backtrace();
error_log(
"\n".
"Parent function file: " . $dbt[1]["file"] . "\n" .
"Parent function class: " . $dbt[2]["class"] . "\n" .
"Parent fiunction name: " . $dbt[2]["function"] . "\n" .
"Par. fiunc. called from line: " . $dbt[2]["line"] . "\n" .
"Child function file: " . $dbt[0]["file"] . "\n" .
"Child function class: " . $dbt[1]["class"] . "\n" .
"Child fiunction name: " . $dbt[1]["function"] . "\n" .
"Child fiunc. called from line: " . $dbt[1]["line"] . "\n" .
"\n"
);
');
test1::a();
?>
This is test1.php
<?PHP
class test1
{
public static function a()
{
test2::b();
}
}
?>
The last is test2.php
<?PHP
class test2
{
public static function b()
{
if(defined('__DEBUG_EVAL')) eval(__DEBUG_EVAL);
echo 'Hello!';
}
}
?>
This is the result:
[13-Apr-2012 14:37:18]
Parent function file: C:\PHP-GTK\MyProjects\Electre\test1.php
Parent function class: test1
Parent fiunction name: a
Par. fiunc. called from line: 29
Child function file: C:\PHP-GTK\MyProjects\Electre\test2.php
Child function class: test2
Child fiunction name: b
Child fiunc. called from line: 7