Posts: 13
Threads: 4
Joined: May 2011
Now component is like an un parameterised micro-template. I wish I have an ability to use it in a manner of function, like
Code: <?
$paramValue2 = 'test';
get_component('article', 'paramValue1', $paramValue2);
?>
This could be usefull when component contains PHP code that should change it's behavior due to parameters.
Posts: 1,108
Threads: 70
Joined: Aug 2009
Posts: 13
Threads: 4
Joined: May 2011
Hm... It seems you've got me wrong. PHP code can be used in components without any plugins - just out of box. It would be cool, if those components should have parameters.
Posts: 2,094
Threads: 54
Joined: Jan 2011
bugman Wrote:Now component is like an un parameterised micro-template. I wish I have an ability to use it in a manner of function, like
Code: <?
$paramValue2 = 'test';
get_component('article', 'paramValue1', $paramValue2);
?>
This could be usefull when component contains PHP code that should change it's behavior due to parameters.
Using the DynPages plugin you have this possibility, when including the component on a page.
If you want to use it from the template, use a function like this:
Code: function get_component_with_params($name, $params=array()) {
global $args;
if (isset($args)) $saved_args = $args;
$args = $params;
get_component($name);
if (isset($saved_args)) $args = $saved_args; else unset($args);
}
In the component use the global variable $args, e.g.
Code: global $args;
echo "Parameter 1 = $args[0]";
Call with
Code: get_component_with_params('article', array('paramValue1','paramValue2'));
Posts: 13
Threads: 4
Joined: May 2011
Thanks, mvlcek. I've thought about implementation just in that way. But I've also hoped, that there's no cons to have this ability right in GS without any plugins I think of components like of function with frendly web interface to develop
Posts: 1,108
Threads: 70
Joined: Aug 2009
<<< is very tired today.. and totally misunderstood 8)
Posts: 13
Threads: 4
Joined: May 2011
n00dles101 Wrote:<<< is very tired today.. and totally misunderstood 8)
Anyway thanks for rapid response. I've seen your cast of processWire - great one! It seems that it has anything i ever need of cms/cmf.
Posts: 2,094
Threads: 54
Joined: Jan 2011
bugman Wrote:Thanks, mvlcek. I've thought about implementation just in that way. But I've also hoped, that there's no cons to have this ability right in GS without any plugins I think of components like of function with frendly web interface to develop
I18N version 1.7 now supports calling components with parameters, set here.
Posts: 972
Threads: 27
Joined: Aug 2009
@mvlcek:
I see you are using a global variable inside your implementation, why? You can do this without leaking any data into the global scoop, that way you don’t have to bother with back-upping any already existing variables either.
This works just as well: (large bit of code directly from the GS core)
Code: function get_component_args($id) {
if (func_num_args() > 1) { $args = func_get_args(); array_shift($args); }
if (file_exists(GSDATAOTHERPATH.'components.xml')) {
$data = getXML(GSDATAOTHERPATH.'components.xml');
$components = $data->item;
if (count($components) != 0) {
foreach ($components as $component) {
if ($id == $component->slug) {
eval("?>" . strip_decode($component->value) . "<?php ");
}
}
}
}
}
And can be used like this, in a template:
Code: get_component_args('credits','Zegnåt','http://zegnat.net/');
and with a component called credits:
Code: <p>Build by <a href="<?php echo $args[1]; ?>"><?php echo $args[0]; ?></a></p>
Please stay out of the global scoop unless you need to communicate with global data.
--- --- --- --- ---
The big question for this topic to answer is: should this be implemented in the core?
Posts: 2,094
Threads: 54
Joined: Jan 2011
Zegnåt Wrote:@mvlcek:
I see you are using a global variable inside your implementation, why? You can do this without leaking any data into the global scoop, that way you don’t have to bother with back-upping any already existing variables either.
Yes, I know this. But I want to stay compatible with the DynPages plugin, which just calls get_component() and thus has to pass the parameters as globals.
Posts: 1,848
Threads: 86
Joined: Aug 2009
Zegnåt Wrote:The big question for this topic to answer is: should this be implemented in the core? can someone explain what needs to change in the core to me so I don't have to try and decipher this whole thread to decide if it should be or not? Thanks
- Chris
Thanks for using GetSimple! - Download
Please do not email me directly for help regarding GetSimple. Please post all your questions/problems in the forum!
Posts: 972
Threads: 27
Joined: Aug 2009
tl;dr for Chris:
The proposed solution has the original get_component() code in it. The one big addition is:
Code: if (func_num_args() > 1) { $args = func_get_args(); array_shift($args); }
This puts all arguments other than the first (which we assume is the component name) in an array $args.
Now the component code can use $args[ n] to make use of arguments passed from the template to the get_component function:
Code: get_component('name','argument0','argument1', …)
Posts: 2,094
Threads: 54
Joined: Jan 2011
Zegnåt Wrote:tl;dr for Chris:
The proposed solution has the original get_component() code in it. The one big addition is:
Code: if (func_num_args() > 1) { $args = func_get_args(); array_shift($args); }
This puts all arguments other than the first (which we assume is the component name) in an array $args.
Now the component code can use $args[n] to make use of arguments passed from the template to the get_component function:
Code: get_component('name','argument0','argument1', …)
Yes, that's it.
BTW: a return after the eval would be beneficial (because of speed and because the component could set the variable $id - which could lead to unwanted results).
Posts: 972
Threads: 27
Joined: Aug 2009
2011-06-20, 19:12:14
(This post was last modified: 2011-06-20, 19:40:08 by vsky.)
mvlcek Wrote:BTW: a return after the eval would be beneficial What kind of return would you suggest? Something like this? (Modifying get_component() from the SVN.)
Code: function get_component($id) {
global $components;
if (func_num_args() > 1) { $args = func_get_args(); array_shift($args); }
if (!$components) {
if (file_exists(GSDATAOTHERPATH.'components.xml')) {
$data = getXML(GSDATAOTHERPATH.'components.xml');
$components = $data->item;
} else {
$components = array();
}
}
if (count($components) > 0) {
foreach ($components as $component) {
if ($id == $component->slug) {
$eval = eval("?>" . strip_decode($component->value) . "<?php ");
}
}
}
return $eval===NULL||$eval!==FALSE;
}
Posts: 2,094
Threads: 54
Joined: Jan 2011
2011-06-20, 19:36:30
(This post was last modified: 2011-06-20, 19:36:52 by nime.)
Zegnåt Wrote:mvlcek Wrote:BTW: a return after the eval would be beneficial What kind of return would you suggest?
I just meant a return directly after the eval. But as you mention it, in the I18N plugin I return, if the component exists or not:
Code: function get_component($id) {
global $components;
if (func_num_args() > 1) { $args = func_get_args(); array_shift($args); }
if (!$components) {
if (file_exists(GSDATAOTHERPATH.'components.xml')) {
$data = getXML(GSDATAOTHERPATH.'components.xml');
$components = $data->item;
} else {
$components = array();
}
}
if (count($components) > 0) {
foreach ($components as $component) {
if ($id == $component->slug) {
eval("?>" . strip_decode($component->value) . "<?php ");
return true;
}
}
}
return false;
}
This way you can use code like this in your template (custom sidebar for specific pages):
Code: <?php get_component('sidebar-'.return_page_slug()) || get_component('sidebar'); ?>
Posts: 972
Threads: 27
Joined: Aug 2009
mvlcek Wrote:Zegnåt Wrote:mvlcek Wrote:BTW: a return after the eval would be beneficial What kind of return would you suggest? I just meant a return directly after the eval. I guess this would be better performance wise, I just don’t like returns inside loops. Maybe put a break there instead.
mvlcek Wrote:But as you mention it, in the I18N plugin I return, if the component exists or not I have one issues with your code as it stands: it doesn’t return whether the component actually works or not. eval() is no magic and the PHP inside might fail. My proposed return is this: (Where $eval holds the return value of eval().)
Code: $eval===NULL||$eval!==FALSE;
Any eval() that just runs code will return NULL on success, it will return FALSE if it encounters a PHP error or it might return any arbitrary value if someone used “returnâ€Â. The above code will return TRUE if the component has produced a non- FALSE response.
Let me know what you think of that.
Combining:
Code: function get_component($id) {
global $components;
if (func_num_args() > 1) { $args = func_get_args(); array_shift($args); }
if (!$components) {
if (file_exists(GSDATAOTHERPATH.'components.xml')) {
$data = getXML(GSDATAOTHERPATH.'components.xml');
$components = $data->item;
} else {
$components = array();
}
}
if (count($components) > 0) {
foreach ($components as $component) {
if ($id == $component->slug) {
$eval = eval("?>" . strip_decode($component->value) . "<?php ");
break;
}
}
}
return $eval===NULL||$eval!==FALSE;
}
If you can agree with this as a solution I could put it in the core right now.
Posts: 2,094
Threads: 54
Joined: Jan 2011
Zegnåt Wrote:mvlcek Wrote:Zegnåt Wrote:What kind of return would you suggest? I just meant a return directly after the eval. I guess this would be better performance wise, I just don’t like returns inside loops. Maybe put a break there instead.
Not just for better performance, but to prevent that variables set within the component influence the function.
And I don't like breaks, as they are basically a goto ;-)
Zegnåt Wrote:I have one issues with your code as it stands: it doesn’t return whether the component actually works or not.
And this is good IMHO.
As developer of components (with PHP code) I have to test the component (in debug mode) and will get error messages.
The result of get_component is for the user = caller of a component. As user I assume that the component works and I am (only) concerned about the functional logic: if component x does not exist, use
component y or display some static text. And it's not: if component x does not exist or is erroneous, ...
And components returning values would add additional complexity, the user would have to look at the component to know what it returns and would not be able to do something as described above.
I see components as snippets to include in the template or (via the DynPages plugin) in a page. In most cases it will contain HTML and simple code like <?php get_something(params); ?>. There is no need for return values. If I need to return something, a function is a better way to do it.
Zegnåt Wrote:My proposed return is this: (Where $eval holds the return value of eval().)
Code: $eval===NULL||$eval!==FALSE;
BTW: I think this will output a warning (at least in debug mode), if the component does not exist, as $eval is not set :-(
So, I think, it's more confusing to "return true, if the component exists and works and does return nothing or at least does not return null or false" than to "return true, if the component exists".
But I can live with it, if with a non-faulty component it will return true, if it exists and false otherwise (given that the component itself does not return anything), and does so in debug mode, too.
Posts: 972
Threads: 27
Joined: Aug 2009
mvlcek Wrote:And I don't like breaks, as they are basically a goto ;-) We’ll let Chris decide over the multiple- returns or break usage then ;-)
mvlcek Wrote:As developer of components (with PHP code) I have to test the component (in debug mode) and will get error messages. You still get error messages my way. Because the code is still eval()’d before I return anything. It’s just that the function will return FALSE if an error occurs, that way you can use it inside the template to offer an alternative when the component were to break.
mvlcek Wrote:And components returning values would add additional complexity, the user would have to look at the component to know what it returns and would not be able to do something as described above. That’s something up to the “user†(as you call them) though. You might never want to use a return inside eval()’d code, I surely never want that, but someone might. It’s just a case I had to include in the check.
mvlcek Wrote:Zegnåt Wrote:My proposed return is this: (Where $eval holds the return value of eval().)
Code: $eval===NULL||$eval!==FALSE;
BTW: I think this will output a warning (at least in debug mode), if the component does not exist, as $eval is not set :-(
You are right, that’s my mistake, I will try to figure out what to do about that. The problem is that I can’t use isset(), because a working eval() will return NULL and isset(NULL)==FALSE.
I’m going to see what I can do.
Posts: 2,094
Threads: 54
Joined: Jan 2011
2011-06-20, 23:55:27
(This post was last modified: 2011-06-20, 23:58:01 by nime.)
Zegnåt Wrote:That’s something up to the “user†(as you call them) though. You might never want to use a return inside eval()’d code, I surely never want that, but someone might. It’s just a case I had to include in the check.
"a case I had to include" is the wrong expression, as it's not necessary in my approach, where return values of the component are ignored (not supported) and the meaning of the return value of get_component is always: "true, if the component exists" ;-)
"a case I want to support" - with that I can agree ;-)
And I still think my approach is the cleaner one...
Posts: 972
Threads: 27
Joined: Aug 2009
After a little testing, this is the correct way to find out whether a variable ($eval) is NULL or non- FALSE:
Code: !isset($eval)&&array_key_exists('eval',get_defined_vars())||isset($eval)&&$eval!==FALSE
This is way too confusing, so it’s much easier to just set $eval to FALSE and take it from there.
We now have two proposed solutions to this problem, both have two alternative ways of writing—since they can even be made to work with a break or with two seperate returns. The only real difference between the solutions is mvlcek’s returns TRUE when a component is found, no matter what happens with eval() while mine will return TRUE only when a component is found and was correctly eval()’d.
Should this be put up for vote or something? :p
mvlcek:
Code: function get_component($id) {
global $components;
if (func_num_args() > 1) { $args = func_get_args(); array_shift($args); }
if (!$components) {
if (file_exists(GSDATAOTHERPATH.'components.xml')) {
$data = getXML(GSDATAOTHERPATH.'components.xml');
$components = $data->item;
} else {
$components = array();
}
}
if (count($components) > 0) {
foreach ($components as $component) {
if ($id == $component->slug) {
eval("?>" . strip_decode($component->value) . "<?php ");
return true;
}
}
}
return false;
}
Uses 2 separate returns (as preferred by mvlcek over breaks). The function will return TRUE when a component exists with the provided $id and FALSE if there doesn’t.
Zegnåt:
Code: function get_component($id) {
global $components;
$eval = FALSE;
if (func_num_args() > 1) { $args = func_get_args(); array_shift($args); }
if (!$components) {
if (file_exists(GSDATAOTHERPATH.'components.xml')) {
$data = getXML(GSDATAOTHERPATH.'components.xml');
$components = $data->item;
} else {
$components = array();
}
}
if (count($components) > 0) {
foreach ($components as $component) {
if ($id == $component->slug) {
$eval = eval("?>" . strip_decode($component->value) . "<?php ");
break;
}
}
}
return $eval!==FALSE;
}
Uses a break to stop the loop after a component has been found. The function will return TRUE when the component eval()’d correctly and FALSE if no component has been found to match the provided $id or the component produced PHP errors when being eval()’d. (In debug mode, these errors are still shown, nothing is hidden!)
Posts: 2,094
Threads: 54
Joined: Jan 2011
2011-06-21, 05:28:08
(This post was last modified: 2011-06-21, 05:29:57 by nime.)
Comparison of the variants:
Code: Component Component Component Result Result
exists has errors returns mvlcek Zegnåt
===============================================================
yes yes false true false <=
yes yes nothing/not false true false <=
yes no false true false <=
yes no nothing/not false true true
no yes false false false
no yes nothing/not false false false
no no false false false
no no nothing/not false false false
In the important case - Component has no errors and returns nothing, both variants return the same.
So my only issues with Zegnåt's approach is that it is overly complex: - It tests, if the component has errors. But will users really check the return value for this? Is anybody - except in special cases - writing code to test, if some other code compiles???
- On the other hand, in a realistic call, for which the return code of get_component was intended (by me, at least, based on feature requests in the forum) - like get_component('sidebar-'.return_page_slug()) || get_component('sidebar') - Zegnåt's approach has no advantages for testing/debugging. See below.
I'm assuming that component 'sidebar' has no errors, as it is the default and was already tested.
My approach: - sidebar is displayed, but shouldn't => sidebar-xxx does not exist
- nothing or an error message is displayed => there is an error in sidebar-xxx
Zegnåt's approach: - sidebar is displayed, but shouldn't => sidebar-xxx does not exist or sidebar-xxx has an error (or sidebar-xxx returns false)
- nothing or an error message is displayed => can't happen
Having said this and trying to keep it simple, I prefer my simple approach, because support for it is much simpler - it's easier to ask "does the component exist?" instead of "Does the component exist and compile and not return anything or at least not false?" - but I'm happy with either way.
BTW: I don't care if break or return is used - if the code works ;-)
Posts: 13
Threads: 4
Joined: May 2011
So as I got it from the above you decided not to put it to core, ehm okay
Posts: 6,266
Threads: 181
Joined: Sep 2011
no but i am glad you brought this up, since i added 2 arguments already to this function and that might cause issues if I want to add this.
however i am not entirely sure what this thread was attempting to solve, seems most of the discussion is on eval return values ???
components are eval'd, essentially anonymous functions
meaning there is no parameterization possible
I would simply pass func_args to the eval using a static variable for now.
Ideally components would be class methods that can have objects passed into them, since we still require php 5.2 and I dont feel like implementing janky old class constructs, I would just hack this in with an object and let you get it via $self or $this, instead of an actual reflection class or whatever the best solution would actually be in 5.3+
another solution would be to see if we can slip an extract into the code, and simply extract your argument array into the scope of the component.
extract is dangerous but shit we are already inside an eval, soooooo..
solutions welcome
Posts: 13
Threads: 4
Joined: May 2011
I like the approach with passing parameters via $args variable available to the evaluated code of component - for my own purpose I hacked my admin/inc/theme_functions.php to fix get_component function the way was shown, but it's up to you to decide on the best approach (if any at all).
Posts: 6,266
Threads: 181
Joined: Sep 2011
I would prefer if users do not have to do args[0]
Other that that
|