mirror of
https://github.com/Part-DB/Part-DB-server.git
synced 2025-06-23 10:18:56 +02:00
Added autocomplete for part parameters
This commit is contained in:
parent
44b288b807
commit
9a7e47863b
18 changed files with 209 additions and 134 deletions
|
@ -8,7 +8,6 @@ export default class extends Controller {
|
||||||
_tomSelect;
|
_tomSelect;
|
||||||
|
|
||||||
connect() {
|
connect() {
|
||||||
|
|
||||||
let settings = {
|
let settings = {
|
||||||
plugins: {
|
plugins: {
|
||||||
remove_button:{
|
remove_button:{
|
||||||
|
|
|
@ -0,0 +1,95 @@
|
||||||
|
import {Controller} from "@hotwired/stimulus";
|
||||||
|
import TomSelect from "tom-select";
|
||||||
|
import katex from "katex";
|
||||||
|
import "katex/dist/katex.css";
|
||||||
|
|
||||||
|
/* stimulusFetch: 'lazy' */
|
||||||
|
export default class extends Controller
|
||||||
|
{
|
||||||
|
static values = {
|
||||||
|
url: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
static targets = ["name", "symbol", "unit"]
|
||||||
|
|
||||||
|
onItemAdd(value, item) {
|
||||||
|
//Retrieve the unit and symbol from the item
|
||||||
|
const symbol = item.dataset.symbol;
|
||||||
|
const unit = item.dataset.unit;
|
||||||
|
|
||||||
|
if (this.symbolTarget && symbol !== undefined) {
|
||||||
|
this.symbolTarget.value = symbol;
|
||||||
|
}
|
||||||
|
if (this.unitTarget && unit !== undefined) {
|
||||||
|
this.unitTarget.value = unit;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
connect() {
|
||||||
|
const settings = {
|
||||||
|
plugins: {
|
||||||
|
clear_button:{}
|
||||||
|
},
|
||||||
|
persistent: false,
|
||||||
|
maxItems: 1,
|
||||||
|
//This a an ugly solution to disable the delimiter parsing of the TomSelect plugin
|
||||||
|
delimiter: 'VERY_L0NG_D€LIMITER_WHICH_WILL_NEVER_BE_ENCOUNTERED_IN_A_STRING',
|
||||||
|
createOnBlur: true,
|
||||||
|
create: true,
|
||||||
|
searchField: "name",
|
||||||
|
//labelField: "name",
|
||||||
|
valueField: "name",
|
||||||
|
onItemAdd: this.onItemAdd.bind(this),
|
||||||
|
render: {
|
||||||
|
option: (data, escape) => {
|
||||||
|
let tmp = '<div>'
|
||||||
|
+ '<span>' + escape(data.name) + '</span><br>';
|
||||||
|
|
||||||
|
if (data.symbol) {
|
||||||
|
tmp += '<span>' + katex.renderToString(data.symbol) + '</span>'
|
||||||
|
}
|
||||||
|
if (data.unit) {
|
||||||
|
tmp += '<span class="ms-2">' + katex.renderToString('[' + data.unit + ']') + '</span>'
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//+ '<span class="text-muted">' + escape(data.unit) + '</span>'
|
||||||
|
tmp += '</div>';
|
||||||
|
|
||||||
|
return tmp;
|
||||||
|
},
|
||||||
|
item: (data, escape) => {
|
||||||
|
//We use the item to transfert data to the onItemAdd function using data attributes
|
||||||
|
const element = document.createElement('div');
|
||||||
|
element.innerText = data.name;
|
||||||
|
if(data.unit !== undefined) {
|
||||||
|
element.dataset.unit = data.unit;
|
||||||
|
}
|
||||||
|
if (data.symbol !== undefined) {
|
||||||
|
element.dataset.symbol = data.symbol;
|
||||||
|
}
|
||||||
|
|
||||||
|
return element.outerHTML;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
if(this.urlValue) {
|
||||||
|
const base_url = this.urlValue;
|
||||||
|
settings.load = (query, callback) => {
|
||||||
|
const url = base_url.replace('__QUERY__', encodeURIComponent(query));
|
||||||
|
|
||||||
|
fetch(url)
|
||||||
|
.then(response => response.json())
|
||||||
|
.then(json => {
|
||||||
|
//const data = json.map(x => {return {"value": x, "text": x}});
|
||||||
|
callback(json);
|
||||||
|
}).catch(()=>{
|
||||||
|
callback();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
this._tomSelect = new TomSelect(this.nameTarget, settings);
|
||||||
|
}
|
||||||
|
}
|
|
@ -42,9 +42,22 @@ declare(strict_types=1);
|
||||||
|
|
||||||
namespace App\Controller;
|
namespace App\Controller;
|
||||||
|
|
||||||
|
use App\Entity\Parameters\AttachmentTypeParameter;
|
||||||
|
use App\Entity\Parameters\CategoryParameter;
|
||||||
|
use App\Entity\Parameters\DeviceParameter;
|
||||||
|
use App\Entity\Parameters\FootprintParameter;
|
||||||
|
use App\Entity\Parameters\GroupParameter;
|
||||||
|
use App\Entity\Parameters\ManufacturerParameter;
|
||||||
|
use App\Entity\Parameters\MeasurementUnitParameter;
|
||||||
|
use App\Entity\Parameters\PartParameter;
|
||||||
|
use App\Entity\Parameters\StorelocationParameter;
|
||||||
|
use App\Entity\Parameters\SupplierParameter;
|
||||||
|
use App\Entity\PriceInformations\Currency;
|
||||||
|
use App\Repository\ParameterRepository;
|
||||||
use App\Services\Attachments\AttachmentURLGenerator;
|
use App\Services\Attachments\AttachmentURLGenerator;
|
||||||
use App\Services\Attachments\BuiltinAttachmentsFinder;
|
use App\Services\Attachments\BuiltinAttachmentsFinder;
|
||||||
use App\Services\TagFinder;
|
use App\Services\TagFinder;
|
||||||
|
use Doctrine\ORM\EntityManagerInterface;
|
||||||
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
|
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
|
||||||
use Symfony\Component\Asset\Packages;
|
use Symfony\Component\Asset\Packages;
|
||||||
use Symfony\Component\HttpFoundation\JsonResponse;
|
use Symfony\Component\HttpFoundation\JsonResponse;
|
||||||
|
@ -99,6 +112,58 @@ class TypeaheadController extends AbstractController
|
||||||
return new JsonResponse($data, 200, [], true);
|
return new JsonResponse($data, 200, [], true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This functions map the parameter type to the class, so we can access its repository
|
||||||
|
* @param string $type
|
||||||
|
* @return class-string
|
||||||
|
*/
|
||||||
|
private function typeToParameterClass(string $type): string
|
||||||
|
{
|
||||||
|
switch ($type) {
|
||||||
|
case 'category':
|
||||||
|
return CategoryParameter::class;
|
||||||
|
case 'part':
|
||||||
|
return PartParameter::class;
|
||||||
|
case 'device':
|
||||||
|
return DeviceParameter::class;
|
||||||
|
case 'footprint':
|
||||||
|
return FootprintParameter::class;
|
||||||
|
case 'manufacturer':
|
||||||
|
return ManufacturerParameter::class;
|
||||||
|
case 'storelocation':
|
||||||
|
return StorelocationParameter::class;
|
||||||
|
case 'supplier':
|
||||||
|
return SupplierParameter::class;
|
||||||
|
case 'attachment_type':
|
||||||
|
return AttachmentTypeParameter::class;
|
||||||
|
case 'group':
|
||||||
|
return GroupParameter::class;
|
||||||
|
case 'measurement_unit':
|
||||||
|
return MeasurementUnitParameter::class;
|
||||||
|
case 'currency':
|
||||||
|
return Currency::class;
|
||||||
|
|
||||||
|
default:
|
||||||
|
throw new \InvalidArgumentException('Invalid parameter type: '.$type);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Route("/parameters/{type}/search/{query}", name="typeahead_parameters", requirements={"type" = ".+"})
|
||||||
|
* @param string $query
|
||||||
|
* @return JsonResponse
|
||||||
|
*/
|
||||||
|
public function parameters(string $type, EntityManagerInterface $entityManager, string $query = ""): JsonResponse
|
||||||
|
{
|
||||||
|
$class = $this->typeToParameterClass($type);
|
||||||
|
/** @var ParameterRepository $repository */
|
||||||
|
$repository = $entityManager->getRepository($class);
|
||||||
|
|
||||||
|
$data = $repository->autocompleteParamName($query);
|
||||||
|
|
||||||
|
return new JsonResponse($data);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @Route("/tags/search/{query}", name="typeahead_tags", requirements={"query"= ".+"})
|
* @Route("/tags/search/{query}", name="typeahead_tags", requirements={"query"= ".+"})
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -33,7 +33,7 @@ use Symfony\Component\Validator\Constraints as Assert;
|
||||||
use function sprintf;
|
use function sprintf;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @ORM\Entity()
|
* @ORM\Entity(repositoryClass="App\Repository\ParameterRepository")
|
||||||
* @ORM\Table("parameters")
|
* @ORM\Table("parameters")
|
||||||
* @ORM\InheritanceType("SINGLE_TABLE")
|
* @ORM\InheritanceType("SINGLE_TABLE")
|
||||||
* @ORM\DiscriminatorColumn(name="type", type="smallint")
|
* @ORM\DiscriminatorColumn(name="type", type="smallint")
|
||||||
|
|
|
@ -28,7 +28,7 @@ use Doctrine\ORM\Mapping as ORM;
|
||||||
use Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntity;
|
use Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntity;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @ORM\Entity()
|
* @ORM\Entity(repositoryClass="App\Repository\ParameterRepository")
|
||||||
* @UniqueEntity(fields={"name", "group", "element"})
|
* @UniqueEntity(fields={"name", "group", "element"})
|
||||||
*/
|
*/
|
||||||
class AttachmentTypeParameter extends AbstractParameter
|
class AttachmentTypeParameter extends AbstractParameter
|
||||||
|
|
|
@ -28,7 +28,7 @@ use Doctrine\ORM\Mapping as ORM;
|
||||||
use Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntity;
|
use Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntity;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @ORM\Entity()
|
* @ORM\Entity(repositoryClass="App\Repository\ParameterRepository")
|
||||||
* @UniqueEntity(fields={"name", "group", "element"})
|
* @UniqueEntity(fields={"name", "group", "element"})
|
||||||
*/
|
*/
|
||||||
class CategoryParameter extends AbstractParameter
|
class CategoryParameter extends AbstractParameter
|
||||||
|
|
|
@ -30,7 +30,7 @@ use Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntity;
|
||||||
/**
|
/**
|
||||||
* A attachment attached to a category element.
|
* A attachment attached to a category element.
|
||||||
*
|
*
|
||||||
* @ORM\Entity()
|
* @ORM\Entity(repositoryClass="App\Repository\ParameterRepository")
|
||||||
* @UniqueEntity(fields={"name", "group", "element"})
|
* @UniqueEntity(fields={"name", "group", "element"})
|
||||||
*/
|
*/
|
||||||
class CurrencyParameter extends AbstractParameter
|
class CurrencyParameter extends AbstractParameter
|
||||||
|
|
|
@ -28,7 +28,7 @@ use Doctrine\ORM\Mapping as ORM;
|
||||||
use Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntity;
|
use Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntity;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @ORM\Entity()
|
* @ORM\Entity(repositoryClass="App\Repository\ParameterRepository")
|
||||||
* @UniqueEntity(fields={"name", "group", "element"})
|
* @UniqueEntity(fields={"name", "group", "element"})
|
||||||
*/
|
*/
|
||||||
class DeviceParameter extends AbstractParameter
|
class DeviceParameter extends AbstractParameter
|
||||||
|
|
|
@ -28,7 +28,7 @@ use Doctrine\ORM\Mapping as ORM;
|
||||||
use Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntity;
|
use Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntity;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @ORM\Entity()
|
* @ORM\Entity(repositoryClass="App\Repository\ParameterRepository")
|
||||||
* @UniqueEntity(fields={"name", "group", "element"})
|
* @UniqueEntity(fields={"name", "group", "element"})
|
||||||
*/
|
*/
|
||||||
class FootprintParameter extends AbstractParameter
|
class FootprintParameter extends AbstractParameter
|
||||||
|
|
|
@ -28,7 +28,7 @@ use Doctrine\ORM\Mapping as ORM;
|
||||||
use Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntity;
|
use Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntity;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @ORM\Entity()
|
* @ORM\Entity(repositoryClass="App\Repository\ParameterRepository")
|
||||||
* @UniqueEntity(fields={"name", "group", "element"})
|
* @UniqueEntity(fields={"name", "group", "element"})
|
||||||
*/
|
*/
|
||||||
class GroupParameter extends AbstractParameter
|
class GroupParameter extends AbstractParameter
|
||||||
|
|
|
@ -28,7 +28,7 @@ use Doctrine\ORM\Mapping as ORM;
|
||||||
use Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntity;
|
use Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntity;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @ORM\Entity()
|
* @ORM\Entity(repositoryClass="App\Repository\ParameterRepository")
|
||||||
* @UniqueEntity(fields={"name", "group", "element"})
|
* @UniqueEntity(fields={"name", "group", "element"})
|
||||||
*/
|
*/
|
||||||
class ManufacturerParameter extends AbstractParameter
|
class ManufacturerParameter extends AbstractParameter
|
||||||
|
|
|
@ -28,7 +28,7 @@ use Doctrine\ORM\Mapping as ORM;
|
||||||
use Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntity;
|
use Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntity;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @ORM\Entity()
|
* @ORM\Entity(repositoryClass="App\Repository\ParameterRepository")
|
||||||
* @UniqueEntity(fields={"name", "group", "element"})
|
* @UniqueEntity(fields={"name", "group", "element"})
|
||||||
*/
|
*/
|
||||||
class MeasurementUnitParameter extends AbstractParameter
|
class MeasurementUnitParameter extends AbstractParameter
|
||||||
|
|
|
@ -28,7 +28,7 @@ use Doctrine\ORM\Mapping as ORM;
|
||||||
use Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntity;
|
use Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntity;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @ORM\Entity()
|
* @ORM\Entity(repositoryClass="App\Repository\ParameterRepository")
|
||||||
* @UniqueEntity(fields={"name", "group", "element"})
|
* @UniqueEntity(fields={"name", "group", "element"})
|
||||||
*/
|
*/
|
||||||
class PartParameter extends AbstractParameter
|
class PartParameter extends AbstractParameter
|
||||||
|
|
|
@ -28,7 +28,7 @@ use Doctrine\ORM\Mapping as ORM;
|
||||||
use Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntity;
|
use Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntity;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @ORM\Entity()
|
* @ORM\Entity(repositoryClass="App\Repository\ParameterRepository")
|
||||||
* @UniqueEntity(fields={"name", "group", "element"})
|
* @UniqueEntity(fields={"name", "group", "element"})
|
||||||
*/
|
*/
|
||||||
class StorelocationParameter extends AbstractParameter
|
class StorelocationParameter extends AbstractParameter
|
||||||
|
|
|
@ -28,7 +28,7 @@ use Doctrine\ORM\Mapping as ORM;
|
||||||
use Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntity;
|
use Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntity;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @ORM\Entity()
|
* @ORM\Entity(repositoryClass="App\Repository\ParameterRepository")
|
||||||
* @UniqueEntity(fields={"name", "group", "element"})
|
* @UniqueEntity(fields={"name", "group", "element"})
|
||||||
*/
|
*/
|
||||||
class SupplierParameter extends AbstractParameter
|
class SupplierParameter extends AbstractParameter
|
||||||
|
|
33
src/Repository/ParameterRepository.php
Normal file
33
src/Repository/ParameterRepository.php
Normal file
|
@ -0,0 +1,33 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Repository;
|
||||||
|
|
||||||
|
class ParameterRepository extends DBElementRepository
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Find parameters using a parameter name
|
||||||
|
* @param string $name The name to search for
|
||||||
|
* @param bool $exact True, if only exact names should match. False, if the name just needs to be contained in the parameter name
|
||||||
|
* @param int $max_results
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function autocompleteParamName(string $name, bool $exact = false, int $max_results = 50): array
|
||||||
|
{
|
||||||
|
$qb = $this->createQueryBuilder('parameter');
|
||||||
|
|
||||||
|
$qb->distinct()
|
||||||
|
->select('parameter.name')
|
||||||
|
->addSelect('parameter.symbol')
|
||||||
|
->addSelect('parameter.unit')
|
||||||
|
->where('parameter.name LIKE :name');
|
||||||
|
if ($exact) {
|
||||||
|
$qb->setParameter('name', $name);
|
||||||
|
} else {
|
||||||
|
$qb->setParameter('name', '%'.$name.'%');
|
||||||
|
}
|
||||||
|
|
||||||
|
$qb->setMaxResults($max_results);
|
||||||
|
|
||||||
|
return $qb->getQuery()->getArrayResult();
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,117 +0,0 @@
|
||||||
<?php
|
|
||||||
/**
|
|
||||||
* This file is part of Part-DB (https://github.com/Part-DB/Part-DB-symfony).
|
|
||||||
*
|
|
||||||
* Copyright (C) 2019 - 2020 Jan Böhmer (https://github.com/jbtronics)
|
|
||||||
*
|
|
||||||
* This program is free software: you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU Affero General Public License as published
|
|
||||||
* by the Free Software Foundation, either version 3 of the License, or
|
|
||||||
* (at your option) any later version.
|
|
||||||
*
|
|
||||||
* This program is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU Affero General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU Affero General Public License
|
|
||||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
declare(strict_types=1);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This file is part of Part-DB (https://github.com/Part-DB/Part-DB-symfony).
|
|
||||||
*
|
|
||||||
* Copyright (C) 2019 Jan Böhmer (https://github.com/jbtronics)
|
|
||||||
*
|
|
||||||
* This program is free software; you can redistribute it and/or
|
|
||||||
* modify it under the terms of the GNU General Public License
|
|
||||||
* as published by the Free Software Foundation; either version 2
|
|
||||||
* of the License, or (at your option) any later version.
|
|
||||||
*
|
|
||||||
* This program is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU General Public License
|
|
||||||
* along with this program; if not, write to the Free Software
|
|
||||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
|
|
||||||
*/
|
|
||||||
|
|
||||||
namespace App\Services;
|
|
||||||
|
|
||||||
use App\Entity\Parts\Part;
|
|
||||||
use Doctrine\ORM\EntityManagerInterface;
|
|
||||||
use Symfony\Component\OptionsResolver\OptionsResolver;
|
|
||||||
|
|
||||||
use function array_slice;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A service related for searching for tags. Mostly useful for autocomplete reasons.
|
|
||||||
*/
|
|
||||||
class TagFinder
|
|
||||||
{
|
|
||||||
protected $em;
|
|
||||||
|
|
||||||
public function __construct(EntityManagerInterface $entityManager)
|
|
||||||
{
|
|
||||||
$this->em = $entityManager;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Search tags that begins with the certain keyword.
|
|
||||||
*
|
|
||||||
* @param string $keyword The keyword the tag must begin with
|
|
||||||
* @param array $options Some options specifying the search behavior. See configureOptions for possible options.
|
|
||||||
*
|
|
||||||
* @return string[] an array containing the tags that match the given keyword
|
|
||||||
*/
|
|
||||||
public function searchTags(string $keyword, array $options = []): array
|
|
||||||
{
|
|
||||||
$results = [];
|
|
||||||
$keyword_regex = '/^'.preg_quote($keyword, '/').'/';
|
|
||||||
|
|
||||||
$resolver = new OptionsResolver();
|
|
||||||
$this->configureOptions($resolver);
|
|
||||||
|
|
||||||
$options = $resolver->resolve($options);
|
|
||||||
|
|
||||||
//If the keyword is too short we will get to much results, which takes too much time...
|
|
||||||
if (mb_strlen($keyword) < $options['min_keyword_length']) {
|
|
||||||
return [];
|
|
||||||
}
|
|
||||||
|
|
||||||
//Build a query to get all
|
|
||||||
$qb = $this->em->createQueryBuilder();
|
|
||||||
|
|
||||||
$qb->select('p.tags')
|
|
||||||
->from(Part::class, 'p')
|
|
||||||
->where('p.tags LIKE ?1')
|
|
||||||
->setMaxResults($options['query_limit'])
|
|
||||||
//->orderBy('RAND()')
|
|
||||||
->setParameter(1, '%'.$keyword.'%');
|
|
||||||
|
|
||||||
$possible_tags = $qb->getQuery()->getArrayResult();
|
|
||||||
|
|
||||||
//Iterate over each possible tags (which are comma separated) and extract tags which match our keyword
|
|
||||||
foreach ($possible_tags as $tags) {
|
|
||||||
$tags = explode(',', $tags['tags']);
|
|
||||||
$results = array_merge($results, preg_grep($keyword_regex, $tags));
|
|
||||||
}
|
|
||||||
|
|
||||||
$results = array_unique($results);
|
|
||||||
//Limit the returned tag count to specified value.
|
|
||||||
return array_slice($results, 0, $options['return_limit']);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected function configureOptions(OptionsResolver $resolver): void
|
|
||||||
{
|
|
||||||
$resolver->setDefaults([
|
|
||||||
'query_limit' => 75,
|
|
||||||
'return_limit' => 75,
|
|
||||||
'min_keyword_length' => 2,
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -68,13 +68,13 @@
|
||||||
|
|
||||||
{% block parameter_widget %}
|
{% block parameter_widget %}
|
||||||
{% import 'components/collection_type.macro.html.twig' as collection %}
|
{% import 'components/collection_type.macro.html.twig' as collection %}
|
||||||
<tr>
|
<tr {{ stimulus_controller('pages/parameters_autocomplete', {"url": url('typeahead_parameters', {"query": "__QUERY__", "type": "part"})}) }}>
|
||||||
<td>{{ form_widget(form.name) }}{{ form_errors(form.name) }}</td>
|
<td>{{ form_widget(form.name, {"attr": {"data-pages--parameters-autocomplete-target": "name"}}) }}{{ form_errors(form.name) }}</td>
|
||||||
<td>{{ form_widget(form.symbol) }}{{ form_errors(form.symbol) }}</td>
|
<td>{{ form_widget(form.symbol, {"attr": {"data-pages--parameters-autocomplete-target": "symbol"}}) }}{{ form_errors(form.symbol) }}</td>
|
||||||
<td>{{ form_widget(form.value_min) }}{{ form_errors(form.value_min) }}</td>
|
<td>{{ form_widget(form.value_min) }}{{ form_errors(form.value_min) }}</td>
|
||||||
<td>{{ form_widget(form.value_typical) }}{{ form_errors(form.value_typical) }}</td>
|
<td>{{ form_widget(form.value_typical) }}{{ form_errors(form.value_typical) }}</td>
|
||||||
<td>{{ form_widget(form.value_max) }}{{ form_errors(form.value_max) }}</td>
|
<td>{{ form_widget(form.value_max) }}{{ form_errors(form.value_max) }}</td>
|
||||||
<td>{{ form_widget(form.unit) }}{{ form_errors(form.unit) }}</td>
|
<td>{{ form_widget(form.unit, {"attr": {"data-pages--parameters-autocomplete-target": "unit"}}) }}{{ form_errors(form.unit) }}</td>
|
||||||
<td>{{ form_widget(form.value_text) }}{{ form_errors(form.value_text) }}</td>
|
<td>{{ form_widget(form.value_text) }}{{ form_errors(form.value_text) }}</td>
|
||||||
<td>{{ form_widget(form.group) }}{{ form_errors(form.group) }}</td>
|
<td>{{ form_widget(form.group) }}{{ form_errors(form.group) }}</td>
|
||||||
<td>
|
<td>
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue