tangra logo
   
[ class tree: tangra_lib ] [ index: tangra_lib ] [ all elements ]
 

Source for file gform_ctrl.class.php

Documentation is available at gform_ctrl.class.php

  1. <?php
  2. // *** Tangra (Application Framework and Tools for PHP)
  3. // $Id$
  4. //
  5.  
  6.  
  7. /**
  8.  * Contains class GForm_Ctrl
  9.  *
  10.  * @package  tangra_lib
  11.  * @subpackage  form
  12.  */
  13.  
  14.  
  15. /**
  16.  *
  17.  */
  18. require_once(TANGRA_MAIN_DIR.'core/vars_manager.class.php');
  19.  
  20. /**
  21.  *
  22.  */
  23. require_once(TANGRA_MAIN_DIR.'form/guardable_form.class.php');
  24.  
  25. /**
  26.  *
  27.  */
  28. require_once(TANGRA_MAIN_DIR.'form/form_ctrl.class.php');
  29.  
  30.  
  31. /**
  32.  * Controller for Guarder_Form
  33.  *
  34.  * @package  tangra_lib
  35.  * @subpackage  form
  36.  */
  37. abstract class GForm_Ctrl extends Form_Ctrl {
  38.     /**
  39.      * Holds Form_Guard object
  40.      *
  41.      * @var Form_Guard 
  42.      * @internal
  43.      */
  44.     protected $form_guard;
  45.  
  46.     /**
  47.      * Holds Vars_Manager object
  48.      *
  49.      * @var Vars_Manager 
  50.      * @internal
  51.      */
  52.     private $vm;
  53.  
  54.     /**
  55.      * Array of processed states ids
  56.      *
  57.      * @var array 
  58.      * @internal
  59.      */
  60.     private $processed_states;
  61.  
  62.     /**
  63.      * Array containing guarded_pairs
  64.      *
  65.      * @var array 
  66.      * @internal
  67.      */
  68.     private $form_guarded_pairs;
  69.  
  70.  
  71.     private $permanent_external_params = array();
  72.  
  73.  
  74.  
  75.     /**
  76.      * Constructor
  77.      *
  78.      * @param stying $<ystem_name Name of the controller
  79.      * @param Vars_Manager $vm Permanent Vars_Manager that will be used. Session of Thread VM
  80.      */
  81.     function __construct($system_nameVars_Manager $vm{
  82.         parent::__construct($system_name);
  83.  
  84.         $this->set_vm($vm);
  85.  
  86.         $this->init_guard_vars();
  87.     }
  88.  
  89.  
  90.     /**
  91.      * Prepares form for show
  92.      * @internal
  93.      *
  94.      */
  95.     public function prepare_for_show({
  96.         parent::prepare_for_show();
  97.         $form_id $this->form_guard->new_guard_pair();
  98.         $this->set_permanent_external_params($form_id);
  99.     }
  100.  
  101.  
  102.     /**
  103.      * Processes submit
  104.      *
  105.      * @param Web_Context $context 
  106.      * @return integer  Returned value will be Form_Ctrl::SUBMIT_RESULT_ERROR or Form_Ctrl::SUBMIT_RESULT_OK
  107.      * @internal
  108.      */
  109.     public function process_submit(Web_Context $context{
  110.         $this->form->capture_submit($context);
  111.         $form_id $this->form->get_field_html_value('form_id');
  112.  
  113.         $this->permanent_external_params = $this->retrieve_permanent_external_params($form_id);
  114.  
  115.         if ($this->form_guard->is_fresh_submit($form_id)) {
  116.             $ret $this->handle_fresh_submit($form_id);
  117.         else {
  118.             $ret $this->handle_repeated_submit($form_id);
  119.         }
  120.  
  121.         return $ret;
  122.     }
  123.  
  124.  
  125.     /**
  126.      * Initialization of guard pairs array and permanent variable
  127.      *
  128.      * @internal
  129.      */
  130.     protected function init_guard_vars({
  131.         $vm $this->get_vm();
  132.  
  133.         if (!$vm->is_var_registered($this->get_system_name().'_form_guarded_pairs')) {
  134.  
  135.             $vm->register_var($this->get_system_name().'_form_guarded_pairs');
  136.             $vm->set_var($this->get_system_name().'_form_guarded_pairs'new Vars_Manager());
  137.         }
  138.         $this->form_guarded_pairs = &$vm->get_var($this->get_system_name().'_form_guarded_pairs');
  139.  
  140.  
  141.         if (!$vm->is_var_registered($this->get_system_name().'_processed_states')) {
  142.             $vm->register_var($this->get_system_name().'_processed_states');
  143.             $vm->set_var($this->get_system_name().'_processed_states'new Vars_Manager());
  144.         }
  145.         $this->processed_states = &$vm->get_var($this->get_system_name().'_processed_states');
  146.  
  147.         $this->form_guard = new Form_Guard($this->form$this->form_guarded_pairs);
  148.     }
  149.  
  150.  
  151.     /**
  152.      * Called right after submit is accepted.
  153.      *
  154.      * After a form is submited and basic_check is passed, Form->accept_submit() method is called
  155.      * to transfer values from $_POST to fields' values. Immediately after that
  156.      * $this->on_accepted_submit() is called in order to give the user a chance to manipulate
  157.      * fields values if there is such need (which happens vary rare, only in low level code. If required
  158.      * in high level code that may indicate that there is some design flaw).
  159.      *
  160.      */
  161.     protected function on_accepted_submit({
  162.  
  163.     }
  164.  
  165.  
  166.     /**
  167.      * Place for your own processing of the validated form data.
  168.      *
  169.      * <p>Called after form is passed successfully basic_check and also on_good_submit returned true.</p>
  170.      * <p>For the sake of example - this method is used in form controllers with object to save the object in the DB.
  171.      * Normally is not used in high level code.</p>
  172.      *
  173.      */
  174.     protected function on_process_submit({
  175.  
  176.     }
  177.  
  178.     /**
  179.      * Sets Vars_Manager that will be used
  180.      *
  181.      * @param Vars_Manager $vm 
  182.      * @internal
  183.      */
  184.     protected function set_vm(Vars_Manager $vm{
  185.         $this->vm = $vm;
  186.     }
  187.  
  188.  
  189.     /**
  190.      * Returns reference to used Vars_Mananger
  191.      *
  192.      * @return Vars_Manager 
  193.      * @internal
  194.      */
  195.     protected function get_vm({
  196.         return $this->vm;
  197.     }
  198.  
  199.  
  200.     /**
  201.      * Returns copy of used Vars_Mananger
  202.      *
  203.      * @return Vars_Mananger 
  204.      * @internal
  205.      */
  206.     protected function query_vm({
  207.         return $this->vm;
  208.     }
  209.  
  210.  
  211.     /**
  212.      * Handles fresh submit of the form.
  213.      *
  214.      * GForm_Ctrl guarantees that <b>only one</b> submit of the form (with same data, for
  215.      * example when visitor to your site clicks multiple times on submit button) will be processed.
  216.      * That means, for example, that you will not get multiple rows in your database with same data,
  217.      * just because visitor was impatient and pumped same form again and again.
  218.      *
  219.      *
  220.      *
  221.      * @param unknown_type $form_id 
  222.      * @return unknown 
  223.      * @internal
  224.      * @see GForm_Ctrl::handle_repeated_submit()
  225.      */
  226.     private function handle_fresh_submit($form_id{
  227.         //it is first submit of this form
  228.         $this->form->basic_check();
  229.         $this->form->accept_submit();
  230.         $this->on_accepted_submit();
  231.  
  232.         if ($this->form->is_form_ok()) {
  233.             if ($this->on_good_submit($this->form)) {
  234.                 $this->on_process_submit();
  235.                 $this->add_processed_state($form_idtrue);
  236.  
  237.                 $ret Form_Ctrl::SUBMIT_RESULT_OK;
  238.             else {
  239.                 $this->on_bad_submit();
  240.                 $this->add_processed_state($form_idfalse);
  241.  
  242.                 $ret Form_Ctrl::SUBMIT_RESULT_ERROR;
  243.             }
  244.         else {
  245.             $this->on_bad_submit();
  246.             $this->add_processed_state($form_idfalse);
  247.  
  248.             $ret Form_Ctrl::SUBMIT_RESULT_ERROR;
  249.         }
  250.  
  251.         return $ret;
  252.     }
  253.  
  254.  
  255.     /**
  256.      * Handles repeated submit.
  257.      *
  258.      * <p>A submit is considered repeated when form_guard detects that same data is submited more than once.
  259.      * In this case "same data" means not just the casual form data but also form_id and guard_value
  260.      * hidden fields. handle_repeated_submit is smart enough to detect state of the last fresh submit
  261.      * (@see GForm_Ctrl::handle_fresh_submit) and to return it.</p>
  262.      * <p>Usualy repeated submits happens when impatient visitor to your site clicks submit button on a
  263.      * form multile times. Other case is when page that has received submit is refreshed with F5 or
  264.      * "Refresh" button of the browser.</p>
  265.      * <p>From application point of view repeated submits are just "skipped", i.e. there are no calls of
  266.      * on_process_submit</p>
  267.      *<p>From visitor's point of view repeated submit is 100% transparent - he/she does not notice any
  268.      * additional activities
  269.      *
  270.      * @param unknown_type $form_id 
  271.      * @return unknown 
  272.      * @internal
  273.      */
  274.     private function handle_repeated_submit($form_id{
  275.         //second+ submit. Cause: double click on submit button, or refreshed page
  276.         if ($this->is_already_processed($form_id)) {
  277.             //we have already processed this event, just show them last result
  278.             $last_state $this->get_processed_state($form_id);
  279.             if ($last_state{
  280.                 $ret Form_Ctrl::SUBMIT_RESULT_OK;
  281.             else {
  282.                 $this->form->basic_check();
  283.                 $this->form->accept_submit();
  284.                 $this->on_accepted_submit();
  285.  
  286.                 if ($this->form->is_form_ok()) {
  287.                     $this->on_good_submit($this->form);
  288.                 }
  289.  
  290.                 $ret Form_Ctrl::SUBMIT_RESULT_ERROR;
  291.             }
  292.  
  293.         else {
  294.             // we never generated such guarded pair, so we assume
  295.             // that this is hackers activity and we are closing application immediatly.
  296.             // exception can be changed to more concrete class if you intend to intercept it
  297.             throw new Tangra_Exception('Form protection detected abnormal condition.');
  298.         }
  299.  
  300.         return $ret;
  301.  
  302.     }
  303.  
  304.  
  305.     /**
  306.      * Checks if this submit is already processed
  307.      *
  308.      * @param string $form_id 
  309.      * @return boolean 
  310.      * @internal
  311.      */
  312.     private function is_already_processed($form_id{
  313.         return $this->processed_states->is_var_registered($form_id.'_processed');
  314.     }
  315.  
  316.  
  317.     /**
  318.      * Adds new processed state
  319.      *
  320.      * @param string $form_id 
  321.      * @param boolean $state 
  322.      * @internal
  323.      */
  324.     private function add_processed_state($form_id$state{
  325.         $this->processed_states->register_var($form_id.'_processed');
  326.         $this->processed_states->set_var($form_id.'_processed'$state);
  327.     }
  328.  
  329.  
  330.     /**
  331.      * Returns processed state for submit identified with <var>$form_id</var>
  332.      *
  333.      * @param string $form_id 
  334.      * @return boolean 
  335.      */
  336.     private function get_processed_state($form_id{
  337.         return $this->processed_states->get_var($form_id.'_processed');
  338.     }
  339.  
  340.  
  341.     /**
  342.      * Stores external parameters in vars manager.
  343.      *
  344.      * @param string $form_id 
  345.      * @internal
  346.      */
  347.     private function set_permanent_external_params($form_id{
  348.         $vm $this->get_vm();
  349.  
  350.         $external_params_var_name GForm_Ctrl::compose_external_params_var_name();
  351.  
  352.         if (!$vm->is_var_registered($external_params_var_name)) {
  353.             $vm->register_var($external_params_var_name);
  354.         }
  355.  
  356.         $tmp array($form_id => $this->permanent_external_params);
  357.         $vm->set_var($external_params_var_name$tmp);
  358.     }
  359.  
  360.  
  361.     /**
  362.      * Retrieves stored external parameters
  363.      *
  364.      * @param string $form_id 
  365.      * @return array 
  366.      * @internal
  367.      */
  368.     private function retrieve_permanent_external_params($form_id{
  369.         $vm $this->get_vm();
  370.  
  371.         $external_params_var_name GForm_Ctrl::compose_external_params_var_name();
  372.  
  373.         $ret array();
  374.  
  375.         if ($vm->is_var_registered($external_params_var_name)) {
  376.             $arr $vm->get_var($external_params_var_name);
  377.  
  378.             foreach($arr as $form_id_key => $ep_arr{
  379.                 if ($form_id_key == $form_id{
  380.                     $ret $ep_arr;
  381.                     break;
  382.                 }
  383.             }
  384.         }
  385.  
  386.         return $ret;
  387.     }
  388.  
  389.  
  390.     /**
  391.      * Composes string with external parameters vars name.
  392.      *
  393.      * @return string 
  394.      * @internal
  395.      */
  396.     private function compose_external_params_var_name({
  397.         return $this->get_system_name().'_external_params';
  398.     }
  399.  
  400.  
  401.     /**
  402.      * Sets parameter that will be stored in vars manager and automatically retrieved after each submit
  403.      *
  404.      * @param string $param_name Parameter name
  405.      * @param mixed $param_value Parameter actual value
  406.      */
  407.     public function set_permanent_external_param($param_name$param_value$do_export false{
  408.         $this->permanent_external_params[$param_namearray('value' => $param_value'do_export' => $do_export);
  409.     }
  410.  
  411.  
  412.     /**
  413.      * Returns value of previosly set external parameter
  414.      *
  415.      * @param string $param_name Parameter name
  416.      * @param boolean $forgiving If true this function will return false if there is no parameter with name $param_name. Otherwise will throw exception. Default is false.
  417.      * @return mixed 
  418.      */
  419.     public function get_permanent_external_param($param_name$forgiving false{
  420.         if (!array_key_exists($param_name$this->permanent_external_params)) {
  421.             if (!$forgiving{
  422.                 throw new Tangra_Exception('Such param does not exists: '.$param_name);
  423.             }
  424.             $ret false;
  425.         else {
  426.             $ret $this->permanent_external_params[$param_name]['value'];
  427.         }
  428.  
  429.         return $ret;
  430.     }
  431.  
  432.  
  433.     /**
  434.      * Gets TPLE_Exports for the form
  435.      *
  436.      * @return TPLE_Exports 
  437.      */
  438.     public function get_tple_exports({
  439.         foreach($this->permanent_external_params as $key => $par{
  440.             if ($par['do_export']{
  441.                 $this->export($this->form->get_name().'_pep_'.$key$par['value']);
  442.             }
  443.         }
  444.  
  445.         return parent::get_tple_exports();
  446.     }
  447. }