Lets say I have a class like:
class SomeClass{
function someAction($param1,$param2){}
}
Is there any way to get analyzing data like array('param1','param2') without actual execution of method? Preferably without php extensions or prior code analysis (fopen...)
I think you can use the Reflection class to get info about method(s) and params.
Great, thank you all, solved it with something like
$oRuleContainer = new cRuleContainer();
$rContainer = new ReflectionClass('cRuleContainer');
$rMethod = $rContainer->getMethod($aRule['method']);
$aArgs = $rMethod->getParameters();
if($aArgs){
foreach($aArgs as $refArgument){
$arrPassedArgData[$refArgument->name]=$_POST[$refArgument->name];
}
}
if(call_user_func_array(array($oRuleContainer,$aRule['method']),$arrPassedArgData)){
//success
}
More details at
http://kurapov.name/rus/technology/web/php/reflection_php_brms/
Related
I have a function which I use like this
$i18n_APP = new i18n($_SERVER['DOCUMENT_ROOT'].'module/'.$modid.'/lang/lang_{LANGUAGE}.ini',
$_SERVER['DOCUMENT_ROOT'].'lang/langcache/', 'en');
$i18n_APP->setPrefix('APP'.$appid);
$i18n_APP->init();
Normally I call the function by the prefix, like this
APP($el)
Now I have to use a variable prefix, cause I use the $appid, so I can't code it like the way above.
Is there any way to make it in a dynamic way maybe like this
App.$appid($el)
Hope I could explain what I tried to do.
By the way, maybe I don't need to do it, if I find a way to "add" different languagefiles to the function. For the moment I initiate a new class for every languagefile.
I find a way to solve it
function langtag($prefix, $value)
{
return $prefix($value);
}
and
$moid=4;
echo langtag('APP'.$modid,$el)
I need to call in checkout/confirm.tpl file a custom function that i've made in controller/product.php
what's the best way to make this?
i've tried this, but doesn't work:
$productController = $this->load->model('product/product');
$productController->customFunction();
yes i find the right answer finally!!! sorry for last bad answer
class ControllerCommonHome extends Controller {
public function index() {
return $this->load->controller('product/ready');
}
}
MVC
in an MVC architecture, a template serves solely for rendering/displaying data; it shouldn't (*) call controller/model functions nor it shouldn't execute SQL queries as I have seen in many third-party modules (and even in answers here at SO).
$productController = $this->load->model('product/product');
nifty eye has to discover that you are trying to load a model into a variable named by controller and you are also trying to use it in such way. Well, for your purpose there would have to be a method controller() in class Loader - which is not (luckily)
How it should be done?
sure there is a way how to access or call controller functions from within templates. In MVC a callable function that is invoked by routing is called action. Using this sentence I can now say that you can invoke an action (controller function) by accessing certain URL.
So let's say your controller is CatalogProductController and the method you want to invoke is custom() - in this case accessing this URL
http://yourstore.com/index.php?route=catalog/product/custom
you will make sure that the custom() method of CatalogProductController is invoked/accessed.
You can access such URL in many ways - as a cURL request, as a link's href or via AJAX request, to name some. In a PHP scope even file_get_contents() or similar approach will work.
(*) By shouldn't I mean that it is (unfortunately) possible in OpenCart but such abuse is against MVC architecture.
$this->load->controller('sale/box',$yourData);
To call ShipmentDate() function of box Controller
$this->load->controller('sale/box/ShipmentDate',$yourData);
May be something like this could help you (or anyone who's interested)
// Load seo pro
require_once(DIR_CATALOG."/controller/common/seo_pro.php"); // load file
$seoPro = new ControllerCommonSeoPro($this->registry); // pass registry to constructor
$url = HTTP_CATALOG . $seoPro->rewrite(
$this->url('information/information&information_id=' . $result['information_id'])
);
return $this->load->controller('error/not_found');
in laravel its so simple just write Controller::call('ApplesController#getSomething');
but there i cant made better than this
$config = new Config();
// Response
$response = new Response();
$response->addHeader('Content-Type: text/html; charset=utf-8');
$response->setCompression($config->get('config_compression'));
$this->registry->set('response', $response);
$action = new Action('product/ready');
$controller = new Front($this->registry);
$controller->addPreAction(new Action('common/maintenance'));
$controller->addPreAction(new Action('common/seo_url'));
$controller->dispatch($action, new Action('error/not_found'));
$response->output();
in this case its well call product/ready
I'm evaluating frameworks for use with an API, and I'm taking a serious look at PHP Phalcon. It's looking promising - "lean" (load what you need), but with a lot of options.
I'm wondering... is it possible to not use views (templates, rather) with it? Do I have to set up a view, or can I just output .json?
Thanks!
There is a way in Phalcon to disable view in the action and avoid unnecessary processing:
public function indexAction() {
$this->view->disable();
$this->response->setContentType('application/json');
echo json_encode($your_data);
}
Depending on what you want to do you can disable the view as others have suggested and echo json encoded data, or you could use the built in response object as below:
$this->view->setRenderLevel(View::LEVEL_NO_RENDER);
$this->response->setContentType('application/json', 'UTF-8');
$this->response->setJsonContent($data); //where data is an array containing what you want
return $this->response;
There is also a tutorial in the docs that goes over building a simple REST api
http://docs.phalconphp.com/en/latest/reference/tutorial-rest.html
If you won't be using any views at all you can disable views at the very start.
$app = new \Phalcon\Mvc\Application();
$app->useImplicitView(false);
Even if you do this, I think you still have to set the view DI for the framework to work.
Also, if you want to output json there's a method for that:
$this->response->setJsonContent($dataArray);
$this->response->send();
Yeah, you can do it, I'm using PHP Phalcon.
To ignore view, in your controller your action should be like
public function indexAction() {
$var = array or other data
die(json_encode($var));
}
die(); in controller will not render any parent layout! :)
I have a page named ChangeApprovalInfo.php - It has a function called Row_Rendered as follows;
function Row_Rendered() {
// To view properties of field class, use:
//var_dump($this-><FieldName>);
$RecordOwner = $this->RequestUser->CurrentValue;
echo $RecordOwner;
}
Echoing $RecordOwner gets me the data I will need for a sql query on another page....
I have another page called ChangeApprovalEdit.php - This page has
<?php include_once "ChangeApprovalinfo.php" ?>
at the top of the file.
ChangeApprovalEdit.php has a function where I need the $RecordOwner variable as defined in ChangedApprovalInfo.php
If I add "echo $RecordOwner" on the ChangeApprovalEdit.php page, I get an error saying it's an unknown variable. My understanding is that I need to "make it global" or some such business. I know very little about PHP and the pages I am editing are long and complex. (to me, at least)
What do I need to do? I know that the information I have provided might not be enough to answer the question. I don't know enough to even know exactly what I need to ask. If more information is needed, I will edit and follow up.
pastebin of the files
ChangeApprovalInfo.php = http://pastebin.com/bSRM1wwN
ChangeApprovalEdit.php = http://pastebin.com/AStG9pqb
EDIT:
Changing Row_Rendered to this seems to be more effective. I'm having trouble seeing WHERE I can later echo this variable... but I'm getting somewhere with this...
function Row_Rendered() {
// To view properties of field class, use:
//var_dump($this-><FieldName>);
$GLOBALS['RecordOwner'] = $this->RequestUser->CurrentValue;
}
Don't echo variables from functions, which just outputs them to the standard output. return them from the function so you can use the value elsewhere as well.
function Row_Rendered() {
$RecordOwner = $this->RequestUser->CurrentValue;
return $RecordOwner;
}
Then instead of
$obj->Row_Rendered();
use
echo $obj->Row_Rendered();
and if you want to use the value elsewhere, use
$value = $obj->Row_Rendered();
You can do a couple of things:
First, you can return $RecordOwner from the function, and store its value in a variable. This method is usually preferred.
function Row_Rendered() {
// To view properties of field class, use:
//var_dump($this-><FieldName>);
$RecordOwner = $this->RequestUser->CurrentValue;
echo $RecordOwner;
return $RecordOwner;
}
// Store it in a variable when calling the function.
$RecordOwner = Row_Rendered();
Or, you can make it global inside the function:
function Row_Rendered() {
// To view properties of field class, use:
//var_dump($this-><FieldName>);
$GLOBALS['RecordOwner'] = $this->RequestUser->CurrentValue;
echo $GLOBALS['RecordOwner'];
}
You can use the $GLOBALS superglobals array, like this:
function Row_Rendered() {
$GLOBALS['RecordOwner'] = $this->RequestUser->CurrentValue;
}
However, you should not do that. Instead, refactor your application so that the view in ChangeApprovalinfo.php just contains a function, which is then called with the appropriate parameters.
EDIT: Chaning Row_Rendered to this seems to be more effective. I'm having trouble seeing WHERE I can later echo this variable... but I'm getting somewhere with this...
function Row_Rendered() {
// To view properties of field class, use:
//var_dump($this-><FieldName>);
$GLOBALS['RecordOwner'] = $this->RequestUser->CurrentValue;
}
I feel compelled to write another answer to this update. Let me demonstrate the use of globals as seen from outside that function:
$obj->Row_Rendered();
$obj->foobar();
echo $GLOBALS['RecordOwner'];
Quick, what will be echoed and where does that value come from? Well, it depends on what $obj-foobar() does. Maybe it changes the global variable. Maybe it doesn't. Who knows if the variable has been set at all? How would you trace back what happened exactly without adding a debug line after every single function call?
And that's just three lines of code. Imagine that in an application of any complexity.
Now, the same thing if I return the value from Row_Rendered:
$owner = $obj->Row_Rendered();
$obj->foobar();
echo $owner;
If the Row_Rendered method is behaving as it should (returning the owner), this code is very predictable. If you do not follow this pattern, you'll have a hell of a time getting anything done when the application grows to any halfway complex size.
Set the variable as global from within the function
$my_global_var = "old value";
function doing_stuff(){
global $my_global_var; //this will use the global variable instead of creating a local one
$my_global_var = "new value";
}
echo $my_global_var;//returns "new value"
I needed to create dynamic breadCrumbs that must be realized automatically by the application. So I have the following structure in the URL for navagation:
nav=user.listPMs.readPM&args=5
then i could have a function-file whose sole purpose would be to define the user.listPMs.readPM function itself:
file: nav/user.listPMs.readPM.php
function readPM($msgId)
{
/*code here*/
}
Of course this ends up cluttering the global scope since i'm not wrapping the function withing a class or using namespaces. The best solution here seems to be namespacing it, no doubt right? But I also thought of another one:
file: nav/user.listPMs.readPM.php
return function($msgId)
{
/*code here*/
};
Yep, that simple, the file is simply returning an anonymous function. I think this is amazing because i don't need to care about naming it - since i've already properly named the file that contains it, creating a user function and yet having to name it would seem just redundant. Then in the index I would have this little dirty trick:
file: index.php
if($closure = #(include 'nav/'.$_GET['nav']))
{
if($closure instanceof Closure)
{
$obj = new ReflectionFunction($closure);
$args = explode(',',#$_GET['args']);
if($obj->getNumberOfParameters($obj)<=count($args))
call_user_func_array($closure,$args);
else
die('Arguments not matching or something...');
} else {
die('Bad call or something...');
}
} else {
die('Bad request etc.');
}
Don't even need to mention that the breadCrumbs can be nicely built latter just by parsing the value within the $_GET['nav'] variable.
So, what do you think, is there a better solution to this problem? Have you found another way to explore Closures and/or Reflection?
I like the basic idea. But the implementation is pretty much terrible. Imagine that I set nav=../../../../../../etc/passwd. That would (depending on your server configuration) allow me to access your password file, which certainly is no good.