diff --git a/README.md b/README.md
index d7446b4..ea1c755 100644
--- a/README.md
+++ b/README.md
@@ -4,14 +4,27 @@ Created for personal use, and is not well documented or tidy. Feel free to use /
QForm for Laravel does a bunch of html form stuff, making use of Laravel components
- Create most types of html inputs with a single component
-- Make use of the QForm::init() set of tools either by itself or with a component to easily access a models data, create form name attributes with prefix etc, and deal with error display and old() for you.
+- Make use of the QForm::new() set of tools either by itself or with a component to easily access a models data, create form name attributes with prefix etc, and deal with error display and old() for you.
- Customize template
- In the provided base Bootstrap 4 template, it makes some attempts to provide labelling, error and other accesibility features.
+```php
+$form = Qform::new()->model(User::first())->text('forms.edit_user');
+```
+```html
+{{ $form->input('name')->render(['type' => 'text']) }}
+{{ $form->input('email')->render(['type' => 'email']) }}
+{{ $form->input('level')->render(['type' => 'select', 'variables' => [0 => 'User', '1' => 'Admin']]) }}
+```
+
+- The input will automatically look for errors and old values based on value given by input()
+- The input will look to array or model given by model() to get input value
+- The input will automatically look to the given text for input label and guide text, eg. text('forms.edit_user') as above, in the case of input('name') will look to 'forms.edit_user.name' for the translation. Or if you give a table via table() such as table('users') it will look to 'columns.users.name'. It looks for text first, then table. You may also pass an array of key to text to text().
+
## Warnings
1. Doesn't play nice when array inputs such as select have muliple options that resolve to false (not strict)
-2. QForm::init() expects that you will have your translations arranged in a certain way, using key translations,
+2. QForm::new() expects that you will have your translations arranged in a certain way, using key translations,
a columns.php translation file arranged with table name as key and array of column names as follows
```php
'users' => [
@@ -46,11 +59,15 @@ and a forms.php (or any name you choose, this is optional) arranged in the same
... Other forms
```
-For example you have a signup form and a login form. Preparing a QForm via `$form = QForm::init(NULL, 'forms.login')->table('users')` means it will first look to forms.login for the column text, then columns.users.
+For example you have a signup form and a login form. Preparing a QForm via `$form = QForm::new()->text('forms.login')->table('users')` means it will first look to forms.login for the column text, then columns.users.
# Setup
+## Composer
+
+composer require corbinjurgens/qform
+
## Manual Installation
Copy the following to main composer.(in the case that the package is added to packages/corbinjurgens/qform)
@@ -112,78 +129,102 @@ Array input, ie. anything that has, or can have multiple options
Using components with the QForm tools is the intended usage of this package
-### Basics
-
In your template or controller, create a form. See the warning section above for an example of the translation files that this would be pointing to
```html
@php
// Initiate the $form either in your template, or from the controller
- // To edit an item, pass a model as the first parameter, or if your form will never edit, just pass null. Personally I usually share form between create and edit and pass a new model when creating
- // For second parameter point to a translation, pass an array of translations, or leave it empty. Pass table with ->table() to point to a table in tables.php translation file
- $form = QForm::init($user, 'forms.permissions')->table('users');
+ // To edit an item, pass a model as the via model(), or if your form will never edit, just pass null or do not call. Personally I usually share form between create and edit and pass a new model when creating
+ // For text() point to a translation, pass an array of translations, or leave it empty. Pass table with ->table() to point to a table in tables.php translation file
+ $form = QForm::new()->model($user)->text('forms.permissions')->table('users');
@endphp
{{-- Shift current column to 'name' and pass it to the form. The form will automatically look to the model for the 'name' value and fill the input, and look to translation files first for forms.permissions.name, then users.name --}}
-
+` `
+{{-- Or --}}
+{{ $form->input('name')->render(['type' => 'text']) }}
@php( $form->input('level') )
{{-- In the previous input, I shifted current input as I passed it to :form, but you can also shift separately, then access.
-Normally, $form->text() would look for the current inputs text, so first it would look to forms.permissions.level, then users.level. But because I passed a value to it, its looking to the same root, just different key to get :variables (See Introduction section for example of translation files)
+Normally, $form->getText() would look for the current inputs text, so first it would look to forms.permissions.level, then users.level. But because I passed a value to it, its looking to the same root, just different key to get :variables (See Introduction section for example of translation files)
--}}
-
+
+
+
+{{-- Or --}}
+{{ $form->render(['variables' => $form->getText('levels'), 'type' => 'radio']) }}
+
{{--
Normally this would look to forms.permissions.notifications, then users.notifications,
- but by passing a translation pointer, or array of columns to text_shift() I am telling it to look elsewhere for the 'notifications' text (and guide text)
- WARNING: text_shift() and value_shift() functions persist between input shifts so you must either pass null again, or call hard_reset() to clear
+ but by passing a translation pointer, or array of columns to textShift() I am telling it to look elsewhere for the 'notifications' text (and guide text)
+ WARNING: textShift() and dataShift() functions persist between input shifts so you must either pass null again, or call hardReset() to clear
--}}
-
+
+{{-- Or --}}
+{{ $form->input('notifications')->textShift('forms.admin')->render(['type' => 'checkbox']) }}
+```
+
+## Freely
+
+You can use QForm tools without using a component. This makes creating your inputs id, name and value easy, saving you a lot of repition
+
+```html
+@php( $form = QForm::new()->model($user)->text('forms.permissions')->table('users') )
+
+@php( $form->input('name') )
+{{ $form->getText() }}
+{{ $form->getGuide() }}
+{{ $form->getError() }}
+
+
```
-### Other functions
+## Other functions
Use the prefix function and pass an array (or null to clear), and it will automatically prefix the inputs name attribute
WARNING prefix persists between input shifts, so you must clear it by passing null or calling hard_reset().
Be sure in situuations where you shift the input and also get some other value that depends on the input, that you set the input first, or set it separately. However, in this example it wouldn't matter even if the input wasn't shifted yet
```html
@php
- $form = QForm::init($user, 'forms.permissions')->table('users');
+ $form = QForm::new()->model($user)->text('forms.permissions')->table('users');
@endphp
-
+
{{-- the inputs name attribute will be name="admin[data][level]" --}}
+{{-- Or --}}
+{{ $form->input('level')->prefix(['admin', 'data'])->render(['type' => 'radio', 'variables' => $form->getText('levels')]) }}
```
+You can also use prefixIn() and prefixOut() to add a set of prefixes, and then after back out again
+```html
-*The following are functions that are set for each input and are cleared when shifting input:*
-
-Call required($required = true) to make the current input required
+{{ $form->input('name')->prefixIn(['admin', 'data'])->render(['type' => 'text']) }}
+{{-- name will be name="admin[data][name]" --}}
-Call set_name($name = null) to set a string name if it is different than the column as passed via input()
+{{ $form->input('address')->render(['type' => 'text']) }}
+{{-- name will be name="admin[data][address]" as prefix is retained between inputs--}}
-Call default($value = null) to set a value for when the model is null or doesn't exist
+{{ $form->input('email')->prefixIn(['preferences'])->render(['type' => 'text']) }}
+{{-- name will be name="admin[data][preferences][email]" --}}
-Call set_text($text, $guide = null) and pass the form label text, and optionally form guide text. This will use the passed string as is
+{{ $form->input('dob')->prefixOut()->render(['type' => 'text']) }}
+{{-- name will be name="admin[data][dob]" so we have gone back to the previous prefix config --}}
+```
-Call alt_text($key) to look to the same translation file passed, but just look for a different column
+*The following are functions that are set for each input and are cleared when shifting input:*
-Call alt_text_base($base) and pass an array, or a string pointing to translation path to shift where the text will be found. This is similar to shift_text() but does not persist between inputs
+Call required($required = true) to make the current input required
-## Freely
+Call name($name = null) to set a string name if it is different than the column as passed via input()
-You can use QForm tools without using a component. This makes creating your inputs id, name and value easy, saving you a lot of repition
+Call default($value = null) to set a value for when the model is null or doesn't exist
-```html
-@php( $form = QForm::init($user, 'forms.permissions')->table('users') )
+Call setText($text, $guide = null) and pass the form label text, and optionally form guide text. This will use the passed string as is
-@php( $form->input('name') )
-{{ $form->text() }}
-{{ $form->guide() }}
-{{ $form->error() }}
-
+Call altText($key) to look to the same translation file passed, but just look for a different column
-```
+Call altTextBase($base) and pass an array, or a string pointing to translation path to shift where the text will be found. This is similar to shiftText() but does not persist between inputs
# Customize template
@@ -208,5 +249,5 @@ This code is untested and not to any standard. It has however been used extensiv
## TODO
- PHPDocs would be nice but not important while I don't expect anyone else to use this code
-- QForm functions are a bit all over the place (the function names aren't clear whether it is setting or getting)
+- DONE getting always starts with get, and class is split into traits: QForm functions are a bit all over the place (the function names aren't clear whether it is setting or getting)
- Untested in a fresh enviroment. I may have accidentally used a local function or other one of my private packages without realizing
\ No newline at end of file
diff --git a/src/Concerns/Build.php b/src/Concerns/Build.php
new file mode 100644
index 0000000..0d33082
--- /dev/null
+++ b/src/Concerns/Build.php
@@ -0,0 +1,101 @@
+array_type = $array_type;
+ return $this;
+ }
+
+ /** @var ViewErrorBag */
+ protected $errors = NULL;
+
+ /**
+ * Load errors from session, if empty set as an empty Error Bag
+ * In the same way template $errors variable works
+ *
+ *
+ */
+ protected function loadErrors(){
+ $this->errors = session()->get('errors', app(ViewErrorBag::class));
+ }
+
+ /**
+ * Points to the input key, or in other words database column.
+ * By default it is also used for ->id() and ->name()
+ *
+ * @var string
+ */
+ protected $key = NULL;
+
+
+ /**
+ * String points to translation file, defaulting to forms.php, it will look for input $key in that file.
+ * You can instead give other file or more deeper like forms.signup and it will look for key inside there
+ * If you use an array, text and guide will look for the key from there instead
+ * When paried with function guide() you can separate out the text and guide
+ *
+ * @var null|string|array
+ */
+ protected $text = NULL;
+
+ /**
+ * Set text used for the form.
+ * Can be an array of translations, or a string pointing to where in your key translations the text is found
+ *
+ * @param null|string|array $text
+ */
+ public function text($text = null){
+ $this->text = $text;
+ return $this;
+ }
+
+ /**
+ * By default, function guide() will look to trans or array of $text with '_guide' appended to $key
+ * Instead you can add either guides array, or string to translaton path to search directly within that
+ * without '_guide' suffix
+ *
+ * @param null|string|array $guides
+ */
+ protected $guides = null;
+
+ public function guides($guides = []){
+ $this->guides = $guides;
+ return $this;
+ }
+
+ /** @var string|null */
+ protected $table = null;
+
+ /**
+ * Set forms table
+ * If key is not found in $text and $table has been set,
+ * It will look to the columns.php file for the table, and key eg
+ * __('columns.user.password')
+ * This is a great way to specify only the columns that are different via $text such as 'forms.signup',
+ * and for the rest use shared values found in columns table such as table('users')
+ *
+ * @param null|string $table
+ */
+ public function table(string $table = null){
+ $this->table = $table;
+ return $this;
+ }
+
+}
diff --git a/src/Concerns/CrossInput.php b/src/Concerns/CrossInput.php
new file mode 100644
index 0000000..885ccc0
--- /dev/null
+++ b/src/Concerns/CrossInput.php
@@ -0,0 +1,116 @@
+prefix)){
+ $this->prefix = [];
+ }
+
+ if (!is_array($prefix)){
+ $prefix = [$prefix];
+ }
+ $this->prefix[] = $prefix;
+ }else{
+ $this->prefix = $prefix;
+ }
+
+
+ return $this;
+ }
+
+ public function prefixIn($prefix){
+ if (!is_array($this->prefix)){
+ $this->prefix = [];
+ }
+
+
+ if (!is_array($prefix)){
+ $prefix = [$prefix];
+ }
+
+ $this->prefix[] = $prefix;
+
+
+ }
+
+ public function prefixOut(){
+
+ if (!is_array($this->prefix)){
+ return;
+ }
+
+ array_pop($this->prefix);
+ if (empty($this->prefix)){
+ $this->prefix = null;
+ }
+
+ }
+
+ /**
+ * Change the current data of the form for multiple inputs.
+ * Such as pointing to a data column array, then accessing it
+ * Should be an array or Model object
+ */
+ protected $shift_data = null;
+
+ public function dataShift($data = null){
+ $this->shift_data = $data;
+ }
+
+ public function dataReset(){
+ $this->shift_data = null;
+ }
+
+ /**
+ * Change text base for longer than just one input, array or string
+ */
+ protected $shift_text = null;
+
+ public function textShift($data){
+ $this->shift_text = $data;
+ }
+ public function textReset(){
+ $this->shift_text = null;
+ }
+
+ /**
+ * The above functions such as text_shift dont get reset between inputs.
+ * You can reset all here
+ */
+ public function hardReset(){
+ $this->prefix = null;
+ $this->shift_data = null;
+ $this->shift_text = null;
+ }
+
+}
diff --git a/src/Concerns/Data.php b/src/Concerns/Data.php
new file mode 100644
index 0000000..820187f
--- /dev/null
+++ b/src/Concerns/Data.php
@@ -0,0 +1,43 @@
+curr_data = $data;
+ $this->curr_data_exists =
+ (
+ ( is_array($data) && !empty($data) ) || ( $data instanceof Model && $data->exists )
+ );
+ return $this;
+ }
+
+ /**
+ * Alias for data
+ *
+ * @param null|array|\Illuminate\Database\Eloquent\Model $data
+ */
+ public function model($data = null){
+ return $this->data($data);
+ }
+
+}
diff --git a/src/Concerns/PerInput.php b/src/Concerns/PerInput.php
new file mode 100644
index 0000000..359ee6c
--- /dev/null
+++ b/src/Concerns/PerInput.php
@@ -0,0 +1,44 @@
+default = NULL;
+
+ $this->force_text_mode = false;
+ $this->alt_text = NULL;
+ $this->guide_text = NULL;
+
+ $this->alt_text_base = NULL;
+
+ $this->required = NULL;
+
+ $this->name = null;
+ $this->value_forced = False;
+ $this->value = NULL;
+
+ $this->array_type = False;
+ }
+
+}
diff --git a/src/Concerns/PerInputGet.php b/src/Concerns/PerInputGet.php
new file mode 100644
index 0000000..5238098
--- /dev/null
+++ b/src/Concerns/PerInputGet.php
@@ -0,0 +1,245 @@
+prefix));
+ }
+
+ /**
+ * Get prefixes array
+ *
+ *
+ */
+ protected function _getPrefix(){
+
+ if (!is_array($this->prefix)){
+ return null;
+ }
+
+ $prefixes = [];
+
+ foreach($this->prefix as $level){
+ foreach($level as $prefix){
+ $prefixes[] = $prefix;
+ }
+ }
+
+ return $prefixes;
+ }
+
+ /**
+ * Get various datas
+ *
+ *
+ */
+ public function getRequired(){
+ return ($this->required === true);
+ }
+
+ /**
+ * Get just the name even if it has prefix
+ */
+ public function getBasename(){
+ return $this->name ?? $this->key;
+ }
+
+ /**
+ * Get form input id attribute
+ *
+ *
+ */
+ public function getId(){
+ $id = $this->getBasename();
+
+ if ($this->_usingPrefix()){
+ $prefix = $this->_getPrefix();
+ $prefix[] = $id;
+ return join('-', $prefix);
+ }
+
+ return $id;
+ }
+
+ /**
+ * Build prefix based on current prefixes in use.
+ * You may manually call this function in a template
+ *
+ * @param bool If true, current input key will be included in built prefix string
+ */
+ public function buildPrefix($append_key = false){
+ if (!$this->_usingPrefix()){
+ return $append_key ? $this->getBasename() : '';
+ }
+
+ $name_path = '';
+ $prefix = $this->_getPrefix();
+ if ($append_key === true) $prefix[] = $this->getBasename();
+ $first = true;
+ foreach($prefix as $part){
+ if ($first === true){
+ $first = false;
+ $name_path .= $part;
+ }else{
+ $name_path .= '['.$part.']';
+ }
+ }
+ return $name_path;
+ }
+
+
+ /**
+ * TODO later I may need to add a way to separate input name from database key
+ *
+ */
+ public function getName(){
+ if ($this->_usingPrefix()){
+ return $this->build_prefix(true);
+ }
+ return $this->getBasename();
+
+ }
+
+ /**
+ * Like name but used for getting old() and errors so it points with prefix included like 'prefix.name'
+ *
+ */
+ public function getNameDot(){
+ $name = $this->getBasename();
+ if ($this->_usingPrefix()){
+ $prefix = $this->_getPrefix();
+ $prefix[] = $name;
+ return join('.', $prefix);
+ }
+ return $name;
+ }
+
+ protected function _getTextTable($key, $guide = false){
+ $function = $guide ? '__' : [self::class, 'transNull'];
+ return (
+ $this->table !== null
+ ? call_user_func( $function, 'columns.' . $this->table . '.'. $key . ($guide ? '_guide' : '') )
+ : ($guide ? '' : $key)
+ );
+ }
+
+ /**
+ * Get current input text
+ * Optionally you can pass a key if you don't want to use key given via funcion input()
+ *
+ * @param null|string $force_key
+ */
+ public function getText($force_key = null){
+ if ($this->force_text_mode === true){
+ return $this->alt_text;
+ }
+
+ $key = $force_key ?? $this->alt_text ?? $this->key;
+ $text = $this->alt_text_base ?? $this->shift_text ?? $this->text;
+
+ if (is_array($text)){
+ return isset($text[$key]) ? $text[$key] : $this->_getTextTable($key);
+ }
+
+ if (is_string($text)){
+ return self::transNull($text . '.' . $key) ?? $this->_getTextTable($key);
+ }
+
+ return $this->_getTextTable($key);
+ }
+
+ /**
+ * Get current input guide text
+ * Optionally you can pass a key if you don't want to use key given via funcion input()
+ *
+ * @param null|string $force_key
+ */
+ public function getGuide($force_key = null){
+ if ($this->force_text_mode === true){
+ return $this->guide_text;
+ }
+
+ $key = $force_key ?? $this->alt_text ?? $this->key;
+ $pointer = $key;
+ $target = $this->guides;
+
+ // If no guides, it means look to normal text
+ // instead with _guide suffix on key
+ if ($target === null){
+ $target = $this->shift_text ?? $this->alt_text_base ?? $this->text;
+ $pointer .= '_guide';
+ }
+
+ if (is_array($target)){
+ return isset($target[$pointer]) ? $target[$pointer] : $this->_getTextTable($key, true);
+ }
+
+ if (is_string($target)){
+ $path = $target . '.' . $pointer;
+ return self::transNull($path) ?? $this->_getTextTable($key, true);
+ }
+
+ return $this->_getTextTable($key, true);
+
+
+ }
+
+ /**
+ * Get single error for current input
+ *
+ */
+ public function getError(){
+ if ($this->errors){
+ return $this->errors->first($this->getNameDot());
+ }
+ }
+
+ /**
+ * Get error array for current input
+ *
+ */
+ public function getErrorArray(){
+ if ($this->array_type === true){
+ $errors = $this->errors->get($this->getNameDot() . '.*');
+ }
+ return $errors ?? [];
+
+ }
+
+ /**
+ * Get current inputs value, optionally pass a $default
+ *
+ * @param null|mixed $default Only used if the data/Model does not exist
+ *
+ */
+ public function getValue($default = null){
+ if (is_null($this->key)){
+ return null;
+ }
+
+ $target_data = $this->shift_data ?? $this->curr_data;
+ $fallback =
+ (
+ $this->value_forced === True ? $this->value :
+ (
+ $this->curr_data_exists && isset($target_data[$this->key]) ? @$target_data[$this->key] :
+ ($default ?? $this->default)
+ )
+ );
+ $value = old($this->getNameDot(), $fallback);
+ return $value;
+ }
+
+
+}
diff --git a/src/Concerns/PerInputSet.php b/src/Concerns/PerInputSet.php
new file mode 100644
index 0000000..a7f66cd
--- /dev/null
+++ b/src/Concerns/PerInputSet.php
@@ -0,0 +1,132 @@
+reset();
+
+ // set key
+ $this->key = $key;
+ return $this;
+ }
+
+ /** @var null|bool */
+ protected $required = NULL;
+
+ /**
+ * Set required
+ *
+ * @param bool|null $required
+ */
+ public function required(bool $required = null){
+ $this->required = $required;
+ return $this;
+ }
+
+ /** @var string|null */
+ protected $name = null;
+
+ /**
+ * Set name for the input,
+ * otherwise $key given via fucntion input() will be used
+ *
+ * @param string|null $name
+ */
+ public function name($name = null){
+ $this->name = $name;
+ return $this;
+ }
+
+ /** @var bool */
+ protected $value_forced = false;
+
+ /** @var mixed */
+ protected $value = NULL;
+
+ /**
+ * By default, value is retrieved from the given data/Model if any based on input $key,
+ * but you can force the current input to use a different value
+ *
+ * @param mixed $value
+ */
+ public function value($value = null){
+ $this->value_forced = True;
+ $this->value = $value;
+ return $this;
+ }
+
+ /** @var null|mixed */
+ protected $default = NULL;
+
+ /**
+ * Set a default value for the currently set input
+ * It will only be used if the data/Model does not exist or is null/empty array
+ *
+ * @param mixed $value
+ */
+ public function default($value = NULL){
+ $this->default = $value;
+ return $this;
+ }
+
+ /** @var bool Force text as is rather than look to trans() or array */
+ protected $force_text_mode = false;
+
+ /** @var null|string */
+ protected $alt_text = NULL;
+
+ /** @var null|string */
+ protected $alt_text_base = NULL;
+
+ /** @var null|string */
+ protected $guide_text = NULL;
+
+ /**
+ * By default, text will be retrieved from given text(), guides() and table() trans or array
+ * You can set text as is here for the current input.
+ * If you use this and do not give a $guide, guide will be empty
+ *
+ * @param string $text
+ * @param string|null $guide
+ */
+ public function setText(string $text, string $guide = null){
+ $this->force_text_mode = true;
+ $this->alt_text = $text;
+ $this->guide_text = $guide;
+ return $this;
+ }
+
+ /**
+ * Look in same text location as given by function text() and table(), but look for different key
+ *
+ * @param null|string|array $key
+ */
+ public function altText($key){
+ $this->alt_text = $key;
+ return $this;
+ }
+
+ /**
+ * Use same key given function input(), but look in a different place
+ * You can give array, or string pointing to translations
+ *
+ * @param null|string|array $key
+ */
+ public function altTextBase($base){
+ $this->alt_text_base = $base;
+ return $this;
+ }
+
+}
diff --git a/src/Concerns/Template.php b/src/Concerns/Template.php
new file mode 100644
index 0000000..f430337
--- /dev/null
+++ b/src/Concerns/Template.php
@@ -0,0 +1,56 @@
+template = $template ?? self::$global_template ?? QForm::$global_template;
+ }
+
+ /**
+ * Get template with underscore ready to append to filename
+ *
+ *
+ */
+ public function getTemplate(){
+ if ($this->template){
+ return '_' . $this->template;
+ }
+ return '';
+ }
+
+ /**
+ * Get template with underscore ready to append to filename
+ *
+ *
+ */
+ public function getTemplateSuffix(){
+ return $this->template;
+ }
+
+ /** @var null|string Globally set template suffix */
+ public static $global_template = null;
+
+ /**
+ * Set template used globally. If a class instance does not have a template set,
+ * it will look to this value
+ */
+ public static function setGlobalTemplate(string $suffix = null){
+ self::$global_template = $suffix;
+ }
+}
diff --git a/src/Concerns/Tools.php b/src/Concerns/Tools.php
new file mode 100644
index 0000000..0932b8d
--- /dev/null
+++ b/src/Concerns/Tools.php
@@ -0,0 +1,47 @@
+type = $type;
$this->block = (bool) $block;
- $this->set_template($template);
+ $this->template($template);
}
/**
@@ -44,6 +44,6 @@ public function __construct($message, $type = 'danger', $block = False, $templat
*/
public function render()
{
- return view(S::$name . '::components.forms.input-error' . $this->template_suffix);
+ return view(S::$name . '::components.forms.input-error' . $this->getTemplate());
}
}
diff --git a/src/Input.php b/src/Input.php
index 8f9eb42..68bd22e 100644
--- a/src/Input.php
+++ b/src/Input.php
@@ -8,12 +8,8 @@
class Input extends Component
{
- use Shared;
- /**
- * Requires the QForm extension (by CJ)
- *
- * @return void
- */
+ use Concerns\Template;
+
public $form = NULL;
public $type = NULL;
public $id = NULL;
@@ -39,7 +35,7 @@ public function __construct($form = null, $type = 'text', $id = null, $name = nu
$form_null = false;
if ($form === null){
$form_null = true;
- $form = QForm::init();
+ $form = QForm::new();
}
$this->form = $form;
$this->type = $type;
@@ -48,23 +44,23 @@ public function __construct($form = null, $type = 'text', $id = null, $name = nu
$this->type = 'json';
$this->alt_type = $type != 'json' ? $type : null;
- $this->form->array_type(true);
+ $this->form->arrayType(true);
}
- $this->error = $error ?? $form->error();
- $this->errors = $errors ?? $form->errors_array();
- $this->text = $text ?? $form->text();
- $this->guide = $guide ?? $form->guide();
- $this->id = $id ?? ($form_null ? $name : $form->id());
- $this->name = $name ?? $form->name();
- $this->basename = !is_null($name) ? $this->strip_name($name) : $form->basename();// in the case that $name is prefixed, such as 'user[email]' then this will get just the email part
+ $this->error = $error ?? $form->getError();
+ $this->errors = $errors ?? $form->getErrorArray();
+ $this->text = $text ?? $form->getText();
+ $this->guide = $guide ?? $form->getGuide();
+ $this->id = $id ?? ($form_null ? $name : $form->getId());
+ $this->name = $name ?? $form->getName();
+ $this->basename = !is_null($name) ? $this->stripName($name) : $form->getBasename();// in the case that $name is prefixed, such as 'user[email]' then this will get just the email part
$this->hideValue = $hideValue;
if ($this->hideValue == false){
- $this->value = $value ?? $form->value();
+ $this->value = $value ?? $form->getValue();
}
- $this->set_template($template ?? $form->template);
+ $this->template($template ?? $form->getTemplateSuffix());
- $this->required = ($required !== NULL ? $required : $form->is_required());
+ $this->required = ($required ?? $form->getRequired());
$this->variables = $variables;
$this->variableAttributes = $variableAttributes;
@@ -104,7 +100,7 @@ public function __construct($form = null, $type = 'text', $id = null, $name = nu
*
* @param string|null $name
*/
- public static function strip_name($name){
+ public static function stripName($name){
$start = strrpos($name, '[',);
if ($start === false){
return $name;
@@ -120,6 +116,6 @@ public static function strip_name($name){
*/
public function render()
{
- return view( S::$name . '::' . 'components.forms.input' . $this->template_suffix);
+ return view( S::$name . '::' . 'components.forms.input' . $this->getTemplate());
}
}
diff --git a/src/QForm.php b/src/QForm.php
index f6b5b91..440411e 100644
--- a/src/QForm.php
+++ b/src/QForm.php
@@ -1,413 +1,82 @@
data($curr_data);
+ $this->template($template_suffix);
- }
- /**
- * Form functions
- * -----------------
- */
- /**
- * Set the templates used for the current class instance. Normally it will look for input.blade.php for example, but if you set a template like "alt" it will look for input_alt.blade.php
- */
- // now in Shared
- /**
- * Model data
- * NULL is ok
- * $curr_data_exists checks if Model is true and $model->exists so it must be a Eloquent instance
- */
- protected $curr_data = NULL;
- protected $curr_data_exists = false;
- /**
- * Points to the input key, or in other words database column.
- * By default it is also used for ->id() and ->name()
- */
- protected $key = NULL;
- /**
- * String points to translation file, defaulting to forms.php, it will look for input $key in that file.
- * You can instead give other file or more deeper like forms.signup and it will look for key inside there
- * If you use an array, text and guide will look for the key from there instead
- * When paried with function guide() you can separate out the text and guide
- * @param NULL|string|array $text
- */
- protected $text = NULL;
- /**
- * Errors from request
- */
- protected $errors = NULL;
- function __construct($curr_data = NULL, $text = NULL, $template_suffix = NULL){
- $this->curr_data = $curr_data;
- $this->curr_data_exists = ($curr_data == True && $curr_data->exists);
+ $this->loadErrors();
- $this->text = $text;
- $this->set_template($template_suffix);
- $this->errors = session()->get('errors', app(ViewErrorBag::class));
- }
- static function init($curr_data = NULL, $text = 'forms', $template_suffix = NULL){
- return new self($curr_data, $text, $template_suffix);
- }
- /**
- * By default, function guide() will look to trans or array of $text with '_guide' appended to $key
- * Instead you can add either guides array, or string to translaton path to search directly within that
- * without '_guide' suffix
- * @param null|string|array $guides
- */
- protected $guides = null;
- function guides($guides = []){
- $this->guides = $guides;
- return $this;
- }
- /**
- * If key is not found in $text and $table has been set,
- * It will look to the columns.php file for the table, and key eg
- * __('columns.user.password')
- * This is a great way to specify only the columns that are different via $text such as 'forms.signup',
- * and for the rest use shared values found in columns table such as table('users')
- */
- protected $table = null;
- function table($table){
- $this->table = $table;
- if ($this->text === null){
- // If setting table and text is empty, point to default trans
- $this->text = 'forms.' . $this->table;
- }
- return $this;
- }
- /**
- * To be used between inputs, changes are retained unless manualy setting back to null
- * or using hard_reset();
- */
-
- /**
- * Set prefix so that id() and name() will return
- * Does not get reset across multiple inputs, so
- * you must set back to null
- * You should use a single string like 'options' to become options[key]
- * OR array like ['options', 0] to become options[0][key]
- */
- protected $prefix = null;
- function prefix($prefix = null){
- if ($prefix !== null){
- if (!is_array($prefix)){
- $prefix = [$prefix];
- }
- }
- $this->prefix = $prefix;
- return $this;
- }
- /**
- * Change the current data of the form for multiple inputs.
- * Such as pointing to a data column array, then accessing it
- * Should be an array or object
- */
- protected $shift_data = null;
- function value_shift($data){
- $this->shift_data = $data;
- }
- function value_reset(){
- $this->shift_data = null;
- }
- /**
- * Change text base for longer than just one input, array or string
- */
- protected $shift_text = null;
- function text_shift($data){
- $this->shift_text = $data;
- }
- function text_reset(){
- $this->shift_text = null;
}
/**
- * The above functions such as text_shift dont get reset between inputs.
- * You can reset all here
+ * Create and return new form
+ *
+ * @param null|array|\Illuminate\Database\Eloquent\Model $curr_data The model or array used for the form
+ * @param null|string $template_suffix Suffix for if you want to use a template other than the default one
*/
- function hard_reset(){
- $this->prefix = null;
- $this->shift_data = null;
- $this->shift_text = null;
+ static public function new($curr_data = NULL, $template_suffix = NULL){
+ return new self($curr_data, $template_suffix);
}
- /**
- * Form init ends
- * --------------
- * The rest are functions per input,
- * Such as setting current input, and
- * getting values for it
- */
-
- /**
- * Clear values between inputs
- */
- function reset(){
- $this->default = NULL;
-
- $this->force_text_mode = false;
- $this->alt_text = NULL;
- $this->guide_text = NULL;
- $this->alt_text_base = NULL;
-
- $this->required = NULL;
-
- $this->name = null;
- $this->value_forced = False;
- $this->value = NULL;
-
- $this->array_type = False;
- }
-
- /**
- * Resolve to a particular input of the instance, and also clear any input specific settings such as default.
- */
- function input($key){
- // clear
- $this->reset();
-
- // set key
- $this->key = $key;
- return $this;
- }
- /**
- * Set required
- */
- protected $required = NULL;
- function required($required = True){
- $this->required = $required;
- return $this;
- }
- /**
- * Set name (othrwise key is used)
- */
- protected $name = null;
- function set_name($name = NULL){
- $this->name = $name;
- return $this;
- }
- /**
- * Set value
- */
- protected $value_forced = False;
- protected $value = NULL;
- function set_value($value = NULL){
- $this->value_forced = True;
- $this->value = $value;
- return $this;
- }
- /**
- * Set a default for the currently set input
- */
- protected $default = NULL;
- function default($value = NULL){
- $this->default = $value;
- return $this;
+ protected function getComponentArray(){
+ return [
+ 'form' => $this
+ ];
}
- // Set text used to force text as is (rather than looking to trans() or array)
- protected $force_text_mode = false;
- protected $alt_text = NULL;
- protected $alt_text_base = NULL;
- protected $guide_text = NULL;
- function set_text($text, $guide = null){
- $this->force_text_mode = true;
- $this->alt_text = $text;
- $this->guide_text = $guide;
- return $this;
- }
- // Look in same text location as in init $text, but look for different key
- function alt_text($key){
- $this->alt_text = $key;
- return $this;
- }
- // Alt text base used to point to an entirely different base eg not the one given in init $text
- function alt_text_base($base){
- $this->alt_text_base = $base;
- return $this;
- }
- /**
- * When the error should return array as https://laravel.com/docs/8.x/validation#retrieving-all-error-messages-for-a-field
- * For example when using a multi dimentional form
- */
- protected $array_type = false;
- function array_type($array_type = false){
- $this->array_type = $array_type;
- return $this;
- }
-
- /**
- * Get various datas
- *
- *
- */
- function is_required(){
- return ($this->required === true);
- }
- /**
- * Get just the name even if it has prefix
- */
- function basename(){
- return $this->name ?? $this->key;
- }
- function id(){
- $id = $this->basename();
- if (is_array($this->prefix)){
- $prefix = $this->prefix;
- $prefix[] = $id;
- return join('-', $prefix);
- }
- return $id;
+ public function render($extra = []){
+ $constructor = (new ReflectionClass(Input::class))->getConstructor();
+ $parameters = $constructor
+ ? collect($constructor->getParameters())->mapWithKeys(function($item){
+ return [$item->getName() => $item->getDefaultValue()];
+ })->all()
+ : [];
- }
- function build_prefix($append_key = false){
- $name_path = '';
- $prefix = $this->prefix;
- if ($append_key === true) $prefix[] = $this->basename();
- $first = true;
- foreach($prefix as $part){
- if ($first === true){
- $first = false;
- $name_path .= $part;
- }else{
- $name_path .= '['.$part.']';
- }
- }
- return $name_path;
- }
- // TODO later I may need to add a way to separate input name from database key
- function name(){
- if (is_array($this->prefix)){
- return $this->build_prefix(true);
- }
- return $this->basename();
+ $attributes = [];
- }
- // Like name but used for getting old() so it points with prefix included like 'prefix.name'
- function name_path(){
- $name = $this->basename();
- if (is_array($this->prefix)){
- $prefix = $this->prefix;
- $prefix[] = $name;
- return join('.', $prefix);
- }
- return $name;
- }
- function text($force_key = null){
- if ($this->force_text_mode === true){
- return $this->alt_text;
- }
- $key = $force_key ?? $this->alt_text ?? $this->key;
- $text = $this->alt_text_base ?? $this->shift_text ?? $this->text;
- if (is_array($text)){
- return isset($text[$key]) ? $text[$key] :
- ($this->table !== null ? __('columns.' . $this->table . '.'. $key) : null)
- ;
- }
- return $this->trans_null($text . '.' . $key) ??
- ($this->table !== null ? __('columns.' . $this->table . '.'. $key) : null)
- ;
- }
-
- function guide($force_key = null){
- if ($this->force_text_mode === true){
- return $this->guide_text;
- }
- $key = $force_key ?? $this->alt_text ?? $this->key;
- $pointer = $key;
- $target = $this->guides;
- if ($target === null){
- $target = $this->shift_text ?? $this->alt_text_base ?? $this->text;
- $pointer .= '_guide';
- }
- if (is_array($target)){
- return isset($target[$pointer]) ? $target[$pointer] :
- // not found in array, will look in columns and expect always to have _guide so using $key and adding _guide
- ($this->table !== null ? $this->trans_null('columns.' . $this->table . '.'. $key . '_guide') : null);
- ;
- }
- $path = $target . '.' . $pointer;
- return $this->trans_null($path) ??
- ($this->table !== null ? $this->trans_null('columns.' . $this->table . '.'. $key . '_guide') : null)
- ;
+ $process_order = [
+ $this->getComponentArray(),
+ $extra
+ ];
- }
- /**
- * Used for guide mostly, to only show translations that exists
- * Doesnt work for json type transations, only php array key type
- */
- function trans_null($path){
- $trans = __($path);
- return ($trans != $path) ? $trans : null;
- }
-
- function error(){
- if ($this->errors){
- return $this->errors->first($this->name_path());
- }
- }
- function errors_array(){
- if ($this->array_type === true){
- $errors = $this->errors->get($this->name_path() . '.*');
+ foreach($process_order as $process){
+ foreach($process as $key => $value){
+ if ( array_key_exists( Str::camel($key), $parameters ) ){
+ $parameters[ Str::camel($key) ] = $value;
+ }else{
+ $attributes[ Str::kebab($key) ] = $value;
+ }
+ }
}
- return $errors ?? [];
+ $component = ( new Input( ...array_values($parameters) ) )->withAttributes($attributes)->withName('qform-input');
+ return $component->render()->with($component->data());
}
-
- function value($default = null){
- $target_data = $this->shift_data ?? $this->curr_data;
- $fallback =
- (
- $this->value_forced === True ? $this->value :
- (
- $this->curr_data_exists && isset($target_data[$this->key]) ? @$target_data[$this->key] :
- ($default ?? $this->default)
- )
- );
- $value = old($this->name_path(), $fallback);
- return $value;
- }
-
-
}
\ No newline at end of file
diff --git a/src/Shared.php b/src/Shared.php
deleted file mode 100644
index 44c915f..0000000
--- a/src/Shared.php
+++ /dev/null
@@ -1,20 +0,0 @@
-template = $template ?? QForm::$global_template;
- if ($this->template){
- $this->template_suffix = '_' . $this->template;
- return;
- }
- $this->template_suffix = '';
- }
-}
diff --git a/src/Submit.php b/src/Submit.php
index a64d279..84a77ce 100644
--- a/src/Submit.php
+++ b/src/Submit.php
@@ -8,7 +8,7 @@
class Submit extends Component
{
- use Shared;
+ use Concerns\Template;
/**
* Requires the QForm extension (by CJ)
*
@@ -28,7 +28,7 @@ public function __construct($form = null, $name = null, $text = 'Submit', $class
$this->class = $class;
$this->id = 'submit' . ($this->name ? '-' . $this->name : '');
- $this->set_template($template ?? ($form ? $form->template : null));
+ $this->template($template ?? ($form ? $form->template : null));
/**
* Guide
@@ -43,6 +43,6 @@ public function __construct($form = null, $name = null, $text = 'Submit', $class
*/
public function render()
{
- return view(S::$name . '::components.forms.submit' . $this->template_suffix);
+ return view(S::$name . '::components.forms.submit' . $this->getTemplate());
}
}
diff --git a/src/resources/views/input-attr.blade.php b/src/resources/views/input-attr.blade.php
index 4e473df..9b00e8e 100644
--- a/src/resources/views/input-attr.blade.php
+++ b/src/resources/views/input-attr.blade.php
@@ -1,7 +1,7 @@
@if ((isset($loop) && $loop->first) || (!isset($loop)))
@if ($required) required @endif
aria-required="{{ $required ? 'true' : 'false' }}"
- aria-invalid="{{ $form->error() ? 'true' : 'false' }}"
+ aria-invalid="{{ $error ? 'true' : 'false' }}"
@endif
@if(isset($loop) && is_array($variableAttributes))
@@ -14,6 +14,7 @@
type="{{ $type }}"
name="{{ (isset($alt_name) ? $alt_name : $name)}}"
+{{-- Alt value used when including loops etc. Or textarea is set as false meaning dont show value at all --}}
@if(($alt_value ?? null) !== false)value="{{ (isset($alt_value) ? $alt_value : $value)}}"@endif
@if(($aria_describedby ?? null) !== false)aria-describedby="{{ ($aria_describedby ?? null) ? $aria_describedby : $id . '-help' }}"@endif
id="input-{{ $id }}{{ isset($loop) ? '-' . $loop->iteration : '' }}"