From 93248b0ff520b9b0d9322dc3eeb2dbac6c50417a Mon Sep 17 00:00:00 2001 From: Matt Lantz Date: Mon, 18 Jul 2016 13:23:54 -0400 Subject: [PATCH] Initial build --- .gitignore | 4 + .styleci.yml | 9 + .travis.yml | 12 + README.md | 81 +++++++ composer.json | 37 ++++ config/form-maker.php | 40 ++++ phpunit.xml | 18 ++ src/Facades/FormMaker.php | 18 ++ src/Facades/InputMaker.php | 18 ++ src/FormMakerProvider.php | 95 ++++++++ src/Generators/HtmlGenerator.php | 220 +++++++++++++++++++ src/Helpers/form_maker.php | 29 +++ src/Helpers/input_maker.php | 15 ++ src/Services/FormMaker.php | 361 +++++++++++++++++++++++++++++++ src/Services/InputCalibrator.php | 126 +++++++++++ src/Services/InputMaker.php | 343 +++++++++++++++++++++++++++++ tests/.gitkeep | 0 tests/AppTest.php | 58 +++++ tests/FormMakerTest.php | 103 +++++++++ tests/HtmlGeneratorTest.php | 107 +++++++++ tests/InputMakerTest.php | 38 ++++ 21 files changed, 1732 insertions(+) create mode 100644 .gitignore create mode 100644 .styleci.yml create mode 100644 .travis.yml create mode 100644 README.md create mode 100644 composer.json create mode 100644 config/form-maker.php create mode 100644 phpunit.xml create mode 100644 src/Facades/FormMaker.php create mode 100644 src/Facades/InputMaker.php create mode 100644 src/FormMakerProvider.php create mode 100644 src/Generators/HtmlGenerator.php create mode 100644 src/Helpers/form_maker.php create mode 100644 src/Helpers/input_maker.php create mode 100644 src/Services/FormMaker.php create mode 100644 src/Services/InputCalibrator.php create mode 100644 src/Services/InputMaker.php create mode 100644 tests/.gitkeep create mode 100644 tests/AppTest.php create mode 100644 tests/FormMakerTest.php create mode 100644 tests/HtmlGeneratorTest.php create mode 100644 tests/InputMakerTest.php diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..5826402 --- /dev/null +++ b/.gitignore @@ -0,0 +1,4 @@ +/vendor +composer.phar +composer.lock +.DS_Store diff --git a/.styleci.yml b/.styleci.yml new file mode 100644 index 0000000..fd50a9d --- /dev/null +++ b/.styleci.yml @@ -0,0 +1,9 @@ +preset: recommended + +risky: false + +linting: true + +finder: + exclude: + - "tests" \ No newline at end of file diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 0000000..66e4d17 --- /dev/null +++ b/.travis.yml @@ -0,0 +1,12 @@ +language: php + +php: + - 5.5 + - 5.6 + - hhvm + +before_script: + - travis_retry composer self-update + - travis_retry composer install --prefer-source --no-interaction --dev + +script: phpunit diff --git a/README.md b/README.md new file mode 100644 index 0000000..b5dc8be --- /dev/null +++ b/README.md @@ -0,0 +1,81 @@ +# FormMaker + +**FormMaker** - A remarkably magical form maker tool for Laravel. + +The FormMaker package provides a set of tools for generating HTML forms with as little as 1 line of code. Don't want to write boring HTML, neither do we. The FormMaker will generate error containers, all fields defined by either the table or object column types, or if you prefer to have more control define a config. + +##### Author(s): +* [Matt Lantz](https://github.com/mlantz) ([@mattylantz](http://twitter.com/mattylantz), matt at yabhq dot com) +* [Chris Blackwell](https://github.com/chrisblackwell) ([@chrisblackwell](https://twitter.com/chrisblackwell), chris at yabhq dot com) + +## Detailed Documentation +Please consult the documentation here: [http://laracogs.com/docs/Utilties/FormMaker](http://laracogs.com/docs/Utilties/FormMaker) + +## Requirements + +1. PHP 5.6+ +2. OpenSSL +3. Laravel 5.1+ + +---- + +### Installation + +Start a new Laravel project: +```php +composer create-project laravel/laravel your-project-name +``` + +Then run the following to add FormMaker +```php +composer require "yab/formmaker" +``` + +Add this to the `config/app.php` in the providers array: +```php +Yab\FormMaker\FormMakerProvider::class +``` + +Time to publish those assets! +```php +php artisan vendor:publish --provider="Yab\FormMaker\FormMakerProvider" +``` + +##### After these few steps you have the following tools at your fingertips: + +The package comes with facades, helpers, and blade directives. + +#### FormMaker Facades +```php +FormMaker::fromTable($table, $columns = null, $class = 'form-control', $view = null, $reformatted = true, $populated = false, $idAndTimestamps = false) +FormMaker::fromObject($object, $columns = null, $view = null, $class = 'form-control', $populated = true, $reformatted = false, $idAndTimestamps = false) +FormMaker::fromArray($array, $columns = null, $view = null, $class = 'form-control', $populated = true, $reformatted = false, $idAndTimestamps = false) +``` + +#### InputMaker Facades +```php +InputMaker::label($name, $attributes = []) +InputMaker::create($name, $field, $object = null, $class = 'form-control', $reformatted = false, $populated = false) +``` + +#### FormMaker Blade +```php +@form_maker_table($table, $columns = null, $class = 'form-control', $view = null, $reformatted = true, $populated = false, $idAndTimestamps = false) +@form_maker_object($object, $columns = null, $view = null, $class = 'form-control', $populated = true, $reformatted = false, $idAndTimestamps = false) +@form_maker_array($array, $columns = null, $view = null, $class = 'form-control', $populated = true, $reformatted = false, $idAndTimestamps = false) +``` + +#### InputMaker Blade +```php +@input_maker_label($name, $attributes = []) +@input_maker_create($name, $field, $object = null, $class = 'form-control', $reformatted = false, $populated = false) +``` + +## License +FormMaker is open-sourced software licensed under the [MIT license](http://opensource.org/licenses/MIT) + +### Bug Reporting and Feature Requests +Please add as many details as possible regarding submission of issues and feature requests + +### Disclaimer +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/composer.json b/composer.json new file mode 100644 index 0000000..bf638da --- /dev/null +++ b/composer.json @@ -0,0 +1,37 @@ +{ + "name": "yab/formmaker", + "description": "Magical Form building Facades, helpers and more!", + "license": "MIT", + "authors": [ + { + "name": "Matt Lantz", + "email": "matt@yabhq.com" + }, + { + "name": "Chris Blackwell", + "email": "chris@yabhq.com" + } + ], + "require": { + "php": ">=5.5.9", + "illuminate/support": "5.*", + "doctrine/dbal": "^2.5", + "laravelcollective/html": "^5.2|^5.1" + }, + "require-dev": { + "illuminate/container": "^5.2|^5.1", + "mockery/mockery": "^0.9.4", + "mikey179/vfsStream": "^1.6", + "orchestra/testbench": "^3.2" + }, + "autoload": { + "psr-4": { + "Yab\\FormMaker\\": "src/" + }, + "files": [ + "src/Helpers/form_maker.php", + "src/Helpers/input_maker.php" + ] + }, + "minimum-stability": "stable" +} diff --git a/config/form-maker.php b/config/form-maker.php new file mode 100644 index 0000000..8008559 --- /dev/null +++ b/config/form-maker.php @@ -0,0 +1,40 @@ + [ + 'group-class' => 'form-group', + 'error-class' => 'has-error', + 'label-class' => 'control-label', + ], + + 'inputTypes' => [ + 'number' => 'number', + 'integer' => 'number', + 'float' => 'number', + 'decimal' => 'number', + 'boolean' => 'number', + 'string' => 'text', + 'email' => 'text', + 'varchar' => 'text', + 'file' => 'file', + 'image' => 'file', + 'datetime' => 'date', + 'date' => 'date', + 'password' => 'password', + 'textarea' => 'textarea', + 'select' => null, + 'checkbox' => null, + 'checkbox-inline' => null, + 'radio' => null, + 'radio-inline' => null, + ] + +]; + diff --git a/phpunit.xml b/phpunit.xml new file mode 100644 index 0000000..247182e --- /dev/null +++ b/phpunit.xml @@ -0,0 +1,18 @@ + + + + + ./tests/ + + + diff --git a/src/Facades/FormMaker.php b/src/Facades/FormMaker.php new file mode 100644 index 0000000..6581a19 --- /dev/null +++ b/src/Facades/FormMaker.php @@ -0,0 +1,18 @@ +publishes([ + __DIR__.'/../config/form-maker.php' => base_path('config/form-maker.php'), + ]); + } + + /** + * Register the service provider. + * + * @return void + */ + public function register() + { + /* + |-------------------------------------------------------------------------- + | Providers + |-------------------------------------------------------------------------- + */ + + $this->app->register(\Collective\Html\HtmlServiceProvider::class); + + /* + |-------------------------------------------------------------------------- + | Register the Utilities + |-------------------------------------------------------------------------- + */ + + $this->app->singleton('FormMaker', function () { + return new FormMaker(); + }); + + $this->app->singleton('InputMaker', function () { + return new InputMaker(); + }); + + $loader = AliasLoader::getInstance(); + + $loader->alias('FormMaker', \Yab\FormMaker\Facades\FormMaker::class); + $loader->alias('InputMaker', \Yab\FormMaker\Facades\InputMaker::class); + + // Thrid party + $loader->alias('Form', \Collective\Html\FormFacade::class); + $loader->alias('HTML', \Collective\Html\HtmlFacade::class); + + /* + |-------------------------------------------------------------------------- + | Blade Directives + |-------------------------------------------------------------------------- + */ + + // Form Maker + Blade::directive('form_maker_table', function ($expression) { + return ""; + }); + + Blade::directive('form_maker_array', function ($expression) { + return ""; + }); + + Blade::directive('form_maker_object', function ($expression) { + return ""; + }); + + Blade::directive('form_maker_columns', function ($expression) { + return ""; + }); + + // Label Maker + Blade::directive('input_maker_label', function ($expression) { + return ""; + }); + + Blade::directive('input_maker_create', function ($expression) { + return ""; + }); + } +} diff --git a/src/Generators/HtmlGenerator.php b/src/Generators/HtmlGenerator.php new file mode 100644 index 0000000..d3dd79b --- /dev/null +++ b/src/Generators/HtmlGenerator.php @@ -0,0 +1,220 @@ +'; + } + + /** + * Make text input. + * + * @param array $config + * @param string $population + * @param string $custom + * + * @return string + */ + public function makeText($config, $population, $custom) + { + return ''; + } + + /** + * Make a select input. + * + * @param array $config + * @param string $selected + * @param string $custom + * + * @return string + */ + public function makeSelected($config, $selected, $custom) + { + $options = ''; + foreach ($config['config']['options'] as $key => $value) { + if ($selected == '') { + $selectedValue = ((string) $config['objectValue'] === (string) $value) ? 'selected' : ''; + } else { + $selectedValue = ((string) $selected === (string) $value) ? 'selected' : ''; + } + $options .= ''; + } + + return ''; + } + + /** + * Make a checkbox. + * + * @param array $config + * @param string $selected + * @param string $custom + * + * @return string + */ + public function makeCheckbox($config, $selected, $custom) + { + return ''; + } + + /** + * Make a radio input. + * + * @param array $config + * @param string $selected + * @param string $custom + * + * @return string + */ + public function makeRadio($config, $selected, $custom) + { + return ''; + } + + /* + |-------------------------------------------------------------------------- + | Relationship based + |-------------------------------------------------------------------------- + */ + + /** + * Make a relationship input. + * + * @param array $config + * @param string $label + * @param string $value + * @param string $custom + * + * @return string + */ + public function makeRelationship($config, $label = 'name', $value = 'id', $custom = '') + { + $object = $config['object']; + $relationship = $config['name']; + + $class = app()->make($config['config']['model']); + $items = $class->all(); + + foreach ($items as $item) { + $config['config']['options'][$item->$label] = $item->$value; + } + + $selected = ''; + if (is_object($object) && $object->$relationship()->first()) { + $selected = $object->$relationship()->first()->$value; + } + + return $this->makeSelected($config, $selected, $custom); + } + + /** + * Generate a standard HTML input string. + * + * @param array $config Config array + * + * @return string + */ + public function makeHTMLInputString($config) + { + $custom = $this->getCustom($config); + $multiple = $this->isMultiple($config, 'multiple'); + $multipleArray = $this->isMultiple($config, '[]'); + $floatingNumber = $this->getFloatingNumber($config); + $population = $this->getPopulation($config); + + if (is_array($config['objectValue']) && $config['type'] === 'file') { + $population = ''; + } + + $inputString = ''; + + return $inputString; + } + + /** + * Is the config a multiple? + * + * @param array $config + * @param string $response + * + * @return bool + */ + public function isMultiple($config, $response) + { + if (isset($config['config']['multiple'])) { + return $response; + } + + return ''; + } + + /** + * Get the population. + * + * @param array $config + * + * @return string + */ + public function getPopulation($config) + { + if ($config['populated'] && $config['name'] !== $config['objectValue']) { + return 'value="'.$config['objectValue'].'"'; + } + + return ''; + } + + /** + * Get the custom details. + * + * @param array $config + * + * @return string + */ + public function getCustom($config) + { + if (isset($config['config']['custom'])) { + return $config['config']['custom']; + } + + return ''; + } + + /** + * Get the floating number. + * + * @param array $config + * + * @return string + */ + public function getFloatingNumber($config) + { + if ($config['inputType'] === 'float' || $config['inputType'] === 'decimal') { + return 'step="any"'; + } + + return ''; + } +} diff --git a/src/Helpers/form_maker.php b/src/Helpers/form_maker.php new file mode 100644 index 0000000..0a3aed9 --- /dev/null +++ b/src/Helpers/form_maker.php @@ -0,0 +1,29 @@ +fromTable($table, $columns, $class, $view, $reformatted, $populated, $idAndTimestamps); + } +} + +if (!function_exists('form_maker_object')) { + function form_maker_object($object, $columns = null, $view = null, $class = 'form-control', $populated = true, $reformatted = false, $idAndTimestamps = false) + { + return app('FormMaker')->fromObject($object, $columns, $view, $class, $populated, $reformatted, $idAndTimestamps); + } +} + +if (!function_exists('form_maker_array')) { + function form_maker_array($array, $columns = null, $view = null, $class = 'form-control', $populated = true, $reformatted = false, $idAndTimestamps = false) + { + return app('FormMaker')->fromArray($array, $columns, $view, $class, $populated, $reformatted, $idAndTimestamps); + } +} + +if (!function_exists('form_maker_columns')) { + function form_maker_columns($table) + { + return app('FormMaker')->getTableColumns($table); + } +} diff --git a/src/Helpers/input_maker.php b/src/Helpers/input_maker.php new file mode 100644 index 0000000..e9e52a6 --- /dev/null +++ b/src/Helpers/input_maker.php @@ -0,0 +1,15 @@ +create($name, $field, $object, $class, $reformatted, $populated); + } +} + +if (!function_exists('input_maker_label')) { + function input_maker_label($name, $attributesConfig = []) + { + return app('InputMaker')->label($name, $attributesConfig); + } +} diff --git a/src/Services/FormMaker.php b/src/Services/FormMaker.php new file mode 100644 index 0000000..b6d87da --- /dev/null +++ b/src/Services/FormMaker.php @@ -0,0 +1,361 @@ +inputMaker = new InputMaker(); + $this->inputUtilities = new InputCalibrator(); + } + + /** + * Generate a form from a table. + * + * @param string $table Table name + * @param array $columns Array of columns and details regarding them see config/forms.php for examples + * @param string $class Class names to be given to the inputs + * @param string $view View to use - for custom form layouts + * @param bool $reformatted Corrects the table column names to clean words if no columns array provided + * @param bool $populated Populates the inputs with the column names as values + * @param bool $idAndTimestamps Allows id and Timestamp columns + * + * @return string + */ + public function fromTable( + $table, + $columns = null, + $class = 'form-control', + $view = null, + $reformatted = true, + $populated = false, + $idAndTimestamps = false + ) { + $formBuild = ''; + $tableColumns = Schema::getColumnListing($table); + + if (is_null($columns)) { + foreach ($tableColumns as $column) { + $type = DB::connection()->getDoctrineColumn($table, $column)->getType()->getName(); + $columns[$column] = $type; + } + } + + if (!$idAndTimestamps) { + unset($columns['id']); + unset($columns['created_at']); + unset($columns['updated_at']); + } + + foreach ($columns as $column => $columnConfig) { + if (is_numeric($column)) { + $column = $columnConfig; + } + + $errors = $this->getFormErrors(); + $input = $this->inputMaker->create($column, $columnConfig, $column, $class, $reformatted, $populated); + $formBuild .= $this->formBuilder($view, $errors, $columnConfig, $column, $input); + } + + return $formBuild; + } + + /** + * Build the form from an array. + * + * @param array $array + * @param array $columns + * @param string $view A template to use for the rows + * @param string $class Default input class + * @param bool $populated Is content populated + * @param bool $reformatted Are column names reformatted + * @param bool $timestamps Are the timestamps available? + * + * @return string + */ + public function fromArray( + $array, + $columns = null, + $view = null, + $class = 'form-control', + $populated = true, + $reformatted = false, + $timestamps = false + ) { + $formBuild = ''; + $array = $this->cleanupIdAndTimeStamps($array, $timestamps, false); + $errors = $this->getFormErrors(); + + if (is_null($columns)) { + $columns = $array; + } + + foreach ($columns as $column => $columnConfig) { + if (is_numeric($column)) { + $column = $columnConfig; + } + if ($column === 'id') { + $columnConfig = ['type' => 'hidden']; + } + + $input = $this->inputMaker->create($column, $columnConfig, $array, $class, $reformatted, $populated); + $formBuild .= $this->formBuilder($view, $errors, $columnConfig, $column, $input); + } + + return $formBuild; + } + + /** + * Build the form from the an object. + * + * @param object $object An object to base the form off + * @param array $columns Columns desired and specified + * @param string $view A template to use for the rows + * @param string $class Default input class + * @param bool $populated Is content populated + * @param bool $reformatted Are column names reformatted + * @param bool $timestamps Are the timestamps available? + * + * @return string + */ + public function fromObject( + $object, + $columns = null, + $view = null, + $class = 'form-control', + $populated = true, + $reformatted = false, + $timestamps = false + ) { + $formBuild = ''; + + if (is_null($columns)) { + $columns = array_keys($object['attributes']); + } + + $columns = $this->cleanupIdAndTimeStamps($columns, $timestamps, false); + $errors = $this->getFormErrors(); + + foreach ($columns as $column => $columnConfig) { + if (is_numeric($column)) { + $column = $columnConfig; + } + if ($column === 'id') { + $columnConfig = ['type' => 'hidden']; + } + $input = $this->inputMaker->create($column, $columnConfig, $object, $class, $reformatted, $populated); + $formBuild .= $this->formBuilder($view, $errors, $columnConfig, $column, $input); + } + + return $formBuild; + } + + /** + * Cleanup the ID and TimeStamp columns. + * + * @param array $collection + * @param bool $timestamps + * @param bool $id + * + * @return array + */ + public function cleanupIdAndTimeStamps($collection, $timestamps, $id) + { + if (!$timestamps) { + unset($collection['created_at']); + unset($collection['updated_at']); + } + + if (!$id) { + unset($collection['id']); + } + + return $collection; + } + + /** + * Get form errors. + * + * @return mixed + */ + public function getFormErrors() + { + $errors = null; + + if (Session::isStarted()) { + $errors = Session::get('errors'); + } + + return $errors; + } + + /** + * Constructs HTML forms. + * + * @param string $view View template + * @param array|object $errors + * @param array $field Array of field values + * @param string $column Column name + * @param string $input Input string + * + * @return string + */ + private function formBuilder($view, $errors, $field, $column, $input) + { + $formGroupClass = Config::get('form-maker.form.group-class', 'form-group'); + $formErrorClass = Config::get('form-maker.form.error-class', 'has-error'); + + $errorHighlight = ''; + $errorMessage = false; + + if (!empty($errors) && $errors->has($column)) { + $errorHighlight = ' '.$formErrorClass; + $errorMessage = $errors->get($column); + } + + if (is_null($view)) { + $formBuild = '
'; + $formBuild .= $this->formContentBuild($field, $column, $input, $errorMessage); + $formBuild .= '
'; + } else { + $formBuild = View::make($view, [ + 'labelFor' => ucfirst($column), + 'label' => $this->columnLabel($field, $column), + 'input' => $input, + 'errorMessage' => $this->errorMessage($errorMessage), + 'errorHighlight' => $errorHighlight, + ]); + } + + return $formBuild; + } + + /** + * Form Content Builder. + * + * @param array $field Array of field values + * @param string $column Column name + * @param string $input Input string + * @param string $errorMessage + * + * @return string + */ + public function formContentBuild($field, $column, $input, $errorMessage) + { + $formLabelClass = Config::get('form-maker.form.label-class', 'control-label'); + + $formBuild = ''.$input.$this->errorMessage($errorMessage); + + if (isset($field['type'])) { + if (in_array($field['type'], ['radio', 'checkbox'])) { + $formBuild = '
'; + $formBuild .= ''.$this->errorMessage($errorMessage).'
'; + } elseif (stristr($field['type'], 'hidden')) { + $formBuild = $input; + } + } + + return $formBuild; + } + + /** + * Generate the error message for the input. + * + * @param string $message Error message + * + * @return string + */ + private function errorMessage($message) + { + if (!$message) { + $realErrorMessage = ''; + } else { + $realErrorMessage = '

'.$message[0].'

'; + } + + return $realErrorMessage; + } + + /** + * Create the column label. + * + * @param array $field Field from Column Array + * @param string $column Column name + * + * @return string + */ + private function columnLabel($field, $column) + { + if (!is_array($field) && !in_array($field, $this->columnTypes)) { + return ucfirst($field); + } + + return (isset($field['alt_name'])) ? $field['alt_name'] : ucfirst($column); + } + + /** + * Get Table Columns. + * + * @param string $table Table name + * + * @return array + */ + public function getTableColumns($table, $allColumns = false) + { + $tableColumns = Schema::getColumnListing($table); + + $tableTypeColumns = []; + $badColumns = ['id', 'created_at', 'updated_at']; + + if ($allColumns) { + $badColumns = []; + } + + foreach ($tableColumns as $column) { + if (!in_array($column, $badColumns)) { + $type = DB::connection()->getDoctrineColumn($table, $column)->getType()->getName(); + $tableTypeColumns[$column]['type'] = $type; + } + } + + return $tableTypeColumns; + } +} diff --git a/src/Services/InputCalibrator.php b/src/Services/InputCalibrator.php new file mode 100644 index 0000000..120a26f --- /dev/null +++ b/src/Services/InputCalibrator.php @@ -0,0 +1,126 @@ +columnTypes)) { + return ucfirst($field); + } + + if (strpos($column, '[') > 0) { + preg_match_all("/\[([^\]]*)\]/", $column, $matches); + $column = $matches[1][0]; + } + + $alt_name = (isset($field['alt_name'])) ? $field['alt_name'] : ucfirst($column); + $placeholder = (isset($field['placeholder'])) ? $field['placeholder'] : $alt_name; + + return $placeholder; + } + + /** + * Clean the string for the column name swap. + * + * @param string $string Original column name + * + * @return string + */ + public function cleanString($string) + { + return ucwords(str_replace('_', ' ', $string)); + } +} diff --git a/src/Services/InputMaker.php b/src/Services/InputMaker.php new file mode 100644 index 0000000..97c6bfe --- /dev/null +++ b/src/Services/InputMaker.php @@ -0,0 +1,343 @@ +elper to make an HTML input. + */ +class InputMaker +{ + protected $htmlGenerator; + + protected $inputUtilities; + + protected $inputGroups = [ + 'text' => [ + 'text', + 'textarea', + ], + 'select' => [ + 'select', + ], + 'hidden' => [ + 'hidden', + ], + 'checkbox' => [ + 'checkbox', + 'checkbox-inline', + ], + 'radio' => [ + 'radio', + 'radio-inline', + ], + 'relationship' => [ + 'relationship', + ], + ]; + + public function __construct() + { + $this->htmlGenerator = new HtmlGenerator(); + $this->inputUtilities = new InputCalibrator(); + } + + /** + * Create the input HTML. + * + * @param string $name Column/ Input name + * @param array $config Array of config info for the input + * @param object|array $object Object or Table Object + * @param string $class CSS class + * @param bool $reformatted Clean the labels and placeholder values + * @param bool $populated Set the value of the input to the object's value + * + * @return string + */ + public function create($name, $config, $object = null, $class = 'form-control', $reformatted = false, $populated = true) + { + $defaultConfig = include(__DIR__.'/../../config/form-maker.php'); + + $inputConfig = [ + 'populated' => $populated, + 'name' => $name, + 'class' => $this->prepareTheClass($class, $config), + 'config' => $config, + 'inputTypes' => Config::get('form-maker.inputTypes', $defaultConfig['inputTypes']), + 'inputs' => $this->getInput(), + 'object' => $object, + 'objectValue' => (isset($object->$name) && !method_exists($object, $name)) ? $object->$name : $name, + 'placeholder' => $this->inputUtilities->placeholder($config, $name), + ]; + + $inputConfig = $this->refineConfigs($inputConfig, $reformatted, $name, $config); + + return $this->inputStringPreparer($inputConfig); + } + + /** + * Input string preparer. + * + * @param array $config + * + * @return string + */ + public function inputStringPreparer($config) + { + $inputString = ''; + $beforeAfterCondition = ($this->before($config) > '' || $this->after($config) > ''); + + if ($beforeAfterCondition) { + $inputString .= '
'; + } + + $inputString .= $this->before($config); + $inputString .= $this->inputStringGenerator($config); + $inputString .= $this->after($config); + + if ($beforeAfterCondition) { + $inputString .= '
'; + } + + return $inputString; + } + + /** + * Create a label for an input. + * + * @param string $name + * @param array $attributes + * + * @return string + */ + public function label($name, $attributes = []) + { + $attributeString = ''; + + foreach ($attributes as $key => $value) { + $attributeString .= $key.'="'.$value.'"'; + } + + return ''; + } + + /** + * Before input. + * + * @param array $config + * + * @return string + */ + private function before($config) + { + $before = (isset($config['config']['before'])) ? $config['config']['before'] : ''; + + return $before; + } + + /** + * After input. + * + * @param array $config + * + * @return string + */ + private function after($config) + { + $after = (isset($config['config']['after'])) ? $config['config']['after'] : ''; + + return $after; + } + + /** + * Prepare the input class. + * + * @param string $class + * + * @return string + */ + public function prepareTheClass($class, $config) + { + $finalizedClass = $class; + + if (isset($config['class'])) { + $finalizedClass .= ' '.$config['class']; + } + + return $finalizedClass; + } + + /** + * Get inputs. + * + * @return array + */ + public function getInput() + { + $input = []; + + if (Session::isStarted()) { + $input = Request::old(); + } + + return $input; + } + + /** + * Set the configs. + * + * @param array $config + * @param bool $reformatted + * @param string $name + * @param array $config + * + * @return array + */ + private function refineConfigs($inputConfig, $reformatted, $name, $config) + { + // If validation inputs are available lets prepopulate the fields! + if (!empty($inputConfig['inputs']) && isset($inputConfig['inputs'][$name])) { + $inputConfig['populated'] = true; + $inputConfig['objectValue'] = $inputConfig['inputs'][$name]; + } + + if ($reformatted) { + $inputConfig['placeholder'] = $this->inputUtilities->cleanString($this->inputUtilities->placeholder($config, $name)); + } + + if (!isset($config['type'])) { + if (is_array($config)) { + $inputConfig['inputType'] = 'string'; + } else { + $inputConfig['inputType'] = $config; + } + } else { + $inputConfig['inputType'] = $config['type']; + } + + return $inputConfig; + } + + /** + * The input string generator. + * + * @param array $config Config + * + * @return string + */ + private function inputStringGenerator($config) + { + $config = $this->prepareObjectValue($config); + $population = $this->inputUtilities->getPopulation($config); + $checkType = $this->inputUtilities->checkType($config, $this->inputGroups['checkbox']); + $selected = $this->inputUtilities->isSelected($config, $checkType); + $custom = $this->inputUtilities->getField($config, 'custom'); + $method = $this->getGeneratorMethod($config['inputType']); + + $standardMethods = [ + 'makeHidden', + 'makeText', + ]; + + $selectedMethods = [ + 'makeSelected', + 'makeCheckbox', + 'makeRadio', + ]; + + if (in_array($method, $standardMethods)) { + $inputString = $this->htmlGenerator->$method($config, $population, $custom); + } elseif (in_array($method, $selectedMethods)) { + $inputString = $this->htmlGenerator->$method($config, $selected, $custom); + } elseif ($method === 'makeRelationship') { + $inputString = $this->htmlGenerator->makeRelationship( + $config, + $this->inputUtilities->getField($config, 'label', 'name'), + $this->inputUtilities->getField($config, 'value', 'id'), + $custom + ); + } else { + $config = $this->prepareType($config); + $inputString = $this->htmlGenerator->makeHTMLInputString($config); + } + + return $inputString; + } + + /** + * prepare the type. + * + * @param array $config + * + * @return array + */ + public function prepareType($config) + { + $config['type'] = $config['inputTypes']['string']; + + if (isset($config['inputTypes'][$config['inputType']])) { + $config['type'] = $config['inputTypes'][$config['inputType']]; + } + + return $config; + } + + /** + * prepare the object Value. + * + * @param array $config + * + * @return array + */ + public function prepareObjectValue($config) + { + if (strpos($config['objectValue'], '[') > 0 && $config['object']) { + $final = $config['object']; + $nameProperties = explode('[', $config['objectValue']); + foreach ($nameProperties as $property) { + $realProperty = str_replace(']', '', $property); + $final = $final->$realProperty; + } + $config['objectValue'] = $final; + } + + return $config; + } + + /** + * Get the generator method. + * + * @param string $type + * + * @return string + */ + public function getGeneratorMethod($type) + { + switch ($type) { + case in_array($type, $this->inputGroups['hidden']): + return 'makeHidden'; + + case in_array($type, $this->inputGroups['text']): + return 'makeText'; + + case in_array($type, $this->inputGroups['select']): + return 'makeSelected'; + + case in_array($type, $this->inputGroups['checkbox']): + return 'makeCheckbox'; + + case in_array($type, $this->inputGroups['radio']): + return 'makeRadio'; + + case in_array($type, $this->inputGroups['relationship']): + return 'makeRelationship'; + + default: + return 'makeHTMLInputString'; + } + } +} diff --git a/tests/.gitkeep b/tests/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/tests/AppTest.php b/tests/AppTest.php new file mode 100644 index 0000000..cac5ea6 --- /dev/null +++ b/tests/AppTest.php @@ -0,0 +1,58 @@ +set('database.default', 'testbench'); + $app['config']->set('database.connections.testbench', [ + 'driver' => 'sqlite', + 'database' => ':memory:', + 'prefix' => '', + ]); + $app->make('Illuminate\Contracts\Http\Kernel'); + } + + protected function getPackageProviders($app) + { + return [ + \Yab\FormMaker\FormMakerProvider::class, + ]; + } + + protected function getPackageAliases($app) + { + return [ + 'Form' => \Collective\Html\FormFacade::class, + 'HTML' => \Collective\Html\HtmlFacade::class, + 'FormMaker' => \Yab\FormMaker\Facades\FormMaker::class, + 'InputMaker' => \Yab\FormMaker\Facades\InputMaker::class, + ]; + } + + public function setUp() + { + parent::setUp(); + $this->withFactories(__DIR__.'/../src/Models/Factories'); + $this->artisan('migrate', [ + '--database' => 'testbench', + '--realpath' => realpath(__DIR__.'/../src/Migrations'), + ]); + $this->withoutMiddleware(); + $this->withoutEvents(); + } + + public function testFormMaker() + { + $formMaker = $this->app['FormMaker']; + $this->assertTrue(is_object($formMaker)); + } + + public function testInputMaker() + { + $inputMaker = $this->app['InputMaker']; + $this->assertTrue(is_object($inputMaker)); + } +} diff --git a/tests/FormMakerTest.php b/tests/FormMakerTest.php new file mode 100644 index 0000000..cc05353 --- /dev/null +++ b/tests/FormMakerTest.php @@ -0,0 +1,103 @@ +app = new Container(); + $this->app->singleton('app', 'Illuminate\Container\Container'); + + $config = Mockery::mock('config'); + $config->shouldReceive('get') + ->with('form-maker.form.group-class', 'form-group') + ->andReturn('form-group'); + $config->shouldReceive('get') + ->with('form-maker.form.label-class', 'control-label') + ->andReturn('control-label'); + $config->shouldReceive('get') + ->with('form-maker.form.error-class', 'has-error') + ->andReturn('has-error'); + $config->shouldReceive('get') + ->with('form-maker.inputTypes', $inputTypes['inputTypes']) + ->andReturn($inputTypes['inputTypes']) + ->getMock(); + + $request = Mockery::mock('request') + ->shouldReceive('old') + ->withAnyArgs() + ->andReturn([]) + ->getMock(); + + $session = Mockery::mock('session'); + $session->shouldReceive('isStarted')->withAnyArgs()->andReturn(true); + $session->shouldReceive('get')->withAnyArgs()->andReturn(collect([])); + + $this->app->instance('config', $config); + $this->app->instance('session', $session); + $this->app->instance('request', $request); + + Facade::setFacadeApplication($this->app); + + $this->formMaker = new FormMaker(); + } + + public function testFromArray() + { + $testArray = [ + 'name' => 'string', + 'age' => 'number', + ]; + + $test = $this->formMaker->fromArray($testArray); + + $this->assertTrue(is_string($test)); + $this->assertEquals($test, '
'); + } + + public function testFromArrayWithColumns() + { + $testArray = [ + 'name' => 'string', + 'age' => 'number', + ]; + + $test = $this->formMaker->fromArray($testArray, ['name']); + + $this->assertTrue(is_string($test)); + $this->assertEquals($test, '
'); + } + + public function testFromObject() + { + (object) $testObject = [ + 'attributes' => [ + 'name' => 'Joe', + 'age' => 18, + ], + ]; + + $columns = [ + 'name' => [ + 'type' => 'string', + ], + 'age' => [ + 'type' => 'number', + ] + ]; + + $test = $this->formMaker->fromObject($testObject, $columns); + + $this->assertTrue(is_string($test)); + $this->assertEquals($test, '
'); + } +} diff --git a/tests/HtmlGeneratorTest.php b/tests/HtmlGeneratorTest.php new file mode 100644 index 0000000..6e503bd --- /dev/null +++ b/tests/HtmlGeneratorTest.php @@ -0,0 +1,107 @@ +app = new Container(); + $this->app->singleton('app', Container::class); + + $config = Mockery::mock('config')->shouldReceive('get')->withAnyArgs()->andReturn(['string' => 'string'])->getMock(); + $session = Mockery::mock('session')->shouldReceive('isStarted')->withAnyArgs()->andReturn(true)->getMock(); + $request = Mockery::mock('request')->shouldReceive('old')->withAnyArgs()->andReturn([])->getMock(); + $this->app->instance('config', $config); + $this->app->instance('session', $session); + $this->app->instance('request', $request); + + Facade::setFacadeApplication($this->app); + + $this->html = new HtmlGenerator(); + } + + public function testMakeHidden() + { + $test = $this->html->makeHidden(['name' => 'test'], 'test', ''); + + $this->assertTrue(is_string($test)); + $this->assertEquals($test, ''); + } + + public function testMakeText() + { + $test = $this->html->makeText([ + 'name' => 'test', + 'class' => 'form-control', + 'placeholder' => 'TestText' + ], 'simple-test', 'data-thing'); + + $this->assertTrue(is_string($test)); + $this->assertEquals($test, ''); + } + + public function testMakeSelected() + { + $test = $this->html->makeSelected([ + 'name' => 'test', + 'class' => 'form-control', + 'config' => [ + 'options' => [ + 'Admin' => 'admin', + 'Member' => 'member' + ] + ] + ], 'member', 'data-thing'); + + $this->assertTrue(is_string($test)); + $this->assertEquals($test, ''); + } + + public function testMakeCheckbox() + { + $test = $this->html->makeCheckbox([ + 'name' => 'test', + 'class' => 'form-control', + ], 'selected', ''); + + $this->assertTrue(is_string($test)); + $this->assertEquals($test, ''); + } + + public function testMakeRadio() + { + $test = $this->html->makeRadio([ + 'name' => 'test', + 'class' => 'form-control', + ], 'selected', ''); + + $this->assertTrue(is_string($test)); + $this->assertEquals($test, ''); + } + + public function testMakeInputString() + { + $test = $this->html->makeHTMLInputString([ + 'config' => [ + 'custom' => 'data-stuff' + ], + 'placeholder' => 'wtf', + 'inputType' => 'text', + 'type' => 'text', + 'populated' => true, + 'name' => 'test', + 'class' => 'form-control', + 'objectValue' => 'sample Test' + ]); + + $this->assertTrue(is_string($test)); + $this->assertEquals($test, ''); + } +} diff --git a/tests/InputMakerTest.php b/tests/InputMakerTest.php new file mode 100644 index 0000000..4a2bb5f --- /dev/null +++ b/tests/InputMakerTest.php @@ -0,0 +1,38 @@ +app = new Container(); + $this->app->singleton('app', Container::class); + + $config = Mockery::mock('config')->shouldReceive('get')->withAnyArgs()->andReturn(['string' => 'string'])->getMock(); + $session = Mockery::mock('session')->shouldReceive('isStarted')->withAnyArgs()->andReturn(true)->getMock(); + $request = Mockery::mock('request')->shouldReceive('old')->withAnyArgs()->andReturn([])->getMock(); + $this->app->instance('config', $config); + $this->app->instance('session', $session); + $this->app->instance('request', $request); + + Facade::setFacadeApplication($this->app); + + $this->inputMaker = new InputMaker(); + } + + public function testCreate() + { + $object = (object) ['name' => 'test']; + $test = $this->inputMaker->create('name', [], $object, 'form-control', false, true); + + $this->assertTrue(is_string($test)); + $this->assertEquals($test, ''); + } +}