1
0
mirror of https://github.com/flextype/flextype.git synced 2025-08-18 02:41:27 +02:00

feat(form-plugin): add Form plugin #360

This commit is contained in:
Awilum
2020-02-06 19:42:08 +03:00
parent 418ef7073f
commit 97586d4bb7
11 changed files with 807 additions and 0 deletions

21
site/plugins/form/LICENSE.txt Executable file
View File

@@ -0,0 +1,21 @@
The MIT License (MIT)
Copyright (c) 2018-2020 Sergey Romanenko
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
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.

8
site/plugins/form/README.md Executable file
View File

@@ -0,0 +1,8 @@
# Form Plugin for [Flextype](http://flextype.org/)
![MIT License](https://img.shields.io/badge/license-MIT-blue.svg?style=flat-square)
Form Plugin for Flextype.
## LICENSE
[The MIT License (MIT)](https://github.com/flextype/flextype/blob/master/LICENSE.txt)
Copyright (c) 2018-2020 [Sergey Romanenko](https://github.com/Awilum)

View File

@@ -0,0 +1,658 @@
<?php
declare(strict_types=1);
/**
* @link http://digital.flextype.org
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Flextype;
use Flextype\Component\Arr\Arr;
use Flextype\Component\Form\Form;
use Flextype\Component\Html\Html;
use Flextype\Component\Filesystem\Filesystem;
use Psr\Http\Message\ServerRequestInterface as Request;
use function count;
use function date;
use function Flextype\Component\I18n\__;
use function str_replace;
use function strlen;
use function strpos;
use function strtotime;
use function substr_replace;
class FormController extends Controller
{
/**
* Flextype Dependency Container
*
* @var
* @access private
*/
private $flextype;
/**
* Form controls sizes
*
* @var array
* @access private
*/
private $sizes = [
'1/12' => 'col w-1/12',
'2/12' => 'col w-2/12',
'3/12' => 'col w-3/12',
'4/12' => 'col w-4/12',
'5/12' => 'col w-5/12',
'6/12' => 'col w-6/12',
'7/12' => 'col w-7/12',
'8/12' => 'col w-8/12',
'9/12' => 'col w-9/12',
'10/12' => 'col w-10/12',
'12/12' => 'col w-full',
'12' => 'col w-full',
];
/**
* Field class
*
* @var string
* @access private
*/
private $field_class = 'form-control';
/**
* Constructor
*
* @access public
*/
public function __construct($flextype)
{
$this->flextype = $flextype;
}
/**
* Render form
*
* @param array $fieldset Fieldset
* @param array $values Fieldset values
* @param Request $request PSR7 request
*
* @return string Returns form based on fieldsets
*
* @access public
*/
public function render(array $fieldset, array $values = [], Request $request) : string
{
$form = Form::open(null, ['id' => 'form']);
$form .= $this->_csrfHiddenField();
$form .= $this->_actionHiddenField();
// Go through all sections
if (count($fieldset['sections']) > 0) {
$form .= '<div class="tabs flex">';
// Go through all sections and create nav tabs
foreach ($fieldset['sections'] as $key => $section) {
$form .= '<div class="tabs__content w-9/12 ' . ($key === 'main' ? 'tabs__content--active' : '') . '">';
$form .= '<div class="row">';
foreach ($section['fields'] as $element => $properties) {
// Set empty form field element
$form_field = '';
// Set element name
$field_name = $this->getElementName($element);
// Set element id
$field_id = $this->getElementID($element);
// Set element default value
$field_value = $this->getElementValue($element, $values, $properties);
// Seletct field type
switch ($properties['type']) {
case 'textarea':
$form_field = $this->textareaField($field_id, $field_name, $field_value, $properties);
break;
case 'hidden':
$form_field = $this->hiddenField($field_id, $field_name, $field_value, $properties);
break;
case 'html':
$form_field = $this->htmlField($field_id, $field_name, $field_value, $properties);
break;
case 'select':
$form_field = $this->selectField($field_id, $field_name, $field_value, $properties);
break;
case 'template_select':
$form_field = $this->templateSelectField($field_id, $field_name, $field_value, $properties);
break;
case 'visibility_select':
$form_field = $this->visibilitySelectField($field_id, $field_name, $field_value, $properties);
break;
case 'heading':
$form_field = $this->headingField($field_id, $properties);
break;
case 'routable_select':
$form_field = $this->routableSelectField($field_id, $field_name, $field_value, $properties);
break;
case 'tags':
$form_field = $this->tagsField($field_id, $field_name, $field_value, $properties);
break;
case 'datetimepicker':
$form_field = $this->dateField($field_id, $field_name, $field_value, $properties);
break;
case 'media_select':
$form_field = $this->mediaSelectField($field_id, $field_name, $field_value, $properties, $request);
break;
default:
$form_field = $this->textField($field_id, $field_name, $field_value, $properties);
break;
}
$form .= $form_field;
}
$form .= '</div>';
$form .= '</div>';
}
$form .= '<nav class="tabs__nav w-3/12 pl-10"><div class="bg-dark text-white">';
// Go through all sections and create nav items
foreach ($fieldset['sections'] as $key => $section) {
$form .= '<a href="javascript:;" class="block opacity-90 p-2 pl-4 hover:bg-dark-muted hover:opacity-100 tabs__nav__link ' . ($key === 'main' ? 'tabs__nav__link--active' : '') . '">' . __($section['title']) . '</a>';
}
$form .= '</div></nav>';
$form .= '</div>';
}
$form .= Form::close();
return $form;
}
/**
* Get element value
*
* @param string $element Form Element
* @param array $values Form Values
* @param array $properties Field properties
*
* @return mixed Returns form element value
*
* @access protected
*/
protected function getElementValue(string $element, array $values, array $properties)
{
if (Arr::keyExists($values, $element)) {
$field_value = Arr::get($values, $element);
} elseif(Arr::keyExists($properties, 'default')) {
$field_value = $properties['default'];
} else {
$field_value = '';
}
return $field_value;
}
/**
* Get element name
*
* @param string $element Element
*
* @return string Returns form element name
*
* @access protected
*/
protected function getElementName(string $element) : string
{
$pos = strpos($element, '.');
if ($pos === false) {
$field_name = $element;
} else {
$field_name = str_replace('.', '][', "$element") . ']';
}
$pos = strpos($field_name, ']');
if ($pos !== false) {
$field_name = substr_replace($field_name, '', $pos, strlen(']'));
}
return $field_name;
}
/**
* Get element id
*
* @param string $element Element
*
* @return string Returns form element id
*
* @access protected
*/
protected function getElementID(string $element) : string
{
$pos = strpos($element, '.');
if ($pos === false) {
$field_name = $element;
} else {
$field_name = str_replace('.', '_', "$element");
}
return $field_name;
}
/**
* Media select field
*
* @param string $field_id Field ID
* @param string $field_name Field name
* @param mixed $field_value Field value
* @param array $properties Field properties
* @param Request $request PSR7 request
*
* @return string Returns field
*
* @access protected
*/
protected function mediaSelectField(string $field_id, string $field_name, $field_value, array $properties, Request $request) : string
{
$title = isset($properties['title']) ? $properties['title'] : '';
$size = isset($properties['size']) ? $this->sizes[$properties['size']] : $this->sizes['12'];
$help = isset($properties['help']) ? $properties['help'] : '';
$options = $this->flextype->EntriesController->getMediaList($request->getQueryParams()['id'], false);
$attributes = isset($properties['attributes']) ? $properties['attributes'] : [];
$attributes['id'] = isset($attributes['id']) ? $attributes['id'] : $field_id;
$attributes['class'] = isset($attributes['class']) ? $attributes['class'] : $this->field_class . ' js-select';
$field = '<div class="form-group ' . $size . '">';
$field .= ($title ? Form::label($field_id, __($title)) : '');
$field .= Form::select($field_name, $options, $field_value, $attributes);
$field .= ($help ? '<small class="form-text text-muted">' . __($help) . '</small>' : '');
$field .= '</div>';
return $field;
}
/**
* Template select field
*
* @param string $field_id Field ID
* @param string $field_name Field name
* @param mixed $field_value Field value
* @param array $properties Field properties
*
* @return string Returns field
*
* @access protected
*/
protected function templateSelectField(string $field_id, string $field_name, $field_value, array $properties) : string
{
$title = isset($properties['title']) ? $properties['title'] : '';
$size = isset($properties['size']) ? $this->sizes[$properties['size']] : $this->sizes['12'];
$help = isset($properties['help']) ? $properties['help'] : '';
$attributes = isset($properties['attributes']) ? $properties['attributes'] : [];
$attributes['id'] = isset($attributes['id']) ? $attributes['id'] : $field_id;
$attributes['class'] = isset($attributes['class']) ? $attributes['class'] : $this->field_class . ' js-select';
$_templates_list = $this->flextype['themes']->getTemplates($this->flextype['registry']->get('settings.theme'));
$options = [];
if (count($_templates_list) > 0) {
foreach ($_templates_list as $template) {
if ($template['type'] !== 'file' || $template['extension'] !== 'html') {
continue;
}
$options[$template['basename']] = $template['basename'];
}
}
$field = '<div class="form-group ' . $size . '">';
$field .= ($title ? Form::label($field_id, __($title)) : '');
$field .= Form::select($field_name, $options, $field_value, $attributes);
$field .= ($help ? '<small class="form-text text-muted">' . __($help) . '</small>' : '');
$field .= '</div>';
return $field;
}
/**
* Routable select field
*
* @param string $field_id Field ID
* @param string $field_name Field name
* @param mixed $field_value Field value
* @param array $properties Field properties
*
* @return string Returns field
*
* @access protected
*/
protected function routableSelectField(string $field_id, string $field_name, $field_value, array $properties) : string
{
$title = isset($properties['title']) ? $properties['title'] : '';
$size = isset($properties['size']) ? $this->sizes[$properties['size']] : $this->sizes['12'];
$help = isset($properties['help']) ? $properties['help'] : '';
$options = [true => __('admin_yes'), false => __('admin_no')];
$attributes = isset($properties['attributes']) ? $properties['attributes'] : [];
$attributes['id'] = isset($attributes['id']) ? $attributes['id'] : $field_id;
$attributes['class'] = isset($attributes['class']) ? $attributes['class'] : $this->field_class . ' js-select';
$field = '<div class="form-group ' . $size . '">';
$field .= ($title ? Form::label($field_id, __($title)) : '');
$field .= Form::select($field_name, $options, (is_string($field_value) ? true : ($field_value ? true : false)), $attributes);
$field .= ($help ? '<small class="form-text text-muted">' . __($help) . '</small>' : '');
$field .= '</div>';
return $field;
}
/**
* Select field
*
* @param string $field_id Field ID
* @param string $field_name Field name
* @param mixed $field_value Field value
* @param array $properties Field properties
*
* @return string Returns field
*
* @access protected
*/
protected function selectField(string $field_id, string $field_name, $field_value, array $properties) : string
{
$title = isset($properties['title']) ? $properties['title'] : '';
$size = isset($properties['size']) ? $this->sizes[$properties['size']] : $this->sizes['12'];
$help = isset($properties['help']) ? $properties['help'] : '';
$options = isset($properties['options']) ? $properties['options'] : [];
$attributes = isset($properties['attributes']) ? $properties['attributes'] : [];
$attributes['id'] = isset($attributes['id']) ? $attributes['id'] : $field_id;
$attributes['class'] = isset($attributes['class']) ? $attributes['class'] : $this->field_class . ' js-select';
$field = '<div class="form-group ' . $size . '">';
$field .= ($title ? Form::label($field_id, __($title)) : '');
$field .= Form::select($field_name, $options, $field_value, $attributes);
$field .= ($help ? '<small>' . __($help) . '</small>' : '');
$field .= '</div>';
return $field;
}
/**
* Heading field
*
* @param string $field_id Field ID
* @param array $properties Field properties
*
* @return string Returns field
*
* @access protected
*/
protected function headingField(string $field_id, array $properties) : string
{
$title = isset($properties['title']) ? $properties['title'] : '';
$size = isset($properties['size']) ? $this->sizes[$properties['size']] : $this->sizes['12'];
$h = isset($properties['h']) ? $properties['h'] : 3;
$attributes = isset($properties['attributes']) ? $properties['attributes'] : [];
$attributes['id'] = isset($attributes['id']) ? $attributes['id'] : $field_id;
$attributes['class'] = isset($attributes['class']) ? $attributes['class'] . 'text-3xl border-b border-black' : 'text-3xl border-b border-black';
$field = '<div class="form-group ' . $size . '">';
$field .= Html::heading(__($title), $h, $attributes);
$field .= '</div>';
return $field;
}
/**
* Html field
*
* @param string $field_id Field ID
* @param string $field_name Field name
* @param mixed $field_value Field value
* @param array $properties Field properties
*
* @return string Returns field
*
* @access protected
*/
protected function htmlField(string $field_id, string $field_name, $field_value, array $properties) : string
{
$title = isset($properties['title']) ? $properties['title'] : '';
$size = isset($properties['size']) ? $this->sizes[$properties['size']] : $this->sizes['12'];
$help = isset($properties['help']) ? $properties['help'] : '';
$attributes = isset($properties['attributes']) ? $properties['attributes'] : [];
$attributes['id'] = isset($attributes['id']) ? $attributes['id'] : $field_id;
$attributes['class'] = isset($attributes['class']) ? $attributes['class'] : $this->field_class;
$attributes['class'] .= ' js-html-editor';
$field = '<div class="form-group ' . $size . '">';
$field .= ($title ? Form::label($field_id, __($title)) : '');
$field .= Form::textarea($field_name, $field_value, $attributes);
$field .= ($help ? '<small class="form-text text-muted">' . __($help) . '</small>' : '');
$field .= '</div>';
return $field;
}
/**
* Hidden field
*
* @param string $field_id Field ID
* @param string $field_name Field name
* @param mixed $field_value Field value
* @param array $properties Field properties
*
* @return string Returns field
*
* @access protected
*/
protected function hiddenField(string $field_id, string $field_name, $field_value, array $properties) : string
{
$attributes = isset($properties['attributes']) ? $properties['attributes'] : [];
$attributes['id'] = isset($attributes['id']) ? $attributes['id'] : $field_id;
return Form::hidden($field_name, $field_value, $attributes);
}
/**
* Textarea field
*
* @param string $field_id Field ID
* @param string $field_name Field name
* @param string $field_value Field value
* @param array $properties Field properties
*
* @return string Returns field
*
* @access protected
*/
protected function textareaField(string $field_id, string $field_name, $field_value, array $properties) : string
{
$title = isset($properties['title']) ? $properties['title'] : '';
$size = isset($properties['size']) ? $this->sizes[$properties['size']] : $this->sizes['12'];
$help = isset($properties['help']) ? $properties['help'] : '';
$attributes = isset($properties['attributes']) ? $properties['attributes'] : [];
$attributes['id'] = isset($attributes['id']) ? $attributes['id'] : $field_id;
$attributes['class'] = isset($attributes['class']) ? $attributes['class'] : $this->field_class;
$field = '<div class="form-group ' . $size . '">';
$field .= ($title ? Form::label($field_id, __($title)) : '');
$field .= Form::textarea($field_name, $field_value, $attributes);
$field .= ($help ? '<small class="form-text text-muted">' . __($help) . '</small>' : '');
$field .= '</div>';
return $field;
}
/**
* Visibility field
*
* @param string $field_id Field ID
* @param string $field_name Field name
* @param mixed $field_value Field value
* @param array $properties Field properties
*
* @return string Returns field
*
* @access protected
*/
protected function visibilitySelectField(string $field_id, string $field_name, $field_value, array $properties) : string
{
$title = isset($properties['title']) ? $properties['title'] : '';
$size = isset($properties['size']) ? $this->sizes[$properties['size']] : $this->sizes['12'];
$help = isset($properties['help']) ? $properties['help'] : '';
$options = ['draft' => __('admin_entries_draft'), 'visible' => __('admin_entries_visible'), 'hidden' => __('admin_entries_hidden')];
$attributes = isset($properties['attributes']) ? $properties['attributes'] : [];
$attributes['id'] = isset($attributes['id']) ? $attributes['id'] : $field_id;
$attributes['class'] = isset($attributes['class']) ? $attributes['class'] : $this->field_class . ' js-select';
$field = '<div class="form-group ' . $size . '">';
$field .= ($title ? Form::label($field_id, __($title)) : '');
$field .= Form::select($field_name, $options, (! empty($field_value) ? $field_value : 'visible'), $attributes);
$field .= ($help ? '<small class="form-text text-muted">' . __($help) . '</small>' : '');
$field .= '</div>';
return $field;
}
/**
* Text field
*
* @param string $field_id Field ID
* @param string $field_name Field name
* @param mixed $field_value Field value
* @param array $properties Field properties
*
* @return string Returns field
*
* @access protected
*/
protected function textField(string $field_id, string $field_name, $field_value, array $properties) : string
{
$title = isset($properties['title']) ? $properties['title'] : '';
$size = isset($properties['size']) ? $this->sizes[$properties['size']] : $this->sizes['12'];
$help = isset($properties['help']) ? $properties['help'] : '';
$attributes = isset($properties['attributes']) ? $properties['attributes'] : [];
$attributes['id'] = isset($attributes['id']) ? $attributes['id'] : $field_id;
$attributes['class'] = isset($attributes['class']) ? $attributes['class'] : $this->field_class;
$field = '<div class="form-group ' . $size . '">';
$field .= ($title ? Form::label($field_id, __($title)) : '');
$field .= Form::input($field_name, $field_value, $attributes);
$field .= ($help ? '<small class="form-text text-muted">' . __($help) . '</small>' : '');
$field .= '</div>';
return $field;
}
/**
* Tags field
*
* @param string $field_id Field ID
* @param string $field_name Field name
* @param mixed $field_value Field value
*
* @return string Returns field
*
* @access protected
*/
protected function tagsField(string $field_id, string $field_name, $field_value, array $properties) : string
{
$title = isset($properties['title']) ? $properties['title'] : '';
$size = isset($properties['size']) ? $this->sizes[$properties['size']] : $this->sizes['12'];
$help = isset($properties['help']) ? $properties['help'] : '';
$attributes = isset($properties['attributes']) ? $properties['attributes'] : [];
$attributes['id'] = isset($attributes['id']) ? $attributes['id'] : $field_id;
$attributes['class'] = isset($attributes['class']) ? $attributes['class'] : $this->field_class;
$field = '<div class="form-group ' . $size . '">';
$field .= ($title ? Form::label($field_id, __($title)) : '');
$field .= '<input type="text" value="' . $field_value . '" name="' . $field_name . '" class="' . $attributes['class'] . '" data-role="tagsinput" />';
$field .= ($help ? '<small class="form-text text-muted">' . __($help) . '</small>' : '');
$field .= '</div>';
return $field;
}
/**
* Date field
*
* @param string $field_id Field ID
* @param string $field_name Field name
* @param mixed $field_value Field value
* @param array $properties Field properties
*
* @return string Returns field
*
* @access protected
*/
protected function dateField(string $field_id, string $field_name, $field_value, array $properties) : string
{
$title = isset($properties['title']) ? $properties['title'] : '';
$size = isset($properties['size']) ? $this->sizes[$properties['size']] : $this->sizes['12'];
$help = isset($properties['help']) ? $properties['help'] : '';
$field = '<div class="form-group ' . $size . '">';
$field .= ($title ? Form::label($field_id, __($title)) : '');
$field .= '<div class="input-group date" id="datetimepicker" data-target-input="nearest">';
$field .= '<input name="' . $field_name . '" type="text" class="form-control datetimepicker-input" data-target="#datetimepicker" value="' . date($this->flextype->registry->get('settings.date_format'), strtotime($field_value)) . '" />
<div class="input-group-append" data-target="#datetimepicker" data-toggle="datetimepicker">
<div class="input-group-text"><i class="far fa-calendar-alt"></i></div>
</div>';
$field .= ($help ? '<small class="form-text text-muted">' . __($help) . '</small>' : '');
$field .= '</div>';
$field .= '</div>';
return $field;
}
/**
* _csrfHiddenField
*
* @return string Returns field
*
* @access protected
*/
protected function _csrfHiddenField() : string
{
$field = '<input type="hidden" name="' . $this->flextype['csrf']->getTokenNameKey() . '" value="' . $this->flextype['csrf']->getTokenName() . '">';
$field .= '<input type="hidden" name="' . $this->flextype['csrf']->getTokenValueKey() . '" value="' . $this->flextype['csrf']->getTokenValue() . '">';
return $field;
}
/**
* _actionHiddenField
*
* @return string Returns field
*
* @access protected
*/
protected function _actionHiddenField() : string
{
return Form::hidden('action', 'save-form');
}
}

View File

@@ -0,0 +1,40 @@
<?php
declare(strict_types=1);
/**
* @link http://digital.flextype.org
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Flextype;
use function is_file;
/**
* Ensure vendor libraries exist
*/
! is_file($site_autoload = __DIR__ . '/vendor/autoload.php') and exit('Please run: <i>composer install</i>');
/**
* Register The Auto Loader
*
* Composer provides a convenient, automatically generated class loader for
* our application. We just need to utilize it! We'll simply require it
* into the script here so that we don't have to worry about manual
* loading any of our classes later on. It feels nice to relax.
* Register The Auto Loader
*/
$site_loader = require_once $site_autoload;
/**
* Include web routes
*/
include_once 'routes/web.php';
/**
* Include dependencies
*/
include_once 'dependencies.php';

View File

@@ -0,0 +1,33 @@
{
"name": "flextype-plugins/form",
"type": "project",
"description": "Form plugin for Flextype",
"keywords": ["form", "plugin", "flextype", "php", "html"],
"homepage": "https://github.com/flextype",
"license": "MIT",
"authors": [
{
"name": "Sergey Romanenko",
"email": "hello@romanenko.digital",
"homepage": "http://digital.flextype.org"
}
],
"support": {
"issues": "https://github.com/flextype/issues"
},
"require": {
"php": ">=7.2.0"
},
"config": {
"apcu-autoloader": true,
"optimize-autoloader": true,
"platform": {
"php": "7.2.0"
}
},
"autoload": {
"classmap": [
"app"
]
}
}

View File

@@ -0,0 +1,19 @@
<?php
declare(strict_types=1);
/**
* @link http://digital.flextype.org
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Flextype;
/**
* Add forms controller to Flextype container
*/
$flextype['FormController'] = static function ($container) {
return new FormController($container);
};

View File

@@ -0,0 +1,2 @@
form: "Form"
form_description: "Form plugin for Flextype"

View File

@@ -0,0 +1,2 @@
form: "Form"
form_description: "Form plugin for Flextype"

11
site/plugins/form/plugin.yaml Executable file
View File

@@ -0,0 +1,11 @@
name: Form
version: 0.9.6
description: Form plugin for Flextype
icon: fas fa-check-circle
author:
name: Sergey Romanenko
email: hello@romanenko.digital
url: http://flextype.org
homepage: https://github.com/flextype
bugs: https://github.com/flextype/issues
license: MIT

View File

@@ -0,0 +1,12 @@
<?php
declare(strict_types=1);
/**
* @link http://digital.flextype.org
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Flextype;

View File

@@ -0,0 +1 @@
enabled: true