mirror of
https://gitlab.com/Chill-Projet/chill-bundles.git
synced 2025-09-11 17:25:02 +00:00
Compare commits
53 Commits
issue_59_p
...
fix-templa
Author | SHA1 | Date | |
---|---|---|---|
96d40c0fd3 | |||
3b2d4142c1 | |||
9a6bab7ba2 | |||
c2bbee299c | |||
f4db9be557 | |||
5449efdd97 | |||
7896d288e7 | |||
b98d6fa505 | |||
e4d1b951a3 | |||
ae8e5bc2e3 | |||
9b66f7a83f | |||
|
13d5b7078e | ||
|
679665d9db | ||
|
1d4edd5b7b | ||
|
f1c77277f3 | ||
73790db700 | |||
|
743b456030 | ||
0dbd42ba5b | |||
|
cb897cfef1 | ||
|
bafbc2dd74 | ||
ca33580831 | |||
64e37c5235 | |||
bf576e171c | |||
3f2fe6a138 | |||
f18ccce814 | |||
2386a35eb7 | |||
1fbda740a7 | |||
d35e1fe21e | |||
771b9eb616 | |||
4261ddcde4 | |||
6ee03b7ebb | |||
1217578202 | |||
c7b6788288 | |||
02f1d2ff8a | |||
bb677152c9 | |||
ad6519fb87 | |||
d08f2e0e11 | |||
73aeca0916 | |||
080a54231f | |||
34fcefa1bd | |||
c9e6935f15 | |||
ebe3bc5f7b | |||
|
5cc5e6a1f7 | ||
|
1f4735caac | ||
|
d672a29dda | ||
857298b8b8 | |||
220f1ea0eb | |||
6bd7a0105d | |||
|
51c2408878 | ||
912a8d53af | |||
|
d73fd697dd | ||
52637c2919 | |||
f3a8552829 |
@@ -11,9 +11,10 @@ before_script:
|
||||
- PGPASSWORD=$POSTGRES_PASSWORD psql -U $POSTGRES_USER -h db -c "CREATE EXTENSION IF NOT EXISTS unaccent; CREATE EXTENSION IF NOT EXISTS pg_trgm;"
|
||||
# Install and run Composer
|
||||
- curl -sS https://getcomposer.org/installer | php
|
||||
- php composer.phar install
|
||||
- php -d memory_limit=2G composer.phar install
|
||||
- php tests/app/bin/console doctrine:migrations:migrate -n
|
||||
- php tests/app/bin/console doctrine:fixtures:load -n
|
||||
- php -d memory_limit=2G tests/app/bin/console doctrine:fixtures:load -n
|
||||
- echo "before_script finished"
|
||||
|
||||
# Bring in any services we need http://docs.gitlab.com/ee/ci/docker/using_docker_images.html#what-is-a-service
|
||||
# See http://docs.gitlab.com/ee/ci/services/README.html for examples.
|
||||
@@ -38,4 +39,4 @@ variables:
|
||||
# Run our tests
|
||||
test:
|
||||
script:
|
||||
- bin/phpunit --colors=never
|
||||
- php -d memory_limit=3G bin/phpunit --colors=never
|
||||
|
@@ -18,11 +18,13 @@
|
||||
<testsuite name="MainBundle">
|
||||
<directory suffix="Test.php">src/Bundle/ChillMainBundle/Tests/</directory>
|
||||
</testsuite>
|
||||
<!-- remove tests for person temporarily
|
||||
<testsuite name="PersonBundle">
|
||||
<directory suffix="Test.php">src/Bundle/ChillPersonBundle/Tests/</directory>
|
||||
<exclude>src/Bundle/ChillPersonBundle/Tests/Export/*</exclude>
|
||||
</testsuite>
|
||||
</testsuites>
|
||||
-->
|
||||
</testsuites>
|
||||
|
||||
<listeners>
|
||||
<listener class="Symfony\Bridge\PhpUnit\SymfonyTestsListener" />
|
||||
|
@@ -40,6 +40,20 @@ class AbstractCRUDController extends AbstractController
|
||||
return $e;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create an entity.
|
||||
*
|
||||
* @param string $action
|
||||
* @param Request $request
|
||||
* @return object
|
||||
*/
|
||||
protected function createEntity(string $action, Request $request): object
|
||||
{
|
||||
$type = $this->getEntityClass();
|
||||
|
||||
return new $type;
|
||||
}
|
||||
|
||||
/**
|
||||
* Count the number of entities
|
||||
*
|
||||
|
@@ -85,11 +85,75 @@ class ApiController extends AbstractCRUDController
|
||||
case Request::METHOD_PUT:
|
||||
case Request::METHOD_PATCH:
|
||||
return $this->entityPut('_entity', $request, $id, $_format);
|
||||
case Request::METHOD_POST:
|
||||
return $this->entityPostAction('_entity', $request, $id, $_format);
|
||||
default:
|
||||
throw new \Symfony\Component\HttpFoundation\Exception\BadRequestException("This method is not implemented");
|
||||
}
|
||||
}
|
||||
public function entityPost(Request $request, $_format): Response
|
||||
{
|
||||
switch($request->getMethod()) {
|
||||
case Request::METHOD_POST:
|
||||
return $this->entityPostAction('_entity', $request, $_format);
|
||||
default:
|
||||
throw new \Symfony\Component\HttpFoundation\Exception\BadRequestException("This method is not implemented");
|
||||
}
|
||||
}
|
||||
|
||||
protected function entityPostAction($action, Request $request, string $_format): Response
|
||||
{
|
||||
$entity = $this->createEntity($action, $request);
|
||||
|
||||
try {
|
||||
$entity = $this->deserialize($action, $request, $_format, $entity);
|
||||
} catch (NotEncodableValueException $e) {
|
||||
throw new BadRequestException("invalid json", 400, $e);
|
||||
}
|
||||
|
||||
$errors = $this->validate($action, $request, $_format, $entity);
|
||||
|
||||
$response = $this->onAfterValidation($action, $request, $_format, $entity, $errors);
|
||||
if ($response instanceof Response) {
|
||||
return $response;
|
||||
}
|
||||
|
||||
if ($errors->count() > 0) {
|
||||
$response = $this->json($errors);
|
||||
$response->setStatusCode(Response::HTTP_UNPROCESSABLE_ENTITY);
|
||||
|
||||
return $response;
|
||||
}
|
||||
|
||||
$response = $this->checkACL($action, $request, $_format, $entity);
|
||||
if ($response instanceof Response) {
|
||||
return $response;
|
||||
}
|
||||
|
||||
$response = $this->onPostCheckACL($action, $request, $_format, $entity);
|
||||
if ($response instanceof Response) {
|
||||
return $response;
|
||||
}
|
||||
|
||||
$this->getDoctrine()->getManager()->persist($entity);
|
||||
$this->getDoctrine()->getManager()->flush();
|
||||
|
||||
$response = $this->onAfterFlush($action, $request, $_format, $entity, $errors);
|
||||
if ($response instanceof Response) {
|
||||
return $response;
|
||||
}
|
||||
$response = $this->onBeforeSerialize($action, $request, $_format, $entity);
|
||||
if ($response instanceof Response) {
|
||||
return $response;
|
||||
}
|
||||
|
||||
return $this->json(
|
||||
$entity,
|
||||
Response::HTTP_OK,
|
||||
[],
|
||||
$this->getContextForSerializationPostAlter($action, $request, $_format, $entity)
|
||||
);
|
||||
}
|
||||
public function entityPut($action, Request $request, $id, string $_format): Response
|
||||
{
|
||||
$entity = $this->getEntity($action, $id, $request, $_format);
|
||||
@@ -407,6 +471,7 @@ class ApiController extends AbstractCRUDController
|
||||
return [ 'groups' => [ 'read' ]];
|
||||
case Request::METHOD_PUT:
|
||||
case Request::METHOD_PATCH:
|
||||
case Request::METHOD_POST:
|
||||
return [ 'groups' => [ 'write' ]];
|
||||
default:
|
||||
throw new \LogicException("get context for serialization is not implemented for this method");
|
||||
|
File diff suppressed because it is too large
Load Diff
@@ -183,48 +183,26 @@ class CRUDRoutesLoader extends Loader
|
||||
$methods = \array_keys(\array_filter($action['methods'], function($value, $key) { return $value; },
|
||||
ARRAY_FILTER_USE_BOTH));
|
||||
|
||||
$route = new Route($path, $defaults, $requirements);
|
||||
$route->setMethods($methods);
|
||||
|
||||
$collection->add('chill_api_single_'.$crudConfig['name'].'_'.$name, $route);
|
||||
}
|
||||
if (count($methods) === 0) {
|
||||
throw new \RuntimeException("The api configuration named \"{$crudConfig['name']}\", action \"{$name}\", ".
|
||||
"does not have any allowed methods. You should remove this action from the config ".
|
||||
"or allow, at least, one method");
|
||||
}
|
||||
|
||||
return $collection;
|
||||
}
|
||||
if ('_entity' === $name && \in_array(Request::METHOD_POST, $methods)) {
|
||||
unset($methods[\array_search(Request::METHOD_POST, $methods)]);
|
||||
$entityPostRoute = $this->createEntityPostRoute($name, $crudConfig, $action,
|
||||
$controller);
|
||||
$collection->add("chill_api_single_{$crudConfig['name']}_{$name}_create",
|
||||
$entityPostRoute);
|
||||
}
|
||||
|
||||
/**
|
||||
* Load routes for api multi
|
||||
*
|
||||
* @param $crudConfig
|
||||
* @return RouteCollection
|
||||
*/
|
||||
protected function loadApiMultiConfig(array $crudConfig): RouteCollection
|
||||
{
|
||||
$collection = new RouteCollection();
|
||||
$controller ='csapi_'.$crudConfig['name'].'_controller';
|
||||
|
||||
foreach ($crudConfig['actions'] as $name => $action) {
|
||||
// filter only on single actions
|
||||
$singleCollection = $action['single-collection'] ?? $name === '_index' ? 'collection' : NULL;
|
||||
if ('single' === $singleCollection) {
|
||||
if (count($methods) === 0) {
|
||||
// the only method was POST,
|
||||
// continue to next
|
||||
continue;
|
||||
}
|
||||
|
||||
$defaults = [
|
||||
'_controller' => $controller.':'.($action['controller_action'] ?? '_entity' === $name ? 'entityApi' : $name.'Api')
|
||||
];
|
||||
|
||||
// path are rewritten
|
||||
// if name === 'default', we rewrite it to nothing :-)
|
||||
$localName = '_entity' === $name ? '' : '/'.$name;
|
||||
$localPath = $action['path'] ?? '/{id}'.$localName.'.{_format}';
|
||||
$path = $crudConfig['base_path'].$localPath;
|
||||
|
||||
$requirements = $action['requirements'] ?? [ '{id}' => '\d+' ];
|
||||
|
||||
$methods = \array_keys(\array_filter($action['methods'], function($value, $key) { return $value; },
|
||||
ARRAY_FILTER_USE_BOTH));
|
||||
|
||||
$route = new Route($path, $defaults, $requirements);
|
||||
$route->setMethods($methods);
|
||||
|
||||
@@ -233,4 +211,18 @@ class CRUDRoutesLoader extends Loader
|
||||
|
||||
return $collection;
|
||||
}
|
||||
|
||||
private function createEntityPostRoute(string $name, $crudConfig, array $action, $controller): Route
|
||||
{
|
||||
$localPath = $action['path'].'.{_format}';
|
||||
$defaults = [
|
||||
'_controller' => $controller.':'.($action['controller_action'] ?? 'entityPost')
|
||||
];
|
||||
$path = $crudConfig['base_path'].$localPath;
|
||||
$requirements = $action['requirements'] ?? [];
|
||||
$route = new Route($path, $defaults, $requirements);
|
||||
$route->setMethods([ Request::METHOD_POST ]);
|
||||
|
||||
return $route;
|
||||
}
|
||||
}
|
||||
|
@@ -35,6 +35,8 @@ use Chill\MainBundle\Doctrine\DQL\OverlapsI;
|
||||
use Symfony\Component\DependencyInjection\Definition;
|
||||
use Symfony\Component\DependencyInjection\Reference;
|
||||
use Chill\MainBundle\Doctrine\DQL\Replace;
|
||||
use Chill\MainBundle\Doctrine\Type\NativeDateIntervalType;
|
||||
use Chill\MainBundle\Doctrine\Type\PointType;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
|
||||
/**
|
||||
@@ -167,37 +169,49 @@ class ChillMainExtension extends Extension implements PrependExtensionInterface,
|
||||
$container->prependExtensionConfig('twig', $twigConfig);
|
||||
|
||||
//add DQL function to ORM (default entity_manager)
|
||||
$container->prependExtensionConfig('doctrine', array(
|
||||
'orm' => array(
|
||||
'dql' => array(
|
||||
'string_functions' => array(
|
||||
'unaccent' => Unaccent::class,
|
||||
'GET_JSON_FIELD_BY_KEY' => GetJsonFieldByKey::class,
|
||||
'AGGREGATE' => JsonAggregate::class,
|
||||
'REPLACE' => Replace::class,
|
||||
),
|
||||
'numeric_functions' => [
|
||||
'JSONB_EXISTS_IN_ARRAY' => JsonbExistsInArray::class,
|
||||
'SIMILARITY' => Similarity::class,
|
||||
'OVERLAPSI' => OverlapsI::class
|
||||
]
|
||||
)
|
||||
)
|
||||
));
|
||||
$container
|
||||
->prependExtensionConfig(
|
||||
'doctrine',
|
||||
[
|
||||
'orm' => [
|
||||
'dql' => [
|
||||
'string_functions' => [
|
||||
'unaccent' => Unaccent::class,
|
||||
'GET_JSON_FIELD_BY_KEY' => GetJsonFieldByKey::class,
|
||||
'AGGREGATE' => JsonAggregate::class,
|
||||
'REPLACE' => Replace::class,
|
||||
],
|
||||
'numeric_functions' => [
|
||||
'JSONB_EXISTS_IN_ARRAY' => JsonbExistsInArray::class,
|
||||
'SIMILARITY' => Similarity::class,
|
||||
'OVERLAPSI' => OverlapsI::class,
|
||||
],
|
||||
],
|
||||
],
|
||||
],
|
||||
);
|
||||
|
||||
//add dbal types (default entity_manager)
|
||||
$container->prependExtensionConfig('doctrine', array(
|
||||
'dbal' => [
|
||||
'types' => [
|
||||
'dateinterval' => [
|
||||
'class' => \Chill\MainBundle\Doctrine\Type\NativeDateIntervalType::class
|
||||
],
|
||||
'point' => [
|
||||
'class' => \Chill\MainBundle\Doctrine\Type\PointType::class
|
||||
]
|
||||
]
|
||||
]
|
||||
));
|
||||
$container
|
||||
->prependExtensionConfig(
|
||||
'doctrine',
|
||||
[
|
||||
'dbal' => [
|
||||
// This is mandatory since we are using postgis as database.
|
||||
'mapping_types' => [
|
||||
'geometry' => 'string',
|
||||
],
|
||||
'types' => [
|
||||
'dateinterval' => [
|
||||
'class' => NativeDateIntervalType::class
|
||||
],
|
||||
'point' => [
|
||||
'class' => PointType::class
|
||||
]
|
||||
]
|
||||
]
|
||||
]
|
||||
);
|
||||
|
||||
//add current route to chill main
|
||||
$container->prependExtensionConfig('chill_main', array(
|
||||
|
@@ -137,7 +137,7 @@ class Address
|
||||
* @var ThirdParty|null
|
||||
*
|
||||
* @ORM\ManyToOne(targetEntity="Chill\ThirdPartyBundle\Entity\ThirdParty")
|
||||
* @ORM\JoinColumn(nullable=true)
|
||||
* @ORM\JoinColumn(nullable=true, onDelete="SET NULL")
|
||||
*/
|
||||
private $linkedToThirdParty;
|
||||
|
||||
|
@@ -37,12 +37,16 @@ const messages = {
|
||||
ok: "OK",
|
||||
cancel: "Annuler",
|
||||
close: "Fermer",
|
||||
next: "Suivant",
|
||||
previous: "Précédent",
|
||||
back: "Retour",
|
||||
check_all: "cocher tout",
|
||||
reset: "réinitialiser"
|
||||
},
|
||||
nav: {
|
||||
next: "Suivant",
|
||||
previous: "Précédent",
|
||||
top: "Haut",
|
||||
bottom: "Bas",
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
@@ -20,19 +20,32 @@
|
||||
namespace Chill\MainBundle\Serializer\Normalizer;
|
||||
|
||||
use Chill\MainBundle\Entity\Center;
|
||||
use Chill\MainBundle\Repository\CenterRepository;
|
||||
use Symfony\Component\Serializer\Normalizer\DenormalizerInterface;
|
||||
use Symfony\Component\Serializer\Normalizer\NormalizerInterface;
|
||||
use Symfony\Component\Serializer\Exception\InvalidArgumentException;
|
||||
use Symfony\Component\Serializer\Exception\UnexpectedValueException;
|
||||
|
||||
/**
|
||||
*
|
||||
*
|
||||
*/
|
||||
class CenterNormalizer implements NormalizerInterface
|
||||
class CenterNormalizer implements NormalizerInterface, DenormalizerInterface
|
||||
{
|
||||
private CenterRepository $repository;
|
||||
|
||||
|
||||
public function __construct(CenterRepository $repository)
|
||||
{
|
||||
$this->repository = $repository;
|
||||
}
|
||||
|
||||
public function normalize($center, string $format = null, array $context = array())
|
||||
{
|
||||
/** @var Center $center */
|
||||
return [
|
||||
'id' => $center->getId(),
|
||||
'type' => 'center',
|
||||
'name' => $center->getName()
|
||||
];
|
||||
}
|
||||
@@ -41,4 +54,30 @@ class CenterNormalizer implements NormalizerInterface
|
||||
{
|
||||
return $data instanceof Center;
|
||||
}
|
||||
|
||||
public function denormalize($data, string $type, string $format = null, array $context = [])
|
||||
{
|
||||
if (FALSE === \array_key_exists('type', $data)) {
|
||||
throw new InvalidArgumentException('missing "type" key in data');
|
||||
}
|
||||
if ('center' !== $data['type']) {
|
||||
throw new InvalidArgumentException('type should be equal to "center"');
|
||||
}
|
||||
if (FALSE === \array_key_exists('id', $data)) {
|
||||
throw new InvalidArgumentException('missing "id" key in data');
|
||||
}
|
||||
|
||||
$center = $this->repository->find($data['id']);
|
||||
|
||||
if (null === $center) {
|
||||
throw new UnexpectedValueException("The type with id {$data['id']} does not exists");
|
||||
}
|
||||
|
||||
return $center;
|
||||
}
|
||||
|
||||
public function supportsDenormalization($data, string $type, string $format = null)
|
||||
{
|
||||
return $type === Center::class;
|
||||
}
|
||||
}
|
||||
|
@@ -9,15 +9,14 @@ servers:
|
||||
description: "Your current dev server"
|
||||
|
||||
components:
|
||||
parameters:
|
||||
_format:
|
||||
name: _format
|
||||
in: path
|
||||
required: true
|
||||
schema:
|
||||
type: string
|
||||
enum:
|
||||
- json
|
||||
schemas:
|
||||
Center:
|
||||
type: object
|
||||
properties:
|
||||
id:
|
||||
type: integer
|
||||
name:
|
||||
type: string
|
||||
|
||||
paths:
|
||||
/1.0/search.json:
|
||||
|
@@ -0,0 +1,31 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Chill\Migrations\Main;
|
||||
|
||||
use Doctrine\DBAL\Schema\Schema;
|
||||
use Doctrine\Migrations\AbstractMigration;
|
||||
|
||||
/**
|
||||
* Specify ON DELETE behaviour to handle deletion of parents in associated tables
|
||||
*/
|
||||
final class Version20210525144016 extends AbstractMigration
|
||||
{
|
||||
public function getDescription(): string
|
||||
{
|
||||
return 'Specify ON DELETE behaviour to handle deletion of parents in associated tables';
|
||||
}
|
||||
|
||||
public function up(Schema $schema): void
|
||||
{
|
||||
$this->addSql('ALTER TABLE chill_main_address DROP CONSTRAINT FK_165051F6114B8DD9');
|
||||
$this->addSql('ALTER TABLE chill_main_address ADD CONSTRAINT FK_165051F6114B8DD9 FOREIGN KEY (linkedToThirdParty_id) REFERENCES chill_3party.third_party (id) ON DELETE SET NULL NOT DEFERRABLE INITIALLY IMMEDIATE');
|
||||
}
|
||||
|
||||
public function down(Schema $schema): void
|
||||
{
|
||||
$this->addSql('ALTER TABLE chill_main_address DROP CONSTRAINT fk_165051f6114b8dd9');
|
||||
$this->addSql('ALTER TABLE chill_main_address ADD CONSTRAINT fk_165051f6114b8dd9 FOREIGN KEY (linkedtothirdparty_id) REFERENCES chill_3party.third_party (id) NOT DEFERRABLE INITIALLY IMMEDIATE');
|
||||
}
|
||||
}
|
@@ -75,10 +75,10 @@ $workflow = $this->registry->get($accompanyingPeriod);
|
||||
|
||||
switch ($request->getMethod()) {
|
||||
case Request::METHOD_POST:
|
||||
$participation = $accompanyingPeriod->addPerson($person);
|
||||
$participation = $accompanyingPeriod->createParticipationFor($person);
|
||||
break;
|
||||
case Request::METHOD_DELETE:
|
||||
$participation = $accompanyingPeriod->removePerson($person);
|
||||
$participation = $accompanyingPeriod->closeParticipationFor($person);
|
||||
break;
|
||||
default:
|
||||
throw new BadRequestException("This method is not supported");
|
||||
|
@@ -1,30 +0,0 @@
|
||||
<?php
|
||||
/*
|
||||
* Copyright (C) 2015-2021 Champs-Libres Coopérative <info@champs-libres.coop>
|
||||
*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
namespace Chill\PersonBundle\Controller;
|
||||
|
||||
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
|
||||
use Symfony\Component\HttpFoundation\JsonResponse;
|
||||
|
||||
|
||||
class ApiPersonController extends Controller
|
||||
{
|
||||
public function viewAction($id, $_format)
|
||||
{
|
||||
|
||||
}
|
||||
}
|
@@ -0,0 +1,50 @@
|
||||
<?php
|
||||
/*
|
||||
* Copyright (C) 2015-2021 Champs-Libres Coopérative <info@champs-libres.coop>
|
||||
*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
namespace Chill\PersonBundle\Controller;
|
||||
|
||||
use Chill\PersonBundle\Security\Authorization\PersonVoter;
|
||||
use Chill\MainBundle\Security\Authorization\AuthorizationHelper;
|
||||
use Symfony\Component\Security\Core\Role\Role;
|
||||
use Chill\MainBundle\CRUD\Controller\ApiController;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
|
||||
|
||||
class PersonApiController extends ApiController
|
||||
{
|
||||
private AuthorizationHelper $authorizationHelper;
|
||||
|
||||
/**
|
||||
* @param AuthorizationHelper $authorizationHelper
|
||||
*/
|
||||
public function __construct(AuthorizationHelper $authorizationHelper)
|
||||
{
|
||||
$this->authorizationHelper = $authorizationHelper;
|
||||
}
|
||||
|
||||
protected function createEntity(string $action, Request $request): object
|
||||
{
|
||||
$person = parent::createEntity($action, $request);
|
||||
|
||||
// TODO temporary hack to allow creation of person with fake center
|
||||
$centers = $this->authorizationHelper->getReachableCenters($this->getUser(),
|
||||
new Role(PersonVoter::CREATE));
|
||||
$person->setCenter($centers[0]);
|
||||
|
||||
return $person;
|
||||
}
|
||||
}
|
@@ -37,32 +37,32 @@ class LoadSocialActions extends AbstractFixture implements OrderedFixtureInterfa
|
||||
return 10020;
|
||||
}
|
||||
|
||||
public static $socialActions = array(
|
||||
'social_action_info_conseil' => array(
|
||||
'title' => array(
|
||||
public static $socialActions = [
|
||||
'social_action_info_conseil' => [
|
||||
'title' => [
|
||||
'fr' => 'Informer, conseiller'
|
||||
),
|
||||
],
|
||||
'issue' => 'social_issue_prev_prot'
|
||||
),
|
||||
'social_action_instruire' => array(
|
||||
'title' => array(
|
||||
],
|
||||
'social_action_instruire' => [
|
||||
'title' => [
|
||||
'fr' => 'Instruire l\'imprime unique pour des impayés'
|
||||
),
|
||||
],
|
||||
'issue' => 'social_issue_prev_prot'
|
||||
),
|
||||
'social_action_MASP' => array(
|
||||
'title' => array(
|
||||
],
|
||||
'social_action_MASP' => [
|
||||
'title' => [
|
||||
'fr' => 'MASP'
|
||||
),
|
||||
],
|
||||
'issue' => 'social_issue_diff_fin'
|
||||
),
|
||||
'social_action_protection_enfant' => array(
|
||||
'title' => array(
|
||||
],
|
||||
'social_action_protection_enfant' => [
|
||||
'title' => [
|
||||
'fr' => 'Protection Enfant confié dans le cadre judiciaire'
|
||||
),
|
||||
],
|
||||
'issue' => 'social_issue_enfant_protection'
|
||||
),
|
||||
);
|
||||
],
|
||||
];
|
||||
|
||||
public function load(ObjectManager $manager)
|
||||
{
|
||||
|
@@ -38,20 +38,20 @@ class LoadSocialGoals extends AbstractFixture implements OrderedFixtureInterface
|
||||
return 10030;
|
||||
}
|
||||
|
||||
public static $socialGoals = array(
|
||||
'social_goal_instuire_dossier' => array(
|
||||
'title' => array(
|
||||
public static $socialGoals = [
|
||||
'social_goal_instuire_dossier' => [
|
||||
'title' => [
|
||||
'fr' => 'Instruire le dossier de surendettement'
|
||||
),
|
||||
],
|
||||
'action' => 'social_action_MASP'
|
||||
),
|
||||
'social_goal_proteger' => array(
|
||||
'title' => array(
|
||||
],
|
||||
'social_goal_proteger' => [
|
||||
'title' => [
|
||||
'fr' => 'Protéger via une assistance educative placement'
|
||||
),
|
||||
],
|
||||
'action' => 'social_action_protection_enfant'
|
||||
),
|
||||
);
|
||||
],
|
||||
];
|
||||
|
||||
public function load(ObjectManager $manager)
|
||||
{
|
||||
|
@@ -37,36 +37,36 @@ class LoadSocialIssues extends AbstractFixture implements OrderedFixtureInterfac
|
||||
return 10010;
|
||||
}
|
||||
|
||||
public static $socialIssues = array(
|
||||
'social_issue_diff_fin_or_admin' => array(
|
||||
'title' => array(
|
||||
public static $socialIssues = [
|
||||
'social_issue_diff_fin_or_admin' => [
|
||||
'title' => [
|
||||
'fr' => 'ADULTE - DIFFICULTES FINANCIERES ET/OU ADMINISTRATIVES'
|
||||
)
|
||||
),
|
||||
'social_issue_prev_prot' => array(
|
||||
'title' => array(
|
||||
]
|
||||
],
|
||||
'social_issue_prev_prot' => [
|
||||
'title' => [
|
||||
'fr' => 'ADULTE PREVENTION/PROTECTION'
|
||||
),
|
||||
],
|
||||
'parent' => 'social_issue_diff_fin_or_admin'
|
||||
),
|
||||
'social_issue_diff_fin' => array(
|
||||
'title' => array(
|
||||
],
|
||||
'social_issue_diff_fin' => [
|
||||
'title' => [
|
||||
'fr' => 'Difficulté financière'
|
||||
),
|
||||
],
|
||||
'parent' => 'social_issue_diff_fin_or_admin'
|
||||
),
|
||||
'social_issue_enfant_famille' => array(
|
||||
'title' => array(
|
||||
],
|
||||
'social_issue_enfant_famille' => [
|
||||
'title' => [
|
||||
'fr' => 'Enfant / famille'
|
||||
)
|
||||
),
|
||||
'social_issue_enfant_protection' => array(
|
||||
'title' => array(
|
||||
]
|
||||
],
|
||||
'social_issue_enfant_protection' => [
|
||||
'title' => [
|
||||
'fr' => 'enfant - protection'
|
||||
),
|
||||
],
|
||||
'parent' => 'social_issue_enfant_famille'
|
||||
),
|
||||
);
|
||||
],
|
||||
];
|
||||
|
||||
public function load(ObjectManager $manager)
|
||||
{
|
||||
|
@@ -38,34 +38,34 @@ class LoadSocialResults extends AbstractFixture implements OrderedFixtureInterfa
|
||||
return 10040;
|
||||
}
|
||||
|
||||
public static $socialResults = array(
|
||||
'social_result_FSL_acces' => array(
|
||||
'title' => array(
|
||||
public static $socialResults = [
|
||||
'social_result_FSL_acces' => [
|
||||
'title' => [
|
||||
'fr' => 'FSL - accès cautionnement'
|
||||
),
|
||||
],
|
||||
'action' => 'social_action_instruire'
|
||||
),
|
||||
'social_result_FSL_maintien' => array(
|
||||
'title' => array(
|
||||
],
|
||||
'social_result_FSL_maintien' => [
|
||||
'title' => [
|
||||
'fr' => 'FSL maintien - impayés de loyer'
|
||||
),
|
||||
],
|
||||
'action' => 'social_action_MASP'
|
||||
),
|
||||
'social_result_soutien_parental' => array(
|
||||
'title' => array(
|
||||
],
|
||||
'social_result_soutien_parental' => [
|
||||
'title' => [
|
||||
'fr' => 'Soutien parental'
|
||||
),
|
||||
],
|
||||
// 'action' => 'social_action_protection_enfant', (via le goal)
|
||||
'goal' => 'social_goal_proteger'
|
||||
),
|
||||
'social_result_accompagnement_mineur' => array(
|
||||
'title' => array(
|
||||
],
|
||||
'social_result_accompagnement_mineur' => [
|
||||
'title' => [
|
||||
'fr' => 'Accompagnement du mineur'
|
||||
),
|
||||
],
|
||||
// 'action' => 'social_action_protection_enfant', (via le goal)
|
||||
'goal' => 'social_goal_proteger',
|
||||
),
|
||||
);
|
||||
],
|
||||
];
|
||||
|
||||
public function load(ObjectManager $manager)
|
||||
{
|
||||
|
@@ -476,7 +476,6 @@ class ChillPersonExtension extends Extension implements PrependExtensionInterfac
|
||||
'class' => \Chill\PersonBundle\Entity\SocialWork\SocialIssue::class,
|
||||
'name' => 'social_work_social_issue',
|
||||
'base_path' => '/api/1.0/person/social-work/social-issue',
|
||||
// 'controller' => \Chill\PersonBundle\Controller\OpeningApiController::class,
|
||||
'base_role' => 'ROLE_USER',
|
||||
'actions' => [
|
||||
'_index' => [
|
||||
@@ -493,6 +492,28 @@ class ChillPersonExtension extends Extension implements PrependExtensionInterfac
|
||||
],
|
||||
]
|
||||
],
|
||||
[
|
||||
'class' => \Chill\PersonBundle\Entity\Person::class,
|
||||
'name' => 'person',
|
||||
'base_path' => '/api/1.0/person/person',
|
||||
'base_role' => \Chill\PersonBundle\Security\Authorization\PersonVoter::SEE,
|
||||
'controller' => \Chill\PersonBundle\Controller\PersonApiController::class,
|
||||
'actions' => [
|
||||
'_entity' => [
|
||||
'methods' => [
|
||||
Request::METHOD_GET => true,
|
||||
Request::METHOD_HEAD => true,
|
||||
Request::METHOD_POST=> true,
|
||||
],
|
||||
'roles' => [
|
||||
Request::METHOD_GET => \Chill\PersonBundle\Security\Authorization\PersonVoter::SEE,
|
||||
Request::METHOD_HEAD => \Chill\PersonBundle\Security\Authorization\PersonVoter::SEE,
|
||||
Request::METHOD_POST => \Chill\PersonBundle\Security\Authorization\PersonVoter::CREATE,
|
||||
|
||||
]
|
||||
],
|
||||
]
|
||||
],
|
||||
]
|
||||
]);
|
||||
}
|
||||
|
@@ -483,9 +483,9 @@ class AccompanyingPeriod implements TrackCreationInterface, TrackUpdateInterface
|
||||
}
|
||||
|
||||
/**
|
||||
* Add Person
|
||||
* Open a new participation for a person
|
||||
*/
|
||||
public function addPerson(Person $person = null): AccompanyingPeriodParticipation
|
||||
public function createParticipationFor(Person $person): AccompanyingPeriodParticipation
|
||||
{
|
||||
$participation = new AccompanyingPeriodParticipation($this, $person);
|
||||
$this->participations[] = $participation;
|
||||
@@ -493,10 +493,24 @@ class AccompanyingPeriod implements TrackCreationInterface, TrackUpdateInterface
|
||||
return $participation;
|
||||
}
|
||||
|
||||
public function addPerson(Person $person = null): self
|
||||
{
|
||||
if (NULL !== $person) {
|
||||
$this->createParticipationFor($person);
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove Person
|
||||
* Close a participation for a person
|
||||
*
|
||||
* Search for the person's participation and set the end date at
|
||||
* 'now'.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function removePerson(Person $person): ?AccompanyingPeriodParticipation
|
||||
public function closeParticipationFor($person): ?AccompanyingPeriodParticipation
|
||||
{
|
||||
$participation = $this->getOpenParticipationContainsPerson($person);
|
||||
|
||||
@@ -506,6 +520,17 @@ class AccompanyingPeriod implements TrackCreationInterface, TrackUpdateInterface
|
||||
|
||||
return $participation;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Remove Person
|
||||
*/
|
||||
public function removePerson(Person $person): self
|
||||
{
|
||||
$this->closeParticipationFor($person);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
|
||||
public function getClosingMotive(): ?ClosingMotive
|
||||
|
@@ -51,7 +51,7 @@ class Comment implements TrackCreationInterface, TrackUpdateInterface
|
||||
* @ORM\ManyToOne(
|
||||
* targetEntity="Chill\PersonBundle\Entity\AccompanyingPeriod",
|
||||
* inversedBy="comments")
|
||||
* @ORM\JoinColumn(nullable=false)
|
||||
* @ORM\JoinColumn(nullable=false, onDelete="CASCADE")
|
||||
*/
|
||||
private $accompanyingPeriod;
|
||||
|
||||
|
@@ -32,7 +32,7 @@ use Symfony\Component\Serializer\Annotation\DiscriminatorMap;
|
||||
use Symfony\Component\Serializer\Annotation\Groups;
|
||||
|
||||
/**
|
||||
* @ORM\Entity(repositoryClass=ResourceRepository::class)
|
||||
* @ORM\Entity
|
||||
* @ORM\Table(name="chill_person_accompanying_period_resource")
|
||||
* @DiscriminatorMap(typeProperty="type", mapping={
|
||||
* "accompanying_period_resource"=Resource::class
|
||||
|
@@ -27,46 +27,41 @@ use Doctrine\ORM\EntityManagerInterface;
|
||||
use Doctrine\ORM\EntityRepository;
|
||||
use Doctrine\ORM\Query\ResultSetMappingBuilder;
|
||||
|
||||
/**
|
||||
* Class ClosingMotiveRepository
|
||||
* Entity repository for closing motives
|
||||
*
|
||||
* @package Chill\PersonBundle\Repository
|
||||
*/
|
||||
final class ClosingMotiveRepository
|
||||
{
|
||||
private EntityRepository $repository;
|
||||
|
||||
private EntityManagerInterface $entityManager;
|
||||
|
||||
public function __construct(EntityManagerInterface $entityManager)
|
||||
{
|
||||
$this->entityManager = $entityManager;
|
||||
$this->repository = $entityManager->getRepository(ClosingMotive::class);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param bool $onlyLeaf
|
||||
* @return mixed
|
||||
*/
|
||||
public function getActiveClosingMotive(bool $onlyLeaf = true)
|
||||
{
|
||||
$rsm = new ResultSetMappingBuilder($this->repository->getEntityManager());
|
||||
$rsm = new ResultSetMappingBuilder($this->entityManager);
|
||||
$rsm->addRootEntityFromClassMetadata($this->repository->getClassName(), 'cm');
|
||||
|
||||
$sql = "SELECT ".(string) $rsm."
|
||||
$sql = "SELECT " . (string) $rsm . "
|
||||
FROM chill_person_accompanying_period_closingmotive AS cm
|
||||
WHERE
|
||||
active IS TRUE ";
|
||||
|
||||
|
||||
if ($onlyLeaf) {
|
||||
$sql .= "AND cm.id NOT IN (
|
||||
SELECT DISTINCT parent_id FROM chill_person_accompanying_period_closingmotive WHERE parent_id IS NOT NULL
|
||||
)";
|
||||
}
|
||||
|
||||
|
||||
$sql .= " ORDER BY cm.ordering ASC";
|
||||
|
||||
return $this
|
||||
->repository
|
||||
->getEntityManager()
|
||||
->entityManager
|
||||
->createNativeQuery($sql, $rsm)
|
||||
->getResult();
|
||||
}
|
||||
|
@@ -26,12 +26,6 @@ use Chill\PersonBundle\Entity\AccompanyingPeriod\Comment;
|
||||
use Doctrine\ORM\EntityManagerInterface;
|
||||
use Doctrine\ORM\EntityRepository;
|
||||
|
||||
/**
|
||||
* @method Comment|null find($id, $lockMode = null, $lockVersion = null)
|
||||
* @method Comment|null findOneBy(array $criteria, array $orderBy = null)
|
||||
* @method Comment[] findAll()
|
||||
* @method Comment[] findBy(array $criteria, array $orderBy = null, $limit = null, $offset = null)
|
||||
*/
|
||||
final class CommentRepository
|
||||
{
|
||||
private EntityRepository $repository;
|
||||
|
@@ -26,12 +26,6 @@ use Chill\PersonBundle\Entity\AccompanyingPeriod\Origin;
|
||||
use Doctrine\ORM\EntityManagerInterface;
|
||||
use Doctrine\ORM\EntityRepository;
|
||||
|
||||
/**
|
||||
* @method Origin|null find($id, $lockMode = null, $lockVersion = null)
|
||||
* @method Origin|null findOneBy(array $criteria, array $orderBy = null)
|
||||
* @method Origin[] findAll()
|
||||
* @method Origin[] findBy(array $criteria, array $orderBy = null, $limit = null, $offset = null)
|
||||
*/
|
||||
final class OriginRepository
|
||||
{
|
||||
private EntityRepository $repository;
|
||||
|
@@ -24,21 +24,19 @@ namespace Chill\PersonBundle\Repository\AccompanyingPeriod;
|
||||
|
||||
use Chill\PersonBundle\Entity\AccompanyingPeriod\Resource;
|
||||
use Doctrine\ORM\EntityRepository;
|
||||
use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository;
|
||||
use Doctrine\Persistence\ManagerRegistry;
|
||||
use Doctrine\ORM\EntityManagerInterface;
|
||||
|
||||
/**
|
||||
* @method Resource|null find($id, $lockMode = null, $lockVersion = null)
|
||||
* @method Resource|null findOneBy(array $criteria, array $orderBy = null)
|
||||
* @method Resource[] findAll()
|
||||
* @method Resource[] findBy(array $criteria, array $orderBy = null, $limit = null, $offset = null)
|
||||
*/
|
||||
final class ResourceRepository extends ServiceEntityRepository
|
||||
final class ResourceRepository
|
||||
{
|
||||
private EntityRepository $repository;
|
||||
|
||||
public function __construct(ManagerRegistry $registry)
|
||||
public function __construct(EntityManagerInterface $entityManager)
|
||||
{
|
||||
parent::__construct($registry, Resource::class);
|
||||
$this->repository = $entityManager->getRepository(Resource::class);
|
||||
}
|
||||
|
||||
public function find($id, $lockMode = null, $lockVersion = null): ?Resource
|
||||
{
|
||||
return $this->repository->find($id, $lockMode, $lockVersion);
|
||||
}
|
||||
}
|
||||
|
@@ -26,12 +26,6 @@ use Chill\PersonBundle\Entity\AccompanyingPeriodParticipation;
|
||||
use Doctrine\ORM\EntityManagerInterface;
|
||||
use Doctrine\ORM\EntityRepository;
|
||||
|
||||
/**
|
||||
* @method AccompanyingPeriodParticipation|null find($id, $lockMode = null, $lockVersion = null)
|
||||
* @method AccompanyingPeriodParticipation|null findOneBy(array $criteria, array $orderBy = null)
|
||||
* @method AccompanyingPeriodParticipation[] findAll()
|
||||
* @method AccompanyingPeriodParticipation[] findBy(array $criteria, array $orderBy = null, $limit = null, $offset = null)
|
||||
*/
|
||||
final class AccompanyingPeriodParticipationRepository
|
||||
{
|
||||
private EntityRepository $repository;
|
||||
|
@@ -26,12 +26,6 @@ use Chill\PersonBundle\Entity\AccompanyingPeriod;
|
||||
use Doctrine\ORM\EntityManagerInterface;
|
||||
use Doctrine\ORM\EntityRepository;
|
||||
|
||||
/**
|
||||
* @method AccompanyingPeriod|null find($id, $lockMode = null, $lockVersion = null)
|
||||
* @method AccompanyingPeriod|null findOneBy(array $criteria, array $orderBy = null)
|
||||
* @method AccompanyingPeriod[] findAll()
|
||||
* @method AccompanyingPeriod[] findBy(array $criteria, array $orderBy = null, $limit = null, $offset = null)
|
||||
*/
|
||||
final class AccompanyingPeriodRepository
|
||||
{
|
||||
private EntityRepository $repository;
|
||||
|
@@ -6,12 +6,6 @@ use Chill\PersonBundle\Entity\Household\HouseholdMembers;
|
||||
use Doctrine\ORM\EntityManagerInterface;
|
||||
use Doctrine\ORM\EntityRepository;
|
||||
|
||||
/**
|
||||
* @method HouseholdMembers|null find($id, $lockMode = null, $lockVersion = null)
|
||||
* @method HouseholdMembers|null findOneBy(array $criteria, array $orderBy = null)
|
||||
* @method HouseholdMembers[] findAll()
|
||||
* @method HouseholdMembers[] findBy(array $criteria, array $orderBy = null, $limit = null, $offset = null)
|
||||
*/
|
||||
final class HouseholdMembersRepository
|
||||
{
|
||||
private EntityRepository $repository;
|
||||
@@ -20,33 +14,4 @@ final class HouseholdMembersRepository
|
||||
{
|
||||
$this->repository = $entityManager->getRepository(HouseholdMembers::class);
|
||||
}
|
||||
|
||||
// /**
|
||||
// * @return HouseholdMembers[] Returns an array of HouseholdMembers objects
|
||||
// */
|
||||
/*
|
||||
public function findByExampleField($value)
|
||||
{
|
||||
return $this->createQueryBuilder('h')
|
||||
->andWhere('h.exampleField = :val')
|
||||
->setParameter('val', $value)
|
||||
->orderBy('h.id', 'ASC')
|
||||
->setMaxResults(10)
|
||||
->getQuery()
|
||||
->getResult()
|
||||
;
|
||||
}
|
||||
*/
|
||||
|
||||
/*
|
||||
public function findOneBySomeField($value): ?HouseholdMembers
|
||||
{
|
||||
return $this->createQueryBuilder('h')
|
||||
->andWhere('h.exampleField = :val')
|
||||
->setParameter('val', $value)
|
||||
->getQuery()
|
||||
->getOneOrNullResult()
|
||||
;
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
@@ -6,12 +6,6 @@ use Chill\PersonBundle\Entity\Household\Household;
|
||||
use Doctrine\ORM\EntityManagerInterface;
|
||||
use Doctrine\ORM\EntityRepository;
|
||||
|
||||
/**
|
||||
* @method Household|null find($id, $lockMode = null, $lockVersion = null)
|
||||
* @method Household|null findOneBy(array $criteria, array $orderBy = null)
|
||||
* @method Household[] findAll()
|
||||
* @method Household[] findBy(array $criteria, array $orderBy = null, $limit = null, $offset = null)
|
||||
*/
|
||||
final class HouseholdRepository
|
||||
{
|
||||
private EntityRepository $repository;
|
||||
@@ -20,33 +14,4 @@ final class HouseholdRepository
|
||||
{
|
||||
$this->repository = $entityManager->getRepository(Household::class);
|
||||
}
|
||||
|
||||
// /**
|
||||
// * @return Household[] Returns an array of Household objects
|
||||
// */
|
||||
/*
|
||||
public function findByExampleField($value)
|
||||
{
|
||||
return $this->createQueryBuilder('h')
|
||||
->andWhere('h.exampleField = :val')
|
||||
->setParameter('val', $value)
|
||||
->orderBy('h.id', 'ASC')
|
||||
->setMaxResults(10)
|
||||
->getQuery()
|
||||
->getResult()
|
||||
;
|
||||
}
|
||||
*/
|
||||
|
||||
/*
|
||||
public function findOneBySomeField($value): ?Household
|
||||
{
|
||||
return $this->createQueryBuilder('h')
|
||||
->andWhere('h.exampleField = :val')
|
||||
->setParameter('val', $value)
|
||||
->getQuery()
|
||||
->getOneOrNullResult()
|
||||
;
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
@@ -6,12 +6,6 @@ use Chill\PersonBundle\Entity\PersonAltName;
|
||||
use Doctrine\ORM\EntityManagerInterface;
|
||||
use Doctrine\ORM\EntityRepository;
|
||||
|
||||
/**
|
||||
* PersonAltNameRepository
|
||||
*
|
||||
* This class was generated by the Doctrine ORM. Add your own custom
|
||||
* repository methods below.
|
||||
*/
|
||||
final class PersonAltNameRepository
|
||||
{
|
||||
private EntityRepository $repository;
|
||||
|
@@ -7,11 +7,6 @@ use Chill\PersonBundle\Entity\PersonNotDuplicate;
|
||||
use Doctrine\ORM\EntityManagerInterface;
|
||||
use Doctrine\ORM\EntityRepository;
|
||||
|
||||
/**
|
||||
* Class PersonNotDuplicateRepository
|
||||
*
|
||||
* @package Chill\PersonBundle\Repository
|
||||
*/
|
||||
final class PersonNotDuplicateRepository
|
||||
{
|
||||
private EntityRepository $repository;
|
||||
@@ -21,12 +16,7 @@ final class PersonNotDuplicateRepository
|
||||
$this->repository = $entityManager->getRepository(PersonNotDuplicate::class);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param \Chill\PersonBundle\Entity\Person $person
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function findNotDuplicatePerson(Person $person)
|
||||
public function findNotDuplicatePerson(Person $person): array
|
||||
{
|
||||
$qb = $this->repository->createQueryBuilder('pnd');
|
||||
$qb->select('pnd')
|
||||
@@ -36,6 +26,7 @@ final class PersonNotDuplicateRepository
|
||||
$result = $qb->getQuery()->getResult();
|
||||
|
||||
$persons = [];
|
||||
|
||||
foreach ($result as $row) {
|
||||
if ($row->getPerson1() === $person) {
|
||||
$persons[] = $row->getPerson2();
|
||||
|
@@ -32,105 +32,88 @@ final class PersonRepository
|
||||
$this->repository = $entityManager->getRepository(Person::class);
|
||||
}
|
||||
|
||||
public function find($id, $lockMode = null, $lockVersion = null)
|
||||
public function find($id, $lockMode = null, $lockVersion = null): ?Person
|
||||
{
|
||||
return $this->repository->find($id, $lockMode, $lockVersion);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $phonenumber
|
||||
* @param $centers
|
||||
* @param $firstResult
|
||||
* @param $maxResults
|
||||
* @param array $only
|
||||
* @return mixed
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function findByPhone(
|
||||
string $phonenumber,
|
||||
$centers,
|
||||
string $phonenumber,
|
||||
$centers,
|
||||
$firstResult,
|
||||
$maxResults,
|
||||
array $only = ['mobile', 'phone']
|
||||
) {
|
||||
$qb = $this->repository->createQueryBuilder('p');
|
||||
$qb->select('p');
|
||||
|
||||
|
||||
$this->addByCenters($qb, $centers);
|
||||
$this->addPhoneNumber($qb, $phonenumber, $only);
|
||||
|
||||
|
||||
$qb->setFirstResult($firstResult)
|
||||
->setMaxResults($maxResults)
|
||||
;
|
||||
|
||||
|
||||
return $qb->getQuery()->getResult();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param string $phonenumber
|
||||
* @param $centers
|
||||
* @param array $only
|
||||
* @return int
|
||||
* @throws \Doctrine\ORM\NoResultException
|
||||
* @throws \Doctrine\ORM\NonUniqueResultException
|
||||
*/
|
||||
public function countByPhone(
|
||||
string $phonenumber,
|
||||
$centers,
|
||||
string $phonenumber,
|
||||
$centers,
|
||||
array $only = ['mobile', 'phone']
|
||||
): int
|
||||
{
|
||||
): int {
|
||||
$qb = $this->repository->createQueryBuilder('p');
|
||||
$qb->select('COUNT(p)');
|
||||
|
||||
|
||||
$this->addByCenters($qb, $centers);
|
||||
$this->addPhoneNumber($qb, $phonenumber, $only);
|
||||
|
||||
|
||||
return $qb->getQuery()->getSingleScalarResult();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param QueryBuilder $qb
|
||||
* @param string $phonenumber
|
||||
* @param array $only
|
||||
* @throws \Exception
|
||||
*/
|
||||
protected function addPhoneNumber(QueryBuilder $qb, string $phonenumber, array $only)
|
||||
protected function addPhoneNumber(QueryBuilder $qb, string $phonenumber, array $only): void
|
||||
{
|
||||
if (count($only) === 0) {
|
||||
throw new \Exception("No array field to search");
|
||||
}
|
||||
|
||||
|
||||
$phonenumber = $this->parsePhoneNumber($phonenumber);
|
||||
|
||||
|
||||
$orX = $qb->expr()->orX();
|
||||
|
||||
|
||||
if (\in_array('mobile', $only)) {
|
||||
$orX->add($qb->expr()->like("REPLACE(p.mobilenumber, ' ', '')", ':phonenumber'));
|
||||
}
|
||||
if (\in_array('phone', $only)) {
|
||||
$orX->add($qb->expr()->like("REPLACE(p.phonenumber, ' ', '')", ':phonenumber'));
|
||||
}
|
||||
|
||||
|
||||
$qb->andWhere($orX);
|
||||
|
||||
|
||||
$qb->setParameter('phonenumber', '%'.$phonenumber.'%');
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $phonenumber
|
||||
* @return string
|
||||
*/
|
||||
protected function parsePhoneNumber($phonenumber): string
|
||||
|
||||
protected function parsePhoneNumber(string $phonenumber): string
|
||||
{
|
||||
return \str_replace(' ', '', $phonenumber);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param QueryBuilder $qb
|
||||
* @param array $centers
|
||||
*/
|
||||
protected function addByCenters(QueryBuilder $qb, array $centers)
|
||||
|
||||
protected function addByCenters(QueryBuilder $qb, array $centers): void
|
||||
{
|
||||
if (count($centers) > 0) {
|
||||
$qb->andWhere($qb->expr()->in('p.center', ':centers'));
|
||||
|
@@ -6,12 +6,6 @@ use Chill\PersonBundle\Entity\SocialWork\Evaluation;
|
||||
use Doctrine\ORM\EntityManagerInterface;
|
||||
use Doctrine\ORM\EntityRepository;
|
||||
|
||||
/**
|
||||
* @method Evaluation|null find($id, $lockMode = null, $lockVersion = null)
|
||||
* @method Evaluation|null findOneBy(array $criteria, array $orderBy = null)
|
||||
* @method Evaluation[] findAll()
|
||||
* @method Evaluation[] findBy(array $criteria, array $orderBy = null, $limit = null, $offset = null)
|
||||
*/
|
||||
final class EvaluationRepository
|
||||
{
|
||||
private EntityRepository $repository;
|
||||
|
@@ -6,12 +6,6 @@ use Chill\PersonBundle\Entity\SocialWork\Goal;
|
||||
use Doctrine\ORM\EntityManagerInterface;
|
||||
use Doctrine\ORM\EntityRepository;
|
||||
|
||||
/**
|
||||
* @method Goal|null find($id, $lockMode = null, $lockVersion = null)
|
||||
* @method Goal|null findOneBy(array $criteria, array $orderBy = null)
|
||||
* @method Goal[] findAll()
|
||||
* @method Goal[] findBy(array $criteria, array $orderBy = null, $limit = null, $offset = null)
|
||||
*/
|
||||
final class GoalRepository
|
||||
{
|
||||
private EntityRepository $repository;
|
||||
|
@@ -6,12 +6,6 @@ use Chill\PersonBundle\Entity\SocialWork\Result;
|
||||
use Doctrine\ORM\EntityManagerInterface;
|
||||
use Doctrine\ORM\EntityRepository;
|
||||
|
||||
/**
|
||||
* @method Result|null find($id, $lockMode = null, $lockVersion = null)
|
||||
* @method Result|null findOneBy(array $criteria, array $orderBy = null)
|
||||
* @method Result[] findAll()
|
||||
* @method Result[] findBy(array $criteria, array $orderBy = null, $limit = null, $offset = null)
|
||||
*/
|
||||
final class ResultRepository
|
||||
{
|
||||
private EntityRepository $repository;
|
||||
|
@@ -6,12 +6,6 @@ use Chill\PersonBundle\Entity\SocialWork\SocialAction;
|
||||
use Doctrine\ORM\EntityManagerInterface;
|
||||
use Doctrine\ORM\EntityRepository;
|
||||
|
||||
/**
|
||||
* @method SocialAction|null find($id, $lockMode = null, $lockVersion = null)
|
||||
* @method SocialAction|null findOneBy(array $criteria, array $orderBy = null)
|
||||
* @method SocialAction[] findAll()
|
||||
* @method SocialAction[] findBy(array $criteria, array $orderBy = null, $limit = null, $offset = null)
|
||||
*/
|
||||
final class SocialActionRepository
|
||||
{
|
||||
private EntityRepository $repository;
|
||||
|
@@ -7,12 +7,6 @@ use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository;
|
||||
use Doctrine\ORM\EntityManagerInterface;
|
||||
use Doctrine\ORM\EntityRepository;
|
||||
|
||||
/**
|
||||
* @method SocialIssue|null find($id, $lockMode = null, $lockVersion = null)
|
||||
* @method SocialIssue|null findOneBy(array $criteria, array $orderBy = null)
|
||||
* @method SocialIssue[] findAll()
|
||||
* @method SocialIssue[] findBy(array $criteria, array $orderBy = null, $limit = null, $offset = null)
|
||||
*/
|
||||
final class SocialIssueRepository
|
||||
{
|
||||
private EntityRepository $repository;
|
||||
|
@@ -1,5 +1,6 @@
|
||||
<template>
|
||||
<banner></banner>
|
||||
<sticky-nav></sticky-nav>
|
||||
|
||||
<h1 v-if="accompanyingCourse.step === 'DRAFT'">{{ $t('course.title.draft') }}</h1>
|
||||
<h1 v-else>{{ $t('course.title.active') }}</h1>
|
||||
@@ -17,6 +18,7 @@
|
||||
<script>
|
||||
import { mapState } from 'vuex'
|
||||
import Banner from './components/Banner.vue';
|
||||
import StickyNav from './components/StickyNav.vue';
|
||||
import PersonsAssociated from './components/PersonsAssociated.vue';
|
||||
import Requestor from './components/Requestor.vue';
|
||||
import SocialIssue from './components/SocialIssue.vue';
|
||||
@@ -29,16 +31,17 @@ export default {
|
||||
name: 'App',
|
||||
components: {
|
||||
Banner,
|
||||
StickyNav,
|
||||
PersonsAssociated,
|
||||
Requestor,
|
||||
SocialIssue,
|
||||
//Referrer, //fait foirer socialissues
|
||||
Referrer,
|
||||
Resources,
|
||||
Comment,
|
||||
Confirm,
|
||||
},
|
||||
computed: mapState([
|
||||
'accompanyingCourse', 'socialIssueOptions'
|
||||
'accompanyingCourse'
|
||||
])
|
||||
};
|
||||
</script>
|
||||
@@ -68,7 +71,7 @@ export default {
|
||||
}
|
||||
a[name^="section"] {
|
||||
position: absolute;
|
||||
top: -2em;
|
||||
top: -3.5em; // ref. stickNav
|
||||
}
|
||||
}
|
||||
padding: 0.8em 0em;
|
||||
@@ -77,7 +80,7 @@ export default {
|
||||
border-radius: 5px;
|
||||
border-left: 1px dotted #718596ab;
|
||||
border-right: 1px dotted #718596ab;
|
||||
/*
|
||||
/* debug components
|
||||
position: relative;
|
||||
&:before {
|
||||
content: "vuejs component";
|
||||
@@ -98,5 +101,6 @@ export default {
|
||||
table {
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
</style>
|
||||
|
@@ -20,11 +20,9 @@
|
||||
|
||||
<teleport to="#header-accompanying_course-name #banner-status">
|
||||
<div v-if="accompanyingCourse.step === 'DRAFT'">
|
||||
<a href="#bottom">
|
||||
<span class="badge badge-secondary">
|
||||
{{ $t('course.step.draft') }}
|
||||
</span>
|
||||
</a>
|
||||
<span class="badge badge-secondary">
|
||||
{{ $t('course.step.draft') }}
|
||||
</span>
|
||||
</div>
|
||||
<div v-else>
|
||||
<div>
|
||||
@@ -46,11 +44,11 @@
|
||||
|
||||
<teleport to="#header-accompanying_course-details #banner-social-issues">
|
||||
<div class="grid-12">
|
||||
<social-issues
|
||||
<social-issue
|
||||
v-for="issue in accompanyingCourse.socialIssues"
|
||||
v-bind:key="issue.id"
|
||||
v-bind:issue="issue">
|
||||
</social-issues>
|
||||
</social-issue>
|
||||
</div>
|
||||
</teleport>
|
||||
|
||||
@@ -58,13 +56,13 @@
|
||||
|
||||
<script>
|
||||
import ToggleFlags from './Banner/ToggleFlags';
|
||||
import SocialIssues from './Banner/SocialIssues.vue';
|
||||
import SocialIssue from './Banner/SocialIssue.vue';
|
||||
|
||||
export default {
|
||||
name: 'Banner',
|
||||
components: {
|
||||
ToggleFlags,
|
||||
SocialIssues
|
||||
SocialIssue
|
||||
},
|
||||
computed: {
|
||||
accompanyingCourse() {
|
||||
|
@@ -11,6 +11,10 @@ export default {
|
||||
|
||||
<style lang="scss" scoped>
|
||||
span.badge {
|
||||
font-size: 95%;
|
||||
text-transform: capitalize !important;
|
||||
font-weight: 500 !important;
|
||||
margin-bottom: 5px;
|
||||
margin-right: 1em;
|
||||
}
|
||||
</style>
|
@@ -1,11 +1,77 @@
|
||||
<template>
|
||||
<div class="vue-component">
|
||||
<h2><a name="section-40"></a>{{ $t('referrer.title') }}</h2>
|
||||
|
||||
<div class="my-4">
|
||||
<label for="" class="">
|
||||
{{ $t('referrer.label') }}
|
||||
</label>
|
||||
|
||||
<VueMultiselect
|
||||
track-by="id"
|
||||
label="text"
|
||||
:multiple="false"
|
||||
:searchable="true"
|
||||
:placeholder="$t('referrer.placeholder')"
|
||||
@update:model-value="updateReferrer"
|
||||
:model-value="value"
|
||||
:options="options">
|
||||
</VueMultiselect>
|
||||
|
||||
<ul class="record_actions">
|
||||
<li>
|
||||
<button
|
||||
class="sc-button bt-create"
|
||||
type="button"
|
||||
name="button"
|
||||
@click="assignMe">
|
||||
{{ $t('referrer.assign_me') }}
|
||||
</button>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import VueMultiselect from 'vue-multiselect';
|
||||
//import { getUsers } from '../api';
|
||||
import { mapState } from 'vuex';
|
||||
|
||||
export default {
|
||||
name: "Referrer",
|
||||
components: { VueMultiselect },
|
||||
data() {
|
||||
return {
|
||||
options: []
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
...mapState({
|
||||
value: state => state.accompanyingCourse.user,
|
||||
}),
|
||||
},
|
||||
mounted() {
|
||||
this.getOptions();
|
||||
},
|
||||
methods: {
|
||||
getOptions() {
|
||||
//getUsers().then(response => new Promise((resolve, reject) => {
|
||||
// console.log(response);
|
||||
// resolve();
|
||||
//})).catch(er => this.$store.commit('catchError'), error));
|
||||
},
|
||||
updateReferrer(value) {
|
||||
//this.$store.dispatch('updateReferrer', this.transformValue(value));
|
||||
},
|
||||
transformValue(value) {
|
||||
let payload = value;
|
||||
return { payload, body, method };
|
||||
},
|
||||
assignMe() {
|
||||
console.log('assign me');
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
@@ -47,9 +47,9 @@ export default {
|
||||
},
|
||||
methods: {
|
||||
getOptions() {
|
||||
getSocialIssues().then(elements => new Promise((resolve, reject) => {
|
||||
console.log('get socialIssues', elements.results);
|
||||
this.options = elements.results;
|
||||
getSocialIssues().then(response => new Promise((resolve, reject) => {
|
||||
//console.log('get socialIssues', response.results);
|
||||
this.options = response.results;
|
||||
resolve();
|
||||
})).catch(error => this.$store.commit('catchError', error));
|
||||
},
|
||||
@@ -64,7 +64,7 @@ export default {
|
||||
let changed = (typeof removed === 'undefined') ? added : removed;
|
||||
let body = { type: "social_issue", id: changed.id };
|
||||
//console.log('body', body);
|
||||
console.log('@@@ CHANGED', method, changed.text);
|
||||
//console.log('@@@', method, changed.text);
|
||||
let payload = updated;
|
||||
return { payload, body, method };
|
||||
}
|
||||
|
@@ -0,0 +1,191 @@
|
||||
<template>
|
||||
<teleport to="#content_conainter .container.content .container">
|
||||
<div id="navmap">
|
||||
<nav>
|
||||
<a class="top" href="#top">
|
||||
<i class="fa fa-fw fa-square"></i>
|
||||
<span>{{ $t('nav.top') }}</span>
|
||||
</a>
|
||||
<item
|
||||
v-for="item of items"
|
||||
:key="item.key"
|
||||
:item="item"
|
||||
:step="step">
|
||||
</item>
|
||||
</nav>
|
||||
</div>
|
||||
</teleport>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import Item from './StickyNav/Item.vue';
|
||||
|
||||
export default {
|
||||
name: "StickyNav",
|
||||
components: {
|
||||
Item
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
header: document.querySelector("header.navigation.container"),
|
||||
bannerName: document.querySelector("#header-accompanying_course-name"),
|
||||
bannerDetails: document.querySelector("#header-accompanying_course-details"),
|
||||
container: null,
|
||||
heightSum: null,
|
||||
stickyNav: null,
|
||||
limit: 25,
|
||||
anchors: null,
|
||||
items: [],
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
accompanyingCourse() {
|
||||
return this.$store.state.accompanyingCourse;
|
||||
},
|
||||
step() {
|
||||
return this.accompanyingCourse.step;
|
||||
},
|
||||
top() {
|
||||
return parseInt(window.getComputedStyle(this.stickyNav).getPropertyValue('top').slice(0, -2));
|
||||
},
|
||||
},
|
||||
mounted() {
|
||||
this.ready();
|
||||
window.addEventListener('scroll', this.handleScroll);
|
||||
},
|
||||
destroyed() {
|
||||
window.removeEventListener('scroll', this.handleScroll);
|
||||
},
|
||||
methods: {
|
||||
ready() {
|
||||
|
||||
// load datas DOM when mounted ready
|
||||
this.container = document.querySelector("#content_conainter .container.content .container");
|
||||
this.stickyNav = document.querySelector('#navmap');
|
||||
this.anchors = document.querySelectorAll("h2 a[name^='section']");
|
||||
this.initItemsMap();
|
||||
|
||||
// TODO resizeObserver not supports IE !
|
||||
// Listen when elements change size, then recalculate heightSum and initItemsMap
|
||||
const resizeObserver = new ResizeObserver(entries => {
|
||||
this.refreshPos();
|
||||
});
|
||||
|
||||
resizeObserver.observe(this.header);
|
||||
resizeObserver.observe(this.bannerName);
|
||||
resizeObserver.observe(this.bannerDetails);
|
||||
resizeObserver.observe(this.container);
|
||||
},
|
||||
initItemsMap() {
|
||||
|
||||
this.anchors.forEach(anchor => {
|
||||
this.items.push({
|
||||
pos: null,
|
||||
active: false,
|
||||
key: parseInt(anchor.name.slice(8).slice(0, -1)),
|
||||
name: '#' + anchor.name
|
||||
})
|
||||
});
|
||||
},
|
||||
refreshPos() {
|
||||
|
||||
//console.log('refreshPos');
|
||||
this.heightSum = this.header.offsetHeight + this.bannerName.offsetHeight + this.bannerDetails.offsetHeight;
|
||||
|
||||
this.anchors.forEach((anchor, i) => {
|
||||
this.items[i].pos = this.findPos(anchor)['y'];
|
||||
});
|
||||
},
|
||||
findPos(element) {
|
||||
|
||||
let posX = 0, posY = 0;
|
||||
do {
|
||||
posX += element.offsetLeft;
|
||||
posY += element.offsetTop;
|
||||
element = element.offsetParent;
|
||||
}
|
||||
while( element != null );
|
||||
|
||||
let pos = [];
|
||||
pos['x'] = posX;
|
||||
pos['y'] = posY;
|
||||
|
||||
return pos;
|
||||
},
|
||||
handleScroll(event) {
|
||||
|
||||
let pos = this.findPos(this.stickyNav);
|
||||
let top = this.heightSum + this.top - window.scrollY;
|
||||
//console.log(window.scrollY);
|
||||
|
||||
if (top > this.limit) {
|
||||
this.stickyNav.style.position = 'absolute';
|
||||
this.stickyNav.style.left = '-60px';
|
||||
} else {
|
||||
this.stickyNav.style.position = 'fixed';
|
||||
this.stickyNav.style.left = pos['x'] + 'px';
|
||||
}
|
||||
|
||||
this.switchActive();
|
||||
},
|
||||
switchActive() {
|
||||
|
||||
this.items.forEach((item, i) => {
|
||||
let next = (this.items[i+1]) ? this.items[i+1].pos : '100000';
|
||||
item.active =
|
||||
(window.scrollY >= item.pos & window.scrollY < next) ? true : false;
|
||||
}, this);
|
||||
|
||||
// last item never switch active because scroll reach bottom of page
|
||||
if (document.body.scrollHeight == window.scrollY + window.innerHeight) {
|
||||
this.items[this.items.length-1].active = true;
|
||||
this.items[this.items.length-2].active = false;
|
||||
} else {
|
||||
this.items[this.items.length-1].active = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
div#navmap {
|
||||
position: absolute;
|
||||
top: 30px;
|
||||
left: -60px; //-10%;
|
||||
nav {
|
||||
font-size: small;
|
||||
a {
|
||||
display: block;
|
||||
box-sizing: border-box;
|
||||
margin-bottom: -3px;
|
||||
color: #71859669;
|
||||
&.top {
|
||||
color: #718596;
|
||||
}
|
||||
span {
|
||||
display: none;
|
||||
}
|
||||
&:hover,
|
||||
&.active {
|
||||
span {
|
||||
display: inline;
|
||||
padding-left: 8px;
|
||||
}
|
||||
}
|
||||
&:hover {
|
||||
color: #718596b5;
|
||||
}
|
||||
&.active {
|
||||
color: #e2793d; //orange
|
||||
//color: #eec84a; //jaune
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@media only screen and (max-width: 768px) {
|
||||
div.sticky-section {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
</style>
|
@@ -0,0 +1,30 @@
|
||||
<template>
|
||||
<a
|
||||
v-if="item.key <= 5"
|
||||
:href="item.name"
|
||||
:class="{ 'active': isActive }"
|
||||
>
|
||||
<i class="fa fa-fw fa-square"></i>
|
||||
<span>{{ item.key }}</span>
|
||||
</a>
|
||||
<a
|
||||
v-else-if="step === 'DRAFT'"
|
||||
:href="item.name"
|
||||
:class="{ 'active': isActive }"
|
||||
>
|
||||
<i class="fa fa-fw fa-square"></i>
|
||||
<span>{{ item.key }}</span>
|
||||
</a>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: "Item",
|
||||
props: ['item', 'step'],
|
||||
computed: {
|
||||
isActive() {
|
||||
return this.item.active;
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
@@ -60,8 +60,8 @@ const appMessages = {
|
||||
referrer: {
|
||||
title: "Référent du parcours",
|
||||
label: "Vous pouvez choisir un TMS ou vous assigner directement comme référent",
|
||||
assign_me: "M'assigner comme référent",
|
||||
placeholder: "Choisir un TMS",
|
||||
assign_me: "M'assigner comme référent",
|
||||
},
|
||||
resources: {
|
||||
title: "Interlocuteurs privilégiés",
|
||||
|
@@ -182,7 +182,7 @@ let initPromise = getAccompanyingCourse(id)
|
||||
//console.log('## action: payload', { payload, body, method });
|
||||
postSocialIssue(id, body, method)
|
||||
.then(response => new Promise((resolve, reject) => {
|
||||
console.log('response', response);
|
||||
//console.log('response', response);
|
||||
commit('updateSocialIssues', payload);
|
||||
resolve();
|
||||
})).catch((error) => { commit('catchError', error) });
|
||||
|
@@ -18,7 +18,11 @@
|
||||
*/
|
||||
namespace Chill\PersonBundle\Serializer\Normalizer;
|
||||
|
||||
use Chill\MainBundle\Entity\Center;
|
||||
use Chill\PersonBundle\Entity\Person;
|
||||
use Symfony\Component\Serializer\Normalizer\DenormalizerAwareInterface;
|
||||
use Symfony\Component\Serializer\Normalizer\DenormalizerAwareTrait;
|
||||
use Symfony\Component\Serializer\Normalizer\NormalizerAwareTrait;
|
||||
use Symfony\Component\Serializer\Normalizer\NormalizerInterface;
|
||||
use Symfony\Component\Serializer\Normalizer\DenormalizerInterface;
|
||||
use Symfony\Component\Serializer\Normalizer\NormalizerAwareInterface;
|
||||
@@ -27,6 +31,7 @@ use Symfony\Component\Serializer\Exception\RuntimeException;
|
||||
use Symfony\Component\Serializer\Exception\UnexpectedValueException;
|
||||
use Chill\MainBundle\Templating\Entity\ChillEntityRenderExtension;
|
||||
use Symfony\Component\Serializer\Normalizer\AbstractNormalizer;
|
||||
use Symfony\Component\Serializer\Normalizer\ObjectToPopulateTrait;
|
||||
|
||||
/**
|
||||
* Serialize a Person entity
|
||||
@@ -34,16 +39,24 @@ use Symfony\Component\Serializer\Normalizer\AbstractNormalizer;
|
||||
*/
|
||||
class PersonNormalizer implements
|
||||
NormalizerInterface,
|
||||
NormalizerAwareInterface
|
||||
NormalizerAwareInterface,
|
||||
DenormalizerInterface,
|
||||
DenormalizerAwareInterface
|
||||
{
|
||||
|
||||
protected NormalizerInterface $normalizer;
|
||||
|
||||
private ChillEntityRenderExtension $render;
|
||||
|
||||
public function __construct(ChillEntityRenderExtension $render)
|
||||
private PersonRepository $repository;
|
||||
|
||||
use NormalizerAwareTrait;
|
||||
|
||||
use ObjectToPopulateTrait;
|
||||
|
||||
use DenormalizerAwareTrait;
|
||||
|
||||
public function __construct(ChillEntityRenderExtension $render, PersonRepository $repository)
|
||||
{
|
||||
$this->render = $render;
|
||||
$this->repository = $repository;
|
||||
}
|
||||
|
||||
public function normalize($person, string $format = null, array $context = array())
|
||||
@@ -59,7 +72,9 @@ class PersonNormalizer implements
|
||||
'center' => $this->normalizer->normalize($person->getCenter()),
|
||||
'phonenumber' => $person->getPhonenumber(),
|
||||
'mobilenumber' => $person->getMobilenumber(),
|
||||
'altNames' => $this->normalizeAltNames($person->getAltNames())
|
||||
'altNames' => $this->normalizeAltNames($person->getAltNames()),
|
||||
'gender' => $person->getGender(),
|
||||
'gender_numeric' => $person->getGenderNumeric(),
|
||||
];
|
||||
}
|
||||
|
||||
@@ -80,9 +95,50 @@ class PersonNormalizer implements
|
||||
return $data instanceof Person;
|
||||
}
|
||||
|
||||
|
||||
public function setNormalizer(NormalizerInterface $normalizer)
|
||||
public function denormalize($data, string $type, string $format = null, array $context = [])
|
||||
{
|
||||
$this->normalizer = $normalizer;
|
||||
$person = $this->extractObjectToPopulate($type, $context);
|
||||
|
||||
if (\array_key_exists('id', $data)) {
|
||||
$person = $this->repository->find($data['id']);
|
||||
|
||||
if (null === $person) {
|
||||
throw new UnexpectedValueException("The person with id \"{$data['id']}\" does ".
|
||||
"not exists");
|
||||
}
|
||||
// currently, not allowed to update a person through api
|
||||
// if instantiated with id
|
||||
return $person;
|
||||
}
|
||||
|
||||
if (null === $person) {
|
||||
$person = new Person();
|
||||
}
|
||||
|
||||
foreach (['firstName', 'lastName', 'phonenumber', 'mobilenumber', 'gender']
|
||||
as $item) {
|
||||
if (\array_key_exists($item, $data)) {
|
||||
$person->{'set'.\ucfirst($item)}($data[$item]);
|
||||
}
|
||||
}
|
||||
|
||||
foreach ([
|
||||
'birthdate' => \DateTime::class,
|
||||
'center' => Center::class
|
||||
] as $item => $class) {
|
||||
if (\array_key_exists($item, $data)) {
|
||||
$object = $this->denormalizer->denormalize($data[$item], $class, $format, $context);
|
||||
if ($object instanceof $class) {
|
||||
$person->{'set'.\ucfirst($item)}($object);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $person;
|
||||
}
|
||||
|
||||
public function supportsDenormalization($data, string $type, string $format = null)
|
||||
{
|
||||
return $type === Person::class && ($data['type'] ?? NULL) === 'person';
|
||||
}
|
||||
}
|
||||
|
@@ -0,0 +1,83 @@
|
||||
<?php
|
||||
|
||||
namespace Chill\PersonBundle\Tests\Controller;
|
||||
|
||||
use Chill\MainBundle\Test\PrepareClientTrait;
|
||||
use Chill\PersonBundle\Entity\Person;
|
||||
use Doctrine\ORM\EntityManagerInterface;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
use Symfony\Bundle\FrameworkBundle\Test\WebTestCase;
|
||||
|
||||
class PersonApiControllerTest extends WebTestCase
|
||||
{
|
||||
use PrepareClientTrait;
|
||||
|
||||
/**
|
||||
* @dataProvider dataGetPersonFromCenterB
|
||||
*/
|
||||
public function testPersonGetUnauthorized($personId): void
|
||||
{
|
||||
$client = $this->getClientAuthenticated();
|
||||
|
||||
$client->request(Request::METHOD_GET, "/api/1.0/person/person/{$personId}.json");
|
||||
$response = $client->getResponse();
|
||||
|
||||
$this->assertEquals(403, $response->getStatusCode());
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider dataGetPersonFromCenterA
|
||||
*/
|
||||
public function testPersonGet($personId): void
|
||||
{
|
||||
$client = $this->getClientAuthenticated();
|
||||
|
||||
$client->request(Request::METHOD_GET, "/api/1.0/person/person/{$personId}.json");
|
||||
$response = $client->getResponse();
|
||||
|
||||
$this->assertResponseIsSuccessful();
|
||||
|
||||
$data = \json_decode($client->getResponse()->getContent(), true);
|
||||
|
||||
$this->assertArrayHasKey('type', $data);
|
||||
$this->assertArrayHasKey('id', $data);
|
||||
$this->assertEquals('person', $data['type']);
|
||||
$this->assertEquals($personId, $data['id']);
|
||||
}
|
||||
|
||||
public function dataGetPersonFromCenterA(): \Iterator
|
||||
{
|
||||
self::bootKernel();
|
||||
$em = self::$container->get(EntityManagerInterface::class);
|
||||
$personIds= $em->createQuery("SELECT p.id FROM ".Person::class." p ".
|
||||
"JOIN p.center c ".
|
||||
"WHERE c.name = :center")
|
||||
->setParameter('center', 'Center A')
|
||||
->setMaxResults(100)
|
||||
->getScalarResult()
|
||||
;
|
||||
|
||||
\shuffle($personIds);
|
||||
|
||||
yield \array_pop($personIds);
|
||||
yield \array_pop($personIds);
|
||||
}
|
||||
|
||||
public function dataGetPersonFromCenterB(): \Iterator
|
||||
{
|
||||
self::bootKernel();
|
||||
$em = self::$container->get(EntityManagerInterface::class);
|
||||
$personIds= $em->createQuery("SELECT p.id FROM ".Person::class." p ".
|
||||
"JOIN p.center c ".
|
||||
"WHERE c.name = :center")
|
||||
->setParameter('center', 'Center B')
|
||||
->setMaxResults(100)
|
||||
->getScalarResult()
|
||||
;
|
||||
|
||||
\shuffle($personIds);
|
||||
|
||||
yield \array_pop($personIds);
|
||||
yield \array_pop($personIds);
|
||||
}
|
||||
}
|
@@ -23,6 +23,7 @@
|
||||
namespace Chill\PersonBundle\Tests\Entity;
|
||||
|
||||
use Chill\PersonBundle\Entity\AccompanyingPeriod;
|
||||
use Chill\PersonBundle\Entity\AccompanyingPeriodParticipation;
|
||||
use Chill\PersonBundle\Entity\Person;
|
||||
use Chill\ThirdPartyBundle\Entity\ThirdParty;
|
||||
use Chill\PersonBundle\Entity\AccompanyingPeriod\Comment;
|
||||
@@ -85,10 +86,11 @@ class AccompanyingPeriodTest extends \PHPUnit\Framework\TestCase
|
||||
$person3 = new Person();
|
||||
$period = new AccompanyingPeriod(new \DateTime());
|
||||
|
||||
$period->addPerson($person);
|
||||
$period->addPerson($person2);
|
||||
$period->addPerson($person3);
|
||||
$participation0 = $period->createParticipationFor($person);
|
||||
$period->createParticipationFor($person2);
|
||||
$period->createParticipationFor($person3);
|
||||
|
||||
$this->assertNotNull($participation0);
|
||||
$this->assertEquals(3, $period->getParticipations()->count());
|
||||
$this->assertTrue($period->containsPerson($person));
|
||||
$this->assertFalse($period->containsPerson(new Person()));
|
||||
@@ -97,14 +99,28 @@ class AccompanyingPeriodTest extends \PHPUnit\Framework\TestCase
|
||||
$participations = $period->getParticipationsContainsPerson($person);
|
||||
$this->assertNotNull($participation);
|
||||
$this->assertSame($person, $participation->getPerson());
|
||||
$this->assertSame($participation, $participation0);
|
||||
$this->assertEquals(1, $participations->count());
|
||||
|
||||
$participationL = $period->removePerson($person);
|
||||
$participationL = $period->closeParticipationFor($person);
|
||||
$this->assertSame($participationL, $participation);
|
||||
$this->assertTrue($participation->getEndDate() instanceof \DateTimeInterface);
|
||||
|
||||
$participation = $period->getOpenParticipationContainsPerson($person);
|
||||
$this->assertNull($participation);
|
||||
|
||||
$person4 = new Person();
|
||||
$participations4 = $period->getParticipationsContainsPerson($person4);
|
||||
$this->assertEquals(0, $participations4->count());
|
||||
$participation4 = $period->getOpenParticipationContainsPerson($person4);
|
||||
$this->assertNull($participation4);
|
||||
|
||||
$period->addPerson($person4);
|
||||
$this->assertInstanceOf(AccompanyingPeriodParticipation::class, $period->getOpenParticipationContainsPerson($person4));
|
||||
$this->assertEquals(1, $period->getParticipationsContainsPerson($person4)->count());
|
||||
$period->removePerson($person4);
|
||||
$this->assertNull($period->getOpenParticipationContainsPerson($person4));
|
||||
$this->assertEquals(1, $period->getParticipationsContainsPerson($person4)->count());
|
||||
}
|
||||
|
||||
public function testRequestor()
|
||||
|
@@ -41,6 +41,11 @@ components:
|
||||
properties:
|
||||
id:
|
||||
type: integer
|
||||
readOnly: true
|
||||
type:
|
||||
type: string
|
||||
enum:
|
||||
- 'person'
|
||||
firstName:
|
||||
type: string
|
||||
lastName:
|
||||
@@ -48,12 +53,23 @@ components:
|
||||
text:
|
||||
type: string
|
||||
description: a canonical representation for the person name
|
||||
readOnly: true
|
||||
birthdate:
|
||||
$ref: '#/components/schemas/Date'
|
||||
phonenumber:
|
||||
type: string
|
||||
mobilenumber:
|
||||
type: string
|
||||
gender:
|
||||
type: string
|
||||
enum:
|
||||
- man
|
||||
- woman
|
||||
- both
|
||||
gender_numeric:
|
||||
type: integer
|
||||
description: a numerical representation of gender
|
||||
readOnly: true
|
||||
PersonById:
|
||||
type: object
|
||||
properties:
|
||||
@@ -178,6 +194,53 @@ components:
|
||||
readOnly: true
|
||||
|
||||
paths:
|
||||
/1.0/person/person/{id}.json:
|
||||
get:
|
||||
tags:
|
||||
- person
|
||||
summary: Get a single person
|
||||
parameters:
|
||||
- name: id
|
||||
in: path
|
||||
required: true
|
||||
description: The person's id
|
||||
schema:
|
||||
type: integer
|
||||
format: integer
|
||||
minimum: 1
|
||||
responses:
|
||||
200:
|
||||
description: "OK"
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: "#/components/schemas/Person"
|
||||
403:
|
||||
description: "Unauthorized"
|
||||
/1.0/person/person.json:
|
||||
post:
|
||||
tags:
|
||||
- person
|
||||
summary: Create a single person
|
||||
requestBody:
|
||||
description: "A person"
|
||||
required: true
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/Person'
|
||||
responses:
|
||||
200:
|
||||
description: "OK"
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: "#/components/schemas/Person"
|
||||
403:
|
||||
description: "Unauthorized"
|
||||
422:
|
||||
description: "Invalid data: the data is a valid json, could be deserialized, but does not pass validation"
|
||||
|
||||
/1.0/person/social-work/social-issue.json:
|
||||
get:
|
||||
tags:
|
||||
|
@@ -53,3 +53,9 @@ services:
|
||||
$validator: '@Symfony\Component\Validator\Validator\ValidatorInterface'
|
||||
$registry: '@Symfony\Component\Workflow\Registry'
|
||||
tags: ['controller.service_arguments']
|
||||
|
||||
Chill\PersonBundle\Controller\PersonApiController:
|
||||
arguments:
|
||||
$authorizationHelper: '@Chill\MainBundle\Security\Authorization\AuthorizationHelper'
|
||||
tags: ['controller.service_arguments']
|
||||
|
||||
|
@@ -13,7 +13,11 @@ services:
|
||||
Chill\PersonBundle\Templating\Entity\ClosingMotiveRender:
|
||||
arguments:
|
||||
$translatableStringHelper: '@Chill\MainBundle\Templating\TranslatableStringHelper'
|
||||
tags:
|
||||
- 'chill.render_entity'
|
||||
|
||||
Chill\PersonBundle\Templating\Entity\SocialIssueRender:
|
||||
arguments:
|
||||
$translatableStringHelper: '@Chill\MainBundle\Templating\TranslatableStringHelper'
|
||||
tags:
|
||||
- 'chill.render_entity'
|
||||
|
@@ -0,0 +1,31 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Chill\Migrations\Person;
|
||||
|
||||
use Doctrine\DBAL\Schema\Schema;
|
||||
use Doctrine\Migrations\AbstractMigration;
|
||||
|
||||
/**
|
||||
* Specify ON DELETE behaviour to handle deletion of parents in associated tables
|
||||
*/
|
||||
final class Version20210525211214 extends AbstractMigration
|
||||
{
|
||||
public function getDescription(): string
|
||||
{
|
||||
return 'Specify ON DELETE behaviour to handle deletion of parents in associated tables';
|
||||
}
|
||||
|
||||
public function up(Schema $schema): void
|
||||
{
|
||||
$this->addSql('ALTER TABLE chill_person_accompanying_period_comment DROP CONSTRAINT FK_CD960EF3D7FA8EF0');
|
||||
$this->addSql('ALTER TABLE chill_person_accompanying_period_comment ADD CONSTRAINT FK_CD960EF3D7FA8EF0 FOREIGN KEY (accompanyingPeriod_id) REFERENCES chill_person_accompanying_period (id) ON DELETE CASCADE NOT DEFERRABLE INITIALLY IMMEDIATE');
|
||||
}
|
||||
|
||||
public function down(Schema $schema): void
|
||||
{
|
||||
$this->addSql('ALTER TABLE chill_person_accompanying_period_comment DROP CONSTRAINT fk_cd960ef3d7fa8ef0');
|
||||
$this->addSql('ALTER TABLE chill_person_accompanying_period_comment ADD CONSTRAINT fk_cd960ef3d7fa8ef0 FOREIGN KEY (accompanyingperiod_id) REFERENCES chill_person_accompanying_period (id) NOT DEFERRABLE INITIALLY IMMEDIATE');
|
||||
}
|
||||
}
|
@@ -32,9 +32,9 @@ use Symfony\Component\Serializer\Annotation\DiscriminatorMap;
|
||||
|
||||
/**
|
||||
* ThirdParty is a party recorded in the database.
|
||||
*
|
||||
* A party may be attached to multiple centers. Being attach to a center allow
|
||||
* all users with the right 'CHILL_3PARTY_3PARTY_SEE', 'CHILL_3PARTY_3 to see, select and edit parties for this
|
||||
*
|
||||
* A party may be attached to multiple centers. Being attach to a center allow
|
||||
* all users with the right 'CHILL_3PARTY_3PARTY_SEE', 'CHILL_3PARTY_3 to see, select and edit parties for this
|
||||
* center.
|
||||
*
|
||||
* @ORM\Table(name="chill_3party.third_party")
|
||||
@@ -66,7 +66,7 @@ class ThirdParty
|
||||
* @var string|null
|
||||
*
|
||||
* @ORM\Column(name="telephone", type="string", length=64, nullable=true)
|
||||
* @Assert\Regex("/^([\+{1}])([0-9\s*]{4,20})$/",
|
||||
* @Assert\Regex("/^([\+{1}])([0-9\s*]{4,20})$/",
|
||||
* message="Invalid phone number: it should begin with the international prefix starting with ""+"", hold only digits and be smaller than 20 characters. Ex: +33123456789"
|
||||
* )
|
||||
*/
|
||||
@@ -94,13 +94,13 @@ class ThirdParty
|
||||
* @Assert\Count(min=1)
|
||||
*/
|
||||
private $type;
|
||||
|
||||
|
||||
/**
|
||||
* @var boolean
|
||||
* @ORM\Column(name="active", type="boolean", options={"defaut": true})
|
||||
*/
|
||||
private $active = true;
|
||||
|
||||
|
||||
/**
|
||||
* @var Collection instances of Center
|
||||
* @ORM\ManyToMany(targetEntity="\Chill\MainBundle\Entity\Center")
|
||||
@@ -108,14 +108,15 @@ class ThirdParty
|
||||
* @Assert\Count(min=1)
|
||||
*/
|
||||
private $centers;
|
||||
|
||||
|
||||
/**
|
||||
* @var Address|null
|
||||
* @ORM\ManyToOne(targetEntity="\Chill\MainBundle\Entity\Address",
|
||||
* cascade={"persist", "remove"})
|
||||
* @ORM\JoinColumn(nullable=true, onDelete="SET NULL")
|
||||
*/
|
||||
private $address;
|
||||
|
||||
|
||||
/**
|
||||
* ThirdParty constructor.
|
||||
*/
|
||||
@@ -249,7 +250,7 @@ class ThirdParty
|
||||
{
|
||||
return $this->type;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
@@ -257,7 +258,7 @@ class ThirdParty
|
||||
{
|
||||
return $this->active;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return Collection
|
||||
*/
|
||||
@@ -265,7 +266,7 @@ class ThirdParty
|
||||
{
|
||||
return $this->centers;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param bool $active
|
||||
* @return $this
|
||||
@@ -275,7 +276,7 @@ class ThirdParty
|
||||
$this->active = $active;
|
||||
return $this;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param Center $center
|
||||
*/
|
||||
@@ -285,7 +286,7 @@ class ThirdParty
|
||||
$this->centers->add($center);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param Center $center
|
||||
*/
|
||||
@@ -295,7 +296,7 @@ class ThirdParty
|
||||
$this->centers->removeElement($center);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param Collection $centers
|
||||
* @return $this
|
||||
@@ -305,16 +306,16 @@ class ThirdParty
|
||||
foreach ($centers as $center) {
|
||||
$this->addCenter($center);
|
||||
}
|
||||
|
||||
|
||||
foreach ($this->centers as $center) {
|
||||
if (FALSE === $centers->contains($center)) {
|
||||
$this->removeCenter($center);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return Address|null
|
||||
*/
|
||||
@@ -322,7 +323,7 @@ class ThirdParty
|
||||
{
|
||||
return $this->address;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param Address $address
|
||||
* @return $this
|
||||
@@ -330,10 +331,10 @@ class ThirdParty
|
||||
public function setAddress(Address $address)
|
||||
{
|
||||
$this->address = $address;
|
||||
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
|
@@ -0,0 +1,31 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Chill\Migrations\ThirdParty;
|
||||
|
||||
use Doctrine\DBAL\Schema\Schema;
|
||||
use Doctrine\Migrations\AbstractMigration;
|
||||
|
||||
/**
|
||||
* Specify ON DELETE behaviour to handle deletion of parents in associated tables
|
||||
*/
|
||||
final class Version20210525211216 extends AbstractMigration
|
||||
{
|
||||
public function getDescription(): string
|
||||
{
|
||||
return 'Specify ON DELETE behaviour to handle deletion of parents in associated tables';
|
||||
}
|
||||
|
||||
public function up(Schema $schema): void
|
||||
{
|
||||
$this->addSql('ALTER TABLE chill_3party.third_party DROP CONSTRAINT FK_D952467BF5B7AF75');
|
||||
$this->addSql('ALTER TABLE chill_3party.third_party ADD CONSTRAINT FK_D952467BF5B7AF75 FOREIGN KEY (address_id) REFERENCES chill_main_address (id) ON DELETE SET NULL NOT DEFERRABLE INITIALLY IMMEDIATE');
|
||||
}
|
||||
|
||||
public function down(Schema $schema): void
|
||||
{
|
||||
$this->addSql('ALTER TABLE chill_3party.third_party DROP CONSTRAINT fk_d952467bf5b7af75');
|
||||
$this->addSql('ALTER TABLE chill_3party.third_party ADD CONSTRAINT fk_d952467bf5b7af75 FOREIGN KEY (address_id) REFERENCES chill_main_address (id) NOT DEFERRABLE INITIALLY IMMEDIATE');
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user