I currently have a page defined which displays some data in rows. At the end of each row, there is a view which shows a total which is extracted from mysql.
$r->add('View_PointsLeft', 'pleft', 'pointsleft')
->setPoints($row['points_left'])
->setBacklog($row['backlog_ref'])
->setID($row['id'].'-points-left');
The view is defined with a template like this
<!-- points left -->
<div class='target points_left'>
<div class='sticky green'>
<div class='story'><?$backlog?></div>
<div id='<?$name?>' class='big_points big_point_margin'><?$pointsleft?></div>
</div>
</div>
<!-- end 0000-points-left -->
The data to populate the view is selected using a sql in the page which is looped through and the /lib/view/pointsleft.php code has set methods which are passed parameters from the page and update the fields in the template.
class View_PointsLeft extends View_Sticky {
function init(){
parent::init();
}
function setPoints($points){
$this->template->set('pointsleft',$points);
return $this;
}
function setBacklog($backlog){
$this->template->set('backlog',$backlog);
return $this;
}
function defaultTemplate(){
return array('view/scrumwall/pointsleft');
}
}
I want to update the database when something is changed on the page and also update the total view (to decrement the counter).
First, I'm wondering if i have approached this the wrong way (should each view should be self contained) - should i just pass the id field to the view, attach the relevant model to the view inside lib/view/pointsleft.php and call the set fields using the model values ?
Secondly, If i change it that way, does it then make it easier to update the view with a particular id when the database value is changed using ajax and if so , how do i do this ?
Thirdly - if i want to also trigger an update into the database based on an action on the client side javascript, where would i put this code e.g. in the non atk4 version of my code, i had a script called using $.post("update.php") which would update mysql. Where would i put such a script in ATK4 ?
Thanks in advance.
Update after answer from Romans
Man, ATK4 rocks ! - it does more than i expected and i was busy creating functions inside the view to populate each field name, so now having redone it using addModel,
the call from the page looks like this
$r->add('View_PointsLeft', 'pleft', 'pointsleft')
->loadData($row['id']);
the templates/view looks like this
<div id='<?$name?>' class='target points_left'>
<div class='sticky green'>
<div class='story'><?$backlog_ref?></div>
<div class='big_points big_point_margin'><?$points_left?></div>
</div>
</div>
and the lib/view code looks like this
<?php
class View_PointsLeft extends View_Sticky {
function loadData($id){
$this->setModel('Story')->loadData($id);
}
function init(){
parent::init();
}
function defaultTemplate(){
return array('view/scrumwall/pointsleft');
}
}
Update after code example from Romans
After following the code example Romans provided, i now add the URL call using jquery selectors at the bottom of my page code and do some jiggery pokery to get the task and status from the id fields (not sure about using HTML5 only stufff using data-id so just set the normal id and extract from that). Previously the drop code was in my own univ.js script but i dont have access to the php variables from there so i move it into the page
$p->js(true)->_selector('.movable')->draggable();
$p->js(true)->_selector('.target')->droppable(array(
'drop'=>$this->js(null,'function(event,ui){'.
' target=$(this).attr("id").split("-");'.
' zone=target[2];'.
' sticky=$(ui.draggable).attr("id").split("-");'.
' task=sticky[1];'.
' switch (zone) {'.
' case "verify": newStatus="V";'.
' break;'.
' case "in": newStatus="P";'.
' break;'.
' case "to": newStatus="I";'.
' break;'.
' case "done": newStatus="D";'.
' break;'.
'}
$.univ().ajaxec({ 0:"'.$this->api->getDestinationURL().'",'.
'task: task, status: newStatus }); } ')
));
and i have a if block which looks like this in the page. I add Model_Task and load the values based on the GET parameter so i then also have more information including the story it relates to so i can also update the points if the status is now done.
if($_GET['task'] && $_GET['status'])
{
$new_status=$_GET['status'];
$task_id=$_GET['task'];
$t=$p->add('Model_Task')->loadData($task_id);
$old_status=$t->get('status');
$task_points=$t->get('points');
if ($new_status<>$old_status & ($new_status=='D' | $old_status=='D'))
{
$s=$p->add('Model_Story')->loadData($t->get('story_id'));
if ($old_status='D')
{
$s->set('points_left',$s->get('points_left')+$task_points);
} else {
$s->set('points_left',$s->get('points_left')-$task_points);
}
$s->update();
$story=$t->get('story_id');
}
$t->set('status',$new_status);
$t->update();
}
i can then calculate the new number of points and update the story with points left and update the task with the new_status by setting the model values and using update().
If i now move one of the draggables, it works but opens a new window showing again the whole page and reporting
Error in AJAXec response: SyntaxError: syntax error
I think opening the extra window is because of the error but the error is something to do with the response having all the html for the whole page. I dont actually want any reload from the ajax call unless the status is a particular one.
Also the last thing i need to do is only reload one view on the page for the particular story that was updated.
I've tried by creating an array and adding the short variables to it like this when the page is first loaded
$this->pl_arr[$row['id']]=$r->add('View_PointsLeft', 'pleft', 'pointsleft')
->loadData($row['id']);
and then in the if block while processing the GET, to recall it
$pleft=$this->pl_arr[$story];
$pleft->js()->reload()->execute();
but it fails with an error
Error in AJAXec response: SyntaxError: missing ; before statement
Fatal error: Call to a member function js() on a non-object in C:\wamp\www\paperless\page\scrumwall.php on line 247
Final update
The last error is caused because i didnt use for the id in the outer div of the whole view i wanted to update. Once i changed this it is no longer null.
So the first time the page is loaded, i store all the view names in an associative array in a loop as i put them on the page
$st = $p->add('Model_Story');
$result = $st->getRows();
foreach ($result as $row) {
if (is_array($row)) {
$r=$p->add('View_Scrumwall_StoryRow')
->setWorkspace('ws-'.$row['id']);
... other code here ...
$points_left[$row['id']]=$r->add('View_PointsLeft', null, 'pointsleft')
->loadData($row['id']);
}
and then have the if GET block like this
if($_GET['task'] && $_GET['status'])
{
$new_status=$_GET['status'];
$task_id=$_GET['task'];
$t=$p->add('Model_Task')->loadData($task_id);
$old_status=$t->get('status');
$task_points=$t->get('points');
if ($new_status<>$old_status && ($new_status=='D' || $old_status=='D'))
{
$s=$p->add('Model_Story')->loadData($t->get('story_id'));
if ($new_status=='D')
{
$s->set('points_left',$s->get('points_left')-$task_points);
} else {
$s->set('points_left',$s->get('points_left')+$task_points);
}
$s->update();
$story=$t->get('story_id');
//reload the points left sticky note for the story of the task
$js[]=$points_left[$story]->js()->reload();
}
$t->set('status',$new_status);
$t->update();
$js[]=$this->js()->reload();
$this->js(null,$js)->execute();
}
Note that if I only want to update one view on the page, i can just call that chaing that object with reload and execute e.g.
$pl->js()->reload()->execute
but if i want to update several views on the page, i need to put them in an array (here called js[]) and then call execute like this - you can also see an example of this in Roman's codepad example.
$js[]=$points_left[$story]->js()->reload();
$js[]=$this->js()->reload();
$this->js(null,$js)->execute();
Problem solved with ATK4 :)
Ok, for a cleaner answer, I've put together a sample:
http://codepad.agiletoolkit.org/dragaction.html
Probably example here answers the question better.
In your case, since you are working with models, it should be easier to set this up. For the performance I decided to use 2 Listers, but in theory you can also have each person and task as a view.
I'm storing associations in session (through memorize) in your case you would store them in database.
Your structure seem to be OK. If you use setModel() on it which would have "pointsleft" and "backlog" fields, those would be automatically filled in.
I don't see how setID is defined though, but you could extend setModel, call parent and then execute that too.
Another thing I noticed, is in your template the most top-level div should have id=''. This gives your view unique selector which js() uses by default.
The .post function you are looking for is univ()->ajaxec(). It sends data to the server, receives javascript and executes it, hence the name. It behaves similarly to the form.
$mybutton->js('click')->ajaxec($this->getDestinationURL(null,array('a'=>'b'));
if($_GET['a']){
// update database
$r->getElement('plfat')->js()->reload()->execute();
}
Usually to make your code universal, you can drop this above code inside the view, but instead of 'a' you should better use the name of the object, like this. This eliminates the need for a separate page handling update:
$this->mybutton->js('click')->ajaxec($this->getDestinationURL(null,
array($this->name=>'reload'));
if($_GET[$this->name]){
// update database
$this->js()->reload()->execute();
}
Update
To clarify the sequence of how it's executed:
The page is rendered into HTML sent to your browser.
Along with the page Javascript chains are sent. All of them which define 1st argument to js, such as js(true), js('click'). in my code i have js('click') so it's sent to browser.
User performs the action such as clicking on a button. This triggers ajaxec() function
ajaxec function performs AJAX request to the page with the arguments you specify there.
PHP again is executed, but this time it goes inside if() branch. A js() without argument is created and ->execute() sends javascript to the browser.
browser receives output of the js()...->execute() and evaluates it. In our case it contains reload() for some other element.
atk4_loader widget is used to perform reload of other part of the page it sends AJAX request to server
PHP is executed with cut_object argument. It re-initializes original page, but renders only one object selectively. Output for that object is sent back to the frontend.
PHP also re-generates JS chains like in #2 but only relevant to that object
Frontend's atk4_loader receives the code, replaces HTML of the element and re-evaluates the javascript.
back to #3
It sounds like a lot of actions. In reality that's 2 requests per click and you can eliminate one if you do reload right away. Note that you can also pass arguments to reload() which you can then fetch from "get". I don't fully understand what triggers the action in your original script, perhaps we can find this out in https://chat.stackoverflow.com/rooms/2966/agile-toolkit-atk4 ?
Related
So i have an object thats draggable to multiple columns and I need to make it so that when it is dropped a variable in that object gets updated depending on what column that is, as another object manipulates that variable for display. i have been unable to get the (ondrop) event to work from the tag, and the dragula event listener's value doesnt pass me any information that would allow me to get the object. Is there anyway to force the event listener to pass the object instead of the html tags? or is there some method im missing?
I think you can update data on drop. I've done it like this:
var drake = dragula({...});
function updateMyObject(elementId, listId) {
// update the object here, for example:
if (listId === 'firstList') {
// use the element id to find the item in your object and update it
myDataObject.filter(function(x) {
return x.id === elementId;
})[0].propertyToUpdate = listId;
}
}
drake.on('drop', function(el, target, source, sibling) {
var elementId = el.id;
updateMyObject(el.id, target.id);
});
This pen may help. I'm mixing Dragula with Angular.js for the data modelling. The event needs to update the data model on drop.
http://codepen.io/chris22smith/pen/37459a002cbe6b6cd37aa5e927698fba
The only solution I have found (short from using a different drag'n'drop module) is to save the order when the user closes the page or goes to something else. Or since the drop event is catch-able, but does not seem to be able to give a class object, you can still detect when there was a change and have it update everything, however that is not the best work around as it is far more taxing on system resources than updating one variable.
Pass the order # as an attribute in your element so it's accessible in your drake.on function. With the oder# and the ID you should be able to figure out what to do with it and make the right updates on the backend.
function appoint_del(sat,sat1)
{
if(confirm("Are You Sure To delete Selected Person Details Completely?"))
{
document.form1.action="student.php?cedit="+sat+"&did="+sat1;//
document.form1.submit();//an alternative to call form
}
}
<?
if($_GET['did']!="")
{
$del=executeupdate("delete from table2 where id=".$_GET[did]);
redirect("student.php?succ=3");
}
?>
To delete the content in data base by clint I have successfully did the job but I am not completelly aware of what is happining by the statement1 document.form1.action="student.php?cedit="+st+"&did="+st1;
and statement2
document.form1.submit()
can any one explane it?
and can sugest any good reference book for clarifing these type of doubts?
document.form1.action="student.php?cedit="+sat+"&did="+sat1;
This line of JavaScript sets a html form's action to the student.php page and appends the two parameters "cedit" and "did" along with their values. I assume you have a form on your page somewhere.
document.form1.submit();
This submits that form. I don't know where to or by what method (POST, GET) because you haven't provided any details on the form. I assume it submits back to the same page because the next line is a handler:
if($_GET['did']!="")
This detects whether the form was submitted by checking if the "did" parameter is present.
$del=executeupdate("delete from table2 where id=".$_GET[did]);
This seems to execute a database query with a massive SQL injection vulnerability. Very dangerous.
redirect("student.php?succ=3");
Redirects back to the same page again, this time passing in a different "succ" parameter which I assume is handled via some other code that you haven't provided.
I am making a basic signup page using PHP Codeigniter.
On the signup page, I ask the user to select from a selection of categories (via a <select> html element). These categories are stored in a list in my MySQL Database.
My current method is to fetch this list from the DB when the user calls the function to load the page and then display it to them. However, if the user enter's incorrect data and the page must be reloaded with the validation errors, the variable that holds the data in the list seems to be cleared, and I must refetch the list data from the database before redisplaying the page.
I believe there's something in the documentation about how to set this variable to be permanently available but upon looking again, I had no luck in finding it.
Could anyone possibly point me in the right direction? It seems silly to me to have to need to refetch this data every time (I know that people won't be putting in wrong info often, but this will come in handy in a few situations).
NOTE: This is not an issue regarding remembering user selections.
this example is for a select drop down list using ci form helper
(i'm modifying this from another form so hopefully its all correct)
the Array of select values is: $categoryarray
the drop down field name is 'category'
the default value is $defaultcategory
a css class to style (bootstrap etc): $dropclass = 'class="input-medium"';
the line of code is:
form_dropdown('category',$categoryarray,set_value('category',$defaultcategory),$dropclass).form_error('category');
the form_error('category'); at the end is for showing a validation error message
and even though there is a default value - if the form fails validation from another field in the form - this will 'remember' what the user selected.
EDIT !
ok there is good and bad news.
bad news - if the categories are coming from a database then you need to get them again.
good news - CI remembers what category the user selected from the drop down list.
and the bad news actually isn't that big a deal - if you create the category array in your model. then its just one line of code to add to the validation.
// In the Model
function makedropdown() {
// get your category list
$cats = $this->getAllCategories() ;
$categoryarray = array();
// make the array
foreach ( $cats->result() as $row ) {
$categoryarray[$row->category] = $row->category ; }
return $categoryarray ;
}
someone has filled out the form, we run validation, validation fails. in the controller:
if ( $this->form_validation->run($formrules) == FALSE ) {
// get the categoryarray
$data['categoryarray'] = $this->categorymodel->makedropdown() ;
// load form again
$this->load->view( 'myform', $data ); }
So even though we are getting the categories again from the db to dynamically populate the select list - CI still remembers the users choice from the first time they did the form.
And what about a default category for the drop down? if its not going to change then it can be set as a config. if the category values are coming from a database and they can change - then the default category could be created in the model.
EDIT 2
gosh i always do this anyway so why didnt i think of it for this. so yeah this is yet another reason to make a specific method for showing your view
function _showCategoryForm(){
// get the categoryarray
$data['categoryarray'] = $this->categorymodel->makedropdown() ;
// anything else thats needed for the view
// load form view
$this->load->view( 'myform', $data ); }
NOW we dont have any repeated code, and its easy to customize the validation failure with an error message if needed.
// since i'm grinding on this - the validation should happen in a model
// and that method returns true or false
if ( $this->somemodel->validateCategoryForm() == FALSE ) {
// custom obnoxious error message
$this->formerrormessage = "What part of required is eluding you?" ;
$this->_showCategoryForm() ; }
This is much better because if the needs of your form changes - the change is only in one place. Also i added an underscore to remind us all that private methods are a good practice. And the form validation should be separate in a model, that is called by the controller.
You just need to set it as the default value, for example
<input type="text" name="username" value="<?php isset($_POST['username']) echo $username;?>" />
That way, $_POST['username'] will always be available.
I have a PHP page that uses jQuery to let a user update a particular item without needing to refresh the page. It is an availability update where they can change their availability for an event to Yes, No, or Maybe. Each time they click on the link the appropriate jQuery function is called to send data to a separate PHP file (update_avail.php) and the appropriate data is returned.
Yes
Then when clicked the params are sent to a PHP file which returns back:
No
Then, if clicked again the PHP will return:
Maybe
It all works fine and I'm loving it.
BUT--
I also have a total count at the bottom of the page that is PHP code to count the total number of users that have selected Yes as their availability by simply using:
<?php count($event1_accepted); ?>
How can I make it so that if a user changes their availability it will also update the count without needing to refresh the page?
My thoughts so far are:
$var = 1;
while ($var > 0) {
count($day1_accepted);
$var = 0;
exit;
}
Then add a line to my 'update_avail.php' (which gets sent data from the jQuery function) to make $var = 1
Any help would be great. I would like to stress that my main strength is PHP, not jQuery, so a PHP solution would be preferred, but if necessary I can tackle some simple jQuery.
Thanks!
In the response from update_avail.php return a JSON object with both your replacement html and your new counter value.
Or to keep it simple, if they click "yes" incriment the counter, if they click No or maybe and their previous action wasn't No or Maybe decrease the counter.
Assuming your users are logged into the system I'd recommend having a status field in the user table, perhaps as an enum with "offline", "available", "busy", "unavailable" or something similar and use the query the number of available users whilst updating the users status.
If you were to do this you'd need to include in extend your methods containing session)start() and session_destroy() to change the availability of the user to available / offline respectively
The best way is the one suggested by Scuzzy with some improvements.
In your php, get the count from the database and return a JSON object like:
{ count: 123, html: 'Yes' }
In your page, in the ajax response you get the values and update the elements:
...
success: function(data) {
$("#linkPlaceholder").html(data.html);
$("#countPlaceholder").html(data.count);
}
...
Ever stumbled on a tutorial that you feel is of great value but not quite explained properly? That's my dilemma. I know THIS TUTORIAL has some value but I just can't get it.
Where do you call each function?
Which function should be called
first and which next, and which
third?
Will all functions be called in all files in an application?
Does anyone know of a better way cure the "Back Button Blues"?
I'm wondering if this will stir some good conversation that includes the author of the article. The part I'm particularly interested in is controlling the back button in order to prevent form duplicate entries into a database when the back button is pressed. Basically, you want to control the back button by calling the following three functions during the execution of the scripts in your application. In what order exactly to call the functions (see questions above) is not clear from the tutorial.
All forwards movement is performed by
using my scriptNext function. This is
called within the current script in
order to activate the new script.
function scriptNext($script_id)
// proceed forwards to a new script
{
if (empty($script_id)) {
trigger_error("script id is not defined", E_USER_ERROR);
} // if
// get list of screens used in this session
$page_stack = $_SESSION['page_stack'];
if (in_array($script_id, $page_stack)) {
// remove this item and any following items from the stack array
do {
$last = array_pop($page_stack);
} while ($last != $script_id);
} // if
// add next script to end of array and update session data
$page_stack[] = $script_id;
$_SESSION['page_stack'] = $page_stack;
// now pass control to the designated script
$location = 'http://' .$_SERVER['HTTP_HOST'] .$script_id;
header('Location: ' .$location);
exit;
} // scriptNext
When any script has finished its
processing it terminates by calling my
scriptPrevious function. This will
drop the current script from the end
of the stack array and reactivate the
previous script in the array.
function scriptPrevious()
// go back to the previous script (as defined in PAGE_STACK)
{
// get id of current script
$script_id = $_SERVER['PHP_SELF'];
// get list of screens used in this session
$page_stack = $_SESSION['page_stack'];
if (in_array($script_id, $page_stack)) {
// remove this item and any following items from the stack array
do {
$last = array_pop($page_stack);
} while ($last != $script_id);
// update session data
$_SESSION['page_stack'] = $page_stack;
} // if
if (count($page_stack) > 0) {
$previous = array_pop($page_stack);
// reactivate previous script
$location = 'http://' .$_SERVER['HTTP_HOST'] .$previous;
} else {
// no previous scripts, so terminate session
session_unset();
session_destroy();
// revert to default start page
$location = 'http://' .$_SERVER['HTTP_HOST'] .'/index.php';
} // if
header('Location: ' .$location);
exit;
} // scriptPrevious
Whenever a script is activated, which
can be either through the scriptNext
or scriptPrevious functions, or
because of the BACK button in the
browser, it will call the following
function to verify that it is the
current script according to the
contents of the program stack and take
appropriate action if it is not.
function initSession()
// initialise session data
{
// get program stack
if (isset($_SESSION['page_stack'])) {
// use existing stack
$page_stack = $_SESSION['page_stack'];
} else {
// create new stack which starts with current script
$page_stack[] = $_SERVER['PHP_SELF'];
$_SESSION['page_stack'] = $page_stack;
} // if
// check that this script is at the end of the current stack
$actual = $_SERVER['PHP_SELF'];
$expected = $page_stack[count($page_stack)-1];
if ($expected != $actual) {
if (in_array($actual, $page_stack)) {// script is within current stack, so remove anything which follows
while ($page_stack[count($page_stack)-1] != $actual ) {
$null = array_pop($page_stack);
} // while
$_SESSION['page_stack'] = $page_stack;
} // if
// set script id to last entry in program stack
$actual = $page_stack[count($page_stack)-1];
$location = 'http://' .$_SERVER['HTTP_HOST'] .$actual;
header('Location: ' .$location);
exit;
} // if
... // continue processing
} // initSession
The action taken depends on whether
the current script exists within the
program stack or not. There are three
possibilities:
The current script is not in the $page_stack array, in which case it is
not allowed to continue. Instead it is
replaced by the script which is at the
end of the array.
The current script is in the
$page_stack array, but it is not the
last entry. In this case all
following entries in the array are
removed.
The current script is the last entry
in the $page_stack array. This is
the expected situation. Drinks all
round!
That is a good discussion but more to the point you should be looking into Post Redirect Get (PRG) also known as "Get after Post."
http://www.theserverside.com/patterns/thread.tss?thread_id=20936
If you do not understand my article then you should take a close look at figure 1 which depicts a typical scenario where a user passes through a series of screens – logon, menu, list, search, add and update. When I describe a movement of FORWARDS I mean that the current screen is suspended while a new screen is activated. This happens when the user presses a link in the current screen. When I describe a movement as BACKWARDS I mean that the user terminates the current screen (by pressing the QUIT or SUBMIT button) and returns to the previous screen, which resumes processing from where it left off. This may include incorporating any changes made in the screen which has just been terminated.
This is where maintaining a page stack which is independent of the browser history is crucial – the page stack is maintained by the application and is used to verify all requests. These may be valid as far as the browser is concerned, but may be identified by the application as invalid and dealt with accordingly.
The page stack is maintained by two functions:
scriptNext() is used to process a
FORWARDS movement, which adds a new
entry at the end of the stack and
activates the new entry.
scriptPrevious() is used to process
a BACKWARDS movement, which removes
the last entry from the stack and
re-activates the previous entry.
Now take the situation in the example where the user has navigated to page 4 of the LIST screen, gone into the ADD screen, then returned to page 5 of the LIST screen. The last action in the ADD screen was to press the SUBMIT button which used the POST method to send details to the server which were added to the database, after which it terminated automatically and returned to the LIST screen.
If you therefore press the BACK button while in page 5 of the LIST screen the browser history will generate a request for the last action on the ADD screen, which was a POST. This is a valid request as far as the browser is concerned, but is not as far as the application is concerned. How can the application decide that the request is invalid? By checking with its page stack. When the ADD screen was terminated its entry was deleted from the page stack, therefore any request for a screen which is not in the page stack can always be treated as invalid. In this case the invalid request can be redirected to the last entry in the stack.
The answers to your questions should therefore be obvious:
Q: Where do you call each function?
A: You call the scriptNext()
function when the user chooses to
navigate forwards to a new screen,
and call the scriptPrevious()
function when the user terminates
the current screen.
Q: Which function should be called
first and which next, and which
third?
A: Each function is called in
response to an action chosen by the
user, so only one function is used
at a time.
Q: Will all functions be called in
all files in an application?
A: All functions should be available
in all files in an application, but
only called when chosen by the user.
It you wish to see these ideas in action then you can download my sample application.
The part I'm particularly interested in is controlling the back button in order to prevent form duplicate entries into a database when the back button is pressed.
Your premise is wrong. There is no such thing as "Back Button Blues", if you design your application as a web application. If you design your application without any server side state, you will never run into this problem in the first case. This minimalistic approach to web applications works remarkably well, and is usually known as REST.
# troelskn
If you design your application without any server side state ....
It is not possible to design an effective application which does not have state, otherwise all you have is a collection of individual pages which do not communicate with each other. As maintaining state on the client is fraught with issues there is no effective alternative but to maintain state on the server.
#Marston.
I solved the problem with post/redirect/get but I believe the tutorial has some merit and perhaps Tony Marston can elaborate on it. And how it could be used to solve not necessarily my particular problem but perhaps something similar. Or how is it better than post/redirect/get if the functions can in fact be used in solving my particular problem. I think this will be a good addition to the community here.
if ($_POST) {
process_input($_POST);
header("Location: $_SERVER[HTTP_REFERER]");
exit;
}