PageRenderTime 53ms CodeModel.GetById 24ms RepoModel.GetById 1ms app.codeStats 0ms

/atk4-addons/mvc/Form/Field/reference.php

https://github.com/git86/todo
PHP | 246 lines | 147 code | 32 blank | 67 comment | 19 complexity | 7ff5f874e97bdd7e123aabfdac961173 MD5 | raw file
Possible License(s): AGPL-3.0
  1. <?php
  2. /*
  3. * Base class for reference-showing fields
  4. */
  5. class Form_Field_reference extends Form_Field_ValueList {
  6. /*
  7. Reference field enhances ValueList with support for references. In other words - list of values could rely on
  8. other model to get itself from.
  9. This class will also provide API interface to set up behavor for adding new values, however in order to
  10. see them - you would have to use one of field types which supports it, such as "autocomplete" or "reference_pluss"
  11. */
  12. function setController($c){
  13. parent::setController($c);
  14. $this->dictionary($this->getController()->getModel());
  15. return $this;
  16. }
  17. function dictionary($d=null){
  18. if(!is_null($d))$this->dictionary=$d;
  19. return $this->dictionary;
  20. }private $dictionary=null;
  21. function setValueList($model_or_list, $field_definition=null){
  22. if($model_or_list instanceof FieldDefinition){
  23. // ommit first argument
  24. $field_definition=$model_or_list;
  25. $model_or_list=$field->refModel();
  26. }
  27. if($field_definition){
  28. // find out if this field can be empty
  29. $this->required=$field_definition->required();
  30. }
  31. if(!is_object($model_or_list)){
  32. return parent::setValueList($model_or_list);
  33. }else{
  34. // we have been passed a Model, we can do more with this
  35. if(!($model_or_list instanceof AbstractModel))
  36. throw new BaseException('Only Model or Array can be specified to this function');
  37. $this->dictionary=$model_or_list;
  38. $this->allowAdd(method_exists($this->dictionary,'addDefaultEntity'));
  39. }
  40. return $this;
  41. }
  42. function allowAdd($b=null){
  43. if(!is_null($b))$this->allow_add=$b;
  44. return $this->allow_add;
  45. }private $allow_add=false;
  46. function emptyValue($val){
  47. $this->empty_value=$val;
  48. return $this;
  49. }
  50. // This field enhances value list by allowing to store "Model" object inside
  51. // $this->value_list. You can access the field with getValueList and setValueList functions
  52. // and also you can still use arays.
  53. // Should we allow user to add new field? This will be automatically initialised if you
  54. // initialise this field with controller.
  55. public $required=false;
  56. // If field can be empty then use this. You can set this argument to string, which will be
  57. // displayed instead of empty field. $this->allow_empty="Select category";
  58. public $empty_value='';
  59. // For dropdown - display empty value
  60. // ====== Redefine the following functions if necessary ========
  61. function getShowAddDialogJS($js=null){
  62. // This function have to use provided JS which will be executed when client desires
  63. // to add new element
  64. if(!$js)$js=$this->js();
  65. return $js->atk4_reference('showAddDialog',$this->getAddURL());
  66. }
  67. function addEntry($value){
  68. // This function is called when new entry needs to be added. Value can be either
  69. // empty or it can contain array with key=>value.
  70. return $this->getDictionary()->addDefaultEntity($value);
  71. }
  72. // ===== Call the following functions ========
  73. function includeDictionary(array $fields=array()){
  74. /*
  75. * We are already including providing form with id=>value from the model. However sometimes
  76. * it makes sense to provide additional values from the referred model.
  77. *
  78. * You can then use univ().bindFillInFields() to automatically fill-in the fields whenever current
  79. * field is changed.
  80. */
  81. $fields[]='id';
  82. foreach($fields as $key=>$row){
  83. if(is_numeric($key))$key=$row;
  84. $res[$key]=$row;
  85. }
  86. $o=$this->dictionary()->getRows($res);
  87. $res=array();
  88. foreach($o as $row){
  89. $id=$row['id'];
  90. unset($row['id']);
  91. $res[$id]=$row;
  92. }
  93. $this->setProperty('rel',json_encode($res));
  94. return $this;
  95. }
  96. function validate(){
  97. $list=$this->getValueList();
  98. if(!$list || !$this->value)return parent::validate();
  99. if(!isset($list[$this->value])){
  100. if($this->api->isAjaxOutput()){
  101. /*
  102. $this->ajax()->displayAlert($this->short_name.": Please select to continue")
  103. ->execute();
  104. */
  105. $this->owner->showAjaxError($this,'Please select value from the list');
  106. }
  107. $this->owner->errors[$this->short_name]="Please value from the list";
  108. }
  109. return parent::validate();
  110. }
  111. function getInput($attr=array()){
  112. $list=$this->getValueList();
  113. $output=$this->getTag('select',array_merge(array(
  114. 'name'=>$this->name,
  115. 'id'=>$this->name,
  116. ),
  117. $attr,
  118. $this->attr)
  119. );
  120. foreach($list as $value=>$descr){
  121. // Check if a separator is not needed identified with _separator<
  122. $descr = trim($descr);
  123. if ($value === '_separator') {
  124. $output.=
  125. $this->getTag('option',array(
  126. 'disabled'=>'disabled',
  127. ))
  128. .htmlspecialchars($descr)
  129. .$this->getTag('/option');
  130. } else {
  131. $output.=
  132. $this->getOption($value)
  133. .htmlspecialchars($descr)
  134. .$this->getTag('/option');
  135. }
  136. }
  137. $output.=$this->getTag('/select');
  138. return $output;
  139. }
  140. function getOption($value){
  141. return $this->getTag('option',array(
  142. 'value'=>$value,
  143. 'selected'=>$value == $this->value
  144. ));
  145. }
  146. function getValueList(){
  147. if(!$this->dictionary()){
  148. return parent::getValueList();
  149. }
  150. $res=array();
  151. $o=array();
  152. if(!is_null($this->empty_value)){
  153. $o=$o+array(''=>array('name'=>$this->empty_value));
  154. }
  155. /*
  156. // REVERT back sorting (from #1345) becasue it breaks vat rates
  157. $q=$this->dictionary->resetQuery('get_rows')->dsql('get_rows');
  158. $this->dictionary->setQueryFields('get_rows',$this->dictionary()->getListFields());
  159. if(method_exists($this->dictionary(),'getSortColumn') && $sc=$this->dictionary()->getSortColumn()){
  160. $desc=false;
  161. if($sc[0]=='-'){
  162. $desc=true;$sc=substr($sc,1);
  163. }
  164. if($this->dictionary()->fieldExists($sc)){
  165. $this->dictionary()->setOrder('get_rows',$sc,$desc);
  166. }
  167. }
  168. $o=$o+$q->do_getAllHash();
  169. */
  170. // getRows do not support sorting, so we do ourselves.
  171. // This is to avoid changing getRows in the core, which would have much more severe
  172. // impact on the system!!
  173. // TODO: refactor during next major release
  174. $data=$this->dictionary()->getRows($this->dictionary()->getListFields());
  175. // fucking good to sort in some certainly the-only-really-ever-needed order. yeah, in the core library.
  176. //usort($data,'usort_cmp');
  177. $o=$o+$data;
  178. foreach($o as $row){
  179. @$res[$row['id']]=isset($row['name'])?$row['name']:$row['id'];
  180. }
  181. return $res;
  182. }
  183. private function getShortName(){
  184. //return $this->short_name;
  185. $r=explode('_',$this->short_name);
  186. if(is_numeric($r[count($r)-1]))array_pop($r);
  187. return join('_',$r);
  188. }
  189. function set($value){
  190. if($value==='')$value=null;
  191. parent::set($value);
  192. }
  193. function setDictionary($model){
  194. /*
  195. * Please refer to a model descendand of Model_dictionary
  196. */
  197. throw new BaseException('please use standard method setValueList and pass array, controller or fieldDefinition');
  198. $this->dictionary=$model;
  199. return $this;
  200. }
  201. function render(){
  202. $this->js(true)
  203. ->_load('ui.atk4_reference')
  204. ->atk4_reference();
  205. parent::render();
  206. }
  207. }
  208. function usort_cmp($a,$b){
  209. return strcasecmp($a['name'],$b['name']);
  210. }