├── .editorconfig ├── .gitignore ├── CHANGELOG.md ├── CONDUCT.md ├── CONTRIBUTING.md ├── LICENSE ├── LICENSE.md ├── README.md ├── composer.json ├── config └── form.php └── src ├── Elements ├── Base.php ├── Checkbox.php ├── HoneyPot.php ├── Input.php ├── Radio.php ├── Select.php ├── Textarea.php └── TimeTrap.php ├── Facades └── Form.php ├── FormFactory.php ├── FormServiceProvider.php ├── lang ├── en │ └── antispam.php └── fr │ └── antispam.php └── views ├── checkbox.blade.php ├── honeypot.blade.php ├── input.blade.php ├── radio.blade.php ├── select.blade.php ├── textarea.blade.php └── timetrap.blade.php /.editorconfig: -------------------------------------------------------------------------------- 1 | ; This file is for unifying the coding style for different editors and IDEs. 2 | ; More information at http://editorconfig.org 3 | 4 | root = true 5 | 6 | [*] 7 | charset = utf-8 8 | indent_size = 4 9 | indent_style = space 10 | end_of_line = lf 11 | insert_final_newline = true 12 | trim_trailing_whitespace = true 13 | 14 | [*.md] 15 | trim_trailing_whitespace = false 16 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /bootstrap/compiled.php 2 | .env.*.php 3 | .env.php 4 | .env 5 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | All Notable changes to this package will be documented in this file 4 | 5 | ## NEXT - YYYY-MM-DD 6 | 7 | ### Added 8 | - Nothing 9 | 10 | ### Deprecated 11 | - Nothing 12 | 13 | ### Fixed 14 | - Nothing 15 | 16 | ### Removed 17 | - Nothing 18 | 19 | ### Security 20 | - Nothing 21 | -------------------------------------------------------------------------------- /CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Contributor Code of Conduct 2 | 3 | As contributors and maintainers of this project, and in the interest of fostering an open and welcoming community, we pledge to respect all people who contribute through reporting issues, posting feature requests, updating documentation, submitting pull requests or patches, and other activities. 4 | 5 | We are committed to making participation in this project a harassment-free experience for everyone, regardless of level of experience, gender, gender identity and expression, sexual orientation, disability, personal appearance, body size, race, ethnicity, age, religion, or nationality. 6 | 7 | Examples of unacceptable behavior by participants include: 8 | 9 | * The use of sexualized language or imagery 10 | * Personal attacks 11 | * Trolling or insulting/derogatory comments 12 | * Public or private harassment 13 | * Publishing other's private information, such as physical or electronic addresses, without explicit permission 14 | * Other unethical or unprofessional conduct. 15 | 16 | Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct. By adopting this Code of Conduct, project maintainers commit themselves to fairly and consistently applying these principles to every aspect of managing this project. Project maintainers who do not follow or enforce the Code of Conduct may be permanently removed from the project team. 17 | 18 | This code of conduct applies both within project spaces and in public spaces when an individual is representing the project or its community in a direct capacity. Personal views, beliefs and values of individuals do not necessarily reflect those of the organisation or affiliated individuals and organisations. 19 | 20 | Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by opening an issue or contacting one or more of the project maintainers. 21 | 22 | This Code of Conduct is adapted from the [Contributor Covenant](http://contributor-covenant.org), version 1.2.0, available at [http://contributor-covenant.org/version/1/2/0/](http://contributor-covenant.org/version/1/2/0/) 23 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing 2 | 3 | Contributions are **welcome** and will be fully **credited**. 4 | 5 | We accept contributions via Pull Requests on [Github](https://github.com/webup/form). 6 | 7 | 8 | ## Pull Requests 9 | 10 | - **[PSR-2 Coding Standard](https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-2-coding-style-guide.md)** - The easiest way to apply the conventions is to install [PHP Code Sniffer](http://pear.php.net/package/PHP_CodeSniffer). 11 | 12 | - **Add tests!** - Your patch won't be accepted if it doesn't have tests. 13 | 14 | - **Document any change in behaviour** - Make sure the `README.md` and any other relevant documentation are kept up-to-date. 15 | 16 | - **Consider our release cycle** - We try to follow [SemVer v2.0.0](http://semver.org/). Randomly breaking public APIs is not an option. 17 | 18 | - **Create feature branches** - Don't ask us to pull from your master branch. 19 | 20 | - **One pull request per feature** - If you want to do more than one thing, send multiple pull requests. 21 | 22 | - **Send coherent history** - Make sure each individual commit in your pull request is meaningful. If you had to make multiple intermediate commits while developing, please [squash them](http://www.git-scm.com/book/en/v2/Git-Tools-Rewriting-History#Changing-Multiple-Commit-Messages) before submitting. 23 | 24 | 25 | ## Running Tests 26 | 27 | ``` bash 28 | $ composer test 29 | ``` 30 | 31 | 32 | **Happy coding**! 33 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015 Agence Webup 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | 23 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | # The MIT License (MIT) 2 | 3 | Copyright (c) 2015 Robin PARISI 4 | 5 | > Permission is hereby granted, free of charge, to any person obtaining a copy 6 | > of this software and associated documentation files (the "Software"), to deal 7 | > in the Software without restriction, including without limitation the rights 8 | > to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | > copies of the Software, and to permit persons to whom the Software is 10 | > furnished to do so, subject to the following conditions: 11 | > 12 | > The above copyright notice and this permission notice shall be included in 13 | > all copies or substantial portions of the Software. 14 | > 15 | > THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | > IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | > FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | > AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | > LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | > OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | > THE SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # laravel-form 2 | 3 | ## Install 4 | 5 | ### Step 1: Install via Composer 6 | 7 | ``` bash 8 | $ composer require webup/laravel-form 9 | ``` 10 | 11 | ### Step 2: Add the Service Provider 12 | 13 | Add this line to config/app.php: 14 | 15 | ``` php 16 | 'providers' => [ 17 | //... 18 | Webup\LaravelForm\FormServiceProvider::class 19 | ] 20 | ``` 21 | 22 | ### Step 3: Use Facade (optional) 23 | 24 | For shorter code, you can use the facade by adding this line to config/app.php: 25 | 26 | ``` php 27 | 'aliases' => [ 28 | //... 29 | 'Form' => Webup\LaravelForm\Facades\Form::class, 30 | ] 31 | ``` 32 | 33 | You can now use Laravel Form directly into your views (check some examples bellow) 34 | 35 | ### Step 4: Publish config 36 | 37 | You can publish config and override it in config/form.php: 38 | 39 | ``` 40 | php artisan vendor:publish 41 | ``` 42 | 43 | ## Using 44 | 45 | ### Methods 46 | 47 | These methods can be used with any type of elements: 48 | 49 | * label($label = null, $escape = true) 50 | * value($value = null) 51 | * placeholder($placeholder = null) 52 | * name($name = null) 53 | * required($showStar = true) 54 | * errors($errors = []) 55 | * attr(array $attr = []) 56 | * wrapperAttr(array $attr = []) 57 | * wrapperClass($wrapperClass) **deprecated** use wrapperAttr(['class' => 'myclass']) 58 | 59 | ### Generated HTML 60 | 61 | 62 | ``` php 63 | {!! Form::create('text', 'name') 64 | ->label('Name') 65 | ->value('Barney') 66 | ->required() 67 | ->attr(['maxlenght' => '50']) 68 | ->wrapperAttr(['class' => 'f-custom-class']) !!} 69 | ``` 70 | 71 | Without errors: 72 | 73 | ``` html 74 |
75 | 76 | 77 |
78 | ``` 79 | 80 | With errors (retrieve from Laravel validation): 81 | ``` html 82 |
83 | 84 | 85 | 88 |
89 | ``` 90 | 91 | You can override default CSS class in config/form.php. 92 | 93 | **Important**: Laravel Form can handle HTML generation and client side validation only. You need to manage server side validation on your own. 94 | 95 | ### Elements 96 | #### input 97 | 98 | ``` php 99 | {!! Form::create('email', 'name') 100 | ->label('Email') 101 | ->value('homer.simpson@example.com') 102 | ->placeholder('example@adresse.com') 103 | ->required() 104 | ->wrapperAttr(['class' => 'custom-class']) !!} 105 | ``` 106 | 107 | #### textarea 108 | 109 | ``` php 110 | {!! Form::create('textarea', 'name') 111 | ->label('Name') 112 | ->value('Nullam id dolor id nibh ultricies vehicula ut id elit.') !!} 113 | ``` 114 | 115 | #### radio 116 | 117 | ``` php 118 | {!! Form::create('radio', 'gender')->label('Gender') 119 | ->addRadio(1, 'Male', 'male') 120 | ->addRadio(0, 'Female', 'female') 121 | ->wrapperAttr(['class' => 'custom-class']) 122 | ->value(0) !!} 123 | ``` 124 | 125 | Specific methods : 126 | 127 | * addRadio($value, $label, $id, $attr = []) 128 | 129 | #### select 130 | 131 | ``` php 132 | {!! Form::create('select', 'fruits') 133 | ->label("Fruits") 134 | ->placeholder("What's your favorite?") 135 | ->addOptions(['apple' => 'Apple', 'strawberry' => 'Strawberry', 'melon' => 'Melon']) 136 | ->value('apple') !!} 137 | ``` 138 | 139 | Specific methods : 140 | 141 | * addOptions(array $options) 142 | 143 | #### checkbox 144 | 145 | ``` php 146 | {!! Form::create('checkbox', 'cgu') 147 | ->label("I accept the general terms and conditions") 148 | ->value(true) !!} 149 | ``` 150 | 151 | You can use `->attr(['value' => '1'])` to change the value of the checkbox 152 | 153 | ## AntiSpam feature 154 | 155 | ### Honeypot 156 | 157 | ``` php 158 | {!! Form::honeypot("unicorn_mail") !!} 159 | ``` 160 | Will create an input `text` with `name='unicorn_mail'` within a hidden div (by javascript) 161 | 162 | #### Validation 163 | 164 | ``` php 165 | $request->validate([ 166 | [...] 167 | 'unicorn_mail' => 'honeypot', 168 | ]); 169 | ``` 170 | 171 | ### TimeTrap 172 | 173 | ``` php 174 | {!! Form::timetrap("unicorn_time") !!} 175 | ``` 176 | Will create an input `text` with `name='unicorn_time'` and `value="{encryptedTimestamp}"` within a hidden div (by javascript) 177 | 178 | #### Validation 179 | 180 | ``` php 181 | $request->validate([ 182 | [...] 183 | 'unicorn_time' => 'timetrap:2', 184 | ]); 185 | ``` 186 | In this example, timetrap time is set to `2` seconds. If no value is set, config `form.antiSpam.minFormSubmitTime` is taken. Finally if config `form.antiSpam.minFormSubmitTime` is not set, default value is `3` seconds. 187 | 188 | ## Styling 189 | 190 | Bellow, you will find default styles that can work with Laravel Form. 191 | 192 | ``` css 193 | 194 | .f-group { 195 | margin-bottom: 1rem; 196 | } 197 | 198 | .f-group label { 199 | margin-bottom: .5rem; 200 | } 201 | 202 | .f-required { 203 | color: #c0392b; 204 | font-weight: bold; 205 | } 206 | 207 | .f-error input { 208 | border: 1px solid #c0392b; 209 | } 210 | 211 | .f-error-message { 212 | margin-top: 4px; 213 | color: #c0392b; 214 | } 215 | 216 | ``` 217 | 218 | ## Contributing 219 | 220 | Please see [CONTRIBUTING](CONTRIBUTING.md) and [CONDUCT](CONDUCT.md) for details. 221 | 222 | ## Credits 223 | 224 | Developed by [Agence Webup](https://github.com/agence-webup) 225 | 226 | ## License 227 | 228 | The MIT License (MIT). Please see [License File](LICENSE.md) for more information. 229 | -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "webup/laravel-form", 3 | "description": "A Laravel package to help build forms.", 4 | "keywords": [ 5 | "webup", 6 | "form", 7 | "laravel" 8 | ], 9 | "homepage": "https://github.com/agence-webup/laravel-form", 10 | "license": "MIT", 11 | "authors": [ 12 | { 13 | "name": "Robin Parisi", 14 | "email": "robin@agence-webup.com", 15 | "homepage": "http://agence-webup.com", 16 | "role": "Developer" 17 | } 18 | ], 19 | "require": { 20 | "illuminate/support": "~5.1|^6.0|^7.0|^8.0|^9.0|^10.0|^11.0", 21 | "php": ">=5.3.0" 22 | }, 23 | "require-dev": { 24 | "phpunit/phpunit": "4.*", 25 | "scrutinizer/ocular": "~1.1" 26 | }, 27 | "autoload": { 28 | "psr-4": { 29 | "Webup\\LaravelForm\\": "src" 30 | } 31 | }, 32 | "autoload-dev": { 33 | "psr-4": { 34 | "Webup\\LaravelForm\\Test\\": "tests" 35 | } 36 | }, 37 | "scripts": { 38 | "test": "phpunit" 39 | }, 40 | "extra": { 41 | "branch-alias": { 42 | "dev-master": "1.0-dev" 43 | } 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /config/form.php: -------------------------------------------------------------------------------- 1 | 'f-group', 5 | 'requiredClass' => 'f-required', 6 | 'errorClass' => 'f-error', 7 | 'errorMessageClass' => 'f-error-message', 8 | 'antiSpam' => [ 9 | 'minFormSubmitTime' => "3",//Number of seconds for the form to be valid 10 | ] 11 | ); 12 | -------------------------------------------------------------------------------- /src/Elements/Base.php: -------------------------------------------------------------------------------- 1 | required = false; 24 | $this->requiredStar = false; 25 | $this->attr = []; 26 | $this->wrapperAttr = []; 27 | $this->errors = []; 28 | $this->oldValue = $oldValue; 29 | } 30 | 31 | public function label($label = null, $escape = false) 32 | { 33 | $label = $escape ? htmlentities($label, ENT_QUOTES, 'UTF-8', false) : $label; 34 | $this->label = $label; 35 | 36 | return $this; 37 | } 38 | 39 | public function value($value = null) 40 | { 41 | $this->value = $value; 42 | 43 | return $this; 44 | } 45 | 46 | public function placeholder($placeholder = null) 47 | { 48 | $this->placeholder = $placeholder; 49 | 50 | return $this; 51 | } 52 | 53 | public function name($name = null) 54 | { 55 | $this->name = $name; 56 | 57 | return $this; 58 | } 59 | 60 | public function required($requiredStar = true) 61 | { 62 | $this->required = true; 63 | $this->requiredStar = $requiredStar; 64 | 65 | return $this; 66 | } 67 | 68 | public function errors($errors = []) 69 | { 70 | $this->errors = $errors; 71 | 72 | return $this; 73 | } 74 | 75 | public function attr(array $attr = []) 76 | { 77 | $this->attr = $attr; 78 | 79 | return $this; 80 | } 81 | 82 | public function wrapperClass($wrapperClass) 83 | { 84 | $this->wrapperClass = $wrapperClass; 85 | 86 | return $this; 87 | } 88 | 89 | public function wrapperAttr(array $attr = []) 90 | { 91 | $this->wrapperAttr = $attr; 92 | 93 | return $this; 94 | } 95 | 96 | protected function getValue() 97 | { 98 | return $this->oldValue !== null ? $this->oldValue : $this->value; 99 | } 100 | } 101 | -------------------------------------------------------------------------------- /src/Elements/Checkbox.php: -------------------------------------------------------------------------------- 1 | type = $type; 14 | } 15 | 16 | public function render() 17 | { 18 | if (array_key_exists('class', $this->wrapperAttr)) { 19 | $this->wrapperClass = $this->wrapperAttr['class'] . ' ' . $this->wrapperClass; 20 | unset($this->wrapperAttr['class']); 21 | } 22 | 23 | return view('form::checkbox', [ 24 | 'placeholder' => $this->placeholder, 25 | 'value' => $this->value, 26 | 'label' => $this->label, 27 | 'required' => $this->required, 28 | 'requiredStar' => $this->requiredStar, 29 | 'checked' => $this->getChecked(), 30 | 'name' => $this->name, 31 | 'errors' => $this->errors, 32 | 'type' => $this->type, 33 | 'attr' => $this->attr, 34 | 'wrapperClass' => $this->wrapperClass, 35 | 'wrapperAttr' => $this->wrapperAttr, 36 | ])->render(); 37 | } 38 | 39 | public function __toString() 40 | { 41 | return $this->render(); 42 | } 43 | 44 | public function value($value = null) 45 | { 46 | $this->checked = $value; 47 | 48 | return $this; 49 | } 50 | 51 | private function getChecked() 52 | { 53 | return $this->oldValue === null ? $this->checked : $this->oldValue; 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /src/Elements/HoneyPot.php: -------------------------------------------------------------------------------- 1 | name = $name; 13 | $this->errors = []; 14 | } 15 | 16 | public function render() 17 | { 18 | return view('form::honeypot', [ 19 | 'name' => $this->name, 20 | 'errors' => $this->errors, 21 | ])->render(); 22 | } 23 | 24 | public function errors($errors = []) 25 | { 26 | $this->errors = $errors; 27 | 28 | return $this; 29 | } 30 | 31 | public function __toString() 32 | { 33 | return $this->render(); 34 | } 35 | 36 | public function checkHoneypot($attribute, $value, $parameters, $validator) 37 | { 38 | $data = $validator->getData(); 39 | 40 | return array_key_exists($attribute, $data) && !$value; 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /src/Elements/Input.php: -------------------------------------------------------------------------------- 1 | type = $type; 13 | } 14 | 15 | public function render() 16 | { 17 | if (array_key_exists('class', $this->wrapperAttr)) { 18 | $this->wrapperClass = $this->wrapperAttr['class'] . ' ' . $this->wrapperClass; 19 | unset($this->wrapperAttr['class']); 20 | } 21 | 22 | return view('form::input', [ 23 | 'placeholder' => $this->placeholder, 24 | 'value' => $this->getValue(), 25 | 'label' => $this->label, 26 | 'required' => $this->required, 27 | 'requiredStar' => $this->requiredStar, 28 | 'name' => $this->name, 29 | 'errors' => $this->errors, 30 | 'type' => $this->type, 31 | 'attr' => $this->attr, 32 | 'wrapperClass' => $this->wrapperClass, 33 | 'wrapperAttr' => $this->wrapperAttr, 34 | ])->render(); 35 | } 36 | 37 | public function __toString() 38 | { 39 | return $this->render(); 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /src/Elements/Radio.php: -------------------------------------------------------------------------------- 1 | type = $type; 14 | } 15 | 16 | public function render() 17 | { 18 | if (array_key_exists('class', $this->wrapperAttr)) { 19 | $this->wrapperClass = $this->wrapperAttr['class'] . ' ' . $this->wrapperClass; 20 | unset($this->wrapperAttr['class']); 21 | } 22 | 23 | return view('form::radio', [ 24 | 'value' => $this->getValue(), 25 | 'label' => $this->label, 26 | 'required' => $this->required, 27 | 'requiredStar' => $this->requiredStar, 28 | 'name' => $this->name, 29 | 'errors' => $this->errors, 30 | 'type' => $this->type, 31 | 'attr' => $this->attr, 32 | 'radios' => $this->radios, 33 | 'wrapperClass' => $this->wrapperClass, 34 | 'wrapperAttr' => $this->wrapperAttr, 35 | ])->render(); 36 | } 37 | 38 | public function addRadio($value, $label = false, $id = null, $attr = []) 39 | { 40 | $id = is_null($id) ? $label : $id; 41 | $this->radios[] = [ 42 | 'label' => $label, 43 | 'value' => $value, 44 | 'id' => $id, 45 | 'attr' => $attr, 46 | ]; 47 | 48 | return $this; 49 | } 50 | 51 | public function __toString() 52 | { 53 | return $this->render(); 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /src/Elements/Select.php: -------------------------------------------------------------------------------- 1 | type = $type; 14 | } 15 | 16 | public function render() 17 | { 18 | if (array_key_exists('class', $this->wrapperAttr)) { 19 | $this->wrapperClass = $this->wrapperAttr['class'] . ' ' . $this->wrapperClass; 20 | unset($this->wrapperAttr['class']); 21 | } 22 | 23 | $value = $this->getValue(); 24 | 25 | return view('form::select', [ 26 | 'placeholder' => $this->placeholder, 27 | 'value' => $this->getValue(), 28 | 'values' => $value ? explode(',', $value) : [], 29 | 'label' => $this->label, 30 | 'required' => $this->required, 31 | 'requiredStar' => $this->requiredStar, 32 | 'name' => $this->name, 33 | 'errors' => $this->errors, 34 | 'type' => $this->type, 35 | 'attr' => $this->attr, 36 | 'options' => $this->options, 37 | 'wrapperClass' => $this->wrapperClass, 38 | 'wrapperAttr' => $this->wrapperAttr, 39 | ])->render(); 40 | } 41 | 42 | public function addOptions(array $options) 43 | { 44 | foreach ($options as $value => $label) { 45 | $this->options[] = [ 46 | 'value' => $value, 47 | 'label' => $label, 48 | ]; 49 | } 50 | 51 | return $this; 52 | } 53 | 54 | public function __toString() 55 | { 56 | return $this->render(); 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /src/Elements/Textarea.php: -------------------------------------------------------------------------------- 1 | type = $type; 13 | } 14 | 15 | public function render() 16 | { 17 | if (array_key_exists('class', $this->wrapperAttr)) { 18 | $this->wrapperClass = $this->wrapperAttr['class'] . ' ' . $this->wrapperClass; 19 | unset($this->wrapperAttr['class']); 20 | } 21 | 22 | return view('form::textarea', [ 23 | 'placeholder' => $this->placeholder, 24 | 'value' => $this->getValue(), 25 | 'label' => $this->label, 26 | 'required' => $this->required, 27 | 'requiredStar' => $this->requiredStar, 28 | 'name' => $this->name, 29 | 'errors' => $this->errors, 30 | 'type' => $this->type, 31 | 'attr' => $this->attr, 32 | 'wrapperClass' => $this->wrapperClass, 33 | 'wrapperAttr' => $this->wrapperAttr, 34 | ])->render(); 35 | } 36 | 37 | public function __toString() 38 | { 39 | return $this->render(); 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /src/Elements/TimeTrap.php: -------------------------------------------------------------------------------- 1 | name = $name; 15 | $this->errors = []; 16 | } 17 | 18 | public function render() 19 | { 20 | return view('form::timetrap', [ 21 | 'name' => $this->name, 22 | 'value' => $this->getTimeEncrypted(), 23 | 'errors' => $this->errors, 24 | ])->render(); 25 | } 26 | 27 | public function errors($errors = []) 28 | { 29 | $this->errors = $errors; 30 | 31 | return $this; 32 | } 33 | 34 | public function getTimeEncrypted() 35 | { 36 | return Crypt::encrypt(time()); 37 | } 38 | 39 | public function decryptTime($time) 40 | { 41 | return Crypt::decrypt($time); 42 | } 43 | 44 | public function checkTimeTrap($attribute, $value, $parameters) 45 | { 46 | try { 47 | $submitedTime = $this->decryptTime($value); 48 | } catch (\Illuminate\Contracts\Encryption\DecryptException $e) { 49 | return false; 50 | } 51 | 52 | $timeToSubmit = (is_array($parameters) && count($parameters) > 0) ? $parameters[0] : config("form.antiSpam.minFormSubmitTime", 3); 53 | 54 | return ($submitedTime && ($submitedTime + $timeToSubmit) < time()); 55 | } 56 | 57 | 58 | public function __toString() 59 | { 60 | return $this->render(); 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /src/Facades/Form.php: -------------------------------------------------------------------------------- 1 | errors = $errors; 25 | $this->oldValues = $values; 26 | $this->config = $config; 27 | } 28 | 29 | public function create($type, $name) 30 | { 31 | $inputTypes = [ 32 | 'text', 33 | 'email', 34 | 'password', 35 | 'file', 36 | 'number', 37 | 'color', 38 | 'date', 39 | 'range', 40 | 'tel', 41 | 'url', 42 | ]; 43 | $element = null; 44 | $oldValue = null; 45 | $dottedKey = $this->nameToDottedKey($name); 46 | if (isset($this->oldValues[$name])) { 47 | $oldValue = $this->oldValues[$name]; 48 | } elseif (Arr::has($this->oldValues, $dottedKey)) { 49 | $oldValue = Arr::get($this->oldValues, $dottedKey); 50 | } 51 | 52 | if (in_array($type, $inputTypes)) { 53 | $element = new Input($type, $oldValue); 54 | } elseif ($type == 'radio') { 55 | $element = new Radio($type, $oldValue); 56 | } elseif ($type == 'checkbox') { 57 | $oldValue = $this->oldValues === null ? null : isset($this->oldValues[$name]); 58 | $element = new Checkbox($type, $oldValue); 59 | } elseif ($type == 'select') { 60 | $element = new Select($type, $oldValue); 61 | } elseif ($type == 'textarea') { 62 | $element = new Textarea($type, $oldValue); 63 | } else { 64 | throw new Exception('Invalid form type'); 65 | } 66 | 67 | $errors = []; 68 | if ($this->errors) { 69 | if ($this->errors->getBag('default')->has($name)) { 70 | $errors = $this->errors->get($name); 71 | } elseif ($this->errors->getBag('default')->has($dottedKey)) { 72 | $errors = $this->errors->get($dottedKey); 73 | } 74 | } 75 | 76 | return $element->name($name)->errors($errors); 77 | } 78 | 79 | public function honeypot($name) 80 | { 81 | $errors = []; 82 | if ($this->errors) { 83 | $errors = $this->errors->getBag('default')->has($name) ? $this->errors->get($name) : []; 84 | } 85 | return (new HoneyPot($name))->errors($errors); 86 | } 87 | 88 | public function timetrap($name) 89 | { 90 | $errors = []; 91 | if ($this->errors) { 92 | $errors = $this->errors->getBag('default')->has($name) ? $this->errors->get($name) : []; 93 | } 94 | return (new TimeTrap($name))->errors($errors); 95 | } 96 | 97 | private function nameToDottedKey($name) 98 | { 99 | $key = str_replace('[', '.', $name); 100 | $key = str_replace(']', '', $key); 101 | 102 | return trim($key, '.'); 103 | } 104 | } 105 | -------------------------------------------------------------------------------- /src/FormServiceProvider.php: -------------------------------------------------------------------------------- 1 | setupConfig(); 18 | view()->share('config', $this->app['config']->get('form')); 19 | $this->loadViewsFrom(__DIR__.'/views/', 'form'); 20 | 21 | 22 | Validator::extendImplicit('honeypot', "form_honeypot@checkHoneypot", trans("form::antispam.honeypot")); 23 | Validator::extendImplicit('timetrap', "form_timetrap@checkTimeTrap", trans("form::antispam.timetrap")); 24 | } 25 | 26 | protected function setupConfig() 27 | { 28 | $source = realpath(__DIR__.'/../config/form.php'); 29 | $this->publishes([$source => config_path('form.php')]); 30 | $this->mergeConfigFrom($source, 'form'); 31 | 32 | 33 | $translationSource = realpath(__DIR__.'/lang/'); 34 | $this->loadTranslationsFrom($translationSource, 'form'); 35 | 36 | if (function_exists("resource_path")) { 37 | $this->publishes([$translationSource => resource_path('lang/vendor/form')]); 38 | } else { 39 | $this->publishes([$translationSource => app_path('resources/lang/vendor/form')]); 40 | } 41 | } 42 | 43 | /** 44 | * Register any package services. 45 | */ 46 | public function register() 47 | { 48 | $this->app->singleton('form', function ($app) { 49 | return new FormFactory( 50 | $this->app['config']->get('form'), 51 | $this->app['request']->session()->get('_old_input'), 52 | $this->app['request']->session()->get('errors') 53 | ); 54 | }); 55 | 56 | $this->app->singleton('form_honeypot', function ($app) { 57 | return new HoneyPot(null); 58 | }); 59 | 60 | $this->app->singleton('form_timetrap', function ($app) { 61 | return new TimeTrap(null); 62 | }); 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /src/lang/en/antispam.php: -------------------------------------------------------------------------------- 1 | 'Spam detected.', 5 | 'timetrap' => 'Spam detected. Please wait a few seconds before submitting the form again.', 6 | ]; 7 | -------------------------------------------------------------------------------- /src/lang/fr/antispam.php: -------------------------------------------------------------------------------- 1 | 'Spam detecté', 5 | 'timetrap' => 'Spam detecté. Veuillez patienter quelques secondes avant de soumettre à nouveau le formulaire.', 6 | ]; 7 | -------------------------------------------------------------------------------- /src/views/checkbox.blade.php: -------------------------------------------------------------------------------- 1 |
$val) @if(is_int($key)){{$val}}@else{{$key}}="{{$val}}"@endif @endforeach> 2 | 17 | @if($errors) 18 | 23 | @endif 24 |
25 | -------------------------------------------------------------------------------- /src/views/honeypot.blade.php: -------------------------------------------------------------------------------- 1 |
2 | 3 | 7 |
8 | 9 | 10 | @if($errors) 11 |
12 | 17 |
18 | @endif 19 | -------------------------------------------------------------------------------- /src/views/input.blade.php: -------------------------------------------------------------------------------- 1 |
$val) @if(is_int($key)){{$val}}@else{{$key}}="{{$val}}"@endif @endforeach> 2 | @if($label) 3 | 4 | @endif 5 | $val) 13 | @if(is_int($key)){{$val}}@else{{$key}}="{{$val}}"@endif 14 | @endforeach 15 | > 16 | @if($errors) 17 | 22 | @endif 23 |
24 | -------------------------------------------------------------------------------- /src/views/radio.blade.php: -------------------------------------------------------------------------------- 1 |
$val) @if(is_int($key)){{$val}}@else{{$key}}="{{$val}}"@endif @endforeach> 2 | 3 | @if($errors) 4 | 9 | @endif 10 | @foreach($radios as $radio) 11 | 25 | @endforeach 26 |
27 | -------------------------------------------------------------------------------- /src/views/select.blade.php: -------------------------------------------------------------------------------- 1 |
$val) @if(is_int($key)){{$val}}@else{{$key}}="{{$val}}"@endif @endforeach> 2 | @if($label) 3 | 4 | @endif 5 | 20 | @if($errors) 21 | 26 | @endif 27 |
28 | -------------------------------------------------------------------------------- /src/views/textarea.blade.php: -------------------------------------------------------------------------------- 1 |
$val) @if(is_int($key)){{$val}}@else{{$key}}="{{$val}}"@endif @endforeach> 2 | @if($label) 3 | 4 | @endif 5 | 15 | @if($errors) 16 | 21 | @endif 22 |
23 | -------------------------------------------------------------------------------- /src/views/timetrap.blade.php: -------------------------------------------------------------------------------- 1 |
2 | 3 | 7 |
8 | 9 | 10 | @if($errors) 11 |
12 | 17 |
18 | @endif 19 | --------------------------------------------------------------------------------