Skip to content
Snippets Groups Projects
Commit a3b1cad5 authored by Bertrand Gauthier's avatar Bertrand Gauthier
Browse files

Nouvel élément de formulaire SearchAndSelect2 (basé sur le widget js Select2).

parent fb33a485
No related branches found
No related tags found
No related merge requests found
Pipeline #16910 passed
CHANGELOG
=========
5.1.5
-----
- Nouvel élément de formulaire SearchAndSelect2 (basé sur le widget js Select2).
5.1.4
-----
-
5.1.3
-----
-
5.1.2
-----
-
5.1.1
-----
- Suppression du fix pour bootstrap-select-1.14.0-beta2 donc nécessaité de passer à bootstrap-select-1.14.0-beta3 dans vos applis.
......
......@@ -2,12 +2,15 @@
namespace UnicaenApp;
use Laminas\ServiceManager\Factory\InvokableFactory;
use UnicaenApp\Controller\CacheControllerFactory;
use UnicaenApp\Controller\ConsoleController;
use UnicaenApp\Controller\ConsoleControllerFactory;
use UnicaenApp\Controller\InstadiaControllerFactory;
use UnicaenApp\Form\Element\SearchAndSelect2;
use UnicaenApp\Form\View\Helper\FormControlGroup;
use UnicaenApp\Form\View\Helper\FormControlGroupFactory;
use UnicaenApp\Form\View\Helper\FormSearchAndSelect2;
use UnicaenApp\HostLocalization\HostLocalization;
use UnicaenApp\HostLocalization\HostLocalizationFactory;
use UnicaenApp\Message\View\Helper\MessageHelper;
......@@ -366,6 +369,7 @@ return [
'form_elements' => [
'invokables' => [
'UploadForm' => 'UnicaenApp\Controller\Plugin\Upload\UploadForm',
SearchAndSelect2::class => InvokableFactory::class,
],
'initializers' => [
'UnicaenApp\Service\EntityManagerAwareInitializer',
......@@ -426,6 +430,7 @@ return [
'formDateInfSup' => 'UnicaenApp\Form\View\Helper\FormDateInfSup',
'formRowDateInfSup' => 'UnicaenApp\Form\View\Helper\FormRowDateInfSup',
'formSearchAndSelect' => 'UnicaenApp\Form\View\Helper\FormSearchAndSelect',
'formSearchAndSelect2' => FormSearchAndSelect2::class,
'formLdapPeople' => 'UnicaenApp\Form\View\Helper\FormLdapPeople',
'formErrors' => 'UnicaenApp\Form\View\Helper\FormErrors',
'form' => 'UnicaenApp\Form\View\Helper\Form',
......
<?php
namespace UnicaenApp\Filter;
use Laminas\Filter\AbstractFilter;
class SearchAndSelect2Filter extends AbstractFilter
{
/**
* @inheritDoc
*/
public function filter($value)
{
// TODO: Implement filter() method.
}
}
\ No newline at end of file
<?php
namespace UnicaenApp\Form\Element;
use InvalidArgumentException;
use Laminas\Form\Element\Select;
/**
* Elément de formulaire permettant de sélectionner un ou plusieurs items recherchés dans une source de
* données distante (via ajax).
*
* NB: Il faut utiliser l'aide de vue 'FormSearchAndSelect2' pour dessiner cet élément.
*
* @see \UnicaenApp\Form\View\Helper\FormSearchAndSelect
* @author Unicaen
*/
class SearchAndSelect2 extends Select
{
const SEPARATOR = '|';
protected bool $selectionRequired = false;
protected ?string $autocompleteSource = null;
/**
* Spécifie la source de données dans laquelle est effectuée la recherche.
*/
public function setAutocompleteSource(string $autocompleteSource): self
{
$this->autocompleteSource = $autocompleteSource;
return $this;
}
/**
* Retourne la source de données dans laquelle est effectuée la recherche.
*/
public function getAutocompleteSource(): ?string
{
return $this->autocompleteSource;
}
public function setValue($value): self
{
if ($value) {
if (!is_string($value)) {
throw new InvalidArgumentException(
"Cet élément de formulaire n'accepte que les chaînes de caractères"
);
}
if (!str_contains($value, $sep = self::SEPARATOR)) {
throw new InvalidArgumentException(
"Cet élément de formulaire n'accepte que les valeurs de la forme 'id{$sep}label'"
);
}
}
$valueOptions = $this->extractValueOptionsFromValue($value);
$this->setValueOptions($valueOptions);
return parent::setValue($value);
}
// public function getValue()
// {
// if ($this->isMultiple()) {
// return array_keys($this->getValueOptions());
// } else {
// return key($this->getValueOptions()) ?: null;
// }
// }
// /**
// * @return string|int|array
// */
// public function getValueIds()
// {
// if ($this->isMultiple()) {
// return array_keys($this->getValueOptions());
// } else {
// return key($this->getValueOptions()) ?: null;
// }
// }
protected function extractValueOptionsFromValue($value): array
{
if (!$value) {
return [];
}
$valueOptions = [];
if ($this->isMultiple()) {
foreach ($value as $item) {
$valueOptions[$item] = self::extractLabelFromValue($item);
}
} else {
$valueOptions[$value] = self::extractLabelFromValue($value);
}
return $valueOptions;
}
static public function createValueFromIdAndLabel($id, string $label): string
{
return implode(self::SEPARATOR, [$id, $label]);
}
static public function extractIdFromValue(string $value): string
{
return explode(self::SEPARATOR, $value)[0];
}
static public function extractLabelFromValue(string $value): string
{
return explode(self::SEPARATOR, $value)[1];
}
}
\ No newline at end of file
......@@ -2,19 +2,18 @@
namespace UnicaenApp\Form\View\Helper;
use UnicaenApp\Exception\LogicException;
use UnicaenApp\Form\Element\Date;
use UnicaenApp\Form\Element\DateInfSup;
use UnicaenApp\Form\Element\SearchAndSelect;
use Laminas\Form\Element\Button;
use Laminas\Form\Element\Checkbox;
use Laminas\Form\Element\DateTime;
use Laminas\Form\Element\MultiCheckbox;
use Laminas\Form\Element\Radio;
use Laminas\Form\Element\Select;
use Laminas\Form\ElementInterface;
use Laminas\Form\View\Helper\AbstractHelper;
use Laminas\Form\View\Helper\FormElementErrors;
use UnicaenApp\Exception\LogicException;
use UnicaenApp\Form\Element\Date;
use UnicaenApp\Form\Element\DateInfSup;
use UnicaenApp\Form\Element\SearchAndSelect;
use UnicaenApp\Form\Element\SearchAndSelect2;
/**
* Aide de vue générant un élément de fomulaire à la mode Bootsrap 5.
......@@ -66,11 +65,11 @@ class FormControlGroup extends AbstractHelper
* Appel de l'objet comme une fonction.
*
* @param \Laminas\Form\ElementInterface|null $element Élément de formulaire
* @param string|null $pluginClass Plugin
* @param string|AbstractHelper $pluginClass Plugin
*
* @return string|FormControlGroup
*/
public function __invoke(ElementInterface $element = null, $pluginClass = 'formElement')
public function __invoke(ElementInterface $element = null, $pluginClass = null)
{
if (null === $element) {
return $this;
......@@ -85,11 +84,11 @@ class FormControlGroup extends AbstractHelper
* Génère le code HTML.
*
* @param ElementInterface $element
* @param string|null $pluginClass
* @param string|AbstractHelper $pluginClass
*
* @return string
*/
public function render(ElementInterface $element, $pluginClass = 'formElement'): string
public function render(ElementInterface $element, $pluginClass = null): string
{
$this->normalizeElement($element);
$this->customFromOptions($element);
......@@ -236,13 +235,23 @@ class FormControlGroup extends AbstractHelper
return $helpContentAfter;
}
private function inputHtml(ElementInterface $element, $pluginClass = 'formElement')
private function inputHtml(ElementInterface $element, $pluginClass = null)
{
if (!$pluginClass) {
$pluginClass = 'formElement';
if ($pluginClass) {
if (is_string($pluginClass)) {
$helper = $this->getView()->plugin($pluginClass);
$html = $helper($element);
} elseif ($pluginClass instanceof AbstractHelper) {
$html = $pluginClass->__invoke($element);
} else {
throw new LogicException('Argument $pluginClass incorrect');
}
if ($element instanceof SearchAndSelect) {
} elseif ($element instanceof SearchAndSelect2) {
/** @var \UnicaenApp\Form\View\Helper\FormSearchAndSelect2 $helper */
$helper = $this->getView()->plugin('formSearchAndSelect2');
$helper->setAutocompleteMinLength(2);
$html = $helper($element);
} elseif ($element instanceof SearchAndSelect) {
/** @var FormSearchAndSelect $helper */
$helper = $this->getView()->plugin('formSearchAndSelect');
$helper->setAutocompleteMinLength(2);
......@@ -257,14 +266,8 @@ class FormControlGroup extends AbstractHelper
$helper = $this->getView()->plugin('formDateTime');
$html = $helper($element);
} else {
if (is_string($pluginClass)) {
$helper = $this->getView()->plugin($pluginClass);
$helper = $this->getView()->plugin('formElement');
$html = $helper($element);
} elseif ($pluginClass instanceof \Laminas\Form\View\Helper\AbstractHelper) {
$html = $pluginClass($element);
} else {
throw new LogicException('Argument $pluginClass incorrect');
}
}
if ($element instanceof MultiCheckbox) {
......
<?php
namespace UnicaenApp\Form\View\Helper;
use Laminas\Form\ElementInterface;
use Laminas\Form\Exception\InvalidElementException;
use Laminas\Form\View\Helper\FormSelect;
use UnicaenApp\Exception\LogicException;
use UnicaenApp\Form\Element\SearchAndSelect2;
/**
* Aide de vue dédiée à l'élément {@see \UnicaenApp\Form\Element\SearchAndSelect}.
* Génère un <select> sur lequel est installé le widget "Select2" (https://select2.org).
*
* @property \Application\View\Renderer\PhpRenderer $view
*
* @author Unicaen
* @see \UnicaenApp\Form\Element\SearchAndSelect
*/
class FormSearchAndSelect2 extends FormSelect
{
protected SearchAndSelect2 $element;
protected ?string $autocompleteSource = null;
protected int $autocompleteMinLength = 2;
public function setAutocompleteSource(string $autocompleteSource): self
{
$this->autocompleteSource = $autocompleteSource;
return $this;
}
public function setAutocompleteMinLength($autocompleteMinLength): self
{
$this->autocompleteMinLength = $autocompleteMinLength;
return $this;
}
public function __invoke(ElementInterface $element = null)
{
if ($element && !$element instanceof SearchAndSelect2) {
throw new InvalidElementException("L'élément spécifié n'est pas du type attendu.");
}
$this->element = $element;
return parent::__invoke($element);
}
/**
* @param SearchAndSelect2 $element
* @return string
*/
public function render(ElementInterface $element): string
{
if (!$element instanceof SearchAndSelect2) {
throw new InvalidElementException("L'élément spécifié n'est pas du type attendu.");
}
$this->element = $element;
if (!$this->element->getAttribute('id')) {
$this->element->setAttribute('id', uniqid('sas-'));
}
// $this->element->setAttribute('class', 'sas');
// $element = new Select();
// $element
// ->setAttributes($this->element->getAttributes())
// ->setName($this->element->getName())
// ->setAttribute('multiple', $this->element->isMultiple())
// ->setAttribute('id', $this->element->getAttribute('id'))
// ->setAttribute('class', 'sas form-control form-control-sm');
//
// $element->setValueOptions($this->element->getValueOptions());
// $element->setValue($this->element->getValueIds());
$markup = $this->view->formSelect($this->element);
$markup .= PHP_EOL . '<script>' . $this->getJavascript() . '</script>' . PHP_EOL;
return $markup;
}
public function getJavascript(): string
{
if (!$this->element) {
throw new LogicException("Aucun élément spécifié, appelez render() auparavant.");
}
$elementDomId = $this->element->getAttribute('id');
$autocompleteMinLength = $this->autocompleteMinLength;
$autocompleteSource = $this->autocompleteSource ?: $this->element->getAutocompleteSource();
$placeholder = $this->element->getAttribute('placeholder');
$separator = SearchAndSelect2::SEPARATOR;
return <<<EOT
$(function() {
$("#$elementDomId").select2({
allowClear: true,
minimumInputLength: $autocompleteMinLength,
placeholder: "$placeholder",
ajax: {
url: '$autocompleteSource',
processResults: function (data) {
data.forEach(function(item) {
item.id = item.id + '$separator' + item.label; // concat de l'id et du label
});
//console.log(data);
return { results: data };
},
dataType: 'json',
delay: 500
},
templateResult: function(item) {
if (!item.id) {
return item.text;
}
if (item.extra && item.extra.trim()) {
return $('<span>' + item.text + ' <span class="badge bg-secondary">' + item.extra + '</span></span>');
} else {
return $('<span>' + item.text + '</span>');
}
}
});
});
EOT;
}
}
\ No newline at end of file
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment