├── .gitignore ├── tests ├── Dummy │ ├── DummyMacros.php │ ├── DummyToArray.php │ ├── DummyButton.php │ └── DummyEloquent.php ├── TestCases │ └── MacroableContainer.php ├── Framework │ ├── FrameworkTest.php │ ├── NudeFrameworkTest.php │ ├── TwitterBootstrapTest.php │ ├── ZurbFrameworkTest.php │ ├── ZurbFramework5Test.php │ ├── ZurbFramework4Test.php │ ├── TwitterBootstrap5Test.php │ ├── TwitterBootstrap3Test.php │ └── TwitterBootstrap4Test.php ├── Fields │ ├── HiddenTest.php │ ├── TextareaTest.php │ ├── UneditableTest.php │ ├── ButtonTest.php │ ├── FileTest.php │ ├── FloatingLabelTest.php │ └── PlainTextTest.php ├── MethodDispatcherTest.php ├── HelpersTest.php ├── ActionsTest.php ├── FormerTest.php └── Traits │ └── FieldTest.php ├── src ├── Former │ ├── Form │ │ ├── CheckableGroup.php │ │ ├── Fields │ │ │ ├── Textarea.php │ │ │ ├── Switchbox.php │ │ │ ├── Radio.php │ │ │ ├── Uneditable.php │ │ │ ├── Checkbox.php │ │ │ ├── Plaintext.php │ │ │ ├── Hidden.php │ │ │ ├── Button.php │ │ │ ├── File.php │ │ │ └── Input.php │ │ ├── Elements.php │ │ └── Actions.php │ ├── Interfaces │ │ ├── FieldInterface.php │ │ └── FrameworkInterface.php │ ├── Facades │ │ └── Former.php │ ├── Exceptions │ │ └── InvalidFrameworkException.php │ ├── Traits │ │ ├── FormerObject.php │ │ └── Framework.php │ ├── Framework │ │ ├── Nude.php │ │ ├── ZurbFoundation.php │ │ ├── ZurbFoundation4.php │ │ └── ZurbFoundation5.php │ ├── Populator.php │ ├── FormerServiceProvider.php │ ├── Helpers.php │ ├── MethodDispatcher.php │ └── LiveValidation.php ├── Laravel │ └── File.php └── config │ └── former.php ├── CONTRIBUTING.md ├── phpunit.xml ├── .github └── workflows │ └── tests.yml ├── composer.json ├── README.md └── CHANGELOG.md /.gitignore: -------------------------------------------------------------------------------- 1 | # Development 2 | .idea 3 | .phpunit.result.cache 4 | 5 | # Dependencies 6 | composer.lock 7 | vendor 8 | -------------------------------------------------------------------------------- /tests/Dummy/DummyMacros.php: -------------------------------------------------------------------------------- 1 | values = $values; 11 | } 12 | 13 | public function toArray() 14 | { 15 | return $this->values; 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /tests/Dummy/DummyButton.php: -------------------------------------------------------------------------------- 1 | text = $text; 11 | } 12 | 13 | public function __toString() 14 | { 15 | return ''; 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contribution guidelines 2 | 3 | Thank you for contributing to Former! Please target all changes to the master branch. 4 | 5 | Don't forget to add a test in the `tests` folder : 6 | - If it's a feature you're adding, add a test proving it works. 7 | - If it's a bug you're fixing, write a test proving it doesn't occur anymore. 8 | 9 | Thanks for you input and thanks for using Former! 10 | -------------------------------------------------------------------------------- /src/Former/Form/Fields/Textarea.php: -------------------------------------------------------------------------------- 1 | 2 | 11 | 12 | 13 | tests 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /src/Former/Facades/Former.php: -------------------------------------------------------------------------------- 1 | isGrouped()) { 16 | // Remove any possible items added by the Populator. 17 | $this->items = array(); 18 | } 19 | $this->items(func_get_args()); 20 | 21 | return $this; 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/Former/Form/Fields/Radio.php: -------------------------------------------------------------------------------- 1 | items(func_get_args()); 28 | 29 | return $this; 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/Former/Exceptions/InvalidFrameworkException.php: -------------------------------------------------------------------------------- 1 | framework = $framework; 21 | $this->message = "Framework was not found [{$this->framework}]"; 22 | 23 | return $this; 24 | } 25 | /** 26 | * Gets the errors object. 27 | * 28 | * @return string 29 | */ 30 | public function getFramework() 31 | { 32 | return $this->framework; 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /src/Former/Form/Fields/Uneditable.php: -------------------------------------------------------------------------------- 1 | addClass($this->app['former.framework']->getUneditableClasses()); 24 | 25 | $this->setId(); 26 | 27 | return $this->app['former.framework']->createDisabledField($this); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/Former/Form/Fields/Checkbox.php: -------------------------------------------------------------------------------- 1 | isGrouped()) { 28 | // Remove any possible items added by the Populator. 29 | $this->items = array(); 30 | } 31 | $this->items(func_get_args()); 32 | 33 | return $this; 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /tests/Framework/FrameworkTest.php: -------------------------------------------------------------------------------- 1 | former->framework('ZurbFoundation'); 11 | 12 | $this->assertEquals('ZurbFoundation', $this->former->framework()); 13 | } 14 | 15 | public function testCanCheckWhatTheFrameworkIs() 16 | { 17 | $current = $this->app['former.framework']->current(); 18 | $isCurrent = $this->app['former.framework']->is($current); 19 | 20 | $this->assertTrue($isCurrent); 21 | } 22 | 23 | public function testCanCreateFieldOutsideOfForm() 24 | { 25 | $this->former->closeGroup(); 26 | $this->former->close(); 27 | 28 | $text = $this->former->text('foobar')->__toString(); 29 | 30 | $this->assertEquals('', $text); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /.github/workflows/tests.yml: -------------------------------------------------------------------------------- 1 | name: Tests 2 | 3 | on: [ push, pull_request ] 4 | 5 | jobs: 6 | test: 7 | strategy: 8 | fail-fast: true 9 | matrix: 10 | os: [ ubuntu-latest, windows-latest ] 11 | php: [ "8.4", "8.3", "8.2", "8.1", "8.0", "7.4", "7.3", "7.2" ] 12 | 13 | name: PHP ${{ matrix.php }} - ${{ matrix.os }} 14 | runs-on: ${{ matrix.os }} 15 | 16 | steps: 17 | - name: Checkout code 18 | uses: actions/checkout@v4 19 | 20 | - name: Cache dependencies 21 | uses: actions/cache@v4 22 | with: 23 | path: ~/.composer/cache/files 24 | key: dependencies-php-${{ matrix.php }}-composer-${{ hashFiles('composer.json') }} 25 | 26 | - name: Setup PHP 27 | uses: shivammathur/setup-php@v2 28 | with: 29 | php-version: ${{ matrix.php }} 30 | coverage: none 31 | 32 | - name: Install dependencies 33 | run: composer update --prefer-stable --prefer-dist --no-interaction --no-suggest 34 | 35 | - name: Execute tests 36 | run: vendor/bin/phpunit 37 | -------------------------------------------------------------------------------- /tests/Fields/HiddenTest.php: -------------------------------------------------------------------------------- 1 | former->hidden('foo')->value('bar')->__toString(); 13 | $matcher = $this->matchField(array(), 'hidden'); 14 | $field = Arr::except($matcher, 'id'); 15 | 16 | $this->assertHTML($field, $input); 17 | } 18 | 19 | public function testCanPopulateHiddenFields() 20 | { 21 | $this->former->populate(array('foo' => 'bar')); 22 | 23 | $input = $this->former->hidden('foo')->value('bis')->__toString(); 24 | $matcher = $this->matchField(array(), 'hidden'); 25 | $field = Arr::except($matcher, 'id'); 26 | $field['attributes']['value'] = 'bar'; 27 | 28 | $this->assertHTML($field, $input); 29 | } 30 | 31 | public function testEncodedValue() 32 | { 33 | $input = $this->former->hidden('foo')->value('bar')->__toString(); 34 | $this->assertStringContainsString('value="<a>bar</a>"', $input); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /src/Former/Form/Fields/Plaintext.php: -------------------------------------------------------------------------------- 1 | addClass($this->app['former.framework']->getPlainTextClasses()); 24 | $this->setId(); 25 | if ($this->app['former']->getOption('escape_plaintext_value', true)) { 26 | $this->escapeValue(); 27 | } 28 | 29 | return $this->app['former.framework']->createPlainTextField($this); 30 | } 31 | 32 | protected function escapeValue() 33 | { 34 | $valueToEscape = $this->getValue(); 35 | $value = is_string($valueToEscape) || $valueToEscape instanceof HtmlString ? e($valueToEscape) : $valueToEscape; 36 | 37 | return $this->forceValue($value); 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /tests/Dummy/DummyEloquent.php: -------------------------------------------------------------------------------- 1 | shouldReceive('getResults')->andReturn(array( 21 | new DummyEloquent(array('id' => 1, 'name' => 'foo')), 22 | new DummyEloquent(array('id' => 3, 'name' => 'bar')), 23 | )) 24 | ->mock(); 25 | } 26 | 27 | public function rolesAsCollection() 28 | { 29 | return Mockery::mock('Illuminate\Database\Eloquent\Relations\HasMany') 30 | ->shouldReceive('getResults')->andReturn(new Collection(array( 31 | new DummyEloquent(array('id' => 1, 'name' => 'foo')), 32 | new DummyEloquent(array('id' => 3, 'name' => 'bar')), 33 | ))) 34 | ->mock(); 35 | } 36 | 37 | public function getCustomAttribute() 38 | { 39 | return 'custom'; 40 | } 41 | 42 | public function __toString() 43 | { 44 | return $this->name; 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /src/Former/Form/Fields/Hidden.php: -------------------------------------------------------------------------------- 1 | 37 | */ 38 | public function render() 39 | { 40 | return HtmlInput::create('hidden', $this->name, Helpers::encode($this->value), $this->attributes)->render(); 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "anahkiasen/former", 3 | "description": "A powerful form builder", 4 | "homepage": "http://formers.github.io/former/", 5 | "license": "MIT", 6 | "keywords": [ 7 | "bootstrap", 8 | "form", 9 | "foundation", 10 | "laravel" 11 | ], 12 | "authors": [ 13 | { 14 | "name": "Maxime Fabre", 15 | "email": "ehtnam6@gmail.com" 16 | } 17 | ], 18 | "require": { 19 | "php": "^7.2|^8.0", 20 | "illuminate/config": "^5.1.3|^6.0|^7.0|^8.0|^9.0|^10.0|^11.0|^12.0", 21 | "illuminate/container": "^5.1.3|^6.0|^7.0|^8.0|^9.0|^10.0|^11.0|^12.0", 22 | "illuminate/contracts": "^5.1.3|^6.0|^7.0|^8.0|^9.0|^10.0|^11.0|^12.0", 23 | "illuminate/http": "^5.1.3|^6.0|^7.0|^8.0|^9.0|^10.0|^11.0|^12.0", 24 | "illuminate/routing": "^5.1.3|^6.0|^7.0|^8.0|^9.0|^10.0|^11.0|^12.0", 25 | "illuminate/session": "^5.1.3|^6.0|^7.0|^8.0|^9.0|^10.0|^11.0|^12.0", 26 | "illuminate/translation": "^5.1.3|^6.0|^7.0|^8.0|^9.0|^10.0|^11.0|^12.0", 27 | "illuminate/support": "^5.1.3|^6.0|^7.0|^8.0|^9.0|^10.0|^11.0|^12.0", 28 | "kylekatarnls/html-object": "^1.5" 29 | }, 30 | "require-dev": { 31 | "phpunit/phpunit": "^8.5", 32 | "mockery/mockery": "^1.3", 33 | "illuminate/database": "^5.1.3|^6.0|^7.0|^8.0|^9.0|^10.0|^11.0|^12.0" 34 | }, 35 | "autoload": { 36 | "psr-4": { 37 | "Former\\": [ 38 | "src/Former", 39 | "tests" 40 | ], 41 | "Laravel\\": "src/Laravel" 42 | } 43 | }, 44 | "extra": { 45 | "laravel": { 46 | "providers": [ 47 | "Former\\FormerServiceProvider" 48 | ], 49 | "aliases": { 50 | "Former": "Former\\Facades\\Former" 51 | } 52 | } 53 | }, 54 | "minimum-stability": "dev", 55 | "prefer-stable": true 56 | } 57 | -------------------------------------------------------------------------------- /tests/MethodDispatcherTest.php: -------------------------------------------------------------------------------- 1 | app, array()); 13 | 14 | $reflector = new \ReflectionClass($dispatcher); 15 | $attribute = $reflector->getProperty('repositories'); 16 | $attribute->setAccessible(true); 17 | 18 | $this->assertCount(0, $attribute->getValue($dispatcher)); 19 | 20 | $dispatcher->addRepository('A\Namespace\\'); 21 | $this->assertCount(1, $attribute->getValue($dispatcher)); 22 | $this->assertContains('A\Namespace\\', $attribute->getValue($dispatcher)); 23 | } 24 | 25 | /** 26 | * Test that camel-cased names like Former::fakeField get translated to 27 | * a titlecased class of A\Fakefield. This is the original Former approach. 28 | */ 29 | public function testSupportsTitleCasedFields() 30 | { 31 | $dispatcher = new MethodDispatcher($this->app, array('A\\')); 32 | $method = new ReflectionMethod($dispatcher, 'getClassFromMethod'); 33 | $method->setAccessible(true); 34 | 35 | $mock = Mockery::mock('A\Fakefield'); 36 | 37 | $this->assertEquals('A\Fakefield', $method->invoke($dispatcher, 'fakefield')); 38 | } 39 | 40 | /** 41 | * Test that camel-cased names (Former::fakeField) or snake-cased names 42 | * (Fomer::fake_field) get translated to a study cased class name (FakeField) 43 | */ 44 | public function testSupportsCamelCasedAndSnakeCasedFields() 45 | { 46 | $dispatcher = new MethodDispatcher($this->app, array('A\\')); 47 | $method = new ReflectionMethod($dispatcher, 'getClassFromMethod'); 48 | $method->setAccessible(true); 49 | 50 | $mock = Mockery::mock('A\FakeField'); 51 | 52 | $this->assertEquals('A\FakeField', $method->invoke($dispatcher, 'fakeField')); 53 | $this->assertEquals('A\FakeField', $method->invoke($dispatcher, 'fake_field')); 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /tests/Framework/NudeFrameworkTest.php: -------------------------------------------------------------------------------- 1 | former->framework('Nude'); 14 | } 15 | 16 | //////////////////////////////////////////////////////////////////// 17 | //////////////////////////////// TESTS ///////////////////////////// 18 | //////////////////////////////////////////////////////////////////// 19 | 20 | public function testCanDisplayErrorMessages() 21 | { 22 | // Create field 23 | $this->former->withErrors($this->validator); 24 | $required = $this->former->text('required')->wrapAndRender(); 25 | 26 | // Matcher 27 | $matcher = 28 | ''. 29 | ''. 30 | 'The required field is required.'; 31 | 32 | $this->assertEquals($matcher, $required); 33 | } 34 | 35 | public function testCanDisplayNestedErrorMessages() 36 | { 37 | // Use special one-time-use validator 38 | $this->former->withErrors($this->mockValidator("foo.bar", "Foo", null)); 39 | 40 | // Create field 41 | $required = $this->former->text("foo[bar]")->id('foo')->label('Foo')->wrapAndRender(); 42 | 43 | // Matcher 44 | $matcher = 45 | ''. 46 | ''. 47 | 'The Foo field is required.'; 48 | 49 | $this->assertEquals($matcher, $required); 50 | } 51 | 52 | public function testGroupOpenHasNoElement() 53 | { 54 | $group = $this->former->group('foo')->__toString(); 55 | $matcher = ''; 56 | 57 | $this->assertEquals($matcher, $group); 58 | } 59 | 60 | public function testGroupCloseHasNoElement() 61 | { 62 | $this->former->group('foo'); 63 | $text = $this->former->closeGroup(); 64 | 65 | $this->assertEmpty($text); 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /tests/Framework/TwitterBootstrapTest.php: -------------------------------------------------------------------------------- 1 | former->framework('TwitterBootstrap'); 15 | } 16 | 17 | //////////////////////////////////////////////////////////////////// 18 | ////////////////////////////// MATCHERS //////////////////////////// 19 | //////////////////////////////////////////////////////////////////// 20 | 21 | public function createPrependAppendMatcher($prepend = array(), $append = array()) 22 | { 23 | foreach ($prepend as $k => $p) { 24 | if (!Str::startsWith($p, ''; 26 | } 27 | } 28 | foreach ($append as $k => $a) { 29 | if (!Str::startsWith($a, ''; 31 | } 32 | } 33 | 34 | $class = array(); 35 | if ($prepend) { 36 | $class[] = "input-prepend"; 37 | } 38 | if ($append) { 39 | $class[] = "input-append"; 40 | } 41 | 42 | return 43 | '
'. 44 | ''. 45 | '
'. 46 | '
'. 47 | implode('', $prepend). 48 | ''. 49 | implode('', $append). 50 | '
'. 51 | '
'. 52 | '
'; 53 | } 54 | 55 | //////////////////////////////////////////////////////////////////// 56 | //////////////////////////////// TESTS ///////////////////////////// 57 | //////////////////////////////////////////////////////////////////// 58 | 59 | public function testAppendWhiteIcon() 60 | { 61 | $control = $this->former->text('foo')->appendIcon('white-something')->__toString(); 62 | $matcher = $this->createPrependAppendMatcher(array(), array('')); 63 | 64 | $this->assertEquals($matcher, $control); 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /tests/HelpersTest.php: -------------------------------------------------------------------------------- 1 | former->text('pagination')->__toString(); 12 | $matcher = $this->matchField(array(), 'text', 'pagination'); 13 | 14 | $this->assertHTML($matcher, $former); 15 | } 16 | 17 | public function testTranslateFieldNameUnderScoreToSpace() 18 | { 19 | $input = $this->former->text('field_name_with_underscore')->__toString(); 20 | $matcher = $this->matchLabel('Field name with underscore', 'field_name_with_underscore'); 21 | 22 | $this->assertHTML($matcher, $input); 23 | } 24 | 25 | public function testCanDisableTranslationCapitalization() 26 | { 27 | $this->app['config'] = Mockery::mock('Config') 28 | ->shouldReceive('get')->with('former.live_validation', '')->andReturn(true) 29 | ->shouldReceive('get')->with('former.translate_from', '')->andReturn(true) 30 | ->shouldReceive('get')->with('former.automatic_label', '')->andReturn(true) 31 | ->shouldReceive('get')->with('former.capitalize_translations', '')->andReturn(false) 32 | ->mock(); 33 | Helpers::setApp($this->app); 34 | 35 | $this->assertEquals('field', Helpers::translate('field')); 36 | } 37 | 38 | public function testNestedTranslationFieldNames() 39 | { 40 | $matcher = $this->matchLabel('City', 'address.city'); 41 | $input = $this->former->text('address.city')->__toString(); 42 | $this->assertHTML($matcher, $input); 43 | 44 | $matcher = $this->matchLabel('City', 'address[city]'); 45 | $input = $this->former->text('address[city]')->__toString(); 46 | $this->assertHTML($matcher, $input); 47 | } 48 | 49 | public function testDoesntTryInvalidKeys() 50 | { 51 | $input = $this->former->text('Invalid Label?')->__toString(); 52 | $matcher = $this->matchLabel('Invalid Label?', 'Invalid Label?'); 53 | 54 | $this->assertHTML($matcher, $input); 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /tests/Fields/TextareaTest.php: -------------------------------------------------------------------------------- 1 | 'textarea', 22 | 'content' => 'bar', 23 | 'attributes' => array( 24 | 'class' => 'foo', 25 | 'cols' => '50', 26 | 'data-foo' => 'bar', 27 | 'id' => 'foo', 28 | 'name' => 'foo', 29 | 'rows' => '10', 30 | ), 31 | ); 32 | } 33 | 34 | //////////////////////////////////////////////////////////////////// 35 | //////////////////////////////// TESTS ///////////////////////////// 36 | //////////////////////////////////////////////////////////////////// 37 | 38 | public function testCanCreateArrayFields() 39 | { 40 | $this->former->populate(array('foo' => array('fr' => 'bar'))); 41 | $textarea = $this->former->textarea('foo[fr]')->__toString(); 42 | $matcher = '
'; 43 | 44 | $this->assertEquals($matcher, $textarea); 45 | } 46 | 47 | public function testCanCreateTextareas() 48 | { 49 | $attributes = $this->matchTextarea(); 50 | $textarea = $this->former->textarea('foo')->setAttributes($attributes['attributes'])->value('bar')->__toString(); 51 | $matcher = $this->matchTextarea(); 52 | 53 | $this->assertControlGroup($textarea); 54 | $this->assertHTML($matcher, $textarea); 55 | } 56 | 57 | public function testTextareaContentIsProperlyEncoded() 58 | { 59 | $value = 'foo'; 60 | $attributes = $this->matchTextarea(); 61 | $textarea = $this->former 62 | ->textarea('foo') 63 | ->setAttributes($attributes['attributes']) 64 | ->value($value) 65 | ->__toString(); 66 | $matcher = $this->matchTextarea(); 67 | $matcher['content'] = $value; 68 | 69 | $this->assertControlGroup($textarea); 70 | $this->assertHTML($matcher, $textarea); 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /tests/Fields/UneditableTest.php: -------------------------------------------------------------------------------- 1 | 'label', 22 | 'attributes' => array('for' => 'foo'), 23 | ); 24 | } 25 | 26 | /** 27 | * Matches an uneditable input 28 | * 29 | * @return array 30 | */ 31 | public function matchUneditableInput() 32 | { 33 | return array( 34 | 'tag' => 'input', 35 | 'attributes' => array( 36 | 'disabled' => 'disabled', 37 | 'type' => 'text', 38 | 'name' => 'foo', 39 | 'value' => 'bar', 40 | 'id' => 'foo', 41 | ), 42 | ); 43 | } 44 | 45 | /** 46 | * Matches an uneditable input as a span 47 | * 48 | * @return [type] [description] 49 | */ 50 | public function matchUneditableSpan() 51 | { 52 | return array( 53 | 'tag' => 'span', 54 | 'content' => 'bar', 55 | 'attributes' => array( 56 | 'class' => 'uneditable-input', 57 | ), 58 | ); 59 | } 60 | 61 | //////////////////////////////////////////////////////////////////// 62 | //////////////////////////////// TESTS ///////////////////////////// 63 | //////////////////////////////////////////////////////////////////// 64 | 65 | public function testCanCreateClassicDisabledFields() 66 | { 67 | $this->former->framework('Nude'); 68 | $nude = $this->former->uneditable('foo')->value('bar')->__toString(); 69 | 70 | $this->assertHTML($this->matchPlainLabel(), $nude); 71 | $this->assertHTML($this->matchUneditableInput(), $nude); 72 | 73 | $this->resetLabels(); 74 | $this->former->framework('ZurbFoundation'); 75 | $zurb = $this->former->uneditable('foo')->value('bar')->__toString(); 76 | 77 | $this->assertHTML($this->matchPlainLabel(), $zurb); 78 | $this->assertHTML($this->matchUneditableInput(), $zurb); 79 | } 80 | 81 | public function testCanCreateUneditableFieldsWithBootstrap() 82 | { 83 | $input = $this->former->uneditable('foo')->value('bar')->__toString(); 84 | 85 | $this->assertControlGroup($input); 86 | $this->assertHTML($this->matchUneditableSpan(), $input); 87 | } 88 | } 89 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Former 2 | ## A Laravelish way to create and format forms 3 | 4 | [![Latest Stable Version](http://img.shields.io/packagist/v/anahkiasen/former.svg?style=flat)](https://packagist.org/packages/anahkiasen/former) 5 | [![Total Downloads](http://img.shields.io/packagist/dt/anahkiasen/former.svg?style=flat)](https://packagist.org/packages/anahkiasen/former) 6 | 7 | Former outputs form elements in HTML compatible with your favorite CSS framework (Bootstrap and Foundation are currently supported). Former also handles repopulation after validation errors, including automatically rendering error text with affected fields. 8 | 9 | ### Introduction 10 | 11 | Former provides a fluent method of form creation, allowing you to do: 12 | 13 | ```php 14 | Former::framework('TwitterBootstrap3'); 15 | 16 | Former::horizontal_open() 17 | ->id('MyForm') 18 | ->rules(['name' => 'required']) 19 | ->method('GET'); 20 | 21 | Former::xlarge_text('name') # Bootstrap sizing 22 | ->class('myclass') # arbitrary attribute support 23 | ->label('Full name') 24 | ->value('Joseph') 25 | ->required() # HTML5 validation 26 | ->help('Please enter your full name'); 27 | 28 | Former::textarea('comments') 29 | ->rows(10) 30 | ->columns(20) 31 | ->autofocus(); 32 | 33 | Former::actions() 34 | ->large_primary_submit('Submit') # Combine Bootstrap directives like "lg and btn-primary" 35 | ->large_inverse_reset('Reset'); 36 | 37 | Former::close(); 38 | ``` 39 | 40 | Every time you call a method that doesn't actually exist, Former assumes you're trying to set an attribute and creates it magically. That's why you can do in the above example `->rows(10)` ; in case you want to set attributes that contain dashes, just replace them by underscores : `->data_foo('bar')` equals `data-foo="bar"`. 41 | Now of course in case you want to set an attribute that actually contains an underscore you can always use the fallback method `setAttribute('data_foo', 'bar')`. You're welcome. 42 | 43 | This is the core of it, but Former offers a lot more. I invite you to consult the wiki to see the extent of what Former does. 44 | 45 | ----- 46 | 47 | ### Installation 48 | Require Former package using Composer: 49 | 50 | composer require anahkiasen/former 51 | 52 | Publish config files with artisan: 53 | 54 | php artisan vendor:publish --provider="Former\FormerServiceProvider" 55 | 56 | #### App.php config for Laravel 5.4 and below 57 | 58 | For Laravel 5.4 and below, you must modify your `config/app.php`. 59 | 60 | In the `providers` array add : 61 | 62 | Former\FormerServiceProvider::class 63 | 64 | Add then alias Former's main class by adding its facade to the `aliases` array in the same file : 65 | 66 | 'Former' => 'Former\Facades\Former', 67 | 68 | ----- 69 | 70 | ### Documentation 71 | 72 | Please refer to the [wiki](https://github.com/formers/former/wiki) for the full documentation. 73 | -------------------------------------------------------------------------------- /src/Former/Form/Elements.php: -------------------------------------------------------------------------------- 1 | app = $app; 37 | $this->session = $session; 38 | } 39 | 40 | /** 41 | * Generate a hidden field containing the current CSRF token. 42 | * 43 | * @return string 44 | */ 45 | public function token() 46 | { 47 | $csrf = method_exists($this->session, 'getToken') ? $this->session->getToken() : $this->session->token(); 48 | 49 | return (string) $this->app['former']->hidden('_token', $csrf); 50 | } 51 | 52 | /** 53 | * Creates a label tag 54 | * 55 | * @param string $label The label content 56 | * @param string $for The field the label's for 57 | * @param array $attributes The label's attributes 58 | * 59 | * @return Element A