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

Source for file form.class.php

Documentation is available at form.class.php

  1. <?php
  2. // *** Tangra (Application Framework and Tools for PHP)
  3. //  $Id$
  4. //
  5.  
  6. /**
  7.  * Contains class Form
  8.  *
  9.  * @package  tangra_lib
  10.  * @subpackage  form
  11.  */
  12.  
  13.  
  14. /**
  15.  * Needed for Tangra_Form_Submit_Method::POST and Tangra_Form_Submit_Method::GET
  16.  */
  17. require_once(TANGRA_MAIN_DIR.'core/tangra_form_submit_method.class.php');
  18.  
  19. /**
  20.  *
  21.  */
  22. require_once(TANGRA_MAIN_DIR.'form/fields/form_field.class.php');
  23.  
  24. /**
  25.  * Needed for automatic change of form encoding to Form::ENCODING_MULTIPART
  26.  */
  27. require_once(TANGRA_MAIN_DIR.'form/fields/file/form_field_file.class.php');
  28.  
  29.  
  30. /**
  31.  *
  32.  */
  33. require_once(TANGRA_MAIN_DIR.'web_site/web_event_simple.class.php');
  34.  
  35. /**
  36.  *
  37.  */
  38. require_once(TANGRA_MAIN_DIR.'exceptions/te_form_field_already_exists.class.php');
  39.  
  40. /**
  41.  *
  42.  */
  43. require_once(TANGRA_MAIN_DIR.'exceptions/te_form_field_not_exists.class.php');
  44.  
  45.  
  46. /**
  47.  * Class Form is used to handle most of the aspects when working with HTML forms
  48.  *
  49.  * @package  tangra_lib
  50.  * @subpackage  form
  51.  */
  52. class Form extends Tangra_Class {
  53.     /**
  54.      * Enter description here...
  55.      *
  56.      */
  57.     const ENCODING_APPLICATION = 'application/x-www-form-urlencoded';
  58.     const ENCODING_MULTIPART = 'multipart/form-data';
  59.  
  60.  
  61.     /**
  62.      * Name of the form
  63.      *
  64.      * @var string 
  65.      * @internal
  66.      *
  67.      */
  68.     private $name;
  69.  
  70.     /**
  71.      * Method of sending the form Tangra_Form_Submit_Method::POST/Tangra_Form_Submit_Method::GET
  72.      *
  73.      * @var integer 
  74.      * @internal
  75.      */
  76.     private $method;
  77.  
  78.     /**
  79.      * Encoding Form::ENCODING_APPLICATION / Form::ENCODING_MULTIPART
  80.      *
  81.      * @var unknown_type 
  82.      * @internal
  83.      */
  84.     private $enctype;
  85.  
  86.     /**
  87.      * Action - page for action attribute
  88.      *
  89.      * @var string 
  90.      * @internal
  91.      */
  92.     private $action;
  93.  
  94.     /**
  95.      * Fields of the form
  96.      *
  97.      * @var array 
  98.      * @internal
  99.      */
  100.     protected $fields;
  101.  
  102.     /**
  103.      * Status of the submission of the form
  104.      *
  105.      * @var boolean 
  106.      * @internal
  107.      */
  108.     private $form_ok;
  109.  
  110.  
  111.     /**
  112.      * Constructor
  113.      *
  114.      * @param string $name Name of the form
  115.      * @param string $action Action page
  116.      * @param integer $method Tangra_Form_Submit_Method::POST or Tangra_Form_Submit_Method::GET
  117.      * @param integer $enctype Form::ENCODING_APPLICATION or Form::ENCODING_MULTIPART
  118.      */
  119.     function __construct($name$action$method Tangra_Form_Submit_Method::POST$enctype Form::ENCODING_APPLICATION{
  120.         $this->name = $name;
  121.         $this->action = $action;
  122.         $this->method = $method;
  123.         $this->enctype = $enctype;
  124.         $this->fields = array();
  125.     }
  126.  
  127.  
  128.     /**
  129.      * Gets form name
  130.      *
  131.      * @return string 
  132.      */
  133.     public function get_name({
  134.         return $this->name;
  135.     }
  136.  
  137.  
  138.     /**
  139.      * Gets method of form submission.
  140.      *
  141.      * Returned value will Tangra_Form_Submit_Method::POST or Tangra_Form_Submit_Method::GET
  142.      *
  143.      * @return integer 
  144.      */
  145.     public function get_method({
  146.         return $this->method;
  147.     }
  148.  
  149.  
  150.     /**
  151.      * Gets encoding type
  152.      *
  153.      * @return unknown 
  154.      */
  155.     public function get_enctype({
  156.         return $this->enctype;
  157.     }
  158.  
  159.  
  160.     /**
  161.      * Gets action property of the form
  162.      *
  163.      * @return string 
  164.      */
  165.     public function get_action({
  166.         return $this->action;
  167.     }
  168.  
  169.  
  170.     /**
  171.      * Adds field to the form
  172.      *
  173.      * Please note that if the field is Form_Field_File type, encoding of the form will be automatically changed to Form::ENCODING_MULTIPART (that way form will be submited correctly)
  174.      *
  175.      * @param Form_Field $field 
  176.      * @throws TE_Form_Field_Already_Exists
  177.      */
  178.     public function add_field(Form_Field $field{
  179.         if (!array_key_exists($field->get_name()$this->fields)) {
  180.             $this->fields[$field->get_name()$field;
  181.             if ($field instanceof Form_Field_File{
  182.                 $this->set_enctype(Form::ENCODING_MULTIPART);
  183.             }
  184.         else {
  185.             throw new TE_Form_Field_Already_Exists($field->get_name());
  186.         }
  187.     }
  188.  
  189.  
  190.     /**
  191.      * Sets value of form fiels
  192.      *
  193.      * @param string $field_name Name of the field
  194.      * @param mixed $value Value of the field
  195.      * @throws TE_Form_Field_Not_Exists
  196.      */
  197.     public function set_field_value($field_name$value{
  198.         if (array_key_exists($field_name$this->fields)) {
  199.             $this->fields[$field_name]->set_value($value);
  200.         else {
  201.             throw new TE_Form_Field_Not_Exists($field_name);
  202.         }
  203.     }
  204.  
  205.  
  206.     /**
  207.      * Gets Field value
  208.      *
  209.      * @param string $field_name Name of the field
  210.      * @return mixed 
  211.      * @throws TE_Form_Field_Not_Exists
  212.      */
  213.     public function get_field_value($field_name{
  214.         if (array_key_exists($field_name$this->fields)) {
  215.             $ret $this->fields[$field_name]->get_value();
  216.         else {
  217.             throw new TE_Form_Field_Not_Exists($field_name);
  218.         }
  219.  
  220.         return $ret;
  221.     }
  222.  
  223.  
  224.     /**
  225.      * Gets field HTML value
  226.      *
  227.      * HTML value is value of the field as sent by HTTP POST/GET.
  228.      * It is not intended to be called directly by the user except in vary rare and specific circumstances.
  229.      *
  230.      * @param unknown_type $field_name 
  231.      * @return unknown 
  232.      * @throws TE_Form_Field_Not_Exists
  233.      * @internal
  234.      */
  235.     public function get_field_html_value($field_name{
  236.         if (array_key_exists($field_name$this->fields)) {
  237.             $ret $this->fields[$field_name]->get_html_value();
  238.         else {
  239.             throw new TE_Form_Field_Not_Exists($field_name);
  240.         }
  241.  
  242.         return $ret;
  243.     }
  244.  
  245.  
  246.     /**
  247.      * Returns array containing all fields.
  248.      *
  249.      * @return array 
  250.      * @internal
  251.      */
  252.     public function &get_fields({
  253.         return $this->fields;
  254.     }
  255.  
  256.  
  257.     /**
  258.      * Returns field specified by $field_name
  259.      *
  260.      * @param string $field_name name of the field
  261.      * @return Form_Field 
  262.      * @throws  TE_Form_Field_Not_Exists
  263.      */
  264.     public function &get_field($field_name{
  265.         if (array_key_exists($field_name$this->fields)) {
  266.             $ret &$this->fields[$field_name];
  267.         else {
  268.             throw new TE_Form_Field_Not_Exists($field_name);
  269.         }
  270.  
  271.         return $ret;
  272.     }
  273.  
  274.  
  275.     /**
  276.      * Translates HTML values of the fields to "application" values.
  277.      * @internal
  278.      *
  279.      */
  280.     public function translate_values_html2app({
  281.         foreach ($this->fields as $key => $value{
  282.             $this->fields[$key]->translate_value_html2app();
  283.         }
  284.     }
  285.  
  286.  
  287.     /**
  288.      * Performs value check on all fields
  289.      *
  290.      * Cycles all fields and call theirs basic_check method
  291.      *
  292.      * @return boolean 
  293.      * @internal
  294.      */
  295.     public function basic_check({
  296.         $status false;
  297.         reset($this->fields);
  298.         foreach ($this->fields as $key => $val{
  299.             $status |= $this->fields[$key]->basic_check();
  300.         }
  301.  
  302.         if ($status == false{
  303.             $this->form_ok = true;
  304.         else {
  305.             $this->form_ok = false;
  306.         }
  307.  
  308.         return $this->form_ok;
  309.     }
  310.  
  311.  
  312.     /**
  313.      * Returns status of the form
  314.      *
  315.      * Status of the form is the state of the last submission. If all fields are OK then status is true, otherwise - false
  316.      *
  317.      * @return unknown 
  318.      */
  319.     public function is_form_ok({
  320.         return $this->form_ok;
  321.     }
  322.  
  323.  
  324.     /**
  325.      * Returns name of the submit button
  326.      *
  327.      * Name of the submit button contains form name and "_submit" suffix
  328.      *
  329.      * @return string 
  330.      * @internal
  331.      */
  332.     public function get_submit_name({
  333.         return $this->get_name().'_submit';
  334.     }
  335.  
  336.  
  337.     /**
  338.      * Returns name of the submit button with "_x" suffix
  339.      *
  340.      * When submit button is image, browsers return submit name plus _x and _y suffixes (position of the click in the image)
  341.      *
  342.      * @return string 
  343.      * @internal
  344.      */
  345.     public function get_submit_x_name({
  346.         return $this->get_name().'_submit_x';
  347.     }
  348.  
  349.     /**
  350.      * Returns name of the submit button with "_y" suffix
  351.      *
  352.      * When submit button is image, browsers return submit name plus _x and _y suffixes (position of the click in the image)
  353.      *
  354.      * @return string 
  355.      * @internal
  356.      */
  357.     public function get_submit_y_name({
  358.         return $this->get_name().'_submit_y';
  359.     }
  360.  
  361.  
  362.     /**
  363.      * Transfers values from $_POST or $_GET into html_value ofd each field
  364.      *
  365.      * @param Context $context 
  366.      * @internal
  367.      */
  368.     public function capture_submit(Context $context{
  369.         if ($this->method == Tangra_Form_Submit_Method::POST{
  370.             $submit_array $context->get_var('POST');
  371.         else {
  372.             if ($this->method == Tangra_Form_Submit_Method::GET{
  373.                 $submit_array $context->get_var('GET');
  374.             }
  375.         }
  376.  
  377.         $submit_array array_merge($submit_arrayarray('_FILES' => $_FILES));
  378.  
  379.         foreach ($this->fields as $field{
  380.             $field->capture_submit($this->get_name()$submit_array);
  381.         }
  382.     }
  383.  
  384.  
  385.     /**
  386.      * Cycles all fields and calls their accept_submit method
  387.      *
  388.      * @internal
  389.      */
  390.     public function accept_submit({
  391.         foreach ($this->fields as &$field{
  392.             $field->accept_submit();
  393.         }
  394.     }
  395.  
  396.  
  397.     /**
  398.      * Checks if form is receiving submit, i.e. submit_name is present in $_POST or $_GET
  399.      *
  400.      * @param Context $context 
  401.      * @return boolean 
  402.      * @internal
  403.      */
  404.     public function is_receiving_submit(Context $context{
  405.         $ret false;
  406.         if ($this->get_method(== Tangra_Form_Submit_Method::POST{
  407.             $var_func 'exists_in_post';
  408.         else {
  409.             $var_func 'exists_in_get';
  410.         }
  411.  
  412.  
  413.         //first listening for normal submit button capture
  414.         if ($context->$var_func($this->get_submit_name()$context)) {
  415.             $ret true;
  416.         else {
  417.             //second: for image submit button capture
  418.             if ($context->$var_func($this->get_submit_x_name()$context)) {
  419.                 $ret true;
  420.             }
  421.         }
  422.  
  423.         return $ret;
  424.     }
  425.  
  426.  
  427.     /**
  428.      * Sets field error.
  429.      *
  430.      * Each form field may have potential errors. Most of them are built-in,
  431.      * for example - 'mandatory_missing" which means that field is mandatory, but POST/GET
  432.      * does not contain value for it.
  433.      * Each field may have custom errors that are not set during basic_check. In this
  434.      * case, if error condition is true, application have to call set_field_error to tell the
  435.      * field that it is in error.
  436.      *
  437.      * @param string $field_name Name of the field
  438.      * @param string $potential_error_name Name of the error
  439.      * @see Form_Field
  440.      */
  441.     public function set_field_error($field_name$potential_error_name{
  442.         if (array_key_exists($field_name$this->fields)) {
  443.             $this->fields[$field_name]->set_error($potential_error_name);
  444.         else {
  445.             throw new TE_Form_Field_Not_Exists($field_name);
  446.         }
  447.     }
  448.  
  449.  
  450.     /**
  451.      * Returns field erros (if any)
  452.      *
  453.       * @param string $field_name Name of the field
  454.      * @return array 
  455.      */
  456.     public function get_field_errors($field_name{
  457.         if (array_key_exists($field_name$this->fields)) {
  458.             $ret $this->fields[$field_name]->get_errors();
  459.         else {
  460.             throw new TE_Form_Field_Not_Exists($field_name);
  461.         }
  462.  
  463.         return $ret;
  464.     }
  465.  
  466.     /**
  467.      * Returns event of form submission
  468.      *
  469.      * @return Web_Event_Simple 
  470.      */
  471.     public function get_submit_event({
  472.         $ret $this->create_submit_event($this->get_submit_name());
  473.  
  474.         return $ret;
  475.     }
  476.  
  477.  
  478.     /**
  479.      * Returns events of form submission both for <input type="submit" and <input type="image"
  480.      *
  481.      * @return arrray Simple array of Web_Event_Simple elements
  482.      */
  483.     public function get_submit_events({
  484.         $ret[$this->get_submit_event();
  485.         $ret[$this->create_submit_event($this->get_submit_x_name());
  486.  
  487.         return $ret;
  488.     }
  489.  
  490.  
  491.     /**
  492.      * Creates submit event with capture specified by $submit_name
  493.      *
  494.      * @param string $submit_name 
  495.      * @return Web_Event_Simple 
  496.      */
  497.     private function create_submit_event($submit_name{
  498.         switch ($this->get_method()) {
  499.             case Tangra_Form_Submit_Method::POST:
  500.                 $type Tangra_Parameter_Method::POST;
  501.                 break;
  502.             case Tangra_Form_Submit_Method::GET:
  503.                 $type Tangra_Parameter_Method::GET;
  504.                 break;
  505.         }
  506.  
  507.         $ret new Web_Event_Simple($submit_name$type$submit_name);
  508.  
  509.         return $ret;
  510.     }
  511.  
  512.     /**
  513.      * Sets the name of the form
  514.      *
  515.      * Name of the form must be alphanumeric (underscore is allowed), starting with letter, 50 characters max.
  516.      * Please note that $name will be converted to lowercase.
  517.      *
  518.      * @param string $name 
  519.      * @throws Tangra_Exception
  520.      * @internal
  521.      */
  522.     protected function set_name($name{
  523.         if (ereg("^[a-z]{1}[a-z0-9_]{1,50}$"$name)) {
  524.             $this->name = strtolower($name);
  525.         else {
  526.             throw new Tangra_Exception('Invalid form name. Must be alphanumeric (underscore allowed), starting with letter, 50 characters max.');
  527.         }
  528.     }
  529.  
  530.  
  531.     /**
  532.      * Sets the method of submission
  533.      *
  534.      * Must be either Tangra_Form_Submit_Method::POST or Tangra_Form_Submit_Method::GET
  535.      *
  536.      * @param integer $method 
  537.      * @throws Tangra_Exception
  538.      * @internal
  539.      */
  540.     protected function set_method($method{
  541.         switch ($method{
  542.             case Tangra_Form_Submit_Method::POST:
  543.             case Tangra_Form_Submit_Method::GET:
  544.                 $this->method = $method;
  545.                 break;
  546.             default:
  547.                 throw new Tangra_Exception('Invalid form method.');
  548.                 break;
  549.         }
  550.  
  551.     }
  552.  
  553.  
  554.     /**
  555.      * Sets encoding type.
  556.      *
  557.      * Must be either Form::ENCODING_APPLICATION or Form::ENCODING_MULTIPART
  558.      *
  559.      * @param integer $enctype 
  560.      * @throws Tangra_Exception
  561.      * @internal
  562.      */
  563.     protected function set_enctype($enctype{
  564.         switch ($enctype{
  565.             case Form::ENCODING_APPLICATION:
  566.             case Form::ENCODING_MULTIPART:
  567.                 $this->enctype = $enctype;
  568.                 break;
  569.  
  570.             default:
  571.                 throw new Tangra_Exception('Invalid encoding type. Must be either Form::ENCODING_APPLICATION or Form::ENCODING_MULTIPART');
  572.                 break;
  573.         }
  574.  
  575.     }
  576.  
  577.  
  578.  
  579.  
  580. }