├── .gitignore ├── Field ├── AbstractField.php ├── AbstractGroup.php ├── CheckboxField.php ├── CheckboxGroup.php ├── CountrySelectField.php ├── EmailField.php ├── HiddenField.php ├── NumberField.php ├── PasswordField.php ├── ProvinceSelectField.php ├── RadioGroup.php ├── SelectField.php ├── StateSelectField.php ├── TextField.php └── TextareaField.php ├── Form.php ├── Formjack.php ├── LICENSE ├── Layout ├── AbstractLayout.php └── DefaultLayout.php ├── README.md ├── Rule ├── AbstractRule.php ├── Checked.php ├── CompanyVAT.php ├── Email.php ├── Length.php ├── NotEmpty.php ├── Numeric.php └── When.php └── Validator.php /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | -------------------------------------------------------------------------------- /Field/AbstractField.php: -------------------------------------------------------------------------------- 1 | setName($name) 37 | ->setOptions($options) 38 | ->init() 39 | ; 40 | } 41 | 42 | /** 43 | * @return string 44 | */ 45 | public function getId() { 46 | return $this->name; 47 | } 48 | 49 | /** 50 | * @param string $name 51 | * @return $this 52 | */ 53 | public function setName($name) { 54 | $this->name = str_replace(' ', '_', $name); 55 | 56 | return $this; 57 | } 58 | 59 | /** 60 | * @return string 61 | */ 62 | public function getName() { 63 | return "{$this->parent->getName()}[{$this->name}]"; 64 | } 65 | 66 | /** 67 | * @param array $options 68 | * @return $this 69 | */ 70 | public function setOptions(array $options) { 71 | $this->options = $options; 72 | 73 | return $this; 74 | } 75 | 76 | /** 77 | * @param string $name 78 | * @param mixed $value 79 | * @return $this 80 | */ 81 | public function addOption($name, $value) { 82 | $this->options[$name] = $value; 83 | 84 | return $this; 85 | } 86 | 87 | /** 88 | * @param string $name 89 | * @param mixed $default 90 | * @return mixed 91 | */ 92 | public function getOption($name, $default = null) { 93 | return (isset($this->options[$name]))? $this->options[$name] : $default ; 94 | } 95 | 96 | /** 97 | * @return array 98 | */ 99 | public function getOptions() { 100 | return $this->options; 101 | } 102 | 103 | /** 104 | * @param mixed $value 105 | * @return $this 106 | */ 107 | public function setValue($value) { 108 | $this->value = $value; 109 | 110 | return $this; 111 | } 112 | 113 | /** 114 | * @return mixed 115 | */ 116 | public function getValue() { 117 | return $this->value; 118 | } 119 | 120 | /** 121 | * @param Form $parent 122 | * @return $this 123 | */ 124 | public function setParent(Form $parent) { 125 | $this->parent = $parent; 126 | 127 | return $this; 128 | } 129 | 130 | /** 131 | * @return Form 132 | */ 133 | public function getParent() { 134 | return $this->parent; 135 | } 136 | 137 | /** 138 | * @return bool 139 | */ 140 | public function hasLabel() { 141 | return ($this->getOption('label', null))? true : false ; 142 | } 143 | 144 | /** 145 | * @return string 146 | */ 147 | public function getLabel() { 148 | return $this->getOption('label', ''); 149 | } 150 | 151 | /** 152 | * @return bool 153 | */ 154 | public function hasRules() { 155 | return ($this->getOption('rules', null))? true : false ; 156 | } 157 | 158 | /** 159 | * @return AbstractRule[] 160 | */ 161 | public function getRules() { 162 | return $this->getOption('rules', array()); 163 | } 164 | 165 | /** 166 | * @return bool 167 | */ 168 | public function hasErrors() { 169 | if ($this->parent->hasErrors()) { 170 | return array_key_exists($this->name, $this->parent->getErrors()); 171 | } 172 | 173 | return false; 174 | } 175 | 176 | /** 177 | * @return array 178 | */ 179 | public function getErrors() { 180 | $errors = $this->parent->getErrors(); 181 | return isset($errors[$this->name])? $errors[$this->name] : array(); 182 | } 183 | 184 | /** 185 | * @param array $merge 186 | * @return string 187 | */ 188 | public function getAttributes(array $merge = array()) { 189 | $result = ""; 190 | $attributes = $this->getOption('attributes', array()); 191 | if (!empty($merge)) { 192 | $attributes = array_merge_recursive($attributes, $merge); 193 | } 194 | if (!empty($attributes)) { 195 | foreach ($attributes as $name => $value) { 196 | if (is_array($value)) { 197 | $value = implode(' ', $value); 198 | } 199 | $result .= " {$name}=\"{$value}\""; 200 | } 201 | } 202 | 203 | return $result; 204 | } 205 | 206 | abstract public function init(); 207 | 208 | abstract public function bind($value); 209 | 210 | abstract public function render(array $attributes = array()); 211 | 212 | } -------------------------------------------------------------------------------- /Field/AbstractGroup.php: -------------------------------------------------------------------------------- 1 | choices = $this->getOption('choices', array()); 17 | } 18 | 19 | /** 20 | * @param array $attributes 21 | * @return string 22 | */ 23 | public function render(array $attributes = array()) { 24 | return ''; 25 | } 26 | 27 | /** 28 | * @return array 29 | */ 30 | public function getChoices() { 31 | return $this->choices; 32 | } 33 | 34 | /** 35 | * @param string $choice 36 | * @return bool 37 | */ 38 | protected function isValidChoice($choice) { 39 | return array_key_exists($choice, $this->choices); 40 | } 41 | 42 | /** 43 | * @param string $choice 44 | * @param array $attributes 45 | */ 46 | abstract public function renderChoice($choice, array $attributes = array()); 47 | 48 | } -------------------------------------------------------------------------------- /Field/CheckboxField.php: -------------------------------------------------------------------------------- 1 | setValue((bool)$this->getOption('value', false)); 19 | } 20 | 21 | /** 22 | * @param string|null $value 23 | * @return $this 24 | */ 25 | public function bind($value) { 26 | return $this->setValue($value == 1); 27 | } 28 | 29 | /** 30 | * @param array $attributes 31 | * @return string 32 | */ 33 | public function render(array $attributes = array()) { 34 | return "getName()}\" value=\"1\" {$this->getAttributes($attributes)} {$this->checked()} />"; 35 | } 36 | 37 | /** 38 | * @return string 39 | */ 40 | private function checked() { 41 | return $this->getValue()? 'checked' : '' ; 42 | } 43 | 44 | } -------------------------------------------------------------------------------- /Field/CheckboxGroup.php: -------------------------------------------------------------------------------- 1 | setValue($this->getOption('value', array())); 21 | } 22 | 23 | /** 24 | * @param array|null $choices 25 | * @return $this 26 | */ 27 | public function bind($choices) { 28 | $value = array(); 29 | $choices = is_array($choices)? $choices : array() ; 30 | foreach ($choices as $choice => $label) { 31 | if ($this->isValidChoice($choice)) { 32 | $value[] = $choice; 33 | } 34 | } 35 | 36 | return $this->setValue($value); 37 | } 38 | 39 | /** 40 | * {@inheritdoc} 41 | * @return string 42 | */ 43 | public function renderChoice($choice, array $attributes = array()) { 44 | return "getName()}[{$choice}]\" value=\"1\" {$this->getAttributes($attributes)} {$this->checked($choice)} />"; 45 | } 46 | 47 | /** 48 | * @param string $choice 49 | * @return string 50 | */ 51 | private function checked($choice) { 52 | return in_array($choice, $this->value)? 'checked' : '' ; 53 | } 54 | 55 | } -------------------------------------------------------------------------------- /Field/CountrySelectField.php: -------------------------------------------------------------------------------- 1 | choices = array( 13 | 'AF' => 'Afghanistan', 14 | 'AX' => 'Aland Islands', 15 | 'AL' => 'Albania', 16 | 'DZ' => 'Algeria', 17 | 'AS' => 'American Samoa', 18 | 'AD' => 'Andorra', 19 | 'AO' => 'Angola', 20 | 'AI' => 'Anguilla', 21 | 'AQ' => 'Antarctica', 22 | 'AG' => 'Antigua And Barbuda', 23 | 'AR' => 'Argentina', 24 | 'AM' => 'Armenia', 25 | 'AW' => 'Aruba', 26 | 'AU' => 'Australia', 27 | 'AT' => 'Austria', 28 | 'AZ' => 'Azerbaijan', 29 | 'BS' => 'Bahamas', 30 | 'BH' => 'Bahrain', 31 | 'BD' => 'Bangladesh', 32 | 'BB' => 'Barbados', 33 | 'BY' => 'Belarus', 34 | 'BE' => 'Belgium', 35 | 'BZ' => 'Belize', 36 | 'BJ' => 'Benin', 37 | 'BM' => 'Bermuda', 38 | 'BT' => 'Bhutan', 39 | 'BO' => 'Bolivia', 40 | 'BA' => 'Bosnia And Herzegovina', 41 | 'BW' => 'Botswana', 42 | 'BV' => 'Bouvet Island', 43 | 'BR' => 'Brazil', 44 | 'IO' => 'British Indian Ocean Territory', 45 | 'BN' => 'Brunei Darussalam', 46 | 'BG' => 'Bulgaria', 47 | 'BF' => 'Burkina Faso', 48 | 'BI' => 'Burundi', 49 | 'KH' => 'Cambodia', 50 | 'CM' => 'Cameroon', 51 | 'CA' => 'Canada', 52 | 'CV' => 'Cape Verde', 53 | 'KY' => 'Cayman Islands', 54 | 'CF' => 'Central African Republic', 55 | 'TD' => 'Chad', 56 | 'CL' => 'Chile', 57 | 'CN' => 'China', 58 | 'CX' => 'Christmas Island', 59 | 'CC' => 'Cocos (Keeling) Islands', 60 | 'CO' => 'Colombia', 61 | 'KM' => 'Comoros', 62 | 'CG' => 'Congo', 63 | 'CD' => 'Congo, Democratic Republic', 64 | 'CK' => 'Cook Islands', 65 | 'CR' => 'Costa Rica', 66 | 'CI' => 'Cote D\'Ivoire', 67 | 'HR' => 'Croatia', 68 | 'CU' => 'Cuba', 69 | 'CY' => 'Cyprus', 70 | 'CZ' => 'Czech Republic', 71 | 'DK' => 'Denmark', 72 | 'DJ' => 'Djibouti', 73 | 'DM' => 'Dominica', 74 | 'DO' => 'Dominican Republic', 75 | 'EC' => 'Ecuador', 76 | 'EG' => 'Egypt', 77 | 'SV' => 'El Salvador', 78 | 'GQ' => 'Equatorial Guinea', 79 | 'ER' => 'Eritrea', 80 | 'EE' => 'Estonia', 81 | 'ET' => 'Ethiopia', 82 | 'FK' => 'Falkland Islands (Malvinas)', 83 | 'FO' => 'Faroe Islands', 84 | 'FJ' => 'Fiji', 85 | 'FI' => 'Finland', 86 | 'FR' => 'France', 87 | 'GF' => 'French Guiana', 88 | 'PF' => 'French Polynesia', 89 | 'TF' => 'French Southern Territories', 90 | 'GA' => 'Gabon', 91 | 'GM' => 'Gambia', 92 | 'GE' => 'Georgia', 93 | 'DE' => 'Germany', 94 | 'GH' => 'Ghana', 95 | 'GI' => 'Gibraltar', 96 | 'GR' => 'Greece', 97 | 'GL' => 'Greenland', 98 | 'GD' => 'Grenada', 99 | 'GP' => 'Guadeloupe', 100 | 'GU' => 'Guam', 101 | 'GT' => 'Guatemala', 102 | 'GG' => 'Guernsey', 103 | 'GN' => 'Guinea', 104 | 'GW' => 'Guinea-Bissau', 105 | 'GY' => 'Guyana', 106 | 'HT' => 'Haiti', 107 | 'HM' => 'Heard Island & Mcdonald Islands', 108 | 'VA' => 'Holy See (Vatican City State)', 109 | 'HN' => 'Honduras', 110 | 'HK' => 'Hong Kong', 111 | 'HU' => 'Hungary', 112 | 'IS' => 'Iceland', 113 | 'IN' => 'India', 114 | 'ID' => 'Indonesia', 115 | 'IR' => 'Iran, Islamic Republic Of', 116 | 'IQ' => 'Iraq', 117 | 'IE' => 'Ireland', 118 | 'IM' => 'Isle Of Man', 119 | 'IL' => 'Israel', 120 | 'IT' => 'Italy', 121 | 'JM' => 'Jamaica', 122 | 'JP' => 'Japan', 123 | 'JE' => 'Jersey', 124 | 'JO' => 'Jordan', 125 | 'KZ' => 'Kazakhstan', 126 | 'KE' => 'Kenya', 127 | 'KI' => 'Kiribati', 128 | 'KR' => 'Korea', 129 | 'XK' => 'Kosovo', 130 | 'KW' => 'Kuwait', 131 | 'KG' => 'Kyrgyzstan', 132 | 'LA' => 'Lao People\'s Democratic Republic', 133 | 'LV' => 'Latvia', 134 | 'LB' => 'Lebanon', 135 | 'LS' => 'Lesotho', 136 | 'LR' => 'Liberia', 137 | 'LY' => 'Libyan Arab Jamahiriya', 138 | 'LI' => 'Liechtenstein', 139 | 'LT' => 'Lithuania', 140 | 'LU' => 'Luxembourg', 141 | 'MO' => 'Macao', 142 | 'MK' => 'Macedonia', 143 | 'MG' => 'Madagascar', 144 | 'MW' => 'Malawi', 145 | 'MY' => 'Malaysia', 146 | 'MV' => 'Maldives', 147 | 'ML' => 'Mali', 148 | 'MT' => 'Malta', 149 | 'MH' => 'Marshall Islands', 150 | 'MQ' => 'Martinique', 151 | 'MR' => 'Mauritania', 152 | 'MU' => 'Mauritius', 153 | 'YT' => 'Mayotte', 154 | 'MX' => 'Mexico', 155 | 'FM' => 'Micronesia, Federated States Of', 156 | 'MD' => 'Moldova', 157 | 'MC' => 'Monaco', 158 | 'MN' => 'Mongolia', 159 | 'ME' => 'Montenegro', 160 | 'MS' => 'Montserrat', 161 | 'MA' => 'Morocco', 162 | 'MZ' => 'Mozambique', 163 | 'MM' => 'Myanmar', 164 | 'NA' => 'Namibia', 165 | 'NR' => 'Nauru', 166 | 'NP' => 'Nepal', 167 | 'NL' => 'Netherlands', 168 | 'AN' => 'Netherlands Antilles', 169 | 'NC' => 'New Caledonia', 170 | 'NZ' => 'New Zealand', 171 | 'NI' => 'Nicaragua', 172 | 'NE' => 'Niger', 173 | 'NG' => 'Nigeria', 174 | 'NU' => 'Niue', 175 | 'NF' => 'Norfolk Island', 176 | 'MP' => 'Northern Mariana Islands', 177 | 'NO' => 'Norway', 178 | 'OM' => 'Oman', 179 | 'PK' => 'Pakistan', 180 | 'PW' => 'Palau', 181 | 'PS' => 'Palestinian Territory, Occupied', 182 | 'PA' => 'Panama', 183 | 'PG' => 'Papua New Guinea', 184 | 'PY' => 'Paraguay', 185 | 'PE' => 'Peru', 186 | 'PH' => 'Philippines', 187 | 'PN' => 'Pitcairn', 188 | 'PL' => 'Poland', 189 | 'PT' => 'Portugal', 190 | 'PR' => 'Puerto Rico', 191 | 'QA' => 'Qatar', 192 | 'RE' => 'Reunion', 193 | 'RO' => 'Romania', 194 | 'RU' => 'Russian Federation', 195 | 'RW' => 'Rwanda', 196 | 'BL' => 'Saint Barthelemy', 197 | 'SH' => 'Saint Helena', 198 | 'KN' => 'Saint Kitts And Nevis', 199 | 'LC' => 'Saint Lucia', 200 | 'MF' => 'Saint Martin', 201 | 'PM' => 'Saint Pierre And Miquelon', 202 | 'VC' => 'Saint Vincent And Grenadines', 203 | 'WS' => 'Samoa', 204 | 'SM' => 'San Marino', 205 | 'ST' => 'Sao Tome And Principe', 206 | 'SA' => 'Saudi Arabia', 207 | 'SN' => 'Senegal', 208 | 'RS' => 'Serbia', 209 | 'SC' => 'Seychelles', 210 | 'SL' => 'Sierra Leone', 211 | 'SG' => 'Singapore', 212 | 'SK' => 'Slovakia', 213 | 'SI' => 'Slovenia', 214 | 'SB' => 'Solomon Islands', 215 | 'SO' => 'Somalia', 216 | 'ZA' => 'South Africa', 217 | 'GS' => 'South Georgia And Sandwich Isl.', 218 | 'ES' => 'Spain', 219 | 'LK' => 'Sri Lanka', 220 | 'SD' => 'Sudan', 221 | 'SR' => 'Suriname', 222 | 'SJ' => 'Svalbard And Jan Mayen', 223 | 'SZ' => 'Swaziland', 224 | 'SE' => 'Sweden', 225 | 'CH' => 'Switzerland', 226 | 'SY' => 'Syrian Arab Republic', 227 | 'TW' => 'Taiwan', 228 | 'TJ' => 'Tajikistan', 229 | 'TZ' => 'Tanzania', 230 | 'TH' => 'Thailand', 231 | 'TL' => 'Timor-Leste', 232 | 'TG' => 'Togo', 233 | 'TK' => 'Tokelau', 234 | 'TO' => 'Tonga', 235 | 'TT' => 'Trinidad And Tobago', 236 | 'TN' => 'Tunisia', 237 | 'TR' => 'Turkey', 238 | 'TM' => 'Turkmenistan', 239 | 'TC' => 'Turks And Caicos Islands', 240 | 'TV' => 'Tuvalu', 241 | 'UG' => 'Uganda', 242 | 'UA' => 'Ukraine', 243 | 'AE' => 'United Arab Emirates', 244 | 'GB' => 'United Kingdom', 245 | 'US' => 'United States', 246 | 'UM' => 'United States Outlying Islands', 247 | 'UY' => 'Uruguay', 248 | 'UZ' => 'Uzbekistan', 249 | 'VU' => 'Vanuatu', 250 | 'VE' => 'Venezuela', 251 | 'VN' => 'Viet Nam', 252 | 'VG' => 'Virgin Islands, British', 253 | 'VI' => 'Virgin Islands, U.S.', 254 | 'WF' => 'Wallis And Futuna', 255 | 'EH' => 'Western Sahara', 256 | 'YE' => 'Yemen', 257 | 'ZM' => 'Zambia', 258 | 'ZW' => 'Zimbabwe' 259 | ); 260 | } 261 | 262 | } -------------------------------------------------------------------------------- /Field/EmailField.php: -------------------------------------------------------------------------------- 1 | getName()}\" value=\"{$this->getValue()}\" {$this->getAttributes($attributes)} />"; 12 | } 13 | 14 | } -------------------------------------------------------------------------------- /Field/HiddenField.php: -------------------------------------------------------------------------------- 1 | getName()}\" value=\"{$this->getValue()}\" {$this->getAttributes($attributes)} />"; 12 | } 13 | 14 | } -------------------------------------------------------------------------------- /Field/NumberField.php: -------------------------------------------------------------------------------- 1 | getName()}\" value=\"{$this->getValue()}\" {$this->getAttributes($attributes)} />"; 12 | } 13 | 14 | } -------------------------------------------------------------------------------- /Field/PasswordField.php: -------------------------------------------------------------------------------- 1 | getName()}\" value=\"{$this->getValue()}\" {$this->getAttributes($attributes)} />"; 12 | } 13 | 14 | } -------------------------------------------------------------------------------- /Field/ProvinceSelectField.php: -------------------------------------------------------------------------------- 1 | choices = array( 13 | 'BC' => 'British Columbia', 14 | 'ON' => 'Ontario', 15 | 'NL' => 'Newfoundland and Labrador', 16 | 'NS' => 'Nova Scotia', 17 | 'PE' => 'Prince Edward Island', 18 | 'NB' => 'New Brunswick', 19 | 'QC' => 'Quebec', 20 | 'MB' => 'Manitoba', 21 | 'SK' => 'Saskatchewan', 22 | 'AB' => 'Alberta', 23 | 'NT' => 'Northwest Territories', 24 | 'NU' => 'Nunavut', 25 | 'YT' => 'Yukon Territory' 26 | ); 27 | } 28 | 29 | } -------------------------------------------------------------------------------- /Field/RadioGroup.php: -------------------------------------------------------------------------------- 1 | value = $this->getOption('value', null); 13 | } 14 | 15 | /** 16 | * @param string|null $choice 17 | * @return $this 18 | */ 19 | public function bind($choice) { 20 | return ($this->isValidChoice($choice))? $this->setValue($choice) : $this->setValue(null) ; 21 | } 22 | 23 | /** 24 | * {@inheritdoc} 25 | * @return string 26 | */ 27 | public function renderChoice($choice, array $attributes = array()) { 28 | return "getName()}\" value=\"{$choice}\" {$this->getAttributes($attributes)} {$this->checked($choice)}/>"; 29 | } 30 | 31 | /** 32 | * @param string $choice 33 | * @return string 34 | */ 35 | private function checked($choice) { 36 | return ($choice == $this->getValue())? 'checked' : '' ; 37 | } 38 | 39 | } -------------------------------------------------------------------------------- /Field/SelectField.php: -------------------------------------------------------------------------------- 1 | multiselect) { 27 | $value = (is_array($value))? $value : array($value); 28 | return parent::setValue($value); 29 | } 30 | return parent::setValue($value); 31 | } 32 | 33 | /** 34 | * @return void 35 | */ 36 | public function init() { 37 | $this->choices = $this->getOption('choices', array()); 38 | $this->multiselect = (bool)$this->getOption('multiselect', false); 39 | if ($this->multiselect) { 40 | $this->emptyValue = null; 41 | $this->setValue($this->getOption('value', array())); 42 | } else { 43 | $this->emptyValue = $this->getOption('empty_value', null); 44 | if ($this->emptyValue) { 45 | $this->setValue($this->getOption('value', '')); 46 | } else { 47 | $this->setValue($this->getOption('value', null)); 48 | } 49 | } 50 | } 51 | 52 | /** 53 | * @param string|array|null $value 54 | * @return $this 55 | */ 56 | public function bind($value) { 57 | if ($this->multiselect) { 58 | if ($value) { 59 | $valid = array(); 60 | $value = (is_array($value))? $value : array($value); 61 | foreach ($value as $single) { 62 | if ($this->exists($single)) { 63 | $valid[] = $single; 64 | } 65 | } 66 | return $this->setValue($valid); 67 | } 68 | return $this->setValue(array()); 69 | } else { 70 | if (!is_array($value) && $this->exists($value)) { 71 | return $this->setValue($value); 72 | } 73 | return $this->setValue(null); 74 | } 75 | } 76 | 77 | /** 78 | * @param array $attributes 79 | * @return string 80 | */ 81 | public function render(array $attributes = array()) { 82 | $html = ""; 83 | $multiple = ($this->multiselect)? 'multiple' : ''; 84 | $name = ($this->multiselect)? $this->getName() . '[]' : $this->getName(); 85 | $html .= ""; 94 | 95 | return $html; 96 | } 97 | 98 | /** 99 | * @param string $choice 100 | * @return bool 101 | */ 102 | private function selected($choice) { 103 | if (is_array($this->getValue())) { 104 | return in_array($choice, $this->getValue()); 105 | } 106 | return ($choice == $this->getValue()); 107 | } 108 | 109 | /** 110 | * @param string $choice 111 | * @return bool 112 | */ 113 | private function exists($choice) { 114 | if ($choice == '' && $this->emptyValue !== null) { 115 | return true; 116 | } 117 | return array_key_exists($choice, $this->choices); 118 | } 119 | 120 | } -------------------------------------------------------------------------------- /Field/StateSelectField.php: -------------------------------------------------------------------------------- 1 | choices = array( 13 | 'AK' => 'Alaska', 14 | 'AL' => 'Alabama', 15 | 'AR' => 'Arkansas', 16 | 'AZ' => 'Arizona', 17 | 'CA' => 'California', 18 | 'CO' => 'Colorado', 19 | 'CT' => 'Connecticut', 20 | 'DE' => 'Delaware', 21 | 'FL' => 'Florida', 22 | 'GA' => 'Georgia', 23 | 'HI' => 'Hawaii', 24 | 'IA' => 'Iowa', 25 | 'ID' => 'Idaho', 26 | 'IL' => 'Illinois', 27 | 'IN' => 'Indiana', 28 | 'KS' => 'Kansas', 29 | 'KY' => 'Kentucky', 30 | 'LA' => 'Louisiana', 31 | 'MA' => 'Massachusetts', 32 | 'MD' => 'Maryland', 33 | 'ME' => 'Maine', 34 | 'MI' => 'Michigan', 35 | 'MN' => 'Minnesota', 36 | 'MO' => 'Missouri', 37 | 'MS' => 'Mississippi', 38 | 'MT' => 'Montana', 39 | 'NC' => 'North Carolina', 40 | 'ND' => 'North Dakota', 41 | 'NE' => 'Nebraska', 42 | 'NH' => 'New Hampshire', 43 | 'NJ' => 'New Jersey', 44 | 'NM' => 'New Mexico', 45 | 'NV' => 'Nevada', 46 | 'NY' => 'New York', 47 | 'OH' => 'Ohio', 48 | 'OK' => 'Oklahoma', 49 | 'OR' => 'Oregon', 50 | 'PA' => 'Pennsylvania', 51 | 'RI' => 'Rhode Island', 52 | 'SC' => 'South Carolina', 53 | 'SD' => 'South Dakota', 54 | 'TN' => 'Tennessee', 55 | 'TX' => 'Texas', 56 | 'UT' => 'Utah', 57 | 'VA' => 'Virginia', 58 | 'VT' => 'Vermont', 59 | 'WA' => 'Washington', 60 | 'WI' => 'Wisconsin', 61 | 'WV' => 'West Virginia', 62 | 'WY' => 'Wyoming' 63 | ); 64 | } 65 | 66 | } -------------------------------------------------------------------------------- /Field/TextField.php: -------------------------------------------------------------------------------- 1 | setValue($this->getOption('value', '')); 12 | } 13 | 14 | /** 15 | * @param string $value 16 | * @return $this 17 | */ 18 | public function bind($value) { 19 | return $this->setValue($value); 20 | } 21 | 22 | /** 23 | * @param array $attributes 24 | * @return string 25 | */ 26 | public function render(array $attributes = array()) { 27 | return "getName()}\" value=\"{$this->getValue()}\" {$this->getAttributes($attributes)} />"; 28 | } 29 | 30 | } -------------------------------------------------------------------------------- /Field/TextareaField.php: -------------------------------------------------------------------------------- 1 | getName()}\" {$this->getAttributes($attributes)}>{$this->getValue()}"; 12 | } 13 | 14 | } -------------------------------------------------------------------------------- /Form.php: -------------------------------------------------------------------------------- 1 | setName($name) 37 | ->setFields($fields) 38 | ->setLayout(new DefaultLayout()) 39 | ; 40 | } 41 | 42 | /** 43 | * @param string $name 44 | */ 45 | public function setName($name) { 46 | $this->name = str_replace(' ', '_', $name); 47 | 48 | return $this; 49 | } 50 | 51 | /** 52 | * @return string 53 | */ 54 | public function getName() { 55 | return $this->name; 56 | } 57 | 58 | /** 59 | * @param array $fields 60 | */ 61 | public function setFields(array $fields) { 62 | foreach ($fields as $field) { 63 | $this->addField($field); 64 | } 65 | 66 | return $this; 67 | } 68 | 69 | /** 70 | * @param AbstractField $field 71 | * @return $this 72 | */ 73 | public function addField(AbstractField $field) { 74 | $field->setParent($this); 75 | $this->fields[$field->getId()] = $field; 76 | 77 | return $this; 78 | } 79 | 80 | /** 81 | * @param string $name 82 | * @return $this 83 | */ 84 | public function removeField($name) { 85 | if (isset($this->fields[$name])) { 86 | unset($this->fields[$name]); 87 | } 88 | 89 | return $this; 90 | } 91 | 92 | /** 93 | * @return array 94 | */ 95 | public function getFields() { 96 | return $this->fields; 97 | } 98 | 99 | /** 100 | * @param AbstractLayout $layout 101 | * @return $this 102 | */ 103 | public function setLayout(AbstractLayout $layout) { 104 | $this->layout = $layout; 105 | 106 | return $this; 107 | } 108 | 109 | /** 110 | * @param array $data 111 | * @return $this 112 | */ 113 | public function bind(array $data = array()) { 114 | foreach ($this->fields as $field) { 115 | if (isset($data[$field->getId()])) { 116 | $field->bind($data[$field->getId()]); 117 | } else { 118 | $field->bind(null); 119 | } 120 | } 121 | 122 | return $this; 123 | } 124 | 125 | /** 126 | * @return bool 127 | */ 128 | public function isValid() { 129 | foreach ($this->fields as $field) { 130 | $result = Validator::validateField($field); 131 | if (!$result->valid) { 132 | $this->errors[$field->getId()] = $result->trace; 133 | } 134 | } 135 | 136 | return empty($this->errors); 137 | } 138 | 139 | /** 140 | * @return bool 141 | */ 142 | public function hasErrors() { 143 | return !empty($this->errors); 144 | } 145 | 146 | /** 147 | * @return array 148 | */ 149 | public function getErrors() { 150 | return $this->errors; 151 | } 152 | 153 | /** 154 | * @return array 155 | */ 156 | public function getData() { 157 | $result = array(); 158 | foreach ($this->fields as $field) { 159 | $result[$field->getId()] = $field->getValue(); 160 | } 161 | 162 | return $result; 163 | } 164 | 165 | /** 166 | * @return void 167 | */ 168 | public function render() { 169 | foreach ($this->fields as $name => $instance) { 170 | $this->renderField($name); 171 | } 172 | } 173 | 174 | /** 175 | * @return void 176 | */ 177 | public function renderField($name) { 178 | if (isset($this->fields[$name])) { 179 | echo $this->layout->renderField($this->fields[$name]); 180 | } 181 | } 182 | 183 | } 184 | -------------------------------------------------------------------------------- /Formjack.php: -------------------------------------------------------------------------------- 1 | "; 15 | if ($field instanceof \Formjack\Field\CheckboxField) { 16 | if ($field->hasLabel()) { 17 | $html .= ""; 18 | } else { 19 | $html .= $field->render(); 20 | } 21 | } elseif ($field instanceof \Formjack\Field\AbstractGroup) { 22 | if ($field->hasLabel()) { 23 | $html .= ""; 24 | } 25 | foreach ($field->getChoices() as $choice => $label) { 26 | $html .= ""; 27 | } 28 | } else { 29 | if ($field->hasLabel()) { 30 | $html .= ""; 31 | } 32 | $html .= $field->render(); 33 | } 34 | if ($field->hasErrors()) { 35 | $html .= ""; 40 | } 41 | $html .= ""; 42 | 43 | return $html; 44 | } 45 | 46 | } -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Formjack 2 | 3 | Formjack is a open source PHP library that helps you to build and validate custom forms with ease. Keep in mind that this library is still in heavy development stage which means that the API and their implementation could change slightly in the future (but we really try to avoid that as much as possible). 4 | 5 | ## Installation 6 | 7 | Step 1: **Clone the repository** 8 | 9 | ``` 10 | $ git clone git@github.com:Slicejack/Formjack.git path/to/project/lib 11 | ``` 12 | 13 | Step 2: **Include Formjack.php** 14 | 15 | ``` 16 | 'First Name:' 42 | ) 43 | ), 44 | new TextField( 45 | 'last_name', 46 | array( 47 | 'label' => 'Last Name:' 48 | ) 49 | ), 50 | new EmailField( 51 | 'email', 52 | array( 53 | 'label' => 'Email:' 54 | ) 55 | ), 56 | new TextareaField( 57 | 'message', 58 | array( 59 | 'label' => 'Message:' 60 | ) 61 | ) 62 | )); 63 | ``` 64 | 65 | You can also add fields by calling the **addField** method. That method can also be chained which allows you to add multiple fields in a row. 66 | 67 | ``` 68 | addField(new TextField( /* ... */ )) 74 | ->addField(new TextField( /* ... */ )) 75 | ; 76 | ``` 77 | 78 | ## Validation rules 79 | 80 | Formjack library allows you to validate the form data as well, so let's add few validation rules to our form fields. 81 | 82 | ``` 83 | 'First Name:', 95 | 'rules' => array( 96 | new NotEmpty('Please enter your first name.') 97 | ) 98 | ) 99 | ), 100 | new TextField( 101 | 'last_name', 102 | array( 103 | 'label' => 'Last Name:', 104 | 'rules' => array( 105 | new NotEmpty('Please enter your last name.') 106 | ) 107 | ) 108 | ), 109 | new EmailField( 110 | 'email', 111 | array( 112 | 'label' => 'Email:', 113 | 'rules' => array( 114 | new NotEmpty('Please enter your email.'), 115 | new Email('Please enter a valid email.') 116 | ) 117 | ) 118 | ), 119 | new TextareaField( 120 | 'message', 121 | array( 122 | 'label' => 'Message:' 123 | ) 124 | ) 125 | )); 126 | ``` 127 | 128 | ## Rendering 129 | 130 | Let's now render the form within a view file. Keep in mind that the view file needs to be aware of the form instance you've just created. Implementation of that may vary depending on what platform or framework you are using. 131 | 132 | ``` 133 |
134 | render(); ?> 135 | 136 |
137 | ``` 138 | 139 | You can also choose to render each field separately. 140 | 141 | ``` 142 |
143 |
144 | renderField('first_name'); ?> 145 | renderField('last_name'); ?> 146 | renderField('email'); ?> 147 |
148 |
149 | renderField('message'); ?> 150 | 151 |
152 |
153 | ``` 154 | 155 | ## Handling submissions and data validation 156 | 157 | Formjack doesn't bind data automatically so you will need to write your own form submission handler. Here is a working example: 158 | 159 | ``` 160 | getName()]) 167 | ) { 168 | $form->bind($_POST[$form->getName()]); 169 | if ($form->isValid()) { 170 | // Success 171 | } else { 172 | // Fail 173 | } 174 | } 175 | ``` 176 | 177 | Formjack also provides you with few methods that you can use to fetch the validation errors and form data as well. 178 | 179 | ``` 180 | getErrors(); 186 | 187 | // Get form data 188 | $data = $form->getData(); 189 | ``` 190 | 191 | ## Documentation 192 | 193 | If you wish to learn more about Formjack and stuff that you can make with it? Read on! 194 | 195 | - [Fields](https://github.com/Slicejack/Formjack/wiki/Fields) - Learn more about Formjack fields and how to use them 196 | - [Validation](https://github.com/Slicejack/Formjack/wiki/Validation) - List of all available validation rules 197 | - [Layouts](https://github.com/Slicejack/Formjack/wiki/Layouts) - Customize the looks and feels of a form 198 | 199 | ## License 200 | 201 | All contents of this package are licensed under the [MIT license](https://github.com/Slicejack/Formjack/blob/master/LICENSE). 202 | -------------------------------------------------------------------------------- /Rule/AbstractRule.php: -------------------------------------------------------------------------------- 1 | invalidMessage = $invalidMessage; 30 | $this->negate = $negate; 31 | } 32 | 33 | /** 34 | * @param AbstractField $field 35 | * @return bool 36 | */ 37 | public function run(AbstractField $field) { 38 | return true; 39 | } 40 | 41 | /** 42 | * @param string $invalidMessage 43 | * @return $this 44 | */ 45 | public function setInvalidMessage($invalidMessage) { 46 | $this->invalidMessage = $invalidMessage; 47 | 48 | return $this; 49 | } 50 | 51 | /** 52 | * @return string 53 | */ 54 | public function getInvalidMessage() { 55 | return $this->invalidMessage; 56 | } 57 | 58 | /** 59 | * @param AbstractField $field 60 | * @return bool 61 | */ 62 | public function validate(AbstractField $field) { 63 | return ($this->negate)? !$this->isValid($field) : $this->isValid($field); 64 | } 65 | 66 | /** 67 | * @param AbstractField $field 68 | */ 69 | abstract public function isValid(AbstractField $field); 70 | 71 | } 72 | -------------------------------------------------------------------------------- /Rule/Checked.php: -------------------------------------------------------------------------------- 1 | getValue(); 17 | } 18 | 19 | return false; 20 | } 21 | 22 | } 23 | -------------------------------------------------------------------------------- /Rule/CompanyVAT.php: -------------------------------------------------------------------------------- 1 | countryCode = $countryCode; 172 | $this->wsdl = "http://ec.europa.eu/taxation_customs/vies/checkVatService.wsdl"; 173 | if(!class_exists('SoapClient')) { 174 | throw new \Exception('Soap library not found. Please install and enable the library.'); 175 | } else { 176 | try { 177 | $this->client = new \SoapClient($this->wsdl, array( 178 | 'trace' => true 179 | )); 180 | } catch(\Exception $e) { 181 | throw new \Exception($e->getMessage()); 182 | } 183 | } 184 | parent::__construct($invalidMessage, $negate); 185 | } 186 | 187 | /** 188 | * @param AbstractField $field 189 | * @return bool 190 | */ 191 | public function isValid(AbstractField $field) { 192 | $result = $this->client->checkVat(array( 193 | 'countryCode' => (string)$this->countryCode, 194 | 'vatNumber' => (int)$field->getValue() 195 | ) ); 196 | 197 | return $result->valid; 198 | } 199 | 200 | } 201 | -------------------------------------------------------------------------------- /Rule/Email.php: -------------------------------------------------------------------------------- 1 | getValue(), FILTER_VALIDATE_EMAIL); 15 | } 16 | 17 | } 18 | -------------------------------------------------------------------------------- /Rule/Length.php: -------------------------------------------------------------------------------- 1 | min = $min; 27 | $this->max = $max; 28 | $this->inclusive = (bool)$inclusive; 29 | parent::__construct($invalidMessage, $negate); 30 | } 31 | 32 | /** 33 | * @param AbstractField $field 34 | * @return bool 35 | */ 36 | public function isValid(AbstractField $field) { 37 | $value = $field->getValue(); 38 | 39 | if ($this->min !== null) { 40 | if ( 41 | ($this->inclusive == true && !(strlen($value) >= $this->min)) || 42 | ($this->inclusive == false && !(strlen($value) > $this->min)) 43 | ) { 44 | return false; 45 | } 46 | } 47 | 48 | if ($this->max !== null) { 49 | if ( 50 | ($this->inclusive == true && !(strlen($value) <= $this->max)) || 51 | ($this->inclusive == false && !(strlen($value) < $this->max)) 52 | ) { 53 | return false; 54 | } 55 | } 56 | 57 | return true; 58 | } 59 | 60 | } 61 | -------------------------------------------------------------------------------- /Rule/NotEmpty.php: -------------------------------------------------------------------------------- 1 | getValue(); 15 | 16 | if (is_string($value)) { 17 | $value = trim($value); 18 | } 19 | 20 | return !empty($value); 21 | } 22 | 23 | } 24 | -------------------------------------------------------------------------------- /Rule/Numeric.php: -------------------------------------------------------------------------------- 1 | getValue()); 15 | } 16 | 17 | } 18 | -------------------------------------------------------------------------------- /Rule/When.php: -------------------------------------------------------------------------------- 1 | condition = $condition; 20 | $this->children = $children; 21 | } 22 | 23 | /** 24 | * {@inheritdoc} 25 | */ 26 | public function run(AbstractField $field) { 27 | return call_user_func_array($this->condition, array( 28 | $field->getParent()->getData() 29 | )); 30 | } 31 | 32 | /** 33 | * @param AbstractField $field 34 | * @return array 35 | */ 36 | public function isValid(AbstractField $field) { 37 | return $this->children; 38 | } 39 | 40 | } 41 | -------------------------------------------------------------------------------- /Validator.php: -------------------------------------------------------------------------------- 1 | hasRules()) { 18 | self::loop($field, $field->getRules(), $errors); 19 | } 20 | 21 | $result->valid = empty($errors); 22 | $result->trace = $errors; 23 | 24 | return $result; 25 | } 26 | 27 | /** 28 | * @param AbstractField $field 29 | * @param AbstractRule[] $rules 30 | * @param array &$errors 31 | * @return void 32 | */ 33 | private static function loop(AbstractField $field, array $rules, array &$errors) { 34 | foreach ($rules as $rule) { 35 | if ($rule->run($field)) { 36 | $result = $rule->validate($field); 37 | if (is_bool($result) && $result === false) { 38 | $errors[] = $rule->getInvalidMessage(); 39 | } elseif (is_array($result)) { 40 | self::loop($field, $result, $errors); 41 | } 42 | } 43 | } 44 | 45 | return; 46 | } 47 | 48 | } 49 | --------------------------------------------------------------------------------