1 2/* 3 +------------------------------------------------------------------------+ 4 | Phalcon Framework | 5 +------------------------------------------------------------------------+ 6 | Copyright (c) 2011-2017 Phalcon Team (https://phalconphp.com) | 7 +------------------------------------------------------------------------+ 8 | This source file is subject to the New BSD License that is bundled | 9 | with this package in the file LICENSE.txt. | 10 | | 11 | If you did not receive a copy of the license and are unable to | 12 | obtain it through the world-wide-web, please send an email | 13 | to license@phalconphp.com so we can send you a copy immediately. | 14 +------------------------------------------------------------------------+ 15 | Authors: Andres Gutierrez <andres@phalconphp.com> | 16 | Eduar Carvajal <eduar@phalconphp.com> | 17 +------------------------------------------------------------------------+ 18 */ 19 20namespace Phalcon\Tag; 21 22use Phalcon\Tag\Exception; 23use Phalcon\Tag as BaseTag; 24use Phalcon\EscaperInterface; 25 26/** 27 * Phalcon\Tag\Select 28 * 29 * Generates a SELECT html tag using a static array of values or a Phalcon\Mvc\Model resultset 30 */ 31abstract class Select 32{ 33 34 /** 35 * Generates a SELECT tag 36 * 37 * @param array parameters 38 * @param array data 39 */ 40 public static function selectField(parameters, data = null) 41 { 42 var params, name, id, value, useEmpty, code, emptyValue, emptyText, 43 options, using; 44 45 if typeof parameters != "array" { 46 let params = [parameters, data]; 47 } else { 48 let params = parameters; 49 } 50 51 if !fetch id, params[0] { 52 let params[0] = params["id"]; 53 } 54 55 /** 56 * Automatically assign the id if the name is not an array 57 */ 58 if !memstr(id, "[") { 59 if !isset params["id"] { 60 let params["id"] = id; 61 } 62 } 63 64 if !fetch name, params["name"] { 65 let params["name"] = id; 66 } else { 67 if !name { 68 let params["name"] = id; 69 } 70 } 71 72 if !fetch value, params["value"] { 73 let value = BaseTag::getValue(id, params); 74 } else { 75 unset params["value"]; 76 } 77 78 if fetch useEmpty, params["useEmpty"] { 79 80 if !fetch emptyValue, params["emptyValue"] { 81 let emptyValue = ""; 82 } else { 83 unset params["emptyValue"]; 84 } 85 86 if !fetch emptyText, params["emptyText"] { 87 let emptyText = "Choose..."; 88 } else { 89 unset params["emptyText"]; 90 } 91 92 unset params["useEmpty"]; 93 } 94 95 if !fetch options, params[1] { 96 let options = data; 97 } 98 99 if typeof options == "object" { 100 101 /** 102 * The options is a resultset 103 */ 104 if !fetch using, params["using"] { 105 throw new Exception("The 'using' parameter is required"); 106 } else { 107 if typeof using != "array" && typeof using != "object" { 108 throw new Exception("The 'using' parameter should be an array"); 109 } 110 } 111 } 112 113 unset params["using"]; 114 115 let code = BaseTag::renderAttributes("<select", params) . ">" . PHP_EOL; 116 117 if useEmpty { 118 /** 119 * Create an empty value 120 */ 121 let code .= "\t<option value=\"" . emptyValue . "\">" . emptyText . "</option>" . PHP_EOL; 122 } 123 124 if typeof options == "object" { 125 126 /** 127 * Create the SELECT's option from a resultset 128 */ 129 let code .= self::_optionsFromResultset(options, using, value, "</option>" . PHP_EOL); 130 131 } else { 132 if typeof options == "array" { 133 134 /** 135 * Create the SELECT's option from an array 136 */ 137 let code .= self::_optionsFromArray(options, value, "</option>" . PHP_EOL); 138 } else { 139 throw new Exception("Invalid data provided to SELECT helper"); 140 } 141 } 142 143 let code .= "</select>"; 144 145 return code; 146 } 147 148 /** 149 * Generate the OPTION tags based on a resultset 150 * 151 * @param \Phalcon\Mvc\Model\Resultset resultset 152 * @param array using 153 * @param mixed value 154 * @param string closeOption 155 */ 156 private static function _optionsFromResultset(resultset, using, value, closeOption) 157 { 158 var code, params, option, usingZero, usingOne, escaper, 159 optionValue, optionText, strValue, strOptionValue; 160 161 let code = ""; 162 let params = null; 163 164 if typeof using == "array" { 165 if count(using) != 2 { 166 throw new Exception("Parameter 'using' requires two values"); 167 } 168 let usingZero = using[0], usingOne = using[1]; 169 } 170 171 let escaper = <EscaperInterface> BaseTag::getEscaperService(); 172 173 for option in iterator(resultset) { 174 175 if typeof using == "array" { 176 177 if typeof option == "object" { 178 if method_exists(option, "readAttribute") { 179 let optionValue = option->readAttribute(usingZero); 180 let optionText = option->readAttribute(usingOne); 181 } else { 182 let optionValue = option->usingZero; 183 let optionText = option->usingOne; 184 } 185 } else { 186 if typeof option == "array" { 187 let optionValue = option[usingZero]; 188 let optionText = option[usingOne]; 189 } else { 190 throw new Exception("Resultset returned an invalid value"); 191 } 192 } 193 194 let optionValue = escaper->escapeHtmlAttr(optionValue); 195 let optionText = escaper->escapeHtml(optionText); 196 197 /** 198 * If the value is equal to the option's value we mark it as selected 199 */ 200 if typeof value == "array" { 201 if in_array(optionValue, value) { 202 let code .= "\t<option selected=\"selected\" value=\"" . optionValue . "\">" . optionText . closeOption; 203 } else { 204 let code .= "\t<option value=\"" . optionValue . "\">" . optionText . closeOption; 205 } 206 } else { 207 let strOptionValue = (string) optionValue, 208 strValue = (string) value; 209 if strOptionValue === strValue { 210 let code .= "\t<option selected=\"selected\" value=\"" . strOptionValue . "\">" . optionText . closeOption; 211 } else { 212 let code .= "\t<option value=\"" . strOptionValue . "\">" . optionText . closeOption; 213 } 214 } 215 } else { 216 217 /** 218 * Check if using is a closure 219 */ 220 if typeof using == "object" { 221 if params === null { 222 let params = []; 223 } 224 let params[0] = option; 225 let code .= call_user_func_array(using, params); 226 } 227 } 228 } 229 230 return code; 231 } 232 233 /** 234 * Generate the OPTION tags based on an array 235 * 236 * @param array data 237 * @param mixed value 238 * @param string closeOption 239 */ 240 private static function _optionsFromArray(var data, var value, var closeOption) 241 { 242 var strValue, strOptionValue, code, optionValue, optionText, escaped; 243 244 let code = ""; 245 246 for optionValue, optionText in data { 247 248 let escaped = htmlspecialchars(optionValue); 249 250 if typeof optionText == "array" { 251 let code .= "\t<optgroup label=\"" . escaped . "\">" . PHP_EOL . self::_optionsFromArray(optionText, value, closeOption) . "\t</optgroup>" . PHP_EOL; 252 continue; 253 } 254 255 if typeof value == "array" { 256 if in_array(optionValue, value) { 257 let code .= "\t<option selected=\"selected\" value=\"" . escaped . "\">" . optionText . closeOption; 258 } else { 259 let code .= "\t<option value=\"" . escaped . "\">" . optionText . closeOption; 260 } 261 } else { 262 263 let strOptionValue = (string) optionValue, 264 strValue = (string) value; 265 266 if strOptionValue === strValue { 267 let code .= "\t<option selected=\"selected\" value=\"" . escaped . "\">" . optionText . closeOption; 268 } else { 269 let code .= "\t<option value=\"" . escaped . "\">" . optionText . closeOption; 270 } 271 } 272 } 273 274 return code; 275 } 276} 277