How does a block PHP file know the values POSTed through it's controller file?
Permalink
I have been studying and working with a form block (not the default form block) and have all but come to understand how it works so as to able to use it and have it do what I want.
However there is something within this block that is still a mystery to me and I would appreciate help understanding how Concrete5 does what it does here (what it does is no unique to this block in particular I am sure).
Specifically there is a my_contact_form.php file (which I will call the block PHP file) inside the /blocks/external_form/forms/ directory that uses variables that contain the values entered by a visitor into the form.
-
Like so...
Do you see the "isset($name)" and "echo $name" PHP code? Basically $name is a variable that is initialized with the value of the "name" field in the form. That initialization happens inside the my_contact_form.php file inside the /blocks/external_form/forms/controller for the block.
It is initialized like so...
So we have a variable inside the block PHP file called $name which comes from who knows where being initialized inside the controller through the set() method of the BlockController class.
In turn the set() method does this...
All well and good (well...a bit difficult to follow and understand the reason for all this redirection and multiple variable use but anyway...)
My problem is that I have no clue how Concrete5 takes the setting of $this->identifier with the key (i.e. $name) and the value (the value of the field as found inside the POSTED form values) and makes it a variable available to the block PHP file??
What kind of PHP trick allows it to do this?
How does Concrete5 take an array with the POSTed form values as set inside the BlockController class and then make those set values available inside the block PHP file when the block PHP file does not even address or otherwise access the identifier array within it's code anywhere.
It's like the POSTed values just appear out of thin air.
I mean PHP variables need to be created and initialized somewhere to be used...right? Concrete5 seems to pull them out of a hat somehow and presto...they are available for us even though I don't see anywhere in the code where they were...well...created!?
Anybody got any insight or clue as to how Concrete5 does this and how it uses the identifier array as found inside the BlockController class to do this?
I got to tell you that understanding the code beats anything else hands down with respect to understanding what Concrete5 does and how it works but man oh man...it is without a doubt the hardest PHP I have ever had to try and understand. Hardly any comments. Weirdly named variables. Variables named after a reason that no longer exists or applies. All kinds of such things.
This is the last area that I do not understand in the block code I have been studying. I mean I can use it just fine but I want to fully understand what is happening so that I can change things how I want them done in the future or fix things when and if they break.
Any help understand this "magical" variable use would be appreciated.
Thanks.
Carlos
PS. The block in question is an entirely custom block I have created (given all the changes I have made to it) but one which is based on block code I found on the forum so the essential problem described above is just...well...a Concrete5 mystery and not something that I did per se.
However there is something within this block that is still a mystery to me and I would appreciate help understanding how Concrete5 does what it does here (what it does is no unique to this block in particular I am sure).
Specifically there is a my_contact_form.php file (which I will call the block PHP file) inside the /blocks/external_form/forms/ directory that uses variables that contain the values entered by a visitor into the form.
-
Like so...
Do you see the "isset($name)" and "echo $name" PHP code? Basically $name is a variable that is initialized with the value of the "name" field in the form. That initialization happens inside the my_contact_form.php file inside the /blocks/external_form/forms/controller for the block.
It is initialized like so...
// $this->set() defined inside /concrete/libraries/block_controller.php // public function set($key, $value) $name = $_POST['name']; $this->set('name', $name);
So we have a variable inside the block PHP file called $name which comes from who knows where being initialized inside the controller through the set() method of the BlockController class.
In turn the set() method does this...
public function set($key, $value) { BlockController::$sets[$this->identifier][$key] = $value; }
All well and good (well...a bit difficult to follow and understand the reason for all this redirection and multiple variable use but anyway...)
My problem is that I have no clue how Concrete5 takes the setting of $this->identifier with the key (i.e. $name) and the value (the value of the field as found inside the POSTED form values) and makes it a variable available to the block PHP file??
What kind of PHP trick allows it to do this?
How does Concrete5 take an array with the POSTed form values as set inside the BlockController class and then make those set values available inside the block PHP file when the block PHP file does not even address or otherwise access the identifier array within it's code anywhere.
It's like the POSTed values just appear out of thin air.
I mean PHP variables need to be created and initialized somewhere to be used...right? Concrete5 seems to pull them out of a hat somehow and presto...they are available for us even though I don't see anywhere in the code where they were...well...created!?
Anybody got any insight or clue as to how Concrete5 does this and how it uses the identifier array as found inside the BlockController class to do this?
I got to tell you that understanding the code beats anything else hands down with respect to understanding what Concrete5 does and how it works but man oh man...it is without a doubt the hardest PHP I have ever had to try and understand. Hardly any comments. Weirdly named variables. Variables named after a reason that no longer exists or applies. All kinds of such things.
This is the last area that I do not understand in the block code I have been studying. I mean I can use it just fine but I want to fully understand what is happening so that I can change things how I want them done in the future or fix things when and if they break.
Any help understand this "magical" variable use would be appreciated.
Thanks.
Carlos
PS. The block in question is an entirely custom block I have created (given all the changes I have made to it) but one which is based on block code I found on the forum so the essential problem described above is just...well...a Concrete5 mystery and not something that I did per se.
Ah...hmmm...well...yeah...I think that helps LOL.
Seriously, for sure that helps Scott. That's exactly the kind of info I was looking at though of course it is rather obvious I think how your response points to the difficulty of understanding the underlying C5 way of doing things and it's code.
Unbelievable complexity.
Not saying your response was overly complex Scott. Only that it takes a lot to understand the code.
Time well spent though.
Thanks very much Scott! I'm going to spend the next little while studying and trying to follow what you said Scott (again...your explanation is fine..it's the nature and complexity of how C5 does things and where it does things underneath that is the problem I think).
Carlos
Seriously, for sure that helps Scott. That's exactly the kind of info I was looking at though of course it is rather obvious I think how your response points to the difficulty of understanding the underlying C5 way of doing things and it's code.
Unbelievable complexity.
Not saying your response was overly complex Scott. Only that it takes a lot to understand the code.
Time well spent though.
Thanks very much Scott! I'm going to spend the next little while studying and trying to follow what you said Scott (again...your explanation is fine..it's the nature and complexity of how C5 does things and where it does things underneath that is the problem I think).
Carlos
Interesting that php.net strongly discourages use of extract() on untrusted input such as user entry into an online form.
Carlos
Carlos
Hmm...
I have been trying my hardest to find where an extract is used to create the forms POSTed values as variables into the name space.
Or where getSets() is used.
Or where render() is used.
And so on.
There are literally hundreds of places in the code where these functions are found.
Given the two files I have so far in my block...namely...
/blocks/external_form/forms/my_contact_form.php
/blocks/external_form/forms/controller/my_contact_form.php
Do you or anyone else know where the extraction takes place such that the values entered into the form and processed by the controller are then made available to the form block PHP file (the first one) again?
I can't find in the code where these things occur for the particular form I am using (such a place is certainly no unique to the form code that forms the base of my form block...I found the code base on the forum and is pretty standard as to where things are at...at least those things I can follow in the code).
Carlos
I have been trying my hardest to find where an extract is used to create the forms POSTed values as variables into the name space.
Or where getSets() is used.
Or where render() is used.
And so on.
There are literally hundreds of places in the code where these functions are found.
Given the two files I have so far in my block...namely...
/blocks/external_form/forms/my_contact_form.php
/blocks/external_form/forms/controller/my_contact_form.php
Do you or anyone else know where the extraction takes place such that the values entered into the form and processed by the controller are then made available to the form block PHP file (the first one) again?
I can't find in the code where these things occur for the particular form I am using (such a place is certainly no unique to the form code that forms the base of my form block...I found the code base on the forum and is pretty standard as to where things are at...at least those things I can follow in the code).
Carlos
since these things extend blockcontroller youd want to look at BlockController under libraries which extends COntroller which is also in there. If a method is defined in an extending class, the call to parent:: has to be made to continue up, otherwise if it isn't present in the extending class it'll call the parent class automatically and that classes parent class until it finds the function before dying and saying it isn't found.
Thanks Scott. I hadn't looked inside the Controller class just the BlockController class. I'll look inside Controller next.
Carlos
Carlos
Scott,
Do you or anyone else here know how I might be able to force Concrete5 to give me a trace call back? To output where in the code it ran before encountering an error?
That would help me immensily figure out where something is coming from instead of searching all over the files in a hit or miss manner.
I suppose I can just look up how to force a traceback as a PHP thing that can be done on any PHP code and just...well...force C5 to give me one but I thought I would ask here in case anyone had ever done that with C5 before.
Carlos
Do you or anyone else here know how I might be able to force Concrete5 to give me a trace call back? To output where in the code it ran before encountering an error?
That would help me immensily figure out where something is coming from instead of searching all over the files in a hit or miss manner.
I suppose I can just look up how to force a traceback as a PHP thing that can be done on any PHP code and just...well...force C5 to give me one but I thought I would ask here in case anyone had ever done that with C5 before.
Carlos
Install xdebug:http://www.xdebug.org/
Kind of a pain to set up and install, but once you do it is an invaluable tool for the kinds of things you're wanting to do here. I wouldn't be able to solve half the problems I have (in C5 or any other complicated framework) without using a step debugger. The debugger can be REALLY hard to set up right, but even if you can't get that, the stack trace is a basic feature of xdebug that should be very easy to install.
Kind of a pain to set up and install, but once you do it is an invaluable tool for the kinds of things you're wanting to do here. I wouldn't be able to solve half the problems I have (in C5 or any other complicated framework) without using a step debugger. The debugger can be REALLY hard to set up right, but even if you can't get that, the stack trace is a basic feature of xdebug that should be very easy to install.
Thanks for reminding of that particular debug helper Jordan.
Yes...it is a pain to use but I once did use it (wasn't all that satisfied with it so I forgot about it) but now that the need for it's type of capability is here again (for me at least) I'll see if I can insert it into C5 to better "look" at what is being done where.
I don't know why I didn't think about using a backtrace before starting this thread. Duh...
Carlos
Yes...it is a pain to use but I once did use it (wasn't all that satisfied with it so I forgot about it) but now that the need for it's type of capability is here again (for me at least) I'll see if I can insert it into C5 to better "look" at what is being done where.
I don't know why I didn't think about using a backtrace before starting this thread. Duh...
Carlos
By the way...now that I installed xdebug and can finally "see" what is going on where...
I have to say that installing xdebug under Ubuntu Linux is an absolute piece of cake. At a command prompt...
Then edit the file /etc/php5/conf.d/xdebug.ini and add the following two lines at the end.
Finally, restart Apache for change to take affect...
After the above steps just go into the code anywhere you fancy and insert a call to a non-existent function like "nothing();" and voila!
A backtrace showing the functions that were run to that point show up.
How sweet it is! I mean Linux. It's great developing locally on the same operating system as used by many web hosting companies.
Carlos
I have to say that installing xdebug under Ubuntu Linux is an absolute piece of cake. At a command prompt...
~$ sudo apt-get install php5-xdebug
Then edit the file /etc/php5/conf.d/xdebug.ini and add the following two lines at the end.
display_errors = On html_errors = On
Finally, restart Apache for change to take affect...
~$ sudo /etc/init.d/apache2 restart
After the above steps just go into the code anywhere you fancy and insert a call to a non-existent function like "nothing();" and voila!
A backtrace showing the functions that were run to that point show up.
How sweet it is! I mean Linux. It's great developing locally on the same operating system as used by many web hosting companies.
Carlos
Shucks. It appears that my addition of a call to a non-existant function does not cause xdebug to be activated when that call is inside the action file of a form.
I'll have to play around with it some more but I sure hope I can get xdebug to show me it's pretty table of function calls from within the controller of a form block somehow.
Carlos
I'll have to play around with it some more but I sure hope I can get xdebug to show me it's pretty table of function calls from within the controller of a form block somehow.
Carlos
There we go...
Instead of using a call to a non-existant function to force an error (and a backtrace thereby) I just included the following function call in the code of the controller where I want the backtrace to show up instead.
xdebug_print_function_stack();
Carlos
Instead of using a call to a non-existant function to force an error (and a backtrace thereby) I just included the following function call in the code of the controller where I want the backtrace to show up instead.
xdebug_print_function_stack();
Carlos
Another example of this is: if you look up Loader::element('element_file',$args)
if $args is an array then extract is called on it, which essentially takes an associative array and maps the hash or key to a variable and the value of each hash or key becomes the value of that variable/pointer.
If you look at the get sets, those are pulled from the adodb activerecord class where they do the getAttributeNames();
This causes then since the record is actually an adodb active record object it just calls the object properties and passes them to sets. If you look at the save method in the block controller you see how that "magically" happens.
So the sets are made, that's good :) So then you need to go over to the render function
then go to render there you'll see
extract($this->controller->getSets());
then:
note that include($template) the extract mapped again those sets out to where they are available in the view that you are rendering, the extract is further up in the method call.
One neat thing there you see is the ob_start() and ob_end_clean(). That's how they are doing the view caching there.
That help?