119 lines
4.2 KiB
PHP

<?php
declare(strict_types=1);
/*
* Chill is a software for social workers
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/
namespace Chill\ThirdPartyBundle\Search;
use Chill\MainBundle\Search\SearchApiInterface;
use Chill\MainBundle\Search\SearchApiQuery;
use Chill\ThirdPartyBundle\Repository\ThirdPartyRepository;
/*
* Internal note: test query for parametrizing / testing:
*
WITH rows AS (
SELECT 'aide a domicile en milieu rural admr' AS c, 'la roche sur yon' AS l
UNION
SELECT 'aide a domicile en milieu rural admr' AS c, 'fontenay-le-comte' AS l
), searches AS (
SELECT 'admr roche' AS s, 'admr' AS s1, 'roche' As s2
UNION
SELECT 'admr font' AS s, 'admr' AS s1, 'font' AS s2
)
SELECT
c, l, s, s1, s2,
strict_word_similarity(s, c)
+ (c LIKE '%' || s1 || '%')::int
+ (c LIKE '%' || s2 || '%')::int
+ (l LIKE '%' || s1 || '%')::int
+ (l LIKE '%' || s2 || '%')::int,
l LIKE '%' || s1 || '%',
l LIKE '%' || s2 || '%'
FROM rows, searches
*/
/**
* Generate query for searching amongst third parties.
*/
class ThirdPartyApiSearch implements SearchApiInterface
{
public function __construct(private readonly ThirdPartyRepository $thirdPartyRepository) {}
public function getResult(string $key, array $metadata, float $pertinence)
{
return $this->thirdPartyRepository->find($metadata['id']);
}
public function prepare(array $metadatas): void {}
public function provideQuery(string $pattern, array $parameters): SearchApiQuery
{
$query = (new SearchApiQuery())
->setSelectKey('tparty')
->setSelectJsonbMetadata("jsonb_build_object('id', tparty.id)")
->setFromClause('chill_3party.third_party AS tparty
LEFT JOIN chill_3party.third_party AS parent ON tparty.parent_id = parent.id
LEFT JOIN chill_main_address cma ON cma.id = COALESCE(parent.address_id, tparty.address_id)
LEFT JOIN chill_main_postal_code cmpc ON cma.postcode_id = cmpc.id');
$strs = \explode(' ', $pattern);
$wheres = [];
$whereArgs = [];
$pertinence = [];
$pertinenceArgs = [];
foreach ($strs as $str) {
if ('' !== trim($str)) {
$wheres[] = "((LOWER(UNACCENT(?)) <<% tparty.canonicalized OR
tparty.canonicalized LIKE '%' || LOWER(UNACCENT(?)) || '%')
OR
(LOWER(UNACCENT(?)) <<% parent.canonicalized OR
parent.canonicalized LIKE '%' || LOWER(UNACCENT(?)) || '%'))
";
$whereArgs[] = [$str, $str, $str, $str];
$pertinence[] = 'GREATEST(
STRICT_WORD_SIMILARITY(LOWER(UNACCENT(?)), tparty.canonicalized),
STRICT_WORD_SIMILARITY(LOWER(UNACCENT(?)), parent.canonicalized)
) + '.
"GREATEST(
(tparty.canonicalized LIKE '%s' || LOWER(UNACCENT(?)) || '%')::int,
(parent.canonicalized LIKE '%s' || LOWER(UNACCENT(?)) || '%')::int
) + ".
// take postcode label into account, but lower than the canonicalized field
"COALESCE((LOWER(UNACCENT(cmpc.label)) LIKE '%' || LOWER(UNACCENT(?)) || '%')::int * 0.3, 0)";
$pertinenceArgs[] = [$str, $str, $str, $str, $str];
}
}
$query
->setSelectPertinence(\implode(' + ', $pertinence).' + 1', \array_merge(
[],
...$pertinenceArgs
))
->andWhereClause(\implode(' AND ', $wheres)
.' AND tparty.active IS TRUE and (parent.active IS TRUE OR parent IS NULL)', \array_merge(
[],
...$whereArgs
));
return $query;
}
public function supportsResult(string $key, array $metadatas): bool
{
return 'tparty' === $key;
}
public function supportsTypes(string $pattern, array $types, array $parameters): bool
{
return \in_array('thirdparty', $types, true);
}
}