PageRenderTime 61ms CodeModel.GetById 31ms RepoModel.GetById 0ms app.codeStats 0ms

/common/lib/Form/Class.FormHandler.inc.php

https://github.com/xrg/a2billing
PHP | 383 lines | 278 code | 43 blank | 62 comment | 55 complexity | 13bd8b5bc271ab98b81ce5907187654d MD5 | raw file
Possible License(s): AGPL-1.0
  1. <?php
  2. // Please, include ../Form.inc.php instead!
  3. /** Generic form
  4. The form is the main handler of data->html interaction.
  5. */
  6. abstract class FormElemBase extends ElemBase{
  7. abstract function InFormRender(&$form);
  8. };
  9. class FormHandler extends ElemBase{
  10. public $FG_DEBUG = 0;
  11. protected $action = null;
  12. private $rights_checked = false;
  13. /** prefix all url vars with this, so that multiple forms can co-exist
  14. in the same html page! */
  15. public $prefix = '';
  16. public $a2billing; ///< Reference to an a2billing instance
  17. /** Custom elements before the form. These can be search options or anything.
  18. If they are instances of FormElemBase, they will be called with the form
  19. as a parameter, which helps a lot.
  20. */
  21. public $pre_elems = array();
  22. public $meta_elems = array(); ///< Same as pre_elems, but rendered after the form.
  23. // model-related vars
  24. /** The most important var: hold one object per field to be viewed/edited */
  25. public $model = array();
  26. public $model_name = 'Records'; ///< plural form for table
  27. public $model_name_s = 'Record'; ///< Singular form
  28. public $model_table = null; ///< the \b main table related to the model
  29. private $s_modelPK = null; ///< Cached reference to the primary key column
  30. public $views = array(); ///< Each view implements actions/views.
  31. // appearance vars
  32. public $list_class = 'cclist'; ///< class of the table used in list view
  33. public $sens; ///< sort direction, null should default to ascending
  34. public $order; ///< sort field, should match some model[]->fieldname
  35. public $cpage; ///< Current page
  36. public $ndisp; ///< Number of records to display
  37. public $default_order;
  38. public $default_sens;
  39. public $follow_params = array(); ///< Parameters to be followed accross pages
  40. public $always_follow_params = array(); ///< Parameters to follow even when crossing action
  41. //running vars
  42. protected $_dirty_vars=null; ///< all variables starting with 'prefix'. Set on init.
  43. function FormHandler($tablename=null, $inames=null, $iname=null){
  44. $this->model_table = $tablename;
  45. if ($inames) $this->model_name=$inames;
  46. if ($iname) $this->model_name_s = $iname;
  47. }
  48. /** Before this class can be initted, its rights should be
  49. proven. Any attempt to use the class w/o them will fail. */
  50. public function checkRights($rights){
  51. if (!has_rights($rights)){
  52. Header ("HTTP/1.0 401 Unauthorized");
  53. Header ("Location: PP_error.php?c=accessdenied");
  54. die();
  55. }
  56. $this->rights_checked = true;
  57. }
  58. function init($sA2Billing= null, $stdActions=true){
  59. if (!$this->rights_checked){
  60. error_log("Attempt to use FormHandler w/o rights!");
  61. die();
  62. }
  63. if ($sA2Billing)
  64. $this->a2billing= &$sA2Billing;
  65. else
  66. $this->a2billing= &A2Billing::instance();
  67. if (isset($GLOBALS['FG_DEBUG']))
  68. $this->FG_DEBUG = $GLOBALS['FG_DEBUG'];
  69. // Fill a local array with dirty versions of data..
  70. if (!$this->prefix)
  71. $this->_dirty_vars=array_merge($_GET, $_POST);
  72. else {
  73. $tmp_arr = array_merge($_GET, $_POST);
  74. $tlen=strlen($this->prefix);
  75. $this->_dirty_vars=array();
  76. // Find vars matching prefix and strip that!
  77. foreach($tmp_arr as $key => $data)
  78. if (strncmp($this->prefix,$key,$tlen)==0)
  79. $this->_dirty_vars[substr($key,$tlen)]=$data;
  80. }
  81. // set action, for a start:
  82. $this->action = $this->getpost_single('action');
  83. if ($this->action == null)
  84. $this->action = 'list';
  85. if ($this->order= $this->getpost_single('order'))
  86. $this->addFollowParam('order',$this->order);
  87. else $this->order = $this->default_order;
  88. if ($this->sens = $this->getpost_single('sens'))
  89. $this->addFollowParam('sens',$this->sens);
  90. else $this->sens = $this->default_sens;
  91. if ($this->cpage= $this->getpost_single('cpage'))
  92. $this->addFollowParam('cpage',$this->cpage);
  93. if ($this->ndisp = $this->getpost_single('ndisp'))
  94. $this->addFollowParam('ndisp',$this->ndisp);
  95. else
  96. $this->ndisp = 30;
  97. if ($stdActions){
  98. $this->views['idle'] = new IdleView();
  99. $this->views['list'] = new ListView();
  100. if (!session_readonly()){
  101. $this->views['edit'] = new EditView();
  102. $this->views['add'] = new AddView();
  103. $this->views['delete'] = new DeleteView();
  104. $this->views['object-edit'] = new ObjEditView();
  105. }
  106. $this->views['ask-add'] = new AskAddView();
  107. $this->views['ask-add2'] = new AskAdd2View();
  108. $this->views['ask-edit2'] = new AskEdit2View();
  109. $this->views['ask-edit'] = new AskEditView();
  110. $this->views['ask-del'] = new AskDelView();
  111. $this->views['details'] = new DetailsView();
  112. if ($this->FG_DEBUG)
  113. $this->views['dump-form'] = new DbgDumpView();
  114. }
  115. }
  116. /** Perform add, edit etc.
  117. If the action fails (eg. db error), this will throw an \b exception
  118. The exception message shall be human readable, that is, will be output
  119. to the reader.
  120. \return If it returns a string, that will be the url to go after here.
  121. */
  122. public function PerformAction(){
  123. if (!$this->rights_checked){
  124. error_log("Attempt to use FormHandler w/o rights!");
  125. die();
  126. }
  127. if (isset($this->views[$this->action]))
  128. $this->views[$this->action]->PerformAction($this);
  129. }
  130. /** Render the view/edit form for the HTML body */
  131. public function Render(){
  132. if (!$this->rights_checked){
  133. error_log("Attempt to use FormHandler w/o rights!");
  134. die();
  135. }
  136. foreach($this->pre_elems as $el)
  137. if ($el instanceof FormElemBase)
  138. $el->InFormRender($this);
  139. elseif ($el instanceof ElemBase)
  140. $el->Render();
  141. else if ($this->FG_DEBUG)
  142. print_r($el);
  143. if (isset($this->views[$this->action]))
  144. $this->views[$this->action]->Render($this);
  145. else{
  146. if ($this->FG_DEBUG) echo "Cannot handle action: $this->action";
  147. if ($this->FG_DEBUG>2){
  148. echo "<pre>\n";
  149. print_r($this->_dirty_vars);
  150. echo "\n</pre>\n";
  151. }
  152. }
  153. foreach($this->meta_elems as $el)
  154. if ($el instanceof FormElemBase)
  155. $el->InFormRender($this);
  156. elseif ($el instanceof ElemBase)
  157. $el->Render();
  158. else if ($this->FG_DEBUG)
  159. print_r($el);
  160. }
  161. /** Render the view/edit form for the HTML body */
  162. public function RenderSpecial($rmode,&$robj){
  163. if (!$this->rights_checked){
  164. error_log("Attempt to use FormHandler w/o rights!");
  165. die();
  166. }
  167. /* foreach($this->pre_elems as $el)
  168. if ($el instanceof FormElemBase)
  169. $el->InFormRender($this);
  170. elseif ($el instanceof ElemBase)
  171. $el->Render();
  172. else if ($this->FG_DEBUG)
  173. print_r($el);*/
  174. if (isset($this->views[$this->action]))
  175. $this->views[$this->action]->RenderSpecial($rmode,$this,$robj);
  176. else{
  177. if ($this->FG_DEBUG) echo "Cannot handle action: $this->action";
  178. if ($this->FG_DEBUG>2){
  179. print_r($this->_dirty_vars);
  180. }
  181. }
  182. /* foreach($this->meta_elems as $el)
  183. if ($el instanceof FormElemBase)
  184. $el->InFormRender($this);
  185. elseif ($el instanceof ElemBase)
  186. $el->Render();
  187. else if ($this->FG_DEBUG)
  188. print_r($el);*/
  189. }
  190. public function RenderHeadSpecial($rmode,&$robj){
  191. if (!$this->rights_checked){
  192. error_log("Attempt to use FormHandler w/o rights!");
  193. die();
  194. }
  195. if (isset($this->views[$this->action]))
  196. $this->views[$this->action]->RenderHeadSpecial($rmode,$this,$robj);
  197. }
  198. // helper functions
  199. /** Return an array with primary key field/values, used eg. by edit urls.
  200. \param $qrow an array with fields/values for the corresponding db row
  201. */
  202. public function getPKparams(array $qrow,$use_prefix= true){
  203. $ret = array();
  204. foreach($this->model as &$fld)
  205. if($fld && ($fld instanceof PKeyField)){
  206. $arr2=$fld->listHidden($qrow,$this);
  207. if (isset($arr2) && is_array($arr2)){
  208. if ($use_prefix){
  209. foreach($arr2 as $key =>$val)
  210. $ret[$this->prefix.$key]=$val;
  211. }else
  212. $ret= array_merge($ret,$arr2);
  213. }
  214. }
  215. if (count($ret)==0)
  216. throw new Exception('Model doesn\'t have a primary key!');
  217. return $ret;
  218. }
  219. /** Get pkparams from those of the url */
  220. public function getPKparamsU($use_prefix= true){
  221. return $this->getPKparams($this->_dirty_vars,$use_prefix);
  222. }
  223. /** Construct an url out of the follow parameters + some custom ones
  224. @param $arr_more An array to be added in the form ( key => data ...)
  225. @return A string like "?key1=data&key2=data..."
  226. */
  227. function gen_GetParams($arr_more = NULL,$do_amper=false){
  228. $arr = array_merge($this->always_follow_params,$this->follow_params);
  229. if (is_array($arr_more))
  230. $arr = array_merge($arr, $arr_more);
  231. $str = arr2url($arr);
  232. if (strlen($str)){
  233. if ($do_amper)
  234. $str = '&' . $str;
  235. else
  236. $str = '?' . $str;
  237. }
  238. return $str;
  239. }
  240. function gen_AllGetParams($arr_more = NULL,$do_amper=false){
  241. $arr = $this->always_follow_params;
  242. if (is_array($arr_more))
  243. $arr = array_merge($arr, $arr_more);
  244. $str = arr2url($arr);
  245. if (strlen($str)){
  246. if ($do_amper)
  247. $str = '&' . $str;
  248. else
  249. $str = '?' . $str;
  250. }
  251. return $str;
  252. }
  253. function gen_PostParams($arr_more = NULL, $do_nulls=false){
  254. $arr = array_merge($this->always_follow_params,$this->follow_params);
  255. if (is_array($arr_more))
  256. $arr = array_merge($arr, $arr_more);
  257. // unfortunately, it is hard to use CV_FOLLOWPARAMETERS here!
  258. foreach($arr as $key => $value)
  259. if ($do_nulls || $value !=NULL){
  260. ?><input type="hidden" name="<?= $key ?>" value="<?= htmlspecialchars($value) ?>" >
  261. <?php
  262. }
  263. }
  264. /** Return an URL to this page, with some extra params */
  265. function selfUrl(array $arr){
  266. return $_SERVER['PHP_SELF']. $this->gen_GetParams($arr);
  267. }
  268. /** Return a URL to the ask-edit page
  269. \param $arr The row of the query
  270. */
  271. function askeditURL(array $arr){
  272. $pkparams = $this->getPKparams($arr,true);
  273. $pkparams[$this->prefix.'action']='ask-edit';
  274. return $_SERVER['PHP_SELF'].$this->gen_AllGetParams($pkparams);
  275. }
  276. /** Generate a page element calling the graph for one of the sums
  277. \param $ind a key referencing sums[$ind]
  278. \param $type The type of the graph
  279. */
  280. function GraphUrl($grph, $alt = null){
  281. $img_url=$this->selfUrl(array('graph' =>'t','action' => $grph));
  282. if ($title)
  283. $tmp_title = $alt;
  284. else
  285. $tmp_title = _("Graph");
  286. return new StringElem("<div class=\"graph_img\"><img src=\"$img_url\" alt=\"$tmp_title\"></div>");
  287. }
  288. /// Throw away anything that could make data weird.. Sometimes too much.
  289. function sanitize_data($data){
  290. if(is_array($data)){
  291. return $data; //Need to sanatize this later
  292. }
  293. $lowerdata = strtolower ($data);
  294. $data = str_replace('--', '', $data);
  295. $data = str_replace("'", '', $data);
  296. $data = str_replace('=', '', $data);
  297. $data = str_replace(';', '', $data);
  298. //$lowerdata = str_replace('table', '', $lowerdata);
  299. //$lowerdata = str_replace(' or ', '', $data);
  300. if (!(strpos($lowerdata, ' or 1')===FALSE)){ return false;}
  301. if (!(strpos($lowerdata, ' or true')===FALSE)){ return false;}
  302. if (!(strpos($lowerdata, 'table')===FALSE)){ return false;}
  303. return $data;
  304. }
  305. function getpost_single($vname){
  306. return sanitize_data($this->_dirty_vars[$vname]);
  307. }
  308. function getpost_dirty($vname){
  309. return $this->_dirty_vars[$vname];
  310. }
  311. function getAction(){
  312. return $this->action;
  313. }
  314. function setAction($act){
  315. $this->action = $act;
  316. if ($this->FG_DEBUG && !isset($this->views[$this->action]))
  317. error_log("Action ".$this->action ." not defined!");
  318. }
  319. function addFollowParam($key,$var){
  320. $this->follow_params[$this->prefix . $key] = $var;
  321. }
  322. function addAllFollowParam($key,$var,$append_prefix=true){
  323. if ($append_prefix)
  324. $key = $this->prefix . $key;
  325. $this->always_follow_params[$key] = $var;
  326. }
  327. };
  328. ?>