Merge branch '139_demandeur' into _23_addresses_form_2

This commit is contained in:
2021-05-11 15:51:06 +02:00
51 changed files with 1732 additions and 375 deletions

View File

@@ -25,12 +25,19 @@ class AbstractCRUDController extends AbstractController
*
* @param string $id
* @return object
* @throw Symfony\Component\HttpKernel\Exception\NotFoundHttpException if the object is not found
*/
protected function getEntity($action, $id, Request $request): ?object
protected function getEntity($action, $id, Request $request): object
{
return $this->getDoctrine()
$e = $this->getDoctrine()
->getRepository($this->getEntityClass())
->find($id);
if (NULL === $e) {
throw $this->createNotFoundException(sprintf("The object %s for id %s is not found", $this->getEntityClass(), $id));
}
return $e;
}
/**

View File

@@ -22,6 +22,7 @@
namespace Chill\MainBundle\Controller;
use Chill\MainBundle\Serializer\Model\Collection;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\Request;
use Chill\MainBundle\Search\UnknowSearchDomainException;
@@ -34,6 +35,7 @@ use Symfony\Component\HttpFoundation\JsonResponse;
use Chill\MainBundle\Search\SearchProvider;
use Symfony\Contracts\Translation\TranslatorInterface;
use Chill\MainBundle\Pagination\PaginatorFactory;
use Chill\MainBundle\Search\SearchApi;
/**
* Class SearchController
@@ -42,32 +44,24 @@ use Chill\MainBundle\Pagination\PaginatorFactory;
*/
class SearchController extends AbstractController
{
/**
*
* @var SearchProvider
*/
protected $searchProvider;
protected SearchProvider $searchProvider;
/**
*
* @var TranslatorInterface
*/
protected $translator;
protected TranslatorInterface $translator;
/**
*
* @var PaginatorFactory
*/
protected $paginatorFactory;
protected PaginatorFactory $paginatorFactory;
protected SearchApi $searchApi;
function __construct(
SearchProvider $searchProvider,
TranslatorInterface $translator,
PaginatorFactory $paginatorFactory
PaginatorFactory $paginatorFactory,
SearchApi $searchApi
) {
$this->searchProvider = $searchProvider;
$this->translator = $translator;
$this->paginatorFactory = $paginatorFactory;
$this->searchApi = $searchApi;
}
@@ -152,6 +146,19 @@ class SearchController extends AbstractController
array('results' => $results, 'pattern' => $pattern)
);
}
public function searchApi(Request $request, $_format): JsonResponse
{
//TODO this is an incomplete implementation
$query = $request->query->get('q', '');
$results = $this->searchApi->getResults($query, 0, 150);
$paginator = $this->paginatorFactory->create(count($results));
$collection = new Collection($results, $paginator);
return $this->json($collection);
}
public function advancedSearchListAction(Request $request)
{

View File

@@ -55,11 +55,11 @@ class LoadCenters extends AbstractFixture implements OrderedFixtureInterface
public function load(ObjectManager $manager)
{
foreach (static::$centers as $new) {
$centerA = new Center();
$centerA->setName($new['name']);
$center = new Center();
$center->setName($new['name']);
$manager->persist($centerA);
$this->addReference($new['ref'], $centerA);
$manager->persist($center);
$this->addReference($new['ref'], $center);
static::$refs[] = $new['ref'];
}

View File

@@ -39,8 +39,17 @@ div.subheader {
height: 130px;
}
//// VUEJS ////
//// SCRATCH BUTTONS
.sc-button {
&.disabled {
cursor: default;
&.bt-remove {
background-color: #d9d9d9;
}
}
}
//// VUEJS ////
div.vue-component {
padding: 1.5em;
margin: 2em 0;
@@ -95,33 +104,47 @@ div.vue-component {
}
//// AddPersons modal
div.modal-body.up {
margin: auto 4em;
div.search {
position: relative;
input {
padding: 1.2em 1.5em 1.2em 2.5em;
margin: 1em 0;
div.body-head {
overflow-y: unset;
div.modal-body:first-child {
margin: auto 4em;
div.search {
position: relative;
input {
padding: 1.2em 1.5em 1.2em 2.5em;
margin: 1em 0;
}
i {
position: absolute;
opacity: 0.5;
padding: 0.65em 0;
top: 50%;
}
i.fa-search {
left: 0.5em;
}
i.fa-times {
right: 1em;
padding: 0.75em 0;
cursor: pointer;
}
}
i {
position: absolute;
top: 50%;
left: 0.5em;
padding: 0.65em 0;
opacity: 0.5;
}
}
div.modal-body:last-child {
padding-bottom: 0;
}
}
div.results {
div.count {
margin: -0.5em 0 0.7em;
display: flex;
justify-content: space-between;
div.count {
margin: -0.5em 0 0.7em;
display: flex;
justify-content: space-between;
a {
cursor: pointer;
}
}
div.results {
div.list-item {
line-height: 26pt;
padding: 0.3em 0.8em;
padding: 0.4em 0.8em;
display: flex;
flex-direction: row;
&.checked {
@@ -132,11 +155,20 @@ div.results {
& > input {
margin-right: 0.8em;
}
span:not(.name) {
margin-left: 0.5em;
opacity: 0.5;
font-size: 90%;
font-style: italic;
}
}
div.right_actions {
margin: 0 0 0 auto;
display: flex;
align-items: flex-end;
& > * {
margin-left: 0.5em;
align-self: baseline;
}
a.sc-button {
border: 1px solid lightgrey;
@@ -146,7 +178,6 @@ div.results {
}
}
}
.discret {
color: grey;
margin-right: 1em;

View File

@@ -9,8 +9,8 @@
<button class="close sc-button grey" @click="$emit('close')">
<i class="fa fa-times" aria-hidden="true"></i></button>
</div>
<div class="modal-body up" style="overflow-y: unset;">
<slot name="body-fixed"></slot>
<div class="body-head">
<slot name="body-head"></slot>
</div>
<div class="modal-body">
<slot name="body"></slot>

View File

@@ -0,0 +1,36 @@
<?php
namespace Chill\MainBundle\Search\Model;
class Result
{
private float $relevance;
/**
* mixed an arbitrary result
*/
private $result;
/**
* @param float $relevance
* @param $result
*/
public function __construct(float $relevance, $result)
{
$this->relevance = $relevance;
$this->result = $result;
}
public function getRelevance(): float
{
return $this->relevance;
}
public function getResult()
{
return $this->result;
}
}

View File

@@ -0,0 +1,89 @@
<?php
namespace Chill\MainBundle\Search;
use Chill\PersonBundle\Entity\Person;
use Chill\ThirdPartyBundle\Entity\ThirdParty;
use Doctrine\ORM\EntityManagerInterface;
use Chill\MainBundle\Search\SearchProvider;
use Symfony\Component\VarDumper\Resources\functions\dump;
/**
* ***Warning*** This is an incomplete implementation ***Warning***
*/
class SearchApi
{
private EntityManagerInterface $em;
private SearchProvider $search;
public function __construct(EntityManagerInterface $em, SearchProvider $search)
{
$this->em = $em;
$this->search = $search;
}
/**
* @return Model/Result[]
*/
public function getResults(string $query, int $offset, int $maxResult): array
{
// **warning again**: this is an incomplete implementation
$results = [];
foreach ($this->getPersons($query) as $p) {
$results[] = new Model\Result((float)\rand(0, 100) / 100, $p);
}
foreach ($this->getThirdParties($query) as $t) {
$results[] = new Model\Result((float)\rand(0, 100) / 100, $t);
}
\usort($results, function(Model\Result $a, Model\Result $b) {
return ($a->getRelevance() <=> $b->getRelevance()) * -1;
});
return $results;
}
public function countResults(string $query): int
{
return 0;
}
private function getThirdParties(string $query)
{
$thirdPartiesIds = $this->em->createQuery('SELECT t.id FROM '.ThirdParty::class.' t')
->getScalarResult();
$nbResults = rand(0, 15);
if ($nbResults === 1) {
$nbResults++;
} elseif ($nbResults === 0) {
return [];
}
$ids = \array_map(function ($e) use ($thirdPartiesIds) { return $thirdPartiesIds[$e]['id'];},
\array_rand($thirdPartiesIds, $nbResults));
$a = $this->em->getRepository(ThirdParty::class)
->findById($ids);
return $a;
}
private function getPersons(string $query)
{
$params = [
SearchInterface::SEARCH_PREVIEW_OPTION => false
];
$search = $this->search->getResultByName($query, 'person_regular', 0, 50, $params, 'json');
$ids = \array_map(function($r) { return $r['id']; }, $search['results']);
if (count($ids) === 0) {
return [];
}
return $this->em->getRepository(Person::class)
->findById($ids)
;
}
}

View File

@@ -0,0 +1,29 @@
<?php
namespace Chill\MainBundle\Serializer\Normalizer;
use Chill\MainBundle\Entity\Address;
use Symfony\Component\Serializer\Normalizer\NormalizerAwareInterface;
use Symfony\Component\Serializer\Normalizer\NormalizerAwareTrait;
use Symfony\Component\Serializer\Normalizer\NormalizerInterface;
class AddressNormalizer implements NormalizerAwareInterface, NormalizerInterface
{
use NormalizerAwareTrait;
public function normalize($address, string $format = null, array $context = [])
{
$data['address_id'] = $address->getId();
$data['text'] = $address->getStreet().', '.$address->getBuildingName();
$data['postcode']['name'] = $address->getPostCode()->getName();
return $data;
}
public function supportsNormalization($data, string $format = null)
{
return $data instanceof Address;
}
}

View File

@@ -0,0 +1,59 @@
---
openapi: "3.0.0"
info:
version: "1.0.0"
title: "Chill api"
description: "Api documentation for chill. Currently, work in progress"
servers:
- url: "/api"
description: "Your current dev server"
components:
parameters:
_format:
name: _format
in: path
required: true
schema:
type: string
enum:
- json
paths:
/1.0/search.json:
get:
summary: perform a search across multiple entities
tags:
- search
- person
- thirdparty
description: >
**Warning**: This is currently a stub (not really implemented
The search is performed across multiple entities. The entities must be listed into
`type` parameters.
The results are ordered by relevance, from the most to the lowest relevant.
parameters:
- name: q
in: query
required: true
description: the pattern to search
schema:
type: string
- name: type[]
in: query
required: true
description: the type entities amongst the search is performed
schema:
type: array
items:
type: string
enum:
- person
- thirdparty
responses:
200:
description: "OK"

View File

@@ -69,6 +69,13 @@ chill_main_search:
requirements:
_format: html|json
chill_main_search_global:
path: '/api/1.0/search.{_format}'
controller: Chill\MainBundle\Controller\SearchController::searchApi
format: 'json'
requirements:
_format: 'json'
chill_main_advanced_search:
path: /{_locale}/search/advanced/{name}
controller: Chill\MainBundle\Controller\SearchController::advancedSearchAction

View File

@@ -16,6 +16,7 @@ services:
$searchProvider: '@chill_main.search_provider'
$translator: '@Symfony\Contracts\Translation\TranslatorInterface'
$paginatorFactory: '@Chill\MainBundle\Pagination\PaginatorFactory'
$searchApi: '@Chill\MainBundle\Search\SearchApi'
tags: ['controller.service_arguments']
Chill\MainBundle\Controller\PermissionsGroupController:

View File

@@ -1,3 +1,10 @@
services:
chill_main.search_provider:
class: Chill\MainBundle\Search\SearchProvider
class: Chill\MainBundle\Search\SearchProvider
Chill\MainBundle\Search\SearchProvider: '@chill_main.search_provider'
Chill\MainBundle\Search\SearchApi:
arguments:
$em: '@Doctrine\ORM\EntityManagerInterface'
$search: '@Chill\MainBundle\Search\SearchProvider'

View File

@@ -4,6 +4,10 @@ services:
tags:
- { name: 'serializer.normalizer', priority: 64 }
Chill\MainBundle\Serializer\Normalizer\AddressNormalizer:
tags:
- { name: 'serializer.normalizer', priority: 64 }
Chill\MainBundle\Serializer\Normalizer\DateNormalizer:
tags:
- { name: 'serializer.normalizer', priority: 64 }