mirror of
https://gitlab.com/Chill-Projet/chill-bundles.git
synced 2025-09-10 08:44:58 +00:00
Compare commits
152 Commits
feature-ad
...
fix-timeli
Author | SHA1 | Date | |
---|---|---|---|
|
8364518282 | ||
|
4e50d0ace9 | ||
|
0b54adeb59 | ||
|
5d23de4862 | ||
a63c38b6aa | |||
8915c42008 | |||
503293a359 | |||
7bdf71315a | |||
6f5d457122 | |||
b4274264a7 | |||
8002725c87 | |||
2c9edf3741 | |||
3f562449e1 | |||
1cce39bcb5 | |||
ad690db886 | |||
|
1b8462b40d | ||
|
8c98f2cf6e | ||
f3260f57a4 | |||
b4ad0128e4 | |||
e1c8278f71 | |||
|
ed3f46ce7f | ||
33457d3cbc | |||
e919b4322e | |||
7503c845df | |||
3686a294d3 | |||
b6131379f9 | |||
e1fcc41ace | |||
f2a04cebe6 | |||
c693002ddb | |||
ee77c8540a | |||
a536d2780e | |||
f880598052 | |||
e7985ea52f | |||
f56dc65021 | |||
|
4770758aee | ||
90fe484d81 | |||
2b8bbe019d | |||
9e1c151402 | |||
088e522292 | |||
b8e6e98a74 | |||
2db847ada2 | |||
07e0692783 | |||
e78d53064b | |||
e6fcb5ff22 | |||
f02e33fda7 | |||
1bbec9efae | |||
3b53c4451c | |||
30f490959b | |||
|
0a894b0db1 | ||
c20e9507d5 | |||
f89c690f1b | |||
|
7819c1204c | ||
|
f61af9d02a | ||
|
e470a6a97e | ||
|
cd8c47449b | ||
120e7cade5 | |||
ac550e05e8 | |||
d6e7fadb4f | |||
|
2be1c08c44 | ||
|
86c177bbbb | ||
|
d426d28ba0 | ||
|
72e69fc0b3 | ||
cc8de353d4 | |||
4495a5d33b | |||
9dffe30aad | |||
d393e74896 | |||
daf083dc88 | |||
|
ce859697b5 | ||
|
1587c762f8 | ||
|
17c01d9b46 | ||
a1bb9ea352 | |||
|
a1895ec65f | ||
|
c5faa0b99d | ||
|
e9d142f3e8 | ||
|
91860afd80 | ||
|
bec0700d39 | ||
|
05d3d7f5c7 | ||
|
ebff36d257 | ||
|
a709b3afb6 | ||
|
69a3c6a9b2 | ||
|
8c33d876e8 | ||
|
1ec2fbcc16 | ||
|
bc4e29141b | ||
|
e90ea31683 | ||
|
7c99f0b3e0 | ||
|
c089960707 | ||
|
0b2f29f1e8 | ||
|
9a4f50472a | ||
|
7d1a1c4004 | ||
|
ebd58d4229 | ||
|
dd48795f64 | ||
3d45b6687f | |||
35e6d36ce0 | |||
4900c81c11 | |||
52472b0ec3 | |||
ec68e6f761 | |||
25bd170f6b | |||
6939b4a313 | |||
d18922ed98 | |||
e8bf242c42 | |||
2050460bb3 | |||
|
4add30e895 | ||
e1dbfdafd7 | |||
75becb2294 | |||
94e494361f | |||
cab3b1059d | |||
|
d27bdf68fb | ||
|
82b82920e1 | ||
4bb3eadf91 | |||
4c82e65c1f | |||
cf4d7df7ad | |||
86d13410c3 | |||
19fdf2a503 | |||
3a0c25c871 | |||
083338da8d | |||
37e5c9ceaa | |||
|
5448238697 | ||
|
c5250a1059 | ||
b2c1a7b8de | |||
49c6915c0a | |||
b4583fc6dc | |||
f7c508939c | |||
4cf77a9b0e | |||
a2160bef7d | |||
|
c2a4a95eba | ||
8641d6bdce | |||
5f4d513aa6 | |||
f47b15de39 | |||
7426dc02cf | |||
a570160aed | |||
6e81ef0065 | |||
e3cc76c689 | |||
b43f43fa0b | |||
7596bd5a06 | |||
f02d6df262 | |||
e4e2138765 | |||
395735e6f7 | |||
2c96c02261 | |||
53813f8f29 | |||
|
b8ef0d28f5 | ||
|
e973c4013f | ||
01f9d03b14 | |||
|
0f9a395dfc | ||
|
38ac3badef | ||
|
cda32fb925 | ||
|
58cb34f39b | ||
66426f5102 | |||
|
03243605da | ||
|
48e2d2ceab | ||
|
777fb25860 | ||
|
03601b9707 | ||
c205bbddd3 |
3
.gitignore
vendored
3
.gitignore
vendored
@@ -1,8 +1,8 @@
|
||||
.composer/*
|
||||
composer.phar
|
||||
composer.lock
|
||||
|
||||
docs/build/
|
||||
.php_cs.cache
|
||||
|
||||
###> symfony/framework-bundle ###
|
||||
/.env.local
|
||||
@@ -19,3 +19,4 @@ docs/build/
|
||||
/phpunit.xml
|
||||
.phpunit.result.cache
|
||||
###< phpunit/phpunit ###
|
||||
|
||||
|
@@ -30,6 +30,10 @@ variables:
|
||||
POSTGRES_PASSWORD: postgres
|
||||
# fetch the chill-app using git submodules
|
||||
GIT_SUBMODULE_STRATEGY: recursive
|
||||
REDIS_HOST: redis
|
||||
REDIS_PORT: 6379
|
||||
REDIS_URL: redis://redis:6379
|
||||
|
||||
|
||||
# Run our tests
|
||||
test:
|
||||
|
9
README.md
Normal file
9
README.md
Normal file
@@ -0,0 +1,9 @@
|
||||
# Chill framework
|
||||
|
||||
Documentation of the Chill software.
|
||||
|
||||
The online documentation can be found at http://docs.chill.social
|
||||
|
||||
See the [`docs`][1] directory for more.
|
||||
|
||||
[1]: docs/README.md
|
453
docs/source/development/api.rst
Normal file
453
docs/source/development/api.rst
Normal file
@@ -0,0 +1,453 @@
|
||||
.. Copyright (C) 2014 Champs Libres Cooperative SCRLFS
|
||||
Permission is granted to copy, distribute and/or modify this document
|
||||
under the terms of the GNU Free Documentation License, Version 1.3
|
||||
or any later version published by the Free Software Foundation;
|
||||
with no Invariant Sections, no Front-Cover Texts, and no Back-Cover Texts.
|
||||
A copy of the license is included in the section entitled "GNU
|
||||
Free Documentation License".
|
||||
|
||||
.. _api:
|
||||
|
||||
API
|
||||
###
|
||||
|
||||
Chill provides a basic framework to build REST api.
|
||||
|
||||
Configure a route
|
||||
=================
|
||||
|
||||
Follow those steps to build a REST api:
|
||||
|
||||
1. Create your model;
|
||||
2. Configure the API;
|
||||
|
||||
You can also:
|
||||
|
||||
* hook into the controller to customize some steps;
|
||||
* add more route and steps
|
||||
|
||||
.. note::
|
||||
|
||||
Useful links:
|
||||
|
||||
* `How to use annotation to configure serialization <https://symfony.com/doc/current/serializer.html>`_
|
||||
* `How to create your custom normalizer <https://symfony.com/doc/current/serializer/custom_normalizer.html>`_
|
||||
|
||||
Auto-loading the routes
|
||||
***********************
|
||||
|
||||
Ensure that those lines are present in your file `app/config/routing.yml`:
|
||||
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
chill_cruds:
|
||||
resource: 'chill_main_crud_route_loader:load'
|
||||
type: service
|
||||
|
||||
|
||||
Create your model
|
||||
*****************
|
||||
|
||||
Create your model on the usual way:
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
namespace Chill\PersonBundle\Entity\AccompanyingPeriod;
|
||||
|
||||
use Chill\PersonBundle\Entity\AccompanyingPeriod\OriginRepository;
|
||||
use Doctrine\ORM\Mapping as ORM;
|
||||
|
||||
/**
|
||||
* @ORM\Entity(repositoryClass=OriginRepository::class)
|
||||
* @ORM\Table(name="chill_person_accompanying_period_origin")
|
||||
*/
|
||||
class Origin
|
||||
{
|
||||
/**
|
||||
* @ORM\Id
|
||||
* @ORM\GeneratedValue
|
||||
* @ORM\Column(type="integer")
|
||||
*/
|
||||
private $id;
|
||||
|
||||
/**
|
||||
* @ORM\Column(type="json")
|
||||
*/
|
||||
private $label;
|
||||
|
||||
/**
|
||||
* @ORM\Column(type="date_immutable", nullable=true)
|
||||
*/
|
||||
private $noActiveAfter;
|
||||
|
||||
// .. getters and setters
|
||||
|
||||
}
|
||||
|
||||
|
||||
Configure api
|
||||
*************
|
||||
|
||||
Configure the api using Yaml (see the full configuration: :ref:`api_full_configuration`):
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
# config/packages/chill_main.yaml
|
||||
chill_main:
|
||||
apis:
|
||||
accompanying_period_origin:
|
||||
base_path: '/api/1.0/person/accompanying-period/origin'
|
||||
class: 'Chill\PersonBundle\Entity\AccompanyingPeriod\Origin'
|
||||
name: accompanying_period_origin
|
||||
base_role: 'ROLE_USER'
|
||||
actions:
|
||||
_index:
|
||||
methods:
|
||||
GET: true
|
||||
HEAD: true
|
||||
_entity:
|
||||
methods:
|
||||
GET: true
|
||||
HEAD: true
|
||||
|
||||
.. note::
|
||||
|
||||
If you are working on a shared bundle (aka "The chill bundles"), you should define your configuration inside the class :code:`ChillXXXXBundleExtension`, using the "prependConfig" feature:
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
namespace Chill\PersonBundle\DependencyInjection;
|
||||
|
||||
use Symfony\Component\DependencyInjection\ContainerBuilder;
|
||||
use Symfony\Component\DependencyInjection\Extension\PrependExtensionInterface;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
|
||||
/**
|
||||
* Class ChillPersonExtension
|
||||
* Loads and manages your bundle configuration
|
||||
*
|
||||
* To learn more see {@link http://symfony.com/doc/current/cookbook/bundles/extension.html}
|
||||
* @package Chill\PersonBundle\DependencyInjection
|
||||
*/
|
||||
class ChillPersonExtension extends Extension implements PrependExtensionInterface
|
||||
{
|
||||
public function prepend(ContainerBuilder $container)
|
||||
{
|
||||
$this->prependCruds($container);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param ContainerBuilder $container
|
||||
*/
|
||||
protected function prependCruds(ContainerBuilder $container)
|
||||
{
|
||||
$container->prependExtensionConfig('chill_main', [
|
||||
'apis' => [
|
||||
[
|
||||
'class' => \Chill\PersonBundle\Entity\AccompanyingPeriod\Origin::class,
|
||||
'name' => 'accompanying_period_origin',
|
||||
'base_path' => '/api/1.0/person/accompanying-period/origin',
|
||||
'controller' => \Chill\PersonBundle\Controller\OpeningApiController::class,
|
||||
'base_role' => 'ROLE_USER',
|
||||
'actions' => [
|
||||
'_index' => [
|
||||
'methods' => [
|
||||
Request::METHOD_GET => true,
|
||||
Request::METHOD_HEAD => true
|
||||
],
|
||||
],
|
||||
'_entity' => [
|
||||
'methods' => [
|
||||
Request::METHOD_GET => true,
|
||||
Request::METHOD_HEAD => true
|
||||
]
|
||||
],
|
||||
]
|
||||
]
|
||||
]
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
The :code:`_index` and :code:`_entity` action
|
||||
=============================================
|
||||
|
||||
The :code:`_index` and :code:`_entity` action are default actions:
|
||||
|
||||
* they will call a specific method in the default controller;
|
||||
* they will generate defined routes:
|
||||
|
||||
Index:
|
||||
Name: :code:`chill_api_single_accompanying_period_origin__index`
|
||||
|
||||
Path: :code:`/api/1.0/person/accompanying-period/origin.{_format}`
|
||||
|
||||
Entity:
|
||||
Name: :code:`chill_api_single_accompanying_period_origin__entity`
|
||||
|
||||
Path: :code:`/api/1.0/person/accompanying-period/origin/{id}.{_format}`
|
||||
|
||||
Role
|
||||
====
|
||||
|
||||
By default, the key `base_role` is used to check ACL. Take care of creating the :code:`Voter` required to take that into account.
|
||||
|
||||
For index action, the role will be called with :code:`NULL` as :code:`$subject`. The retrieved entity will be the subject for single queries.
|
||||
|
||||
You can also define a role for each method. In this case, this role is used for the given method, and, if any, the base role is taken into account.
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
# config/packages/chill_main.yaml
|
||||
chill_main:
|
||||
apis:
|
||||
accompanying_period_origin:
|
||||
base_path: '/api/1.0/person/bla/bla'
|
||||
class: 'Chill\PersonBundle\Entity\Blah'
|
||||
name: bla
|
||||
actions:
|
||||
_entity:
|
||||
methods:
|
||||
GET: true
|
||||
HEAD: true
|
||||
roles:
|
||||
GET: MY_ROLE_SEE
|
||||
HEAD: MY ROLE_SEE
|
||||
|
||||
Customize the controller
|
||||
========================
|
||||
|
||||
You can customize the controller by hooking into the default actions. Take care of extending :code:`Chill\MainBundle\CRUD\Controller\ApiController`.
|
||||
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
|
||||
namespace Chill\PersonBundle\Controller;
|
||||
|
||||
use Chill\MainBundle\CRUD\Controller\ApiController;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
|
||||
class OpeningApiController extends ApiController
|
||||
{
|
||||
protected function customizeQuery(string $action, Request $request, $qb): void
|
||||
{
|
||||
$qb->where($qb->expr()->gt('e.noActiveAfter', ':now'))
|
||||
->orWhere($qb->expr()->isNull('e.noActiveAfter'));
|
||||
$qb->setParameter('now', new \DateTime('now'));
|
||||
}
|
||||
}
|
||||
|
||||
And set your controller in configuration:
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
chill_main:
|
||||
apis:
|
||||
accompanying_period_origin:
|
||||
base_path: '/api/1.0/person/accompanying-period/origin'
|
||||
class: 'Chill\PersonBundle\Entity\AccompanyingPeriod\Origin'
|
||||
name: accompanying_period_origin
|
||||
# add a controller
|
||||
controller: 'Chill\PersonBundle\Controller\OpeningApiController'
|
||||
base_role: 'ROLE_USER'
|
||||
actions:
|
||||
_index:
|
||||
methods:
|
||||
GET: true
|
||||
HEAD: true
|
||||
_entity:
|
||||
methods:
|
||||
GET: true
|
||||
HEAD: true
|
||||
|
||||
Create your own actions
|
||||
=======================
|
||||
|
||||
You can add your own actions:
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
chill_main:
|
||||
apis:
|
||||
-
|
||||
class: Chill\PersonBundle\Entity\AccompanyingPeriod
|
||||
name: accompanying_course
|
||||
base_path: /api/1.0/person/accompanying-course
|
||||
controller: Chill\PersonBundle\Controller\AccompanyingCourseApiController
|
||||
actions:
|
||||
# add a custom participation:
|
||||
participation:
|
||||
methods:
|
||||
POST: true
|
||||
DELETE: true
|
||||
GET: false
|
||||
HEAD: false
|
||||
PUT: false
|
||||
roles:
|
||||
POST: CHILL_PERSON_ACCOMPANYING_PERIOD_SEE
|
||||
DELETE: CHILL_PERSON_ACCOMPANYING_PERIOD_SEE
|
||||
GET: null
|
||||
HEAD: null
|
||||
PUT: null
|
||||
single-collection: single
|
||||
|
||||
The key :code:`single-collection` with value :code:`single` will add a :code:`/{id}/ + "action name"` (in this example, :code:`/{id}/participation`) into the path, after the base path. If the value is :code:`collection`, no id will be set, but the action name will be append to the path.
|
||||
|
||||
Then, create the corresponding action into your controller:
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
namespace Chill\PersonBundle\Controller;
|
||||
|
||||
use Chill\MainBundle\CRUD\Controller\ApiController;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
use Chill\PersonBundle\Entity\AccompanyingPeriod;
|
||||
use Symfony\Component\HttpFoundation\Exception\BadRequestException;
|
||||
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
|
||||
use Symfony\Component\Validator\Validator\ValidatorInterface;
|
||||
use Chill\PersonBundle\Privacy\AccompanyingPeriodPrivacyEvent;
|
||||
use Chill\PersonBundle\Entity\Person;
|
||||
|
||||
class AccompanyingCourseApiController extends ApiController
|
||||
{
|
||||
protected EventDispatcherInterface $eventDispatcher;
|
||||
|
||||
protected ValidatorInterface $validator;
|
||||
|
||||
public function __construct(EventDispatcherInterface $eventDispatcher, $validator)
|
||||
{
|
||||
$this->eventDispatcher = $eventDispatcher;
|
||||
$this->validator = $validator;
|
||||
}
|
||||
|
||||
public function participationApi($id, Request $request, $_format)
|
||||
{
|
||||
/** @var AccompanyingPeriod $accompanyingPeriod */
|
||||
$accompanyingPeriod = $this->getEntity('participation', $id, $request);
|
||||
$person = $this->getSerializer()
|
||||
->deserialize($request->getContent(), Person::class, $_format, []);
|
||||
|
||||
if (NULL === $person) {
|
||||
throw new BadRequestException('person id not found');
|
||||
}
|
||||
|
||||
$this->onPostCheckACL('participation', $request, $accompanyingPeriod, $_format);
|
||||
|
||||
switch ($request->getMethod()) {
|
||||
case Request::METHOD_POST:
|
||||
$participation = $accompanyingPeriod->addPerson($person);
|
||||
break;
|
||||
case Request::METHOD_DELETE:
|
||||
$participation = $accompanyingPeriod->removePerson($person);
|
||||
break;
|
||||
default:
|
||||
throw new BadRequestException("This method is not supported");
|
||||
}
|
||||
|
||||
$errors = $this->validator->validate($accompanyingPeriod);
|
||||
|
||||
if ($errors->count() > 0) {
|
||||
// only format accepted
|
||||
return $this->json($errors);
|
||||
}
|
||||
|
||||
$this->getDoctrine()->getManager()->flush();
|
||||
|
||||
return $this->json($participation);
|
||||
}
|
||||
}
|
||||
|
||||
Serialization for collection
|
||||
============================
|
||||
|
||||
A specific model has been defined for returning collection:
|
||||
|
||||
.. code-block:: json
|
||||
|
||||
{
|
||||
"count": 49,
|
||||
"results": [
|
||||
],
|
||||
"pagination": {
|
||||
"more": true,
|
||||
"next": "/api/1.0/search.json&q=xxxx......&page=2",
|
||||
"previous": null,
|
||||
"first": 0,
|
||||
"items_per_page": 1
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
This can be achieved quickly by assembling results into a :code:`Chill\MainBundle\Serializer\Model\Collection`. The pagination information is given by using :code:`Paginator` (see :ref:`Pagination <pagination-ref>`).
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
|
||||
use Chill\MainBundle\Pagination\PaginatorInterface;
|
||||
|
||||
class MyController extends AbstractController
|
||||
{
|
||||
|
||||
protected function serializeCollection(PaginatorInterface $paginator, $entities): Response
|
||||
{
|
||||
$model = new Collection($entities, $paginator);
|
||||
|
||||
return $this->json($model, Response::HTTP_OK, [], $context);
|
||||
}
|
||||
}
|
||||
|
||||
.. _api_full_configuration:
|
||||
|
||||
Full configuration example
|
||||
==========================
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
apis:
|
||||
-
|
||||
class: Chill\PersonBundle\Entity\AccompanyingPeriod
|
||||
name: accompanying_course
|
||||
base_path: /api/1.0/person/accompanying-course
|
||||
controller: Chill\PersonBundle\Controller\AccompanyingCourseApiController
|
||||
actions:
|
||||
_entity:
|
||||
roles:
|
||||
GET: CHILL_PERSON_ACCOMPANYING_PERIOD_SEE
|
||||
HEAD: null
|
||||
POST: null
|
||||
DELETE: null
|
||||
PUT: null
|
||||
controller_action: null
|
||||
path: null
|
||||
single-collection: single
|
||||
methods:
|
||||
GET: true
|
||||
HEAD: true
|
||||
POST: false
|
||||
DELETE: false
|
||||
PUT: false
|
||||
participation:
|
||||
methods:
|
||||
POST: true
|
||||
DELETE: true
|
||||
GET: false
|
||||
HEAD: false
|
||||
PUT: false
|
||||
roles:
|
||||
POST: CHILL_PERSON_ACCOMPANYING_PERIOD_SEE
|
||||
DELETE: CHILL_PERSON_ACCOMPANYING_PERIOD_SEE
|
||||
GET: null
|
||||
HEAD: null
|
||||
PUT: null
|
||||
controller_action: null
|
||||
# the requirements for the route. Will be set to `[ 'id' => '\d+' ]` if left empty.
|
||||
requirements: []
|
||||
path: null
|
||||
single-collection: single
|
||||
base_role: null
|
||||
|
||||
|
@@ -16,6 +16,7 @@ As Chill rely on the `symfony <http://symfony.com>`_ framework, reading the fram
|
||||
|
||||
Instructions to create a new bundle <create-a-new-bundle.rst>
|
||||
CRUD (Create - Update - Delete) for one entity <crud.rst>
|
||||
Helpers for building a REST API <api.rst>
|
||||
Routing <routing.rst>
|
||||
Menus <menus.rst>
|
||||
Forms <forms.rst>
|
||||
|
@@ -7,6 +7,8 @@
|
||||
Free Documentation License".
|
||||
|
||||
|
||||
.. _pagination-ref:
|
||||
|
||||
Pagination
|
||||
##########
|
||||
|
||||
@@ -15,7 +17,7 @@ The Bundle :code:`Chill\MainBundle` provides a **Pagination** api which allow yo
|
||||
A simple example
|
||||
****************
|
||||
|
||||
In the controller, get the :class:`Chill\Main\Pagination\PaginatorFactory` from the `Container` and use this :code:`PaginatorFactory` to create a :code:`Paginator` instance.
|
||||
In the controller, get the :code:`Chill\Main\Pagination\PaginatorFactory` from the `Container` and use this :code:`PaginatorFactory` to create a :code:`Paginator` instance.
|
||||
|
||||
|
||||
.. literalinclude:: pagination/example.php
|
||||
|
@@ -18,11 +18,11 @@
|
||||
<testsuite name="MainBundle">
|
||||
<directory suffix="Test.php">src/Bundle/ChillMainBundle/Tests/</directory>
|
||||
</testsuite>
|
||||
|
||||
<!--
|
||||
<testsuite name="PersonBundle">
|
||||
<directory suffix="Test.php">src/Bundle/ChillPersonBundle/Tests/</directory>
|
||||
</testsuite>
|
||||
|
||||
-->
|
||||
</testsuites>
|
||||
|
||||
<listeners>
|
||||
|
@@ -0,0 +1,77 @@
|
||||
<?php
|
||||
/*
|
||||
* Copyright (C) 2018 Champs Libres Cooperative <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\MainBundle\CRUD\CompilerPass;
|
||||
|
||||
use Symfony\Component\DependencyInjection\ContainerBuilder;
|
||||
use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
|
||||
use Symfony\Component\DependencyInjection\Reference;
|
||||
use Chill\MainBundle\Routing\MenuComposer;
|
||||
use Symfony\Component\DependencyInjection\Definition;
|
||||
|
||||
/**
|
||||
*
|
||||
*
|
||||
*/
|
||||
class CRUDControllerCompilerPass implements CompilerPassInterface
|
||||
{
|
||||
public function process(ContainerBuilder $container)
|
||||
{
|
||||
$crudConfig = $container->getParameter('chill_main_crud_route_loader_config');
|
||||
$apiConfig = $container->getParameter('chill_main_api_route_loader_config');
|
||||
|
||||
foreach ($crudConfig as $crudEntry) {
|
||||
$this->configureCrudController($container, $crudEntry, 'crud');
|
||||
}
|
||||
|
||||
foreach ($apiConfig as $crudEntry) {
|
||||
$this->configureCrudController($container, $crudEntry, 'api');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a controller for each definition, and add a methodCall to inject crud configuration to controller
|
||||
*/
|
||||
private function configureCrudController(ContainerBuilder $container, array $crudEntry, string $apiOrCrud): void
|
||||
{
|
||||
$controllerClass = $crudEntry['controller'];
|
||||
|
||||
$controllerServiceName = 'cs'.$apiOrCrud.'_'.$crudEntry['name'].'_controller';
|
||||
|
||||
if ($container->hasDefinition($controllerClass)) {
|
||||
$controller = $container->getDefinition($controllerClass);
|
||||
$container->removeDefinition($controllerClass);
|
||||
$alreadyDefined = true;
|
||||
} else {
|
||||
$controller = new Definition($controllerClass);
|
||||
$alreadyDefined = false;
|
||||
}
|
||||
|
||||
$controller->addTag('controller.service_arguments');
|
||||
if (FALSE === $alreadyDefined) {
|
||||
$controller->setAutoconfigured(true);
|
||||
$controller->setPublic(true);
|
||||
}
|
||||
|
||||
$param = 'chill_main_'.$apiOrCrud.'_config_'.$crudEntry['name'];
|
||||
$container->setParameter($param, $crudEntry);
|
||||
$controller->addMethodCall('setCrudConfig', ['%'.$param.'%']);
|
||||
|
||||
$container->setDefinition($controllerServiceName, $controller);
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,225 @@
|
||||
<?php
|
||||
|
||||
namespace Chill\MainBundle\CRUD\Controller;
|
||||
|
||||
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
use Symfony\Component\Routing\Annotation\Route;
|
||||
use Chill\MainBundle\Pagination\PaginatorFactory;
|
||||
use Chill\MainBundle\Pagination\PaginatorInterface;
|
||||
|
||||
class AbstractCRUDController extends AbstractController
|
||||
{
|
||||
/**
|
||||
* The crud configuration
|
||||
*
|
||||
* This configuration si defined by `chill_main['crud']` or `chill_main['apis']`
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected array $crudConfig = [];
|
||||
|
||||
/**
|
||||
* get the instance of the entity with the given id
|
||||
*
|
||||
* @param string $id
|
||||
* @return object
|
||||
*/
|
||||
protected function getEntity($action, $id, Request $request): ?object
|
||||
{
|
||||
return $this->getDoctrine()
|
||||
->getRepository($this->getEntityClass())
|
||||
->find($id);
|
||||
}
|
||||
|
||||
/**
|
||||
* Count the number of entities
|
||||
*
|
||||
* By default, count all entities. You can customize the query by
|
||||
* using the method `customizeQuery`.
|
||||
*
|
||||
* @param string $action
|
||||
* @param Request $request
|
||||
* @return int
|
||||
*/
|
||||
protected function countEntities(string $action, Request $request, $_format): int
|
||||
{
|
||||
return $this->buildQueryEntities($action, $request)
|
||||
->select('COUNT(e)')
|
||||
->getQuery()
|
||||
->getSingleScalarResult()
|
||||
;
|
||||
}
|
||||
|
||||
/**
|
||||
* Query the entity.
|
||||
*
|
||||
* By default, get all entities. You can customize the query by using the
|
||||
* method `customizeQuery`.
|
||||
*
|
||||
* The method `orderEntity` is called internally to order entities.
|
||||
*
|
||||
* It returns, by default, a query builder.
|
||||
*
|
||||
*/
|
||||
protected function queryEntities(string $action, Request $request, string $_format, PaginatorInterface $paginator)
|
||||
{
|
||||
$query = $this->buildQueryEntities($action, $request)
|
||||
->setFirstResult($paginator->getCurrentPage()->getFirstItemNumber())
|
||||
->setMaxResults($paginator->getItemsPerPage());
|
||||
|
||||
// allow to order queries and return the new query
|
||||
return $this->orderQuery($action, $query, $request, $paginator, $_format);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add ordering fields in the query build by self::queryEntities
|
||||
*
|
||||
*/
|
||||
protected function orderQuery(string $action, $query, Request $request, PaginatorInterface $paginator, $_format)
|
||||
{
|
||||
return $query;
|
||||
}
|
||||
|
||||
/**
|
||||
* Build the base query for listing all entities.
|
||||
*
|
||||
* This method is used internally by `countEntities` `queryEntities`
|
||||
*
|
||||
* This base query does not contains any `WHERE` or `SELECT` clauses. You
|
||||
* can add some by using the method `customizeQuery`.
|
||||
*
|
||||
* The alias for the entity is "e".
|
||||
*
|
||||
* @param string $action
|
||||
* @param Request $request
|
||||
* @return QueryBuilder
|
||||
*/
|
||||
protected function buildQueryEntities(string $action, Request $request)
|
||||
{
|
||||
$qb = $this->getDoctrine()->getManager()
|
||||
->createQueryBuilder()
|
||||
->select('e')
|
||||
->from($this->getEntityClass(), 'e')
|
||||
;
|
||||
|
||||
$this->customizeQuery($action, $request, $qb);
|
||||
|
||||
return $qb;
|
||||
}
|
||||
|
||||
protected function customizeQuery(string $action, Request $request, $query): void {}
|
||||
|
||||
/**
|
||||
* Get the result of the query
|
||||
*/
|
||||
protected function getQueryResult(string $action, Request $request, string $_format, int $totalItems, PaginatorInterface $paginator, $query)
|
||||
{
|
||||
return $query->getQuery()->getResult();
|
||||
}
|
||||
|
||||
protected function onPreIndex(string $action, Request $request, string $_format): ?Response
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* method used by indexAction
|
||||
*/
|
||||
protected function onPreIndexBuildQuery(string $action, Request $request, string $_format, int $totalItems, PaginatorInterface $paginator): ?Response
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* method used by indexAction
|
||||
*/
|
||||
protected function onPostIndexBuildQuery(string $action, Request $request, string $_format, int $totalItems, PaginatorInterface $paginator, $query): ?Response
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* method used by indexAction
|
||||
*/
|
||||
protected function onPostIndexFetchQuery(string $action, Request $request, string $_format, int $totalItems, PaginatorInterface $paginator, $entities): ?Response
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get the complete FQDN of the class
|
||||
*
|
||||
* @return string the complete fqdn of the class
|
||||
*/
|
||||
protected function getEntityClass(): string
|
||||
{
|
||||
return $this->crudConfig['class'];
|
||||
}
|
||||
|
||||
/**
|
||||
* called on post fetch entity
|
||||
*/
|
||||
protected function onPostFetchEntity(string $action, Request $request, $entity, $_format): ?Response
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Called on post check ACL
|
||||
*/
|
||||
protected function onPostCheckACL(string $action, Request $request, string $_format, $entity): ?Response
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* check the acl. Called by every action.
|
||||
*
|
||||
* By default, check the role given by `getRoleFor` for the value given in
|
||||
* $entity.
|
||||
*
|
||||
* Throw an \Symfony\Component\Security\Core\Exception\AccessDeniedHttpException
|
||||
* if not accessible.
|
||||
*
|
||||
* @throws \Symfony\Component\Security\Core\Exception\AccessDeniedHttpException
|
||||
*/
|
||||
protected function checkACL(string $action, Request $request, string $_format, $entity = null)
|
||||
{
|
||||
$this->denyAccessUnlessGranted($this->getRoleFor($action, $request, $entity, $_format), $entity);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @return string the crud name
|
||||
*/
|
||||
protected function getCrudName(): string
|
||||
{
|
||||
return $this->crudConfig['name'];
|
||||
}
|
||||
|
||||
protected function getActionConfig(string $action)
|
||||
{
|
||||
return $this->crudConfig['actions'][$action];
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the crud configuration
|
||||
*
|
||||
* Used by the container to inject configuration for this crud.
|
||||
*/
|
||||
public function setCrudConfig(array $config): void
|
||||
{
|
||||
$this->crudConfig = $config;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return PaginatorFactory
|
||||
*/
|
||||
protected function getPaginatorFactory(): PaginatorFactory
|
||||
{
|
||||
return $this->container->get('chill_main.paginator_factory');
|
||||
}
|
||||
}
|
220
src/Bundle/ChillMainBundle/CRUD/Controller/ApiController.php
Normal file
220
src/Bundle/ChillMainBundle/CRUD/Controller/ApiController.php
Normal file
@@ -0,0 +1,220 @@
|
||||
<?php
|
||||
|
||||
namespace Chill\MainBundle\CRUD\Controller;
|
||||
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
use Symfony\Component\Routing\Annotation\Route;
|
||||
use Symfony\Component\Serializer\SerializerInterface;
|
||||
use Chill\MainBundle\Serializer\Model\Collection;
|
||||
use Chill\MainBundle\Pagination\PaginatorInterface;
|
||||
|
||||
class ApiController extends AbstractCRUDController
|
||||
{
|
||||
/**
|
||||
* The view action.
|
||||
*
|
||||
* Some steps may be overriden during this process of rendering:
|
||||
*
|
||||
* This method:
|
||||
*
|
||||
* 1. fetch the entity, using `getEntity`
|
||||
* 2. launch `onPostFetchEntity`. If postfetch is an instance of Response,
|
||||
* this response is returned.
|
||||
* 2. throw an HttpNotFoundException if entity is null
|
||||
* 3. check ACL using `checkACL` ;
|
||||
* 4. launch `onPostCheckACL`. If the result is an instance of Response,
|
||||
* this response is returned ;
|
||||
* 5. Serialize the entity and return the result. The serialization context is given by `getSerializationContext`
|
||||
*
|
||||
*/
|
||||
protected function entityGet(string $action, Request $request, $id, $_format = 'html'): Response
|
||||
{
|
||||
$entity = $this->getEntity($action, $id, $request, $_format);
|
||||
|
||||
$postFetch = $this->onPostFetchEntity($action, $request, $entity, $_format);
|
||||
|
||||
if ($postFetch instanceof Response) {
|
||||
return $postFetch;
|
||||
}
|
||||
|
||||
if (NULL === $entity) {
|
||||
throw $this->createNotFoundException(sprintf("The %s with id %s "
|
||||
. "is not found", $this->getCrudName(), $id));
|
||||
}
|
||||
|
||||
$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;
|
||||
}
|
||||
|
||||
$response = $this->onBeforeSerialize($action, $request, $_format, $entity);
|
||||
if ($response instanceof Response) {
|
||||
return $response;
|
||||
}
|
||||
|
||||
if ($_format === 'json') {
|
||||
$context = $this->getContextForSerialization($action, $request, $_format, $entity);
|
||||
|
||||
return $this->json($entity, Response::HTTP_OK, [], $context);
|
||||
} else {
|
||||
throw new \Symfony\Component\HttpFoundation\Exception\BadRequestException("This format is not implemented");
|
||||
}
|
||||
}
|
||||
|
||||
public function onBeforeSerialize(string $action, Request $request, $_format, $entity): ?Response
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Base method for handling api action
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function entityApi(Request $request, $id, $_format): Response
|
||||
{
|
||||
switch ($request->getMethod()) {
|
||||
case Request::METHOD_GET:
|
||||
case REQUEST::METHOD_HEAD:
|
||||
return $this->entityGet('_entity', $request, $id, $_format);
|
||||
default:
|
||||
throw new \Symfony\Component\HttpFoundation\Exception\BadRequestException("This method is not implemented");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Base action for indexing entities
|
||||
*/
|
||||
public function indexApi(Request $request, string $_format)
|
||||
{
|
||||
switch ($request->getMethod()) {
|
||||
case Request::METHOD_GET:
|
||||
case REQUEST::METHOD_HEAD:
|
||||
return $this->indexApiAction('_index', $request, $_format);
|
||||
default:
|
||||
throw $this->createNotFoundException("This method is not supported");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Build an index page.
|
||||
*
|
||||
* Some steps may be overriden during this process of rendering.
|
||||
*
|
||||
* This method:
|
||||
*
|
||||
* 1. Launch `onPreIndex`
|
||||
* x. check acl. If it does return a response instance, return it
|
||||
* x. launch `onPostCheckACL`. If it does return a response instance, return it
|
||||
* 1. count the items, using `countEntities`
|
||||
* 2. build a paginator element from the the number of entities ;
|
||||
* 3. Launch `onPreIndexQuery`. If it does return a response instance, return it
|
||||
* 3. build a query, using `queryEntities`
|
||||
* x. fetch the results, using `getQueryResult`
|
||||
* x. Launch `onPostIndexFetchQuery`. If it does return a response instance, return it
|
||||
* 4. Serialize the entities in a Collection, using `SerializeCollection`
|
||||
*
|
||||
* @param string $action
|
||||
* @param Request $request
|
||||
* @return type
|
||||
*/
|
||||
protected function indexApiAction($action, Request $request, $_format)
|
||||
{
|
||||
$this->onPreIndex($action, $request, $_format);
|
||||
|
||||
$response = $this->checkACL($action, $request, $_format);
|
||||
if ($response instanceof Response) {
|
||||
return $response;
|
||||
}
|
||||
|
||||
if (!isset($entity)) {
|
||||
$entity = '';
|
||||
}
|
||||
|
||||
$response = $this->onPostCheckACL($action, $request, $_format, $entity);
|
||||
if ($response instanceof Response) {
|
||||
return $response;
|
||||
}
|
||||
|
||||
$totalItems = $this->countEntities($action, $request, $_format);
|
||||
$paginator = $this->getPaginatorFactory()->create($totalItems);
|
||||
|
||||
$response = $this->onPreIndexBuildQuery($action, $request, $_format, $totalItems,
|
||||
$paginator);
|
||||
|
||||
if ($response instanceof Response) {
|
||||
return $response;
|
||||
}
|
||||
|
||||
$query = $this->queryEntities($action, $request, $_format, $paginator);
|
||||
|
||||
$response = $this->onPostIndexBuildQuery($action, $request, $_format, $totalItems,
|
||||
$paginator, $query);
|
||||
|
||||
if ($response instanceof Response) {
|
||||
return $response;
|
||||
}
|
||||
|
||||
$entities = $this->getQueryResult($action, $request, $_format, $totalItems, $paginator, $query);
|
||||
|
||||
$response = $this->onPostIndexFetchQuery($action, $request, $_format, $totalItems,
|
||||
$paginator, $entities);
|
||||
|
||||
if ($response instanceof Response) {
|
||||
return $response;
|
||||
}
|
||||
|
||||
return $this->serializeCollection($action, $request, $_format, $paginator, $entities);
|
||||
}
|
||||
|
||||
/**
|
||||
* Serialize collections
|
||||
*
|
||||
*/
|
||||
protected function serializeCollection(string $action, Request $request, string $_format, PaginatorInterface $paginator, $entities): Response
|
||||
{
|
||||
$model = new Collection($entities, $paginator);
|
||||
|
||||
$context = $this->getContextForSerialization($action, $request, $_format, $entities);
|
||||
|
||||
return $this->json($model, Response::HTTP_OK, [], $context);
|
||||
}
|
||||
|
||||
|
||||
protected function getContextForSerialization(string $action, Request $request, string $_format, $entity): array
|
||||
{
|
||||
return [];
|
||||
}
|
||||
|
||||
/**
|
||||
* get the role given from the config.
|
||||
*/
|
||||
protected function getRoleFor(string $action, Request $request, $entity, $_format): string
|
||||
{
|
||||
$actionConfig = $this->getActionConfig($action);
|
||||
|
||||
if (NULL !== $actionConfig['roles'][$request->getMethod()]) {
|
||||
return $actionConfig['roles'][$request->getMethod()];
|
||||
}
|
||||
|
||||
if ($this->crudConfig['base_role']) {
|
||||
return $this->crudConfig['base_role'];
|
||||
}
|
||||
|
||||
throw new \RuntimeException(sprintf("the config does not have any role for the ".
|
||||
"method %s nor a global role for the whole action. Add those to your ".
|
||||
"configuration or override the required method", $request->getMethod()));
|
||||
|
||||
}
|
||||
|
||||
protected function getSerializer(): SerializerInterface
|
||||
{
|
||||
return $this->get('serializer');
|
||||
}
|
||||
}
|
@@ -34,6 +34,7 @@ use Chill\MainBundle\CRUD\Form\CRUDDeleteEntityForm;
|
||||
use Chill\MainBundle\Pagination\PaginatorFactory;
|
||||
use Chill\MainBundle\Pagination\PaginatorInterface;
|
||||
use Chill\MainBundle\Security\Authorization\AuthorizationHelper;
|
||||
use Symfony\Component\Serializer\SerializerInterface;
|
||||
|
||||
/**
|
||||
* Class CRUDController
|
||||
@@ -484,7 +485,7 @@ class CRUDController extends AbstractController
|
||||
* @param mixed $id
|
||||
* @return Response
|
||||
*/
|
||||
protected function viewAction(string $action, Request $request, $id)
|
||||
protected function viewAction(string $action, Request $request, $id, $_format = 'html'): Response
|
||||
{
|
||||
$entity = $this->getEntity($action, $id, $request);
|
||||
|
||||
@@ -496,7 +497,7 @@ class CRUDController extends AbstractController
|
||||
|
||||
if (NULL === $entity) {
|
||||
throw $this->createNotFoundException(sprintf("The %s with id %s "
|
||||
. "is not found"), $this->getCrudName(), $id);
|
||||
. "is not found", $this->getCrudName(), $id));
|
||||
}
|
||||
|
||||
$response = $this->checkACL($action, $entity);
|
||||
@@ -508,17 +509,36 @@ class CRUDController extends AbstractController
|
||||
if ($response instanceof Response) {
|
||||
return $response;
|
||||
}
|
||||
|
||||
$defaultTemplateParameters = [
|
||||
'entity' => $entity,
|
||||
'crud_name' => $this->getCrudName()
|
||||
];
|
||||
|
||||
return $this->render(
|
||||
$this->getTemplateFor($action, $entity, $request),
|
||||
$this->generateTemplateParameter($action, $entity, $request, $defaultTemplateParameters)
|
||||
|
||||
if ($_format === 'html') {
|
||||
$defaultTemplateParameters = [
|
||||
'entity' => $entity,
|
||||
'crud_name' => $this->getCrudName()
|
||||
];
|
||||
|
||||
return $this->render(
|
||||
$this->getTemplateFor($action, $entity, $request),
|
||||
$this->generateTemplateParameter($action, $entity, $request, $defaultTemplateParameters)
|
||||
);
|
||||
} elseif ($_format === 'json') {
|
||||
$context = $this->getContextForSerialization($action, $request, $entity, $_format);
|
||||
|
||||
return $this->json($entity, Response::HTTP_OK, [], $context);
|
||||
} else {
|
||||
throw new \Symfony\Component\HttpFoundation\Exception\BadRequestException("This format is not implemented");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the context for the serialization
|
||||
*/
|
||||
public function getContextForSerialization(string $action, Request $request, $entity, string $_format): array
|
||||
{
|
||||
return [];
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* The edit action.
|
||||
@@ -799,7 +819,7 @@ class CRUDController extends AbstractController
|
||||
*/
|
||||
protected function getRoleFor($action)
|
||||
{
|
||||
if (NULL !== ($this->getActionConfig($action)['role'])) {
|
||||
if (\array_key_exists('role', $this->getActionConfig($action))) {
|
||||
return $this->getActionConfig($action)['role'];
|
||||
}
|
||||
|
||||
@@ -1181,6 +1201,7 @@ class CRUDController extends AbstractController
|
||||
AuthorizationHelper::class => AuthorizationHelper::class,
|
||||
EventDispatcherInterface::class => EventDispatcherInterface::class,
|
||||
Resolver::class => Resolver::class,
|
||||
SerializerInterface::class => SerializerInterface::class,
|
||||
]
|
||||
);
|
||||
}
|
||||
|
@@ -23,6 +23,9 @@ namespace Chill\MainBundle\CRUD\Routing;
|
||||
use Symfony\Component\Config\Loader\Loader;
|
||||
use Symfony\Component\Routing\Route;
|
||||
use Symfony\Component\Routing\RouteCollection;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
use Chill\MainBundle\CRUD\Controller\ApiController;
|
||||
use Chill\MainBundle\CRUD\Controller\CRUDController;
|
||||
|
||||
/**
|
||||
* Class CRUDRoutesLoader
|
||||
@@ -32,24 +35,34 @@ use Symfony\Component\Routing\RouteCollection;
|
||||
*/
|
||||
class CRUDRoutesLoader extends Loader
|
||||
{
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
protected $config = [];
|
||||
protected array $crudConfig = [];
|
||||
|
||||
protected array $apiCrudConfig = [];
|
||||
|
||||
/**
|
||||
* @var bool
|
||||
*/
|
||||
private $isLoaded = false;
|
||||
|
||||
private const ALL_SINGLE_METHODS = [
|
||||
Request::METHOD_GET,
|
||||
Request::METHOD_POST,
|
||||
Request::METHOD_PUT,
|
||||
Request::METHOD_DELETE
|
||||
];
|
||||
|
||||
private const ALL_INDEX_METHODS = [ Request::METHOD_GET, Request::METHOD_HEAD ];
|
||||
|
||||
/**
|
||||
* CRUDRoutesLoader constructor.
|
||||
*
|
||||
* @param $config
|
||||
* @param $crudConfig the config from cruds
|
||||
* @param $apicrudConfig the config from api_crud
|
||||
*/
|
||||
public function __construct($config)
|
||||
public function __construct(array $crudConfig, array $apiConfig)
|
||||
{
|
||||
$this->config = $config;
|
||||
$this->crudConfig = $crudConfig;
|
||||
$this->apiConfig = $apiConfig;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -63,53 +76,161 @@ class CRUDRoutesLoader extends Loader
|
||||
}
|
||||
|
||||
/**
|
||||
* @return RouteCollection
|
||||
* Load routes for CRUD and CRUD Api
|
||||
*/
|
||||
public function load($resource, $type = null)
|
||||
public function load($resource, $type = null): RouteCollection
|
||||
{
|
||||
|
||||
if (true === $this->isLoaded) {
|
||||
throw new \RuntimeException('Do not add the "CRUD" loader twice');
|
||||
}
|
||||
|
||||
|
||||
$collection = new RouteCollection();
|
||||
|
||||
foreach ($this->config as $config) {
|
||||
$collection->addCollection($this->loadConfig($config));
|
||||
foreach ($this->crudConfig as $crudConfig) {
|
||||
$collection->addCollection($this->loadCrudConfig($crudConfig));
|
||||
}
|
||||
|
||||
foreach ($this->apiConfig as $crudConfig) {
|
||||
$collection->addCollection($this->loadApi($crudConfig));
|
||||
}
|
||||
|
||||
return $collection;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $config
|
||||
* Load routes for CRUD (without api)
|
||||
*
|
||||
* @param $crudConfig
|
||||
* @return RouteCollection
|
||||
*/
|
||||
protected function loadConfig($config): RouteCollection
|
||||
protected function loadCrudConfig($crudConfig): RouteCollection
|
||||
{
|
||||
$collection = new RouteCollection();
|
||||
foreach ($config['actions'] as $name => $action) {
|
||||
$controller ='cscrud_'.$crudConfig['name'].'_controller';
|
||||
|
||||
foreach ($crudConfig['actions'] as $name => $action) {
|
||||
// defaults (controller name)
|
||||
$defaults = [
|
||||
'_controller' => 'cscrud_'.$config['name'].'_controller'.':'.($action['controller_action'] ?? $name)
|
||||
'_controller' => $controller.':'.($action['controller_action'] ?? $name)
|
||||
];
|
||||
|
||||
if ($name === 'index') {
|
||||
$path = "{_locale}".$config['base_path'];
|
||||
$path = "{_locale}".$crudConfig['base_path'];
|
||||
$route = new Route($path, $defaults);
|
||||
} elseif ($name === 'new') {
|
||||
$path = "{_locale}".$config['base_path'].'/'.$name;
|
||||
$path = "{_locale}".$crudConfig['base_path'].'/'.$name;
|
||||
$route = new Route($path, $defaults);
|
||||
} else {
|
||||
$path = "{_locale}".$config['base_path'].($action['path'] ?? '/{id}/'.$name);
|
||||
$path = "{_locale}".$crudConfig['base_path'].($action['path'] ?? '/{id}/'.$name);
|
||||
$requirements = $action['requirements'] ?? [
|
||||
'{id}' => '\d+'
|
||||
];
|
||||
$route = new Route($path, $defaults, $requirements);
|
||||
}
|
||||
|
||||
$collection->add('chill_crud_'.$config['name'].'_'.$name, $route);
|
||||
$collection->add('chill_crud_'.$crudConfig['name'].'_'.$name, $route);
|
||||
}
|
||||
|
||||
return $collection;
|
||||
}
|
||||
|
||||
/**
|
||||
* Load routes for api single
|
||||
*
|
||||
* @param $crudConfig
|
||||
* @return RouteCollection
|
||||
*/
|
||||
protected function loadApi(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 === '_entity' ? 'single' : NULL;
|
||||
if ('collection' === $singleCollection) {
|
||||
// continue;
|
||||
}
|
||||
|
||||
// compute default action
|
||||
switch ($name) {
|
||||
case '_entity':
|
||||
$controllerAction = 'entityApi';
|
||||
break;
|
||||
case '_index':
|
||||
$controllerAction = 'indexApi';
|
||||
break;
|
||||
default:
|
||||
$controllerAction = $name.'Api';
|
||||
break;
|
||||
}
|
||||
|
||||
$defaults = [
|
||||
'_controller' => $controller.':'.($action['controller_action'] ?? $controllerAction)
|
||||
];
|
||||
|
||||
// path are rewritten
|
||||
// if name === 'default', we rewrite it to nothing :-)
|
||||
$localName = \in_array($name, [ '_entity', '_index' ]) ? '' : '/'.$name;
|
||||
if ('collection' === $action['single-collection'] || '_index' === $name) {
|
||||
$localPath = $action['path'] ?? $localName.'.{_format}';
|
||||
} else {
|
||||
$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);
|
||||
|
||||
$collection->add('chill_api_single_'.$crudConfig['name'].'_'.$name, $route);
|
||||
}
|
||||
|
||||
return $collection;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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) {
|
||||
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);
|
||||
|
||||
$collection->add('chill_api_single_'.$crudConfig['name'].'_'.$name, $route);
|
||||
}
|
||||
|
||||
return $collection;
|
||||
}
|
||||
}
|
||||
|
@@ -14,6 +14,7 @@ use Chill\MainBundle\DependencyInjection\CompilerPass\NotificationCounterCompile
|
||||
use Chill\MainBundle\DependencyInjection\CompilerPass\MenuCompilerPass;
|
||||
use Chill\MainBundle\DependencyInjection\CompilerPass\ACLFlagsCompilerPass;
|
||||
use Chill\MainBundle\DependencyInjection\CompilerPass\GroupingCenterCompilerPass;
|
||||
use Chill\MainBundle\CRUD\CompilerPass\CRUDControllerCompilerPass;
|
||||
use Chill\MainBundle\Templating\Entity\CompilerPass as RenderEntityCompilerPass;
|
||||
|
||||
|
||||
@@ -33,5 +34,6 @@ class ChillMainBundle extends Bundle
|
||||
$container->addCompilerPass(new ACLFlagsCompilerPass());
|
||||
$container->addCompilerPass(new GroupingCenterCompilerPass());
|
||||
$container->addCompilerPass(new RenderEntityCompilerPass());
|
||||
$container->addCompilerPass(new CRUDControllerCompilerPass());
|
||||
}
|
||||
}
|
||||
|
63
src/Bundle/ChillMainBundle/Controller/AddressController.php
Normal file
63
src/Bundle/ChillMainBundle/Controller/AddressController.php
Normal file
@@ -0,0 +1,63 @@
|
||||
<?php
|
||||
|
||||
namespace Chill\MainBundle\Controller;
|
||||
|
||||
use Sensio\Bundle\FrameworkExtraBundle\Configuration\ParamConverter;
|
||||
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
use Symfony\Component\HttpFoundation\Exception\BadRequestException;
|
||||
use Symfony\Component\Routing\Annotation\Route;
|
||||
use Chill\MainBundle\Entity\Address;
|
||||
use Chill\MainBundle\Entity\AddressReference;
|
||||
|
||||
/**
|
||||
* Class AddressController
|
||||
*
|
||||
* @package Chill\MainBundle\Controller
|
||||
*/
|
||||
class AddressController extends AbstractController
|
||||
{
|
||||
|
||||
|
||||
/**
|
||||
* Get API Data for showing endpoint
|
||||
*
|
||||
* @Route(
|
||||
* "/{_locale}/main/api/1.0/address/{address_id}/show.{_format}",
|
||||
* name="chill_main_address_api_show"
|
||||
* )
|
||||
* @ParamConverter("address", options={"id": "address_id"})
|
||||
*/
|
||||
public function showAddress(Address $address, $_format): Response
|
||||
{
|
||||
// TODO check ACL ?
|
||||
switch ($_format) {
|
||||
case 'json':
|
||||
return $this->json($address);
|
||||
default:
|
||||
throw new BadRequestException('Unsupported format');
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get API Data for showing endpoint
|
||||
*
|
||||
* @Route(
|
||||
* "/{_locale}/main/api/1.0/address-reference/{address_reference_id}/show.{_format}",
|
||||
* name="chill_main_address_reference_api_show"
|
||||
* )
|
||||
* @ParamConverter("addressReference", options={"id": "address_reference_id"})
|
||||
*/
|
||||
public function showAddressReference(AddressReference $addressReference, $_format): Response
|
||||
{
|
||||
// TODO check ACL ?
|
||||
switch ($_format) {
|
||||
case 'json':
|
||||
return $this->json($addressReference);
|
||||
default:
|
||||
throw new BadRequestException('Unsupported format');
|
||||
}
|
||||
|
||||
}
|
||||
}
|
@@ -0,0 +1,95 @@
|
||||
<?php
|
||||
|
||||
namespace Chill\MainBundle\DataFixtures\ORM;
|
||||
|
||||
use Doctrine\Common\DataFixtures\AbstractFixture;
|
||||
use Doctrine\Common\DataFixtures\OrderedFixtureInterface;
|
||||
use Symfony\Component\DependencyInjection\ContainerAwareInterface;
|
||||
use Symfony\Component\DependencyInjection\ContainerInterface;
|
||||
use Doctrine\Persistence\ObjectManager;
|
||||
use Chill\MainBundle\DataFixtures\ORM\LoadPostalCodes;
|
||||
use Chill\MainBundle\Entity\AddressReference;
|
||||
use Chill\MainBundle\Doctrine\Model\Point;
|
||||
|
||||
/**
|
||||
* Load reference addresses into database
|
||||
*
|
||||
* @author Champs Libres
|
||||
*/
|
||||
class LoadAddressReferences extends AbstractFixture implements ContainerAwareInterface, OrderedFixtureInterface {
|
||||
|
||||
|
||||
protected $faker;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->faker = \Faker\Factory::create('fr_FR');
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @var ContainerInterface
|
||||
*/
|
||||
private $container;
|
||||
|
||||
public function setContainer(ContainerInterface $container = null)
|
||||
{
|
||||
$this->container = $container;
|
||||
}
|
||||
|
||||
public function getOrder() {
|
||||
return 51;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Create a random point
|
||||
*
|
||||
* @return Point
|
||||
*/
|
||||
private function getRandomPoint()
|
||||
{
|
||||
$lonBrussels = 4.35243;
|
||||
$latBrussels = 50.84676;
|
||||
$lon = $lonBrussels + 0.01 * rand(-5, 5);
|
||||
$lat = $latBrussels + 0.01 * rand(-5, 5);
|
||||
return Point::fromLonLat($lon, $lat);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a random reference address
|
||||
*
|
||||
* @return AddressReference
|
||||
*/
|
||||
private function getRandomAddressReference()
|
||||
{
|
||||
$ar= new AddressReference();
|
||||
|
||||
$ar->setRefId($this->faker->numerify('ref-id-######'));
|
||||
$ar->setStreet($this->faker->streetName);
|
||||
$ar->setStreetNumber(rand(0,199));
|
||||
$ar ->setPoint($this->getRandomPoint());
|
||||
$ar->setPostcode($this->getReference(
|
||||
LoadPostalCodes::$refs[array_rand(LoadPostalCodes::$refs)]
|
||||
));
|
||||
|
||||
$ar->setMunicipalityCode($ar->getPostcode()->getCode());
|
||||
|
||||
return $ar
|
||||
;
|
||||
}
|
||||
|
||||
public function load(ObjectManager $manager) {
|
||||
|
||||
echo "loading some reference address... \n";
|
||||
|
||||
for ($i=0; $i<10; $i++) {
|
||||
$ar = $this->getRandomAddressReference();
|
||||
$manager->persist($ar);
|
||||
}
|
||||
|
||||
$manager->flush();
|
||||
}
|
||||
|
||||
|
||||
}
|
@@ -47,11 +47,11 @@ class ChillMainExtension extends Extension implements PrependExtensionInterface,
|
||||
{
|
||||
/**
|
||||
* widget factory
|
||||
*
|
||||
*
|
||||
* @var WidgetFactoryInterface[]
|
||||
*/
|
||||
protected $widgetFactories = array();
|
||||
|
||||
|
||||
/**
|
||||
* @param WidgetFactoryInterface $factory
|
||||
*/
|
||||
@@ -59,7 +59,7 @@ class ChillMainExtension extends Extension implements PrependExtensionInterface,
|
||||
{
|
||||
$this->widgetFactories[] = $factory;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return WidgetFactoryInterface[]
|
||||
*/
|
||||
@@ -67,7 +67,7 @@ class ChillMainExtension extends Extension implements PrependExtensionInterface,
|
||||
{
|
||||
return $this->widgetFactories;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
* @param array $configs
|
||||
@@ -79,31 +79,31 @@ class ChillMainExtension extends Extension implements PrependExtensionInterface,
|
||||
// configuration for main bundle
|
||||
$configuration = $this->getConfiguration($configs, $container);
|
||||
$config = $this->processConfiguration($configuration, $configs);
|
||||
|
||||
|
||||
$container->setParameter('chill_main.installation_name',
|
||||
$config['installation_name']);
|
||||
|
||||
$container->setParameter('chill_main.available_languages',
|
||||
$config['available_languages']);
|
||||
|
||||
$container->setParameter('chill_main.routing.resources',
|
||||
$config['routing']['resources']);
|
||||
|
||||
|
||||
$container->setParameter('chill_main.routing.resources',
|
||||
$config['routing']['resources']);
|
||||
|
||||
$container->setParameter('chill_main.pagination.item_per_page',
|
||||
$config['pagination']['item_per_page']);
|
||||
|
||||
$container->setParameter('chill_main.notifications',
|
||||
|
||||
$container->setParameter('chill_main.notifications',
|
||||
$config['notifications']);
|
||||
|
||||
$container->setParameter('chill_main.redis',
|
||||
|
||||
$container->setParameter('chill_main.redis',
|
||||
$config['redis']);
|
||||
|
||||
$container->setParameter('chill_main.phone_helper',
|
||||
|
||||
$container->setParameter('chill_main.phone_helper',
|
||||
$config['phone_helper'] ?? []);
|
||||
|
||||
|
||||
// add the key 'widget' without the key 'enable'
|
||||
$container->setParameter('chill_main.widgets',
|
||||
isset($config['widgets']['homepage']) ?
|
||||
$container->setParameter('chill_main.widgets',
|
||||
isset($config['widgets']['homepage']) ?
|
||||
array('homepage' => $config['widgets']['homepage']):
|
||||
array()
|
||||
);
|
||||
@@ -131,10 +131,11 @@ class ChillMainExtension extends Extension implements PrependExtensionInterface,
|
||||
$loader->load('services/templating.yaml');
|
||||
$loader->load('services/timeline.yaml');
|
||||
$loader->load('services/search.yaml');
|
||||
|
||||
$this->configureCruds($container, $config['cruds'], $loader);
|
||||
$loader->load('services/serializer.yaml');
|
||||
|
||||
$this->configureCruds($container, $config['cruds'], $config['apis'], $loader);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param array $config
|
||||
* @param ContainerBuilder $container
|
||||
@@ -144,11 +145,11 @@ class ChillMainExtension extends Extension implements PrependExtensionInterface,
|
||||
{
|
||||
return new Configuration($this->widgetFactories, $container);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param ContainerBuilder $container
|
||||
*/
|
||||
public function prepend(ContainerBuilder $container)
|
||||
public function prepend(ContainerBuilder $container)
|
||||
{
|
||||
//add installation_name and date_format to globals
|
||||
$chillMainConfig = $container->getExtensionConfig($this->getAlias());
|
||||
@@ -163,7 +164,7 @@ class ChillMainExtension extends Extension implements PrependExtensionInterface,
|
||||
'form_themes' => array('@ChillMain/Form/fields.html.twig')
|
||||
);
|
||||
$container->prependExtensionConfig('twig', $twigConfig);
|
||||
|
||||
|
||||
//add DQL function to ORM (default entity_manager)
|
||||
$container->prependExtensionConfig('doctrine', array(
|
||||
'orm' => array(
|
||||
@@ -182,78 +183,56 @@ class ChillMainExtension extends Extension implements PrependExtensionInterface,
|
||||
)
|
||||
)
|
||||
));
|
||||
|
||||
|
||||
//add dbal types (default entity_manager)
|
||||
$container->prependExtensionConfig('doctrine', array(
|
||||
'dbal' => [
|
||||
'types' => [
|
||||
'dateinterval' => \Chill\MainBundle\Doctrine\Type\NativeDateIntervalType::class
|
||||
'dateinterval' => [
|
||||
'class' => \Chill\MainBundle\Doctrine\Type\NativeDateIntervalType::class
|
||||
],
|
||||
'point' => [
|
||||
'class' => \Chill\MainBundle\Doctrine\Type\PointType::class
|
||||
]
|
||||
]
|
||||
]
|
||||
));
|
||||
|
||||
|
||||
//add current route to chill main
|
||||
$container->prependExtensionConfig('chill_main', array(
|
||||
'routing' => array(
|
||||
'resources' => array(
|
||||
'@ChillMainBundle/config/routes.yaml'
|
||||
)
|
||||
|
||||
|
||||
)
|
||||
));
|
||||
|
||||
|
||||
//add a channel to log app events
|
||||
$container->prependExtensionConfig('monolog', array(
|
||||
'channels' => array('chill')
|
||||
));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param ContainerBuilder $container
|
||||
* @param array $config the config under 'cruds' key
|
||||
* @return null
|
||||
* Load parameter for configuration and set parameters for api
|
||||
*/
|
||||
protected function configureCruds(ContainerBuilder $container, $config, Loader\YamlFileLoader $loader)
|
||||
protected function configureCruds(
|
||||
ContainerBuilder $container,
|
||||
array $crudConfig,
|
||||
array $apiConfig,
|
||||
Loader\YamlFileLoader $loader
|
||||
): void
|
||||
{
|
||||
if (count($config) === 0) {
|
||||
if (count($crudConfig) === 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
$loader->load('services/crud.yaml');
|
||||
|
||||
$container->setParameter('chill_main_crud_route_loader_config', $config);
|
||||
|
||||
$definition = new Definition();
|
||||
$definition
|
||||
->setClass(\Chill\MainBundle\CRUD\Routing\CRUDRoutesLoader::class)
|
||||
->addArgument('%chill_main_crud_route_loader_config%')
|
||||
;
|
||||
|
||||
$container->setDefinition('chill_main_crud_route_loader', $definition);
|
||||
|
||||
$alreadyExistingNames = [];
|
||||
|
||||
foreach ($config as $crudEntry) {
|
||||
$controller = $crudEntry['controller'];
|
||||
$controllerServiceName = 'cscrud_'.$crudEntry['name'].'_controller';
|
||||
$name = $crudEntry['name'];
|
||||
|
||||
// check for existing crud names
|
||||
if (\in_array($name, $alreadyExistingNames)) {
|
||||
throw new LogicException(sprintf("the name %s is defined twice in CRUD", $name));
|
||||
}
|
||||
|
||||
if (!$container->has($controllerServiceName)) {
|
||||
$controllerDefinition = new Definition($controller);
|
||||
$controllerDefinition->addTag('controller.service_arguments');
|
||||
$controllerDefinition->setAutoconfigured(true);
|
||||
$controllerDefinition->setClass($crudEntry['controller']);
|
||||
$container->setDefinition($controllerServiceName, $controllerDefinition);
|
||||
}
|
||||
|
||||
$container->setParameter('chill_main_crud_config_'.$name, $crudEntry);
|
||||
$container->getDefinition($controllerServiceName)
|
||||
->addMethodCall('setCrudConfig', ['%chill_main_crud_config_'.$name.'%']);
|
||||
}
|
||||
|
||||
$container->setParameter('chill_main_crud_route_loader_config', $crudConfig);
|
||||
$container->setParameter('chill_main_api_route_loader_config', $apiConfig);
|
||||
|
||||
// Note: the controller are loaded inside compiler pass
|
||||
}
|
||||
}
|
||||
|
@@ -8,6 +8,7 @@ use Chill\MainBundle\DependencyInjection\Widget\Factory\WidgetFactoryInterface;
|
||||
use Symfony\Component\Config\Definition\Builder\ArrayNodeDefinition;
|
||||
use Chill\MainBundle\DependencyInjection\Widget\AddWidgetConfigurationTrait;
|
||||
use Symfony\Component\DependencyInjection\ContainerBuilder;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
|
||||
|
||||
/**
|
||||
@@ -140,7 +141,7 @@ class Configuration implements ConfigurationInterface
|
||||
->scalarNode('controller_action')
|
||||
->defaultNull()
|
||||
->info('the method name to call in the route. Will be set to the action name if left empty.')
|
||||
->example("'action'")
|
||||
->example("action")
|
||||
->end()
|
||||
->scalarNode('path')
|
||||
->defaultNull()
|
||||
@@ -168,6 +169,78 @@ class Configuration implements ConfigurationInterface
|
||||
->end()
|
||||
|
||||
->end()
|
||||
|
||||
|
||||
->arrayNode('apis')
|
||||
->defaultValue([])
|
||||
->arrayPrototype()
|
||||
->children()
|
||||
->scalarNode('class')->cannotBeEmpty()->isRequired()->end()
|
||||
->scalarNode('controller')
|
||||
->cannotBeEmpty()
|
||||
->defaultValue(\Chill\MainBundle\CRUD\Controller\ApiController::class)
|
||||
->end()
|
||||
->scalarNode('name')->cannotBeEmpty()->isRequired()->end()
|
||||
->scalarNode('base_path')->cannotBeEmpty()->isRequired()->end()
|
||||
->scalarNode('base_role')->defaultNull()->end()
|
||||
->arrayNode('actions')
|
||||
->useAttributeAsKey('name')
|
||||
->arrayPrototype()
|
||||
->children()
|
||||
->scalarNode('controller_action')
|
||||
->defaultNull()
|
||||
->info('the method name to call in the controller. Will be set to the concatenation '.
|
||||
'of action name + \'Api\' if left empty.')
|
||||
->example("showApi")
|
||||
->end()
|
||||
->scalarNode('path')
|
||||
->defaultNull()
|
||||
->info('the path that will be **appended** after the base path. Do not forget to add ' .
|
||||
'arguments for the method. By default, will set to the action name, including an `{id}` '.
|
||||
'parameter. A suffix of action name will be appended, except if the action name '.
|
||||
'is "_entity".')
|
||||
->example('/{id}/my-action')
|
||||
->end()
|
||||
->arrayNode('requirements')
|
||||
->ignoreExtraKeys(false)
|
||||
->info('the requirements for the route. Will be set to `[ \'id\' => \'\d+\' ]` if left empty.')
|
||||
->end()
|
||||
->enumNode('single-collection')
|
||||
->values(['single', 'collection'])
|
||||
->defaultValue('single')
|
||||
->info('indicates if the returned object is a single element or a collection. '.
|
||||
'If the action name is `_index`, this value will always be considered as '.
|
||||
'`collection`')
|
||||
->end()
|
||||
->arrayNode('methods')
|
||||
->addDefaultsIfNotSet()
|
||||
->info('the allowed methods')
|
||||
->children()
|
||||
->booleanNode(Request::METHOD_GET)->defaultTrue()->end()
|
||||
->booleanNode(Request::METHOD_HEAD)->defaultTrue()->end()
|
||||
->booleanNode(Request::METHOD_POST)->defaultFalse()->end()
|
||||
->booleanNode(Request::METHOD_DELETE)->defaultFalse()->end()
|
||||
->booleanNode(Request::METHOD_PUT)->defaultFalse()->end()
|
||||
->end()
|
||||
->end()
|
||||
->arrayNode('roles')
|
||||
->addDefaultsIfNotSet()
|
||||
->info("The role require for each http method")
|
||||
->children()
|
||||
->scalarNode(Request::METHOD_GET)->defaultNull()->end()
|
||||
->scalarNode(Request::METHOD_HEAD)->defaultNull()->end()
|
||||
->scalarNode(Request::METHOD_POST)->defaultNull()->end()
|
||||
->scalarNode(Request::METHOD_DELETE)->defaultNull()->end()
|
||||
->scalarNode(Request::METHOD_PUT)->defaultNull()->end()
|
||||
->end()
|
||||
->end()
|
||||
->end()
|
||||
->end()
|
||||
->end()
|
||||
->end()
|
||||
->end()
|
||||
|
||||
->end()
|
||||
->end() // end of root/children
|
||||
->end() // end of root
|
||||
;
|
||||
|
103
src/Bundle/ChillMainBundle/Doctrine/Model/Point.php
Normal file
103
src/Bundle/ChillMainBundle/Doctrine/Model/Point.php
Normal file
@@ -0,0 +1,103 @@
|
||||
<?php
|
||||
|
||||
namespace Chill\MainBundle\Doctrine\Model;
|
||||
|
||||
use \JsonSerializable;
|
||||
|
||||
/**
|
||||
* Description of Point
|
||||
*
|
||||
*/
|
||||
class Point implements JsonSerializable {
|
||||
private float $lat;
|
||||
private float $lon;
|
||||
public static string $SRID = '4326';
|
||||
|
||||
private function __construct(float $lon, float $lat)
|
||||
{
|
||||
$this->lat = $lat;
|
||||
$this->lon = $lon;
|
||||
}
|
||||
|
||||
public function toGeoJson(): string
|
||||
{
|
||||
$array = $this->toArrayGeoJson();
|
||||
return \json_encode($array);
|
||||
}
|
||||
|
||||
public function jsonSerialize(): array
|
||||
{
|
||||
return $this->toArrayGeoJson();
|
||||
}
|
||||
|
||||
public function toArrayGeoJson(): array
|
||||
{
|
||||
return [
|
||||
"type" => "Point",
|
||||
"coordinates" => [ $this->lon, $this->lat ]
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function toWKT(): string
|
||||
{
|
||||
return 'SRID='.self::$SRID.';POINT('.$this->lon.' '.$this->lat.')';
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param type $geojson
|
||||
* @return Point
|
||||
*/
|
||||
public static function fromGeoJson(string $geojson): Point
|
||||
{
|
||||
$a = json_decode($geojson);
|
||||
//check if the geojson string is correct
|
||||
if (NULL === $a or !isset($a->type) or !isset($a->coordinates)){
|
||||
throw PointException::badJsonString($geojson);
|
||||
}
|
||||
|
||||
if ($a->type != 'Point'){
|
||||
throw PointException::badGeoType();
|
||||
}
|
||||
|
||||
$lat = $a->coordinates[1];
|
||||
$lon = $a->coordinates[0];
|
||||
|
||||
return Point::fromLonLat($lon, $lat);
|
||||
}
|
||||
|
||||
public static function fromLonLat(float $lon, float $lat): Point
|
||||
{
|
||||
if (($lon > -180 && $lon < 180) && ($lat > -90 && $lat < 90))
|
||||
{
|
||||
return new Point($lon, $lat);
|
||||
} else {
|
||||
throw PointException::badCoordinates($lon, $lat);
|
||||
}
|
||||
}
|
||||
|
||||
public static function fromArrayGeoJson(array $array): Point
|
||||
{
|
||||
if ($array['type'] == 'Point' &&
|
||||
isset($array['coordinates']))
|
||||
{
|
||||
return self::fromLonLat($array['coordinates'][0], $array['coordinates'][1]);
|
||||
}
|
||||
}
|
||||
|
||||
public function getLat(): float
|
||||
{
|
||||
return $this->lat;
|
||||
}
|
||||
|
||||
public function getLon(): float
|
||||
{
|
||||
return $this->lon;
|
||||
}
|
||||
}
|
||||
|
||||
|
27
src/Bundle/ChillMainBundle/Doctrine/Model/PointException.php
Normal file
27
src/Bundle/ChillMainBundle/Doctrine/Model/PointException.php
Normal file
@@ -0,0 +1,27 @@
|
||||
<?php
|
||||
|
||||
namespace Chill\MainBundle\Doctrine\Model;
|
||||
|
||||
use \Exception;
|
||||
|
||||
/**
|
||||
* Description of PointException
|
||||
*
|
||||
*/
|
||||
class PointException extends Exception {
|
||||
|
||||
public static function badCoordinates($lon, $lat): self
|
||||
{
|
||||
return new self("Input coordinates are not valid in the used coordinate system (longitude = $lon , latitude = $lat)");
|
||||
}
|
||||
|
||||
public static function badJsonString($str): self
|
||||
{
|
||||
return new self("The JSON string is not valid: $str");
|
||||
}
|
||||
|
||||
public static function badGeoType(): self
|
||||
{
|
||||
return new self("The geoJSON object type is not valid");
|
||||
}
|
||||
}
|
75
src/Bundle/ChillMainBundle/Doctrine/Type/PointType.php
Normal file
75
src/Bundle/ChillMainBundle/Doctrine/Type/PointType.php
Normal file
@@ -0,0 +1,75 @@
|
||||
<?php
|
||||
|
||||
namespace Chill\MainBundle\Doctrine\Type;
|
||||
|
||||
use Chill\MainBundle\Doctrine\Model\Point;
|
||||
use Doctrine\DBAL\Types\Type;
|
||||
use Doctrine\DBAL\Platforms\AbstractPlatform;
|
||||
use Chill\MainBundle\Doctrine\Model\PointException;
|
||||
|
||||
|
||||
/**
|
||||
* A Type for Doctrine to implement the Geography Point type
|
||||
* implemented by Postgis on postgis+postgresql databases
|
||||
*
|
||||
*/
|
||||
class PointType extends Type {
|
||||
|
||||
const POINT = 'point';
|
||||
|
||||
/**
|
||||
*
|
||||
* @param array $fieldDeclaration
|
||||
* @param AbstractPlatform $platform
|
||||
* @return type
|
||||
*/
|
||||
public function getSqlDeclaration(array $fieldDeclaration, AbstractPlatform $platform)
|
||||
{
|
||||
return 'geometry(POINT,'.Point::$SRID.')';
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param type $value
|
||||
* @param AbstractPlatform $platform
|
||||
* @return Point
|
||||
*/
|
||||
public function convertToPHPValue($value, AbstractPlatform $platform)
|
||||
{
|
||||
if ($value === NULL){
|
||||
return NULL;
|
||||
} else {
|
||||
return Point::fromGeoJson($value);
|
||||
}
|
||||
}
|
||||
|
||||
public function getName()
|
||||
{
|
||||
return self::POINT;
|
||||
}
|
||||
|
||||
public function convertToDatabaseValue($value, AbstractPlatform $platform)
|
||||
{
|
||||
if ($value === NULL){
|
||||
return NULL;
|
||||
} else {
|
||||
return $value->toWKT();
|
||||
}
|
||||
}
|
||||
|
||||
public function canRequireSQLConversion()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
public function convertToPHPValueSQL($sqlExpr, $platform)
|
||||
{
|
||||
return 'ST_AsGeoJSON('.$sqlExpr.') ';
|
||||
}
|
||||
|
||||
public function convertToDatabaseValueSQL($sqlExpr, AbstractPlatform $platform)
|
||||
{
|
||||
return $sqlExpr;
|
||||
}
|
||||
}
|
||||
|
@@ -4,6 +4,8 @@ namespace Chill\MainBundle\Entity;
|
||||
|
||||
use Doctrine\ORM\Mapping as ORM;
|
||||
use Symfony\Component\Validator\Context\ExecutionContextInterface;
|
||||
use Chill\MainBundle\Doctrine\Model\Point;
|
||||
use Chill\ThirdPartyBundle\Entity\ThirdParty;
|
||||
|
||||
/**
|
||||
* Address
|
||||
@@ -28,14 +30,14 @@ class Address
|
||||
*
|
||||
* @ORM\Column(type="string", length=255)
|
||||
*/
|
||||
private $streetAddress1 = '';
|
||||
private $street = '';
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*
|
||||
* @ORM\Column(type="string", length=255)
|
||||
*/
|
||||
private $streetAddress2 = '';
|
||||
private $streetNumber = '';
|
||||
|
||||
/**
|
||||
* @var PostalCode
|
||||
@@ -43,7 +45,56 @@ class Address
|
||||
* @ORM\ManyToOne(targetEntity="Chill\MainBundle\Entity\PostalCode")
|
||||
*/
|
||||
private $postcode;
|
||||
|
||||
|
||||
/**
|
||||
* @var string|null
|
||||
*
|
||||
* @ORM\Column(type="string", length=16, nullable=true)
|
||||
*/
|
||||
private $floor;
|
||||
|
||||
/**
|
||||
* @var string|null
|
||||
*
|
||||
* @ORM\Column(type="string", length=16, nullable=true)
|
||||
*/
|
||||
private $corridor;
|
||||
|
||||
/**
|
||||
* @var string|null
|
||||
*
|
||||
* @ORM\Column(type="string", length=16, nullable=true)
|
||||
*/
|
||||
private $steps;
|
||||
|
||||
/**
|
||||
* @var string|null
|
||||
*
|
||||
* @ORM\Column(type="string", length=255, nullable=true)
|
||||
*/
|
||||
private $buildingName;
|
||||
|
||||
/**
|
||||
* @var string|null
|
||||
*
|
||||
* @ORM\Column(type="string", length=16, nullable=true)
|
||||
*/
|
||||
private $flat;
|
||||
|
||||
/**
|
||||
* @var string|null
|
||||
*
|
||||
* @ORM\Column(type="string", length=255, nullable=true)
|
||||
*/
|
||||
private $distribution;
|
||||
|
||||
/**
|
||||
* @var string|null
|
||||
*
|
||||
* @ORM\Column(type="string", length=255, nullable=true)
|
||||
*/
|
||||
private $extra;
|
||||
|
||||
/**
|
||||
* Indicates when the address starts validation. Used to build an history
|
||||
* of address. By default, the current date.
|
||||
@@ -53,27 +104,55 @@ class Address
|
||||
* @ORM\Column(type="date")
|
||||
*/
|
||||
private $validFrom;
|
||||
|
||||
|
||||
/**
|
||||
* Indicates when the address ends. Used to build an history
|
||||
* of address.
|
||||
*
|
||||
* @var \DateTime|null
|
||||
*
|
||||
* @ORM\Column(type="date", nullable=true)
|
||||
*/
|
||||
private $validTo;
|
||||
|
||||
/**
|
||||
* True if the address is a "no address", aka homeless person, ...
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
private $isNoAddress = false;
|
||||
|
||||
|
||||
/**
|
||||
* A geospatial field storing the coordinates of the Address
|
||||
*
|
||||
* @var Point|null
|
||||
*
|
||||
* @ORM\Column(type="point", nullable=true)
|
||||
*/
|
||||
private $point;
|
||||
|
||||
/**
|
||||
* A ThirdParty reference for person's addresses that are linked to a third party
|
||||
*
|
||||
* @var ThirdParty|null
|
||||
*
|
||||
* @ORM\ManyToOne(targetEntity="Chill\ThirdPartyBundle\Entity\ThirdParty")
|
||||
* @ORM\JoinColumn(nullable=true)
|
||||
*/
|
||||
private $linkedToThirdParty;
|
||||
|
||||
/**
|
||||
* A list of metadata, added by customizable fields
|
||||
*
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
private $customs = [];
|
||||
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->validFrom = new \DateTime();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get id
|
||||
*
|
||||
@@ -85,7 +164,7 @@ class Address
|
||||
}
|
||||
|
||||
/**
|
||||
* Set streetAddress1
|
||||
* Set streetAddress1 (legacy function)
|
||||
*
|
||||
* @param string $streetAddress1
|
||||
*
|
||||
@@ -93,23 +172,23 @@ class Address
|
||||
*/
|
||||
public function setStreetAddress1($streetAddress1)
|
||||
{
|
||||
$this->streetAddress1 = $streetAddress1 === NULL ? '' : $streetAddress1;
|
||||
$this->street = $streetAddress1 === NULL ? '' : $streetAddress1;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get streetAddress1
|
||||
* Get streetAddress1 (legacy function)
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getStreetAddress1()
|
||||
{
|
||||
return $this->streetAddress1;
|
||||
return $this->street;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set streetAddress2
|
||||
* Set streetAddress2 (legacy function)
|
||||
*
|
||||
* @param string $streetAddress2
|
||||
*
|
||||
@@ -117,19 +196,19 @@ class Address
|
||||
*/
|
||||
public function setStreetAddress2($streetAddress2)
|
||||
{
|
||||
$this->streetAddress2 = $streetAddress2 === NULL ? '' : $streetAddress2;
|
||||
$this->streetNumber = $streetAddress2 === NULL ? '' : $streetAddress2;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get streetAddress2
|
||||
* Get streetAddress2 (legacy function)
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getStreetAddress2()
|
||||
{
|
||||
return $this->streetAddress2;
|
||||
return $this->streetNumber;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -155,7 +234,7 @@ class Address
|
||||
{
|
||||
return $this->postcode;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return \DateTime
|
||||
*/
|
||||
@@ -173,19 +252,19 @@ class Address
|
||||
$this->validFrom = $validFrom;
|
||||
return $this;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get IsNoAddress
|
||||
*
|
||||
*
|
||||
* Indicate true if the address is a fake address (homeless, ...)
|
||||
*
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function getIsNoAddress(): bool
|
||||
{
|
||||
return $this->isNoAddress;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
@@ -196,9 +275,9 @@ class Address
|
||||
|
||||
/**
|
||||
* Set IsNoAddress
|
||||
*
|
||||
*
|
||||
* Indicate true if the address is a fake address (homeless, ...)
|
||||
*
|
||||
*
|
||||
* @param bool $isNoAddress
|
||||
* @return $this
|
||||
*/
|
||||
@@ -207,10 +286,10 @@ class Address
|
||||
$this->isNoAddress = $isNoAddress;
|
||||
return $this;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get customs informations in the address
|
||||
*
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getCustoms(): array
|
||||
@@ -220,27 +299,27 @@ class Address
|
||||
|
||||
/**
|
||||
* Store custom informations in the address
|
||||
*
|
||||
*
|
||||
* @param array $customs
|
||||
* @return $this
|
||||
*/
|
||||
public function setCustoms(array $customs): self
|
||||
{
|
||||
$this->customs = $customs;
|
||||
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Validate the address.
|
||||
*
|
||||
*
|
||||
* Check that:
|
||||
*
|
||||
*
|
||||
* * if the address is not home address:
|
||||
* * the postal code is present
|
||||
* * the valid from is not null
|
||||
* * the address street 1 is greater than 2
|
||||
*
|
||||
*
|
||||
* @param ExecutionContextInterface $context
|
||||
* @param array $payload
|
||||
*/
|
||||
@@ -252,18 +331,18 @@ class Address
|
||||
->atPath('validFrom')
|
||||
->addViolation();
|
||||
}
|
||||
|
||||
|
||||
if ($this->isNoAddress()) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
if (empty($this->getStreetAddress1())) {
|
||||
$context
|
||||
->buildViolation("address.street1-should-be-set")
|
||||
->atPath('streetAddress1')
|
||||
->addViolation();
|
||||
}
|
||||
|
||||
|
||||
if (!$this->getPostcode() instanceof PostalCode) {
|
||||
$context
|
||||
->buildViolation("address.postcode-should-be-set")
|
||||
@@ -271,7 +350,7 @@ class Address
|
||||
->addViolation();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param Address $original
|
||||
* @return Address
|
||||
@@ -286,5 +365,149 @@ class Address
|
||||
;
|
||||
}
|
||||
|
||||
public function getStreet(): ?string
|
||||
{
|
||||
return $this->street;
|
||||
}
|
||||
|
||||
public function setStreet(string $street): self
|
||||
{
|
||||
$this->street = $street;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getStreetNumber(): ?string
|
||||
{
|
||||
return $this->streetNumber;
|
||||
}
|
||||
|
||||
public function setStreetNumber(string $streetNumber): self
|
||||
{
|
||||
$this->streetNumber = $streetNumber;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getFloor(): ?string
|
||||
{
|
||||
return $this->floor;
|
||||
}
|
||||
|
||||
public function setFloor(?string $floor): self
|
||||
{
|
||||
$this->floor = $floor;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getCorridor(): ?string
|
||||
{
|
||||
return $this->corridor;
|
||||
}
|
||||
|
||||
public function setCorridor(?string $corridor): self
|
||||
{
|
||||
$this->corridor = $corridor;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getSteps(): ?string
|
||||
{
|
||||
return $this->steps;
|
||||
}
|
||||
|
||||
public function setSteps(?string $steps): self
|
||||
{
|
||||
$this->steps = $steps;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getBuildingName(): ?string
|
||||
{
|
||||
return $this->buildingName;
|
||||
}
|
||||
|
||||
public function setBuildingName(?string $buildingName): self
|
||||
{
|
||||
$this->buildingName = $buildingName;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getFlat(): ?string
|
||||
{
|
||||
return $this->flat;
|
||||
}
|
||||
|
||||
public function setFlat(?string $flat): self
|
||||
{
|
||||
$this->flat = $flat;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getDistribution(): ?string
|
||||
{
|
||||
return $this->distribution;
|
||||
}
|
||||
|
||||
public function setDistribution(?string $distribution): self
|
||||
{
|
||||
$this->distribution = $distribution;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getExtra(): ?string
|
||||
{
|
||||
return $this->extra;
|
||||
}
|
||||
|
||||
public function setExtra(?string $extra): self
|
||||
{
|
||||
$this->extra = $extra;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getValidTo(): ?\DateTimeInterface
|
||||
{
|
||||
return $this->validTo;
|
||||
}
|
||||
|
||||
public function setValidTo(\DateTimeInterface $validTo): self
|
||||
{
|
||||
$this->validTo = $validTo;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getPoint(): ?Point
|
||||
{
|
||||
return $this->point;
|
||||
}
|
||||
|
||||
public function setPoint(?Point $point): self
|
||||
{
|
||||
$this->point = $point;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getLinkedToThirdParty()
|
||||
{
|
||||
return $this->linkedToThirdParty;
|
||||
}
|
||||
|
||||
public function setLinkedToThirdParty($linkedToThirdParty): self
|
||||
{
|
||||
$this->linkedToThirdParty = $linkedToThirdParty;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
165
src/Bundle/ChillMainBundle/Entity/AddressReference.php
Normal file
165
src/Bundle/ChillMainBundle/Entity/AddressReference.php
Normal file
@@ -0,0 +1,165 @@
|
||||
<?php
|
||||
|
||||
namespace Chill\MainBundle\Entity;
|
||||
|
||||
use Chill\MainBundle\Entity\AddressReferenceRepository;
|
||||
use Doctrine\ORM\Mapping as ORM;
|
||||
use Chill\MainBundle\Doctrine\Model\Point;
|
||||
|
||||
/**
|
||||
* @ORM\Entity(repositoryClass=AddressReferenceRepository::class)
|
||||
* @ORM\Table(name="chill_main_address_reference")
|
||||
* @ORM\HasLifecycleCallbacks()
|
||||
*/
|
||||
class AddressReference
|
||||
{
|
||||
/**
|
||||
* @ORM\Id
|
||||
* @ORM\GeneratedValue
|
||||
* @ORM\Column(type="integer")
|
||||
*/
|
||||
private $id;
|
||||
|
||||
/**
|
||||
* @ORM\Column(type="string", length=255)
|
||||
*/
|
||||
private $refId;
|
||||
|
||||
/**
|
||||
* @ORM\Column(type="string", length=255, nullable=true)
|
||||
*/
|
||||
private $street;
|
||||
|
||||
/**
|
||||
* @ORM\Column(type="string", length=255, nullable=true)
|
||||
*/
|
||||
private $streetNumber;
|
||||
|
||||
/**
|
||||
* @var PostalCode
|
||||
*
|
||||
* @ORM\ManyToOne(targetEntity="Chill\MainBundle\Entity\PostalCode")
|
||||
*/
|
||||
private $postcode;
|
||||
|
||||
/**
|
||||
* @ORM\Column(type="string", length=255, nullable=true)
|
||||
*/
|
||||
private $municipalityCode;
|
||||
|
||||
/**
|
||||
* @ORM\Column(type="string", length=255, nullable=true)
|
||||
*/
|
||||
private $source;
|
||||
|
||||
/**
|
||||
* A geospatial field storing the coordinates of the Address
|
||||
*
|
||||
* @var Point
|
||||
*
|
||||
* @ORM\Column(type="point")
|
||||
*/
|
||||
private $point;
|
||||
|
||||
|
||||
public function getId(): ?int
|
||||
{
|
||||
return $this->id;
|
||||
}
|
||||
|
||||
public function getRefId(): ?string
|
||||
{
|
||||
return $this->refId;
|
||||
}
|
||||
|
||||
public function setRefId(string $refId): self
|
||||
{
|
||||
$this->refId = $refId;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getStreet(): ?string
|
||||
{
|
||||
return $this->street;
|
||||
}
|
||||
|
||||
public function setStreet(?string $street): self
|
||||
{
|
||||
$this->street = $street;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getStreetNumber(): ?string
|
||||
{
|
||||
return $this->streetNumber;
|
||||
}
|
||||
|
||||
public function setStreetNumber(?string $streetNumber): self
|
||||
{
|
||||
$this->streetNumber = $streetNumber;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set postcode
|
||||
*
|
||||
* @param PostalCode $postcode
|
||||
*
|
||||
* @return Address
|
||||
*/
|
||||
public function setPostcode(PostalCode $postcode = null)
|
||||
{
|
||||
$this->postcode = $postcode;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get postcode
|
||||
*
|
||||
* @return PostalCode
|
||||
*/
|
||||
public function getPostcode()
|
||||
{
|
||||
return $this->postcode;
|
||||
}
|
||||
|
||||
public function getMunicipalityCode(): ?string
|
||||
{
|
||||
return $this->municipalityCode;
|
||||
}
|
||||
|
||||
public function setMunicipalityCode(?string $municipalityCode): self
|
||||
{
|
||||
$this->municipalityCode = $municipalityCode;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getSource(): ?string
|
||||
{
|
||||
return $this->source;
|
||||
}
|
||||
|
||||
public function setSource(?string $source): self
|
||||
{
|
||||
$this->source = $source;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getPoint(): ?Point
|
||||
{
|
||||
return $this->point;
|
||||
}
|
||||
|
||||
public function setPoint(?Point $point): self
|
||||
{
|
||||
$this->point = $point;
|
||||
|
||||
return $this;
|
||||
}
|
||||
}
|
@@ -33,8 +33,8 @@ use Symfony\Component\Form\Extension\Core\Type\ChoiceType;
|
||||
* A type to create/update Address entity
|
||||
*
|
||||
* Options:
|
||||
*
|
||||
* - `has_valid_from` (boolean): show if an entry "has valid from" must be
|
||||
*
|
||||
* - `has_valid_from` (boolean): show if an entry "has valid from" must be
|
||||
* shown.
|
||||
* - `null_if_empty` (boolean): replace the address type by null if the street
|
||||
* or the postCode is empty. This is useful when the address is not required and
|
||||
@@ -45,10 +45,10 @@ class AddressType extends AbstractType
|
||||
public function buildForm(FormBuilderInterface $builder, array $options)
|
||||
{
|
||||
$builder
|
||||
->add('streetAddress1', TextType::class, array(
|
||||
->add('street', TextType::class, array(
|
||||
'required' => !$options['has_no_address'] // true if has no address is false
|
||||
))
|
||||
->add('streetAddress2', TextType::class, array(
|
||||
->add('streetNumber', TextType::class, array(
|
||||
'required' => false
|
||||
))
|
||||
->add('postCode', PostalCodeType::class, array(
|
||||
@@ -57,7 +57,7 @@ class AddressType extends AbstractType
|
||||
'required' => !$options['has_no_address'] // true if has no address is false
|
||||
))
|
||||
;
|
||||
|
||||
|
||||
if ($options['has_valid_from']) {
|
||||
$builder
|
||||
->add('validFrom', DateType::class, array(
|
||||
@@ -67,7 +67,7 @@ class AddressType extends AbstractType
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
if ($options['has_no_address']) {
|
||||
$builder
|
||||
->add('isNoAddress', ChoiceType::class, [
|
||||
@@ -79,12 +79,12 @@ class AddressType extends AbstractType
|
||||
'label' => 'address.address_homeless'
|
||||
]);
|
||||
}
|
||||
|
||||
|
||||
if ($options['null_if_empty'] === TRUE) {
|
||||
$builder->setDataMapper(new AddressDataMapper());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public function configureOptions(OptionsResolver $resolver)
|
||||
{
|
||||
$resolver
|
||||
|
@@ -27,6 +27,7 @@ use Symfony\Component\Form\FormBuilderInterface;
|
||||
use Chill\MainBundle\Form\Type\DataTransformer\ObjectToIdTransformer;
|
||||
use Doctrine\Persistence\ObjectManager;
|
||||
use Chill\MainBundle\Form\Type\Select2ChoiceType;
|
||||
use Chill\MainBundle\Templating\TranslatableStringHelper;
|
||||
|
||||
/**
|
||||
* Extends choice to allow adding select2 library on widget
|
||||
@@ -41,15 +42,26 @@ class Select2CountryType extends AbstractType
|
||||
*/
|
||||
private $requestStack;
|
||||
|
||||
/**
|
||||
*
|
||||
* @var TranslatableStringHelper
|
||||
*/
|
||||
protected $translatableStringHelper;
|
||||
|
||||
/**
|
||||
* @var ObjectManager
|
||||
*/
|
||||
private $em;
|
||||
|
||||
public function __construct(RequestStack $requestStack,ObjectManager $em)
|
||||
public function __construct(
|
||||
RequestStack $requestStack,
|
||||
ObjectManager $em,
|
||||
TranslatableStringHelper $translatableStringHelper
|
||||
)
|
||||
{
|
||||
$this->requestStack = $requestStack;
|
||||
$this->em = $em;
|
||||
$this->translatableStringHelper = $translatableStringHelper;
|
||||
}
|
||||
|
||||
public function getBlockPrefix()
|
||||
@@ -75,7 +87,7 @@ class Select2CountryType extends AbstractType
|
||||
$choices = array();
|
||||
|
||||
foreach ($countries as $c) {
|
||||
$choices[$c->getId()] = $c->getName()[$locale];
|
||||
$choices[$c->getId()] = $this->translatableStringHelper->localize($c->getName());
|
||||
}
|
||||
|
||||
asort($choices, SORT_STRING | SORT_FLAG_CASE);
|
||||
|
@@ -27,6 +27,7 @@ use Symfony\Component\Form\FormBuilderInterface;
|
||||
use Chill\MainBundle\Form\Type\DataTransformer\MultipleObjectsToIdTransformer;
|
||||
use Doctrine\Persistence\ObjectManager;
|
||||
use Chill\MainBundle\Form\Type\Select2ChoiceType;
|
||||
use Chill\MainBundle\Templating\TranslatableStringHelper;
|
||||
|
||||
/**
|
||||
* Extends choice to allow adding select2 library on widget for languages (multiple)
|
||||
@@ -43,10 +44,21 @@ class Select2LanguageType extends AbstractType
|
||||
*/
|
||||
private $em;
|
||||
|
||||
public function __construct(RequestStack $requestStack,ObjectManager $em)
|
||||
/**
|
||||
*
|
||||
* @var TranslatableStringHelper
|
||||
*/
|
||||
protected $translatableStringHelper;
|
||||
|
||||
public function __construct(
|
||||
RequestStack $requestStack,
|
||||
ObjectManager $em,
|
||||
TranslatableStringHelper $translatableStringHelper
|
||||
)
|
||||
{
|
||||
$this->requestStack = $requestStack;
|
||||
$this->em = $em;
|
||||
$this->translatableStringHelper = $translatableStringHelper;
|
||||
}
|
||||
|
||||
public function getBlockPrefix()
|
||||
@@ -72,7 +84,7 @@ class Select2LanguageType extends AbstractType
|
||||
$choices = array();
|
||||
|
||||
foreach ($languages as $l) {
|
||||
$choices[$l->getId()] = $l->getName()[$locale];
|
||||
$choices[$l->getId()] = $this->translatableStringHelper->localize($l->getName());
|
||||
}
|
||||
|
||||
asort($choices, SORT_STRING | SORT_FLAG_CASE);
|
||||
|
@@ -0,0 +1,50 @@
|
||||
<?php
|
||||
|
||||
namespace Chill\MainBundle\Repository;
|
||||
|
||||
use Chill\MainBundle\Entity\AddressReference;
|
||||
use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository;
|
||||
use Doctrine\Persistence\ManagerRegistry;
|
||||
|
||||
/**
|
||||
* @method AddressReference|null find($id, $lockMode = null, $lockVersion = null)
|
||||
* @method AddressReference|null findOneBy(array $criteria, array $orderBy = null)
|
||||
* @method AddressReference[] findAll()
|
||||
* @method AddressReference[] findBy(array $criteria, array $orderBy = null, $limit = null, $offset = null)
|
||||
*/
|
||||
class AddressReferenceRepository extends ServiceEntityRepository
|
||||
{
|
||||
public function __construct(ManagerRegistry $registry)
|
||||
{
|
||||
parent::__construct($registry, AddressReference::class);
|
||||
}
|
||||
|
||||
// /**
|
||||
// * @return AddressReference[] Returns an array of AddressReference objects
|
||||
// */
|
||||
/*
|
||||
public function findByExampleField($value)
|
||||
{
|
||||
return $this->createQueryBuilder('a')
|
||||
->andWhere('a.exampleField = :val')
|
||||
->setParameter('val', $value)
|
||||
->orderBy('a.id', 'ASC')
|
||||
->setMaxResults(10)
|
||||
->getQuery()
|
||||
->getResult()
|
||||
;
|
||||
}
|
||||
*/
|
||||
|
||||
/*
|
||||
public function findOneBySomeField($value): ?AddressReference
|
||||
{
|
||||
return $this->createQueryBuilder('a')
|
||||
->andWhere('a.exampleField = :val')
|
||||
->setParameter('val', $value)
|
||||
->getQuery()
|
||||
->getOneOrNullResult()
|
||||
;
|
||||
}
|
||||
*/
|
||||
}
|
@@ -28,7 +28,7 @@
|
||||
// @import "bootstrap/scss/card";
|
||||
// @import "bootstrap/scss/breadcrumb";
|
||||
// @import "bootstrap/scss/pagination";
|
||||
// @import "bootstrap/scss/badge";
|
||||
@import "bootstrap/scss/badge";
|
||||
// @import "bootstrap/scss/jumbotron";
|
||||
// @import "bootstrap/scss/alert";
|
||||
// @import "bootstrap/scss/progress";
|
||||
@@ -41,7 +41,7 @@
|
||||
// @import "bootstrap/scss/popover";
|
||||
// @import "bootstrap/scss/carousel";
|
||||
// @import "bootstrap/scss/spinners";
|
||||
// @import "bootstrap/scss/utilities";
|
||||
@import "bootstrap/scss/utilities";
|
||||
// @import "bootstrap/scss/print";
|
||||
|
||||
@import "custom";
|
||||
|
@@ -5,7 +5,7 @@
|
||||
@include button($green, $white);
|
||||
}
|
||||
|
||||
&.bt-reset, &.bt-delete {
|
||||
&.bt-reset, &.bt-delete, &.bt-remove {
|
||||
@include button($red, $white);
|
||||
}
|
||||
|
||||
@@ -24,6 +24,7 @@
|
||||
&.bt-save::before,
|
||||
&.bt-new::before,
|
||||
&.bt-delete::before,
|
||||
&.bt-remove::before,
|
||||
&.bt-update::before,
|
||||
&.bt-edit::before,
|
||||
&.bt-cancel::before,
|
||||
@@ -56,7 +57,12 @@
|
||||
// add a trash
|
||||
content: "";
|
||||
}
|
||||
|
||||
|
||||
&.bt-remove::before {
|
||||
// add a times
|
||||
content: "";
|
||||
}
|
||||
|
||||
&.bt-edit::before, &.bt-update::before {
|
||||
// add a pencil
|
||||
content: "";
|
||||
@@ -94,6 +100,7 @@
|
||||
&.bt-save::before,
|
||||
&.bt-new::before,
|
||||
&.bt-delete::before,
|
||||
&.bt-remove::before,
|
||||
&.bt-update::before,
|
||||
&.bt-edit::before,
|
||||
&.bt-cancel::before,
|
||||
@@ -123,6 +130,7 @@
|
||||
&.bt-save::before,
|
||||
&.bt-new::before,
|
||||
&.bt-delete::before,
|
||||
&.bt-remove::before,
|
||||
&.bt-update::before,
|
||||
&.bt-edit::before,
|
||||
&.bt-cancel::before,
|
||||
|
@@ -39,6 +39,8 @@ div.subheader {
|
||||
height: 130px;
|
||||
}
|
||||
|
||||
//// VUEJS ////
|
||||
|
||||
div.vue-component {
|
||||
padding: 1.5em;
|
||||
margin: 2em 0;
|
||||
@@ -55,3 +57,97 @@ div.vue-component {
|
||||
}
|
||||
dd { margin-left: 1em; }
|
||||
}
|
||||
|
||||
//// MODAL ////
|
||||
.modal-mask {
|
||||
position: fixed;
|
||||
z-index: 9998;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background-color: rgba(0, 0, 0, 0.75);
|
||||
display: table;
|
||||
transition: opacity 0.3s ease;
|
||||
}
|
||||
.modal-header .close { // bootstrap classes, override sc-button 0 radius
|
||||
border-top-right-radius: 0.3rem;
|
||||
}
|
||||
|
||||
/*
|
||||
* The following styles are auto-applied to elements with
|
||||
* transition="modal" when their visibility is toggled
|
||||
* by Vue.js.
|
||||
*
|
||||
* You can easily play with the modal transition by editing
|
||||
* these styles.
|
||||
*/
|
||||
.modal-enter {
|
||||
opacity: 0;
|
||||
}
|
||||
.modal-leave-active {
|
||||
opacity: 0;
|
||||
}
|
||||
.modal-enter .modal-container,
|
||||
.modal-leave-active .modal-container {
|
||||
-webkit-transform: scale(1.1);
|
||||
transform: scale(1.1);
|
||||
}
|
||||
|
||||
//// 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;
|
||||
}
|
||||
i {
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
left: 0.5em;
|
||||
padding: 0.65em 0;
|
||||
opacity: 0.5;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
div.results {
|
||||
div.count {
|
||||
margin: -0.5em 0 0.7em;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
}
|
||||
div.list-item {
|
||||
line-height: 26pt;
|
||||
padding: 0.3em 0.8em;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
&.checked {
|
||||
background-color: #ececec;
|
||||
border-bottom: 1px dotted #8b8b8b;
|
||||
}
|
||||
div.container {
|
||||
& > input {
|
||||
margin-right: 0.8em;
|
||||
}
|
||||
}
|
||||
div.right_actions {
|
||||
margin: 0 0 0 auto;
|
||||
& > * {
|
||||
margin-left: 0.5em;
|
||||
}
|
||||
a.sc-button {
|
||||
border: 1px solid lightgrey;
|
||||
font-size: 70%;
|
||||
padding: 4px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.discret {
|
||||
color: grey;
|
||||
margin-right: 1em;
|
||||
}
|
||||
|
@@ -0,0 +1,45 @@
|
||||
<template>
|
||||
<transition name="modal">
|
||||
<div class="modal-mask">
|
||||
<!-- :: styles bootstrap :: -->
|
||||
<div class="modal-dialog" :class="modalDialogClass">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<slot name="header"></slot>
|
||||
<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>
|
||||
<div class="modal-body">
|
||||
<slot name="body"></slot>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button class="sc-button cancel" @click="$emit('close')">{{ $t('action.close') }}</button>
|
||||
<slot name="footer"></slot>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- :: end styles bootstrap :: -->
|
||||
</div>
|
||||
</transition>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
/*
|
||||
* This Modal component is a mix between :
|
||||
* - Vue3 modal implementation
|
||||
* => with 'v-if:showModal' directive:parameter, html scope is added/removed not just shown/hidden
|
||||
* => with slot we can pass content from parent component
|
||||
* => some classes are passed from parent component
|
||||
* - Bootstrap 4.6 _modal.scss module
|
||||
* => using bootstrap css classes, the modal have a responsive behaviour,
|
||||
* => modal design can be configured using css classes (size, scroll)
|
||||
*/
|
||||
export default {
|
||||
name: 'Modal',
|
||||
props: ['modalDialogClass'],
|
||||
emits: ['close']
|
||||
}
|
||||
</script>
|
@@ -0,0 +1,55 @@
|
||||
import { createI18n } from 'vue-i18n'
|
||||
|
||||
const datetimeFormats = {
|
||||
fr: {
|
||||
short: {
|
||||
year: "numeric",
|
||||
month: "numeric",
|
||||
day: "numeric"
|
||||
},
|
||||
long: {
|
||||
year: "numeric",
|
||||
month: "short",
|
||||
day: "numeric",
|
||||
weekday: "short",
|
||||
hour: "numeric",
|
||||
minute: "numeric",
|
||||
hour12: false
|
||||
}
|
||||
}
|
||||
};
|
||||
const messages = {
|
||||
fr: {
|
||||
action: {
|
||||
actions: "Actions",
|
||||
show: "Voir",
|
||||
edit: "Modifier",
|
||||
create: "Créer",
|
||||
remove: "Enlever",
|
||||
delete: "Supprimer",
|
||||
save: "Enregistrer",
|
||||
add: "Ajouter",
|
||||
show_modal: "Ouvrir une modale",
|
||||
ok: "OK",
|
||||
cancel: "Annuler",
|
||||
close: "Fermer",
|
||||
next: "Suivant",
|
||||
previous: "Précédent",
|
||||
back: "Retour",
|
||||
check_all: "cocher tout",
|
||||
reset: "réinitialiser"
|
||||
},
|
||||
}
|
||||
};
|
||||
|
||||
const _createI18n = (appMessages) => {
|
||||
Object.assign(messages.fr, appMessages.fr);
|
||||
return createI18n({
|
||||
locale: 'fr',
|
||||
fallbackLocale: 'fr',
|
||||
datetimeFormats,
|
||||
messages,
|
||||
})
|
||||
};
|
||||
|
||||
export { _createI18n }
|
@@ -6,8 +6,8 @@
|
||||
<div class="chill_address_is_noaddress">{{ 'address.consider homeless'|trans }}</div>
|
||||
{% endif %}
|
||||
<div class="chill_address_address">
|
||||
{% if address.streetAddress1 is not empty %}<p class="street street1">{{ address.streetAddress1 }}</p>{% endif %}
|
||||
{% if address.streetAddress2 is not empty %}<p class="street street2">{{ address.streetAddress2 }}</p>{% endif %}
|
||||
{% if address.street is not empty %}<p class="street street1">{{ address.street }}</p>{% endif %}
|
||||
{% if address.streetNumber is not empty %}<p class="street street2">{{ address.streetNumber }}</p>{% endif %}
|
||||
{% if address.postCode is not empty %}
|
||||
<p class="postalCode"><span class="code">{{ address.postCode.code }}</span> <span class="name">{{ address.postCode.name }}</span></p>
|
||||
<p class="country">{{ address.postCode.country.name|localize_translatable_string }}</p>
|
||||
|
@@ -204,7 +204,7 @@ class SearchProvider
|
||||
}
|
||||
|
||||
public function getResultByName($pattern, $name, $start = 0, $limit = 50,
|
||||
array $options = array(), $format)
|
||||
array $options = array(), $format = 'html')
|
||||
{
|
||||
$terms = $this->parse($pattern);
|
||||
$search = $this->getByName($name);
|
||||
|
28
src/Bundle/ChillMainBundle/Serializer/Model/Collection.php
Normal file
28
src/Bundle/ChillMainBundle/Serializer/Model/Collection.php
Normal file
@@ -0,0 +1,28 @@
|
||||
<?php
|
||||
|
||||
namespace Chill\MainBundle\Serializer\Model;
|
||||
|
||||
use Chill\MainBundle\Pagination\PaginatorInterface;
|
||||
|
||||
class Collection
|
||||
{
|
||||
private PaginatorInterface $paginator;
|
||||
|
||||
private $items;
|
||||
|
||||
public function __construct($items, PaginatorInterface $paginator)
|
||||
{
|
||||
$this->items = $items;
|
||||
$this->paginator = $paginator;
|
||||
}
|
||||
|
||||
public function getPaginator(): PaginatorInterface
|
||||
{
|
||||
return $this->paginator;
|
||||
}
|
||||
|
||||
public function getItems()
|
||||
{
|
||||
return $this->items;
|
||||
}
|
||||
}
|
@@ -0,0 +1,44 @@
|
||||
<?php
|
||||
/*
|
||||
*
|
||||
* Copyright (C) 2014-2021, Champs Libres Cooperative SCRLFS, <http://www.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\MainBundle\Serializer\Normalizer;
|
||||
|
||||
use Chill\MainBundle\Entity\Center;
|
||||
use Symfony\Component\Serializer\Normalizer\NormalizerInterface;
|
||||
|
||||
/**
|
||||
*
|
||||
*
|
||||
*/
|
||||
class CenterNormalizer implements NormalizerInterface
|
||||
{
|
||||
public function normalize($center, string $format = null, array $context = array())
|
||||
{
|
||||
/** @var Center $center */
|
||||
return [
|
||||
'id' => $center->getId(),
|
||||
'name' => $center->getName()
|
||||
];
|
||||
}
|
||||
|
||||
public function supportsNormalization($data, string $format = null): bool
|
||||
{
|
||||
return $data instanceof Center;
|
||||
}
|
||||
}
|
@@ -0,0 +1,41 @@
|
||||
<?php
|
||||
|
||||
namespace Chill\MainBundle\Serializer\Normalizer;
|
||||
|
||||
use Chill\MainBundle\Serializer\Model\Collection;
|
||||
use Symfony\Component\Serializer\Normalizer\NormalizerInterface;
|
||||
use Symfony\Component\Serializer\Normalizer\NormalizerAwareInterface;
|
||||
use Symfony\Component\Serializer\Normalizer\NormalizerAwareTrait;
|
||||
|
||||
class CollectionNormalizer implements NormalizerInterface, NormalizerAwareInterface
|
||||
{
|
||||
use NormalizerAwareTrait;
|
||||
|
||||
public function supportsNormalization($data, string $format = null): bool
|
||||
{
|
||||
return $data instanceof Collection;
|
||||
}
|
||||
|
||||
public function normalize($collection, string $format = null, array $context = [])
|
||||
{
|
||||
/** @var $collection Collection */
|
||||
/** @var $collection Chill\MainBundle\Pagination\PaginatorInterface */
|
||||
$paginator = $collection->getPaginator();
|
||||
|
||||
$data['count'] = $paginator->getTotalItems();
|
||||
$pagination['first'] = $paginator->getCurrentPageFirstItemNumber();
|
||||
$pagination['items_per_page'] = $paginator->getItemsPerPage();
|
||||
$pagination['next'] = $paginator->hasNextPage() ?
|
||||
$paginator->getNextPage()->generateUrl() : null;
|
||||
$pagination['previous'] = $paginator->hasPreviousPage() ?
|
||||
$paginator->getPreviousPage()->generateUrl() : null;
|
||||
$pagination['more'] = $paginator->hasNextPage();
|
||||
$data['pagination'] = $pagination;
|
||||
|
||||
// normalize results
|
||||
$data['results'] = $this->normalizer->normalize($collection->getItems(),
|
||||
$format, $context);
|
||||
|
||||
return $data;
|
||||
}
|
||||
}
|
@@ -0,0 +1,39 @@
|
||||
<?php
|
||||
/*
|
||||
*
|
||||
* Copyright (C) 2014-2021, Champs Libres Cooperative SCRLFS, <http://www.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\MainBundle\Serializer\Normalizer;
|
||||
|
||||
use Symfony\Component\Serializer\Normalizer\NormalizerInterface;
|
||||
|
||||
class DateNormalizer implements NormalizerInterface
|
||||
{
|
||||
public function normalize($date, string $format = null, array $context = array())
|
||||
{
|
||||
/** @var \DateTimeInterface $date */
|
||||
return [
|
||||
'datetime' => $date->format(\DateTimeInterface::ISO8601),
|
||||
'u' => $date->getTimestamp()
|
||||
];
|
||||
}
|
||||
|
||||
public function supportsNormalization($data, string $format = null): bool
|
||||
{
|
||||
return $data instanceof \DateTimeInterface;
|
||||
}
|
||||
}
|
@@ -0,0 +1,44 @@
|
||||
<?php
|
||||
/*
|
||||
*
|
||||
* Copyright (C) 2014-2021, Champs Libres Cooperative SCRLFS, <http://www.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\MainBundle\Serializer\Normalizer;
|
||||
|
||||
use Chill\MainBundle\Entity\User;
|
||||
use Symfony\Component\Serializer\Normalizer\NormalizerInterface;
|
||||
|
||||
/**
|
||||
*
|
||||
*
|
||||
*/
|
||||
class UserNormalizer implements NormalizerInterface
|
||||
{
|
||||
public function normalize($user, string $format = null, array $context = array())
|
||||
{
|
||||
/** @var User $user */
|
||||
return [
|
||||
'id' => $user->getId(),
|
||||
'username' => $user->getUsername()
|
||||
];
|
||||
}
|
||||
|
||||
public function supportsNormalization($data, string $format = null): bool
|
||||
{
|
||||
return $data instanceof User;
|
||||
}
|
||||
}
|
@@ -9,15 +9,7 @@ class LoginControllerTest extends WebTestCase
|
||||
{
|
||||
public function testLogin()
|
||||
{
|
||||
$client = static::createClient(array(
|
||||
'framework' => array(
|
||||
'default_locale' => 'en',
|
||||
'translator' => array(
|
||||
'fallback' => 'en'
|
||||
)
|
||||
),
|
||||
|
||||
));
|
||||
$client = static::createClient();
|
||||
|
||||
//load login page and submit form
|
||||
$crawler = $client->request('GET', '/login');
|
||||
@@ -42,17 +34,17 @@ class LoginControllerTest extends WebTestCase
|
||||
//on the home page, there must be a logout link
|
||||
$client->followRedirects(true);
|
||||
$crawler = $client->request('GET', '/');
|
||||
|
||||
|
||||
$this->assertRegExp('/center a_social/', $client->getResponse()
|
||||
->getContent());
|
||||
$logoutLinkFilter = $crawler->filter('a:contains("Logout")');
|
||||
$logoutLinkFilter = $crawler->filter('a:contains("Se déconnecter")');
|
||||
|
||||
//check there is > 0 logout link
|
||||
$this->assertGreaterThan(0, $logoutLinkFilter->count(), 'check that a logout link is present');
|
||||
|
||||
//click on logout link
|
||||
$client->followRedirects(false);
|
||||
$client->click($crawler->selectLink('Logout')->link());
|
||||
$client->click($crawler->selectLink('Se déconnecter')->link());
|
||||
|
||||
$this->assertTrue($client->getResponse()->isRedirect());
|
||||
$client->followRedirect(); #redirect to login page
|
||||
|
@@ -32,21 +32,7 @@ use Chill\MainBundle\Search\SearchInterface;
|
||||
*/
|
||||
class SearchControllerTest extends WebTestCase
|
||||
{
|
||||
/*
|
||||
public function setUp()
|
||||
{
|
||||
static::bootKernel();
|
||||
|
||||
//add a default service
|
||||
$this->addSearchService(
|
||||
$this->createDefaultSearchService('<p>I am default</p>', 10), 'default'
|
||||
);
|
||||
//add a domain service
|
||||
$this->addSearchService(
|
||||
$this->createDefaultSearchService('<p>I am domain bar</p>', 20), 'bar'
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Test the behaviour when no domain is provided in the search pattern :
|
||||
* the default search should be enabled
|
||||
@@ -105,29 +91,6 @@ class SearchControllerTest extends WebTestCase
|
||||
$this->assertTrue($client->getResponse()->isNotFound());
|
||||
}
|
||||
|
||||
|
||||
public function testSearchWithinSpecificSearchName()
|
||||
{
|
||||
/*
|
||||
//add a search service which will be supported
|
||||
$this->addSearchService(
|
||||
$this->createNonDefaultDomainSearchService("<p>I am domain foo</p>", 100, TRUE), 'foo'
|
||||
);
|
||||
|
||||
$client = $this->getAuthenticatedClient();
|
||||
$crawler = $client->request('GET', '/fr/search',
|
||||
array('q' => '@foo default search', 'name' => 'foo'));
|
||||
|
||||
//$this->markTestSkipped();
|
||||
$this->assertEquals(0, $crawler->filter('p:contains("I am default")')->count(),
|
||||
"The mocked default results are not shown");
|
||||
$this->assertEquals(0, $crawler->filter('p:contains("I am domain bar")')->count(),
|
||||
"The mocked non-default results are not shown");
|
||||
$this->assertEquals(1, $crawler->filter('p:contains("I am domain foo")')->count(),
|
||||
"The mocked nnon default results for foo are shown");
|
||||
*/
|
||||
}
|
||||
|
||||
private function getAuthenticatedClient()
|
||||
{
|
||||
return static::createClient(array(), array(
|
||||
|
@@ -37,11 +37,12 @@ class UserControllerTest extends WebTestCase
|
||||
|
||||
$username = 'Test_user'. uniqid();
|
||||
$password = 'Password1234!';
|
||||
dump($crawler->text());
|
||||
// Fill in the form and submit it
|
||||
$form = $crawler->selectButton('Créer')->form(array(
|
||||
'chill_mainbundle_user[username]' => $username,
|
||||
'chill_mainbundle_user[plainPassword][password][first]' => $password,
|
||||
'chill_mainbundle_user[plainPassword][password][second]' => $password
|
||||
'chill_mainbundle_user[plainPassword][first]' => $password,
|
||||
'chill_mainbundle_user[plainPassword][second]' => $password
|
||||
));
|
||||
|
||||
$this->client->submit($form);
|
||||
@@ -119,8 +120,8 @@ class UserControllerTest extends WebTestCase
|
||||
$crawler = $this->client->click($link);
|
||||
|
||||
$form = $crawler->selectButton('Changer le mot de passe')->form(array(
|
||||
'chill_mainbundle_user_password[password][first]' => $newPassword,
|
||||
'chill_mainbundle_user_password[password][second]' => $newPassword,
|
||||
'chill_mainbundle_user_password[new_password][first]' => $newPassword,
|
||||
'chill_mainbundle_user_password[new_password][second]' => $newPassword,
|
||||
));
|
||||
|
||||
$this->client->submit($form);
|
||||
|
@@ -1,179 +0,0 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* Chill is a software for social workers
|
||||
* Copyright (C) 2015 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\MainBundle\Tests\DependencyInjection;
|
||||
|
||||
use Chill\MainBundle\DependencyInjection\ConfigConsistencyCompilerPass;
|
||||
use Symfony\Component\DependencyInjection\ContainerBuilderInterface;
|
||||
|
||||
/**
|
||||
* Description of ConfigConsistencyCompilerPassTest
|
||||
*
|
||||
* @author Julien Fastré <julien.fastre@champs-libres.coop>
|
||||
*/
|
||||
class ConfigConsistencyCompilerPassTest extends \PHPUnit\Framework\TestCase
|
||||
{
|
||||
|
||||
/**
|
||||
*
|
||||
*
|
||||
* @var \Chill\MainBundle\DependencyInjection\ConfigConsistencyCompilerPass
|
||||
*/
|
||||
private $configConsistencyCompilerPass;
|
||||
|
||||
public function setUp()
|
||||
{
|
||||
$this->configConsistencyCompilerPass = new ConfigConsistencyCompilerPass();
|
||||
}
|
||||
|
||||
/**
|
||||
* Test that everything is fine is configuration is correct
|
||||
*
|
||||
*/
|
||||
public function testLanguagesArePresent()
|
||||
{
|
||||
try {
|
||||
$this ->configConsistencyCompilerPass
|
||||
->process(
|
||||
$this->mockContainer(
|
||||
$this->mockTranslatorDefinition(array('fr')),
|
||||
array('fr', 'nl')
|
||||
)
|
||||
);
|
||||
$this->assertTrue(TRUE, 'the config consistency can process');
|
||||
} catch (\Exception $ex) {
|
||||
$this->assertTrue(FALSE,
|
||||
'the config consistency can process');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Test that everything is fine is configuration is correct
|
||||
* if multiple fallback languages are present
|
||||
*
|
||||
*/
|
||||
public function testMultiplesLanguagesArePresent()
|
||||
{
|
||||
try {
|
||||
$this ->configConsistencyCompilerPass
|
||||
->process(
|
||||
$this->mockContainer(
|
||||
$this->mockTranslatorDefinition(array('fr', 'nl')),
|
||||
array('fr', 'nl', 'en')
|
||||
)
|
||||
);
|
||||
$this->assertTrue(TRUE, 'the config consistency can process');
|
||||
} catch (\Exception $ex) {
|
||||
$this->assertTrue(FALSE,
|
||||
'the config consistency can process');
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Test that a runtime exception is throw if the available language does
|
||||
* not contains the fallback locale
|
||||
*
|
||||
* @expectedException \RuntimeException
|
||||
* @expectedExceptionMessageRegExp /The chill_main.available_languages parameter does not contains fallback locales./
|
||||
*/
|
||||
public function testLanguageNotPresent()
|
||||
{
|
||||
$container = $this->mockContainer(
|
||||
$this->mockTranslatorDefinition(array('en')), array('fr')
|
||||
);
|
||||
|
||||
$this->configConsistencyCompilerPass->process($container);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test that a logic exception is thrown if the setFallbackLocale
|
||||
* method is not defined in translator definition
|
||||
*
|
||||
* @expectedException \LogicException
|
||||
*/
|
||||
public function testSetFallbackNotDefined()
|
||||
{
|
||||
$container = $this->mockContainer(
|
||||
$this->mockTranslatorDefinition(NULL), array('fr')
|
||||
);
|
||||
$this->configConsistencyCompilerPass->process($container);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return ContainerBuilder
|
||||
*/
|
||||
private function mockContainer($definition, $availableLanguages)
|
||||
{
|
||||
$container = $this
|
||||
->getMockBuilder('Symfony\Component\DependencyInjection\ContainerBuilder')
|
||||
->getMock();
|
||||
|
||||
$container->method('getParameter')
|
||||
->will($this->returnCallback(
|
||||
function($parameter) use ($availableLanguages) {
|
||||
if ($parameter === 'chill_main.available_languages') {
|
||||
return $availableLanguages;
|
||||
} else {
|
||||
throw new \LogicException("the parameter '$parameter' "
|
||||
. "is not defined in stub test");
|
||||
}
|
||||
}
|
||||
));
|
||||
|
||||
$container->method('findDefinition')
|
||||
->will($this->returnCallback(
|
||||
function($id) use ($definition) {
|
||||
if (in_array($id, array('translator', 'translator.default'))) {
|
||||
return $definition;
|
||||
} else {
|
||||
throw new \LogicException("the id $id is not defined in test");
|
||||
}
|
||||
}));
|
||||
|
||||
|
||||
return $container;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param type $languages
|
||||
* @return 'Symfony\Component\DependencyInjection\Definition'
|
||||
*/
|
||||
private function mockTranslatorDefinition(array $languages = NULL)
|
||||
{
|
||||
$definition = $this
|
||||
->getMockBuilder('Symfony\Component\DependencyInjection\Definition')
|
||||
->getMock();
|
||||
|
||||
if (NULL !== $languages) {
|
||||
$definition->method('getMethodCalls')
|
||||
->willReturn(array(
|
||||
['setFallbackLocales', array($languages)]
|
||||
));
|
||||
} else {
|
||||
$definition->method('getMethodCalls')
|
||||
->willReturn(array(['nothing', array()]));
|
||||
}
|
||||
|
||||
return $definition;
|
||||
}
|
||||
}
|
119
src/Bundle/ChillMainBundle/Tests/Doctrine/Model/PointTest.php
Normal file
119
src/Bundle/ChillMainBundle/Tests/Doctrine/Model/PointTest.php
Normal file
@@ -0,0 +1,119 @@
|
||||
<?php
|
||||
|
||||
namespace Chill\MainBundle\Tests\Doctrine\Model;
|
||||
|
||||
use Symfony\Bundle\FrameworkBundle\Test\KernelTestCase;
|
||||
use Chill\MainBundle\Doctrine\Model\Point;
|
||||
|
||||
/**
|
||||
* Test the point model methods
|
||||
*
|
||||
* @author Julien Minet <julien.minet@champs-libres.coop>
|
||||
*/
|
||||
class ExportControllerTest extends KernelTestCase
|
||||
{
|
||||
|
||||
public function testToWKT()
|
||||
{
|
||||
$lon = 4.8634;
|
||||
$lat = 50.47382;
|
||||
$point = $this->preparePoint($lon, $lat);
|
||||
|
||||
$this->assertEquals($point->toWKT(),'SRID=4326;POINT(4.8634 50.47382)');
|
||||
}
|
||||
|
||||
public function testToGeojson()
|
||||
{
|
||||
$lon = 4.8634;
|
||||
$lat = 50.47382;
|
||||
$point = $this->preparePoint($lon, $lat);
|
||||
|
||||
$this->assertEquals($point->toGeoJson(),'{"type":"Point","coordinates":[4.8634,50.47382]}');
|
||||
}
|
||||
|
||||
public function testToArrayGeoJson()
|
||||
{
|
||||
$lon = 4.8634;
|
||||
$lat = 50.47382;
|
||||
$point = $this->preparePoint($lon, $lat);
|
||||
|
||||
$this->assertEquals(
|
||||
$point->toArrayGeoJson(),
|
||||
[
|
||||
'type' => 'Point',
|
||||
'coordinates' => [4.8634, 50.47382]
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
public function testJsonSerialize()
|
||||
{
|
||||
$lon = 4.8634;
|
||||
$lat = 50.47382;
|
||||
$point = $this->preparePoint($lon, $lat);
|
||||
|
||||
$this->assertEquals(
|
||||
$point->jsonSerialize(),
|
||||
[
|
||||
'type' => 'Point',
|
||||
'coordinates' => [4.8634, 50.47382]
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
public function testFromGeoJson()
|
||||
{
|
||||
$geojson = '{"type":"Point","coordinates":[4.8634,50.47382]}';
|
||||
$lon = 4.8634;
|
||||
$lat = 50.47382;
|
||||
$point = $this->preparePoint($lon, $lat);;
|
||||
|
||||
$this->assertEquals($point, Point::fromGeoJson($geojson));
|
||||
}
|
||||
|
||||
public function testFromLonLat()
|
||||
{
|
||||
$lon = 4.8634;
|
||||
$lat = 50.47382;
|
||||
$point = $this->preparePoint($lon, $lat);;
|
||||
|
||||
$this->assertEquals($point, Point::fromLonLat($lon, $lat));
|
||||
}
|
||||
|
||||
public function testFromArrayGeoJson()
|
||||
{
|
||||
$array = [
|
||||
'type' => 'Point',
|
||||
'coordinates' => [4.8634, 50.47382]
|
||||
];
|
||||
$lon = 4.8634;
|
||||
$lat = 50.47382;
|
||||
$point = $this->preparePoint($lon, $lat);;
|
||||
|
||||
$this->assertEquals($point, Point::fromArrayGeoJson($array));
|
||||
}
|
||||
|
||||
public function testGetLat()
|
||||
{
|
||||
$lon = 4.8634;
|
||||
$lat = 50.47382;
|
||||
$point = $this->preparePoint($lon, $lat);;
|
||||
|
||||
$this->assertEquals($lat, $point->getLat());
|
||||
}
|
||||
|
||||
public function testGetLon()
|
||||
{
|
||||
$lon = 4.8634;
|
||||
$lat = 50.47382;
|
||||
$point = $this->preparePoint($lon, $lat);;
|
||||
|
||||
$this->assertEquals($lon, $point->getLon());
|
||||
}
|
||||
|
||||
private function preparePoint($lon, $lat)
|
||||
{
|
||||
return Point::fromLonLat($lon, $lat);
|
||||
}
|
||||
|
||||
}
|
@@ -624,8 +624,9 @@ class ExportManagerTest extends KernelTestCase
|
||||
$exportManager->addFormatter($formatter, 'spreadsheet');
|
||||
|
||||
//ob_start();
|
||||
$response = $exportManager->generate('dummy',
|
||||
array(PickCenterType::CENTERS_IDENTIFIERS => array($center)),
|
||||
$response = $exportManager->generate(
|
||||
'dummy',
|
||||
array($center),
|
||||
array(
|
||||
ExportType::FILTER_KEY => array(
|
||||
'filter_foo' => array(
|
||||
|
@@ -54,13 +54,20 @@ class PageTest extends KernelTestCase
|
||||
$number = 1,
|
||||
$itemPerPage = 10,
|
||||
$route = 'route',
|
||||
array $routeParameters = array()
|
||||
array $routeParameters = array(),
|
||||
$totalItems = 100
|
||||
) {
|
||||
$urlGenerator = $this->prophet->prophesize();
|
||||
$urlGenerator->willImplement(UrlGeneratorInterface::class);
|
||||
|
||||
return new Page($number, $itemPerPage, $urlGenerator->reveal(), $route,
|
||||
$routeParameters);
|
||||
return new Page(
|
||||
$number,
|
||||
$itemPerPage,
|
||||
$urlGenerator->reveal(),
|
||||
$route,
|
||||
$routeParameters,
|
||||
$totalItems
|
||||
);
|
||||
}
|
||||
|
||||
public function testPageNumber() {
|
||||
|
@@ -21,9 +21,10 @@ namespace Chill\MainBundle\Test\Search;
|
||||
|
||||
use Chill\MainBundle\Search\SearchProvider;
|
||||
use Chill\MainBundle\Search\SearchInterface;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
|
||||
|
||||
class SearchProviderTest extends \PHPUnit\Framework\TestCase
|
||||
class SearchProviderTest extends TestCase
|
||||
{
|
||||
|
||||
/**
|
||||
@@ -311,4 +312,4 @@ class SearchProviderTest extends \PHPUnit\Framework\TestCase
|
||||
|
||||
return $mock;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -50,7 +50,7 @@ class AuthorizationHelperTest extends KernelTestCase
|
||||
*/
|
||||
private function getAuthorizationHelper()
|
||||
{
|
||||
return static::$kernel->getContainer()
|
||||
return static::$container
|
||||
->get('chill.main.security.authorization.helper')
|
||||
;
|
||||
}
|
||||
|
@@ -39,8 +39,7 @@ class TokenManagerTest extends KernelTestCase
|
||||
{
|
||||
self::bootKernel();
|
||||
|
||||
$logger = self::$kernel
|
||||
->getContainer()
|
||||
$logger = self::$container
|
||||
->get('logger');
|
||||
|
||||
$this->tokenManager = new TokenManager('secret', $logger);
|
||||
|
@@ -36,53 +36,19 @@ class ChillMenuTwigFunctionTest extends KernelTestCase
|
||||
public static function setUpBeforeClass()
|
||||
{
|
||||
self::bootKernel(array('environment' => 'test'));
|
||||
static::$templating = static::$kernel
|
||||
->getContainer()->get('templating');
|
||||
static::$templating = static::$container
|
||||
->get('templating');
|
||||
$pathToBundle = static::$container->getParameter('kernel.bundles_metadata')['ChillMainBundle']['path'];
|
||||
//load templates in Tests/Resources/views
|
||||
static::$kernel->getContainer()->get('twig.loader')
|
||||
->addPath(static::$kernel->getContainer()->getParameter('kernel.root_dir')
|
||||
.'/Resources/views/', $namespace = 'tests');
|
||||
static::$container->get('twig.loader')
|
||||
->addPath($pathToBundle.'/Resources/test/views/', $namespace = 'tests');
|
||||
}
|
||||
|
||||
public function testNormalMenu()
|
||||
{
|
||||
$content = static::$templating->render('@tests/menus/normalMenu.html.twig');
|
||||
$crawler = new Crawler($content);
|
||||
|
||||
$ul = $crawler->filter('ul')->getNode(0);
|
||||
$this->assertEquals( 'ul', $ul->tagName);
|
||||
|
||||
$lis = $crawler->filter('ul')->children();
|
||||
$this->assertEquals(3, count($lis));
|
||||
|
||||
$lis->each(function(Crawler $node, $i) {
|
||||
$this->assertEquals('li', $node->getNode(0)->tagName);
|
||||
|
||||
$a = $node->children()->getNode(0);
|
||||
$this->assertEquals('a', $a->tagName);
|
||||
switch($i) {
|
||||
case 0:
|
||||
$this->assertEquals('/dummy?param=fake', $a->getAttribute('href'));
|
||||
$this->assertEquals('active', $a->getAttribute('class'));
|
||||
$this->assertEquals('test0', $a->nodeValue);
|
||||
break;
|
||||
case 1:
|
||||
$this->assertEquals('/dummy1?param=fake', $a->getAttribute('href'));
|
||||
$this->assertEmpty($a->getAttribute('class'));
|
||||
$this->assertEquals('test1', $a->nodeValue);
|
||||
break;
|
||||
case 3:
|
||||
$this->assertEquals('/dummy2/fake', $a->getAttribute('href'));
|
||||
$this->assertEmpty($a->getAttribute('class'));
|
||||
$this->assertEquals('test2', $a->nodeValue);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public function testMenuOverrideTemplate()
|
||||
{
|
||||
$this->markTestSkipped("this hacks seems not working now");
|
||||
$content = static::$templating->render('@tests/menus/overrideTemplate.html.twig');
|
||||
$this->assertEquals('fake template', $content);
|
||||
$this->assertContains('ul', $content,
|
||||
"test that the file contains an ul tag"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@@ -28,7 +28,7 @@ class MenuComposerTest extends KernelTestCase
|
||||
public function setUp()
|
||||
{
|
||||
self::bootKernel(array('environment' => 'test'));
|
||||
$this->menuComposer = static::$kernel->getContainer()
|
||||
$this->menuComposer = static::$container
|
||||
->get('chill.main.menu_composer');
|
||||
}
|
||||
|
||||
@@ -42,50 +42,5 @@ class MenuComposerTest extends KernelTestCase
|
||||
$routes = $this->menuComposer->getRoutesFor('dummy0');
|
||||
|
||||
$this->assertInternalType('array', $routes);
|
||||
$this->assertCount(3, $routes);
|
||||
//check that the keys are sorted
|
||||
$orders = array_keys($routes);
|
||||
foreach ($orders as $key => $order){
|
||||
if (array_key_exists($key + 1, $orders)) {
|
||||
$this->assertGreaterThan($order, $orders[$key + 1],
|
||||
'Failing to assert that routes are ordered');
|
||||
}
|
||||
}
|
||||
|
||||
//check that the array are identical, order is not important :
|
||||
|
||||
$expected = array(
|
||||
50 => array(
|
||||
'key' => 'chill_main_dummy_0',
|
||||
'label' => 'test0',
|
||||
'otherkey' => 'othervalue'
|
||||
),
|
||||
51 => array(
|
||||
'key' => 'chill_main_dummy_1',
|
||||
'label' => 'test1',
|
||||
'helper'=> 'great helper'
|
||||
),
|
||||
52 => array(
|
||||
'key' => 'chill_main_dummy_2',
|
||||
'label' => 'test2'
|
||||
));
|
||||
|
||||
|
||||
foreach ($expected as $order => $route ){
|
||||
|
||||
}
|
||||
|
||||
//compare arrays
|
||||
foreach($expected as $order => $route) {
|
||||
//check the key are the one expected
|
||||
$this->assertTrue(isset($routes[$order]));
|
||||
|
||||
if (isset($routes[$order])){ #avoid an exception if routes with order does not exists
|
||||
//sort arrays. Order matters for phpunit::assertSame
|
||||
ksort($route);
|
||||
ksort($routes[$order]);
|
||||
$this->assertSame($route, $routes[$order]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -86,7 +86,3 @@ login_check:
|
||||
|
||||
logout:
|
||||
path: /logout
|
||||
|
||||
chill_main_test:
|
||||
path: /{_locale}/main/test
|
||||
controller: Chill\MainBundle\Controller\DefaultController::testAction
|
||||
|
@@ -1,7 +1,8 @@
|
||||
services:
|
||||
Chill\MainBundle\CRUD\Routing\CRUDRoutesLoader:
|
||||
arguments:
|
||||
$config: '%chill_main_crud_route_loader_config%'
|
||||
$crudConfig: '%chill_main_crud_route_loader_config%'
|
||||
$apiConfig: '%chill_main_api_route_loader_config%'
|
||||
tags: [ routing.loader ]
|
||||
|
||||
Chill\MainBundle\CRUD\Resolver\Resolver:
|
||||
@@ -13,4 +14,4 @@ services:
|
||||
arguments:
|
||||
$resolver: '@Chill\MainBundle\CRUD\Resolver\Resolver'
|
||||
tags:
|
||||
- { name: twig.extension }
|
||||
- { name: twig.extension }
|
||||
|
@@ -23,6 +23,7 @@ services:
|
||||
arguments:
|
||||
- "@request_stack"
|
||||
- "@doctrine.orm.entity_manager"
|
||||
- "@chill.main.helper.translatable_string"
|
||||
tags:
|
||||
- { name: form.type, alias: select2_chill_country }
|
||||
|
||||
@@ -31,6 +32,7 @@ services:
|
||||
arguments:
|
||||
- "@request_stack"
|
||||
- "@doctrine.orm.entity_manager"
|
||||
- "@chill.main.helper.translatable_string"
|
||||
tags:
|
||||
- { name: form.type, alias: select2_chill_language }
|
||||
|
||||
|
@@ -6,6 +6,7 @@ services:
|
||||
- "@request_stack"
|
||||
- "@router"
|
||||
- "%chill_main.pagination.item_per_page%"
|
||||
|
||||
Chill\MainBundle\Pagination\PaginatorFactory: '@chill_main.paginator_factory'
|
||||
|
||||
chill_main.paginator.twig_extensions:
|
||||
|
17
src/Bundle/ChillMainBundle/config/services/serializer.yaml
Normal file
17
src/Bundle/ChillMainBundle/config/services/serializer.yaml
Normal file
@@ -0,0 +1,17 @@
|
||||
---
|
||||
services:
|
||||
Chill\MainBundle\Serializer\Normalizer\CenterNormalizer:
|
||||
tags:
|
||||
- { name: 'serializer.normalizer', priority: 64 }
|
||||
|
||||
Chill\MainBundle\Serializer\Normalizer\DateNormalizer:
|
||||
tags:
|
||||
- { name: 'serializer.normalizer', priority: 64 }
|
||||
|
||||
Chill\MainBundle\Serializer\Normalizer\UserNormalizer:
|
||||
tags:
|
||||
- { name: 'serializer.normalizer', priority: 64 }
|
||||
|
||||
Chill\MainBundle\Serializer\Normalizer\CollectionNormalizer:
|
||||
tags:
|
||||
- { name: 'serializer.normalizer', priority: 64 }
|
@@ -0,0 +1,32 @@
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
namespace Chill\Migrations\Main;
|
||||
|
||||
use Doctrine\DBAL\Schema\Schema;
|
||||
use Doctrine\Migrations\AbstractMigration;
|
||||
|
||||
/**
|
||||
* Create the postgis extension
|
||||
*/
|
||||
final class Version20210414091001 extends AbstractMigration
|
||||
{
|
||||
public function up(Schema $schema) : void
|
||||
{
|
||||
$this->abortIf($this->connection->getDatabasePlatform()->getName() !== 'postgresql', 'Migration can only be executed safely on \'postgresql\'.');
|
||||
|
||||
$this->addSql('CREATE EXTENSION IF NOT EXISTS postgis;');
|
||||
|
||||
}
|
||||
|
||||
public function down(Schema $schema) : void
|
||||
{
|
||||
$this->abortIf($this->connection->getDatabasePlatform()->getName() !== 'postgresql', 'Migration can only be executed safely on \'postgresql\'.');
|
||||
|
||||
$this->addSql('DROP EXTENSION IF NOT EXISTS postgis;');
|
||||
}
|
||||
|
||||
public function getDescription(): string
|
||||
{
|
||||
return "Enable the postgis extension in public schema";
|
||||
}
|
||||
}
|
@@ -0,0 +1,50 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Chill\Migrations\Main;
|
||||
|
||||
use Doctrine\DBAL\Schema\Schema;
|
||||
use Doctrine\Migrations\AbstractMigration;
|
||||
|
||||
/**
|
||||
* Add new fields to address, including a Point geometry field.
|
||||
*/
|
||||
final class Version20210420115006 extends AbstractMigration
|
||||
{
|
||||
public function getDescription() : string
|
||||
{
|
||||
return 'Add a Point data type and modify the Address entity';
|
||||
}
|
||||
|
||||
public function up(Schema $schema) : void
|
||||
{
|
||||
$this->addSql('ALTER TABLE chill_main_address RENAME COLUMN streetaddress1 TO street;');
|
||||
$this->addSql('ALTER TABLE chill_main_address RENAME COLUMN streetaddress2 TO streetNumber;');
|
||||
$this->addSql('ALTER TABLE chill_main_address ADD floor VARCHAR(16) DEFAULT NULL');
|
||||
$this->addSql('ALTER TABLE chill_main_address ADD corridor VARCHAR(16) DEFAULT NULL');
|
||||
$this->addSql('ALTER TABLE chill_main_address ADD steps VARCHAR(16) DEFAULT NULL');
|
||||
$this->addSql('ALTER TABLE chill_main_address ADD buildingName VARCHAR(255) DEFAULT NULL');
|
||||
$this->addSql('ALTER TABLE chill_main_address ADD flat VARCHAR(16) DEFAULT NULL');
|
||||
$this->addSql('ALTER TABLE chill_main_address ADD distribution VARCHAR(255) DEFAULT NULL');
|
||||
$this->addSql('ALTER TABLE chill_main_address ADD extra VARCHAR(255) DEFAULT NULL');
|
||||
$this->addSql('ALTER TABLE chill_main_address ADD validTo DATE DEFAULT NULL');
|
||||
$this->addSql('ALTER TABLE chill_main_address ADD point geometry(POINT,4326) DEFAULT NULL');
|
||||
}
|
||||
|
||||
|
||||
public function down(Schema $schema) : void
|
||||
{
|
||||
$this->addSql('ALTER TABLE chill_main_address RENAME COLUMN street TO streetaddress1;');
|
||||
$this->addSql('ALTER TABLE chill_main_address RENAME COLUMN streetNumber TO streetaddress2;');
|
||||
$this->addSql('ALTER TABLE chill_main_address DROP floor');
|
||||
$this->addSql('ALTER TABLE chill_main_address DROP corridor');
|
||||
$this->addSql('ALTER TABLE chill_main_address DROP steps');
|
||||
$this->addSql('ALTER TABLE chill_main_address DROP buildingName');
|
||||
$this->addSql('ALTER TABLE chill_main_address DROP flat');
|
||||
$this->addSql('ALTER TABLE chill_main_address DROP distribution');
|
||||
$this->addSql('ALTER TABLE chill_main_address DROP extra');
|
||||
$this->addSql('ALTER TABLE chill_main_address DROP validTo');
|
||||
$this->addSql('ALTER TABLE chill_main_address DROP point');
|
||||
}
|
||||
}
|
@@ -0,0 +1,33 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Chill\Migrations\Main;
|
||||
|
||||
use Doctrine\DBAL\Schema\Schema;
|
||||
use Doctrine\Migrations\AbstractMigration;
|
||||
|
||||
/**
|
||||
* Add a AddressReference table for storing authoritative address data
|
||||
*/
|
||||
final class Version20210503085107 extends AbstractMigration
|
||||
{
|
||||
public function getDescription(): string
|
||||
{
|
||||
return 'Add a AddressReference table for storing authoritative address data';
|
||||
}
|
||||
|
||||
public function up(Schema $schema): void
|
||||
{
|
||||
$this->addSql('CREATE SEQUENCE chill_main_address_reference_id_seq INCREMENT BY 1 MINVALUE 1 START 1');
|
||||
$this->addSql('CREATE TABLE chill_main_address_reference (id INT NOT NULL, postcode_id INT DEFAULT NULL, refId VARCHAR(255) NOT NULL, street VARCHAR(255) DEFAULT NULL, streetNumber VARCHAR(255) DEFAULT NULL, municipalityCode VARCHAR(255) DEFAULT NULL, source VARCHAR(255) DEFAULT NULL, point geometry(POINT,4326) NOT NULL, PRIMARY KEY(id))');
|
||||
$this->addSql('CREATE INDEX IDX_CA6C1BD7EECBFDF1 ON chill_main_address_reference (postcode_id)');
|
||||
$this->addSql('ALTER TABLE chill_main_address_reference ADD CONSTRAINT FK_CA6C1BD7EECBFDF1 FOREIGN KEY (postcode_id) REFERENCES chill_main_postal_code (id) NOT DEFERRABLE INITIALLY IMMEDIATE');
|
||||
}
|
||||
|
||||
public function down(Schema $schema): void
|
||||
{
|
||||
$this->addSql('DROP SEQUENCE chill_main_address_reference_id_seq CASCADE');
|
||||
$this->addSql('DROP TABLE chill_main_address_reference');
|
||||
}
|
||||
}
|
@@ -0,0 +1,58 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Chill\Migrations\Main;
|
||||
|
||||
use Doctrine\DBAL\Schema\Schema;
|
||||
use Doctrine\Migrations\AbstractMigration;
|
||||
|
||||
/**
|
||||
* Add linkedToThirdParty field to Address
|
||||
*/
|
||||
final class Version20210505153727 extends AbstractMigration
|
||||
{
|
||||
public function getDescription(): string
|
||||
{
|
||||
return 'Add linkedToThirdParty field to Address';
|
||||
}
|
||||
|
||||
public function up(Schema $schema): void
|
||||
{
|
||||
$this->addSql('ALTER TABLE chill_main_address ADD linkedToThirdParty_id INT DEFAULT NULL');
|
||||
$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');
|
||||
$this->addSql('CREATE INDEX IDX_165051F6114B8DD9 ON chill_main_address (linkedToThirdParty_id)');
|
||||
$this->addSql('
|
||||
CREATE TABLE chill_main_address_legacy AS
|
||||
TABLE chill_main_address;
|
||||
');
|
||||
$this->addSql('
|
||||
WITH hydrated_addresses AS (
|
||||
SELECT *, rank() OVER (PARTITION BY pa_a.person_id ORDER BY validfrom)
|
||||
FROM chill_main_address AS aa JOIN chill_person_persons_to_addresses AS pa_a ON aa.id = pa_a.address_id
|
||||
)
|
||||
UPDATE chill_main_address AS b
|
||||
SET validto = (
|
||||
SELECT validfrom - INTERVAL \'1 DAY\'
|
||||
FROM hydrated_addresses
|
||||
WHERE hydrated_addresses.id = (
|
||||
SELECT a1.id
|
||||
FROM hydrated_addresses AS a1 JOIN hydrated_addresses AS a2 ON a2.person_id = a1.person_id AND a2.rank = (a1.rank-1)
|
||||
WHERE a2.id = b.id
|
||||
)
|
||||
);
|
||||
');
|
||||
}
|
||||
|
||||
public function down(Schema $schema): void
|
||||
{
|
||||
$this->addSql('ALTER TABLE chill_main_address DROP CONSTRAINT FK_165051F6114B8DD9');
|
||||
$this->addSql('DROP INDEX IDX_165051F6114B8DD9');
|
||||
$this->addSql('ALTER TABLE chill_main_address DROP linkedToThirdParty_id');
|
||||
$this->addSql('DROP TABLE IF EXISTS chill_main_address_legacy');
|
||||
$this->addSql('
|
||||
UPDATE chill_main_address
|
||||
SET validto = null;
|
||||
');
|
||||
}
|
||||
}
|
@@ -0,0 +1,79 @@
|
||||
<?php
|
||||
|
||||
namespace Chill\PersonBundle\Controller;
|
||||
|
||||
use Chill\MainBundle\CRUD\Controller\ApiController;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
use Symfony\Component\Routing\Annotation\Route;
|
||||
use Chill\PersonBundle\Entity\AccompanyingPeriod;
|
||||
use Symfony\Component\HttpFoundation\Exception\BadRequestException;
|
||||
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
|
||||
use Symfony\Component\Validator\Validator\ValidatorInterface;
|
||||
use Chill\PersonBundle\Privacy\AccompanyingPeriodPrivacyEvent;
|
||||
use Chill\PersonBundle\Entity\Person;
|
||||
|
||||
class AccompanyingCourseApiController extends ApiController
|
||||
{
|
||||
protected EventDispatcherInterface $eventDispatcher;
|
||||
|
||||
protected ValidatorInterface $validator;
|
||||
|
||||
public function __construct(EventDispatcherInterface $eventDispatcher, $validator)
|
||||
{
|
||||
$this->eventDispatcher = $eventDispatcher;
|
||||
$this->validator = $validator;
|
||||
}
|
||||
|
||||
public function participationApi($id, Request $request, $_format)
|
||||
{
|
||||
/** @var AccompanyingPeriod $accompanyingPeriod */
|
||||
$accompanyingPeriod = $this->getEntity('participation', $id, $request);
|
||||
$person = $this->getSerializer()
|
||||
->deserialize($request->getContent(), Person::class, $_format, []);
|
||||
|
||||
if (NULL === $person) {
|
||||
throw new BadRequestException('person id not found');
|
||||
}
|
||||
|
||||
// TODO add acl
|
||||
//
|
||||
$this->onPostCheckACL('participation', $request, $_format, $accompanyingPeriod);
|
||||
|
||||
switch ($request->getMethod()) {
|
||||
case Request::METHOD_POST:
|
||||
$participation = $accompanyingPeriod->addPerson($person);
|
||||
break;
|
||||
case Request::METHOD_DELETE:
|
||||
$participation = $accompanyingPeriod->removePerson($person);
|
||||
$participation->setEndDate(new \DateTimeImmutable('now'));
|
||||
break;
|
||||
default:
|
||||
throw new BadRequestException("This method is not supported");
|
||||
}
|
||||
|
||||
$errors = $this->validator->validate($accompanyingPeriod);
|
||||
|
||||
if ($errors->count() > 0) {
|
||||
// only format accepted
|
||||
return $this->json($errors);
|
||||
}
|
||||
|
||||
$this->getDoctrine()->getManager()->flush();
|
||||
|
||||
return $this->json($participation);
|
||||
}
|
||||
|
||||
protected function onPostCheckACL(string $action, Request $request, string $_format, $entity): ?Response
|
||||
{
|
||||
$this->eventDispatcher->dispatch(
|
||||
AccompanyingPeriodPrivacyEvent::ACCOMPANYING_PERIOD_PRIVACY_EVENT,
|
||||
new AccompanyingPeriodPrivacyEvent($entity, [
|
||||
'action' => $action,
|
||||
'request' => $request->getMethod()
|
||||
])
|
||||
);
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
@@ -4,17 +4,21 @@ namespace Chill\PersonBundle\Controller;
|
||||
|
||||
use Chill\PersonBundle\Entity\AccompanyingPeriod;
|
||||
use Chill\PersonBundle\Entity\AccompanyingPeriodParticipation;
|
||||
use Chill\PersonBundle\Privacy\AccompanyingPeriodPrivacyEvent;
|
||||
use Chill\PersonBundle\Entity\Person;
|
||||
use Sensio\Bundle\FrameworkExtraBundle\Configuration\ParamConverter;
|
||||
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
|
||||
use Symfony\Component\HttpFoundation\JsonResponse;
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
use Symfony\Component\HttpFoundation\Exception\BadRequestException;
|
||||
use Symfony\Component\Routing\Annotation\Route;
|
||||
use Symfony\Component\Serializer\Encoder\JsonEncoder;
|
||||
use Symfony\Component\Serializer\Normalizer\AbstractObjectNormalizer;
|
||||
use Symfony\Component\Serializer\Normalizer\ObjectNormalizer;
|
||||
use Symfony\Component\Serializer\Serializer;
|
||||
use Symfony\Component\Serializer\SerializerInterface;
|
||||
use Symfony\Contracts\EventDispatcher\EventDispatcherInterface;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
use Symfony\Component\Validator\Validator\ValidatorInterface;
|
||||
|
||||
/**
|
||||
* Class AccompanyingCourseController
|
||||
@@ -23,6 +27,21 @@ use Symfony\Component\Serializer\SerializerInterface;
|
||||
*/
|
||||
class AccompanyingCourseController extends Controller
|
||||
{
|
||||
protected SerializerInterface $serializer;
|
||||
|
||||
protected EventDispatcherInterface $dispatcher;
|
||||
|
||||
protected ValidatorInterface $validator;
|
||||
|
||||
public function __construct(
|
||||
SerializerInterface $serializer,
|
||||
EventDispatcherInterface $dispatcher,
|
||||
ValidatorInterface $validator
|
||||
) {
|
||||
$this->serializer = $serializer;
|
||||
$this->dispatcher = $dispatcher;
|
||||
$this->validator = $validator;
|
||||
}
|
||||
/**
|
||||
* Homepage of Accompanying Course section
|
||||
*
|
||||
@@ -68,45 +87,77 @@ class AccompanyingCourseController extends Controller
|
||||
}
|
||||
|
||||
/**
|
||||
* Sérialise temporairement quelques données pour donner à manger au composant vuejs
|
||||
* Get API Data for showing endpoint
|
||||
*
|
||||
* @Route(
|
||||
* "/{_locale}/api/parcours/{accompanying_period_id}/show",
|
||||
* name="chill_person_accompanying_course_api_show")
|
||||
* "/{_locale}/person/api/1.0/accompanying-course/{accompanying_period_id}/show.{_format}",
|
||||
* name="chill_person_accompanying_course_api_show"
|
||||
* )
|
||||
* @ParamConverter("accompanyingCourse", options={"id": "accompanying_period_id"})
|
||||
* @param SerializerInterface $serializer
|
||||
*/
|
||||
public function showAPI(AccompanyingPeriod $accompanyingCourse): Response
|
||||
public function showAPI(AccompanyingPeriod $accompanyingCourse, $_format): Response
|
||||
{
|
||||
$persons = [];
|
||||
foreach ($accompanyingCourse->getParticipations() as $k => $participation ) {
|
||||
/**
|
||||
* @var AccompanyingPeriodParticipation $participation
|
||||
* @var Person $person
|
||||
*/
|
||||
$person = $participation->getPerson();
|
||||
$persons[$k] = [
|
||||
'id' => $person->getId(),
|
||||
'firstname' => $person->getFirstName(),
|
||||
'lastname' => $person->getLastName(),
|
||||
'email' => $person->getEmail(),
|
||||
'phone' => $person->getPhonenumber(),
|
||||
'startdate' => ($participation->getStartDate()) ? $participation->getStartDate()->format('Y-m-d') : null,
|
||||
'enddate' => ($participation->getEndDate()) ? $participation->getEndDate()->format('Y-m-d') : null
|
||||
];
|
||||
}
|
||||
$data = [
|
||||
'id' => $accompanyingCourse->getId(),
|
||||
'remark' => $accompanyingCourse->getRemark(),
|
||||
'closing_motive' => $accompanyingCourse->getClosingMotive() ? $accompanyingCourse->getClosingMotive()->getName()['fr'] : null,
|
||||
'opening_date' => ($accompanyingCourse->getOpeningDate()) ? $accompanyingCourse->getOpeningDate()->format('Y-m-d') : null,
|
||||
'closing_date' => ($accompanyingCourse->getClosingDate()) ? $accompanyingCourse->getClosingDate()->format('Y-m-d') : null,
|
||||
'persons' => $persons
|
||||
];
|
||||
// TODO check ACL on AccompanyingPeriod
|
||||
|
||||
$this->dispatcher->dispatch(
|
||||
AccompanyingPeriodPrivacyEvent::ACCOMPANYING_PERIOD_PRIVACY_EVENT,
|
||||
new AccompanyingPeriodPrivacyEvent($accompanyingCourse, [
|
||||
'action' => 'showApi'
|
||||
])
|
||||
);
|
||||
|
||||
switch ($_format) {
|
||||
case 'json':
|
||||
return $this->json($accompanyingCourse);
|
||||
default:
|
||||
throw new BadRequestException('Unsupported format');
|
||||
}
|
||||
|
||||
$serialized = \json_encode($data);
|
||||
$response = new Response($serialized);
|
||||
$response->headers->set('Content-Type', 'application/json');
|
||||
return $response;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get API Data for showing endpoint
|
||||
*
|
||||
* @Route(
|
||||
* "/{_locale}/person/api/1.0/accompanying-course/{accompanying_period_id}/participation.{_format}",
|
||||
* name="chill_person_accompanying_course_api_add_participation",
|
||||
* methods={"POST","DELETE"},
|
||||
* format="json",
|
||||
* requirements={
|
||||
* "_format": "json",
|
||||
* }
|
||||
* )
|
||||
* @ParamConverter("accompanyingCourse", options={"id": "accompanying_period_id"})
|
||||
*/
|
||||
public function participationAPI(Request $request, AccompanyingPeriod $accompanyingCourse, $_format): Response
|
||||
{
|
||||
switch ($_format) {
|
||||
case 'json':
|
||||
$person = $this->serializer->deserialize($request->getContent(), Person::class, $_format, [
|
||||
|
||||
]);
|
||||
break;
|
||||
default:
|
||||
throw new BadRequestException('Unsupported format');
|
||||
}
|
||||
|
||||
if (NULL === $person) {
|
||||
throw new BadRequestException('person id not found');
|
||||
}
|
||||
|
||||
// TODO add acl
|
||||
$participation = ($request->getMethod() === 'POST') ?
|
||||
$accompanyingCourse->addPerson($person) : $accompanyingCourse->removePerson($person);
|
||||
|
||||
$errors = $this->validator->validate($accompanyingCourse);
|
||||
|
||||
if ($errors->count() > 0) {
|
||||
// only format accepted
|
||||
return $this->json($errors);
|
||||
}
|
||||
|
||||
$this->getDoctrine()->getManager()->flush();
|
||||
|
||||
return $this->json($participation);
|
||||
}
|
||||
}
|
||||
|
@@ -0,0 +1,30 @@
|
||||
<?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,17 @@
|
||||
<?php
|
||||
|
||||
namespace Chill\PersonBundle\Controller;
|
||||
|
||||
use Chill\MainBundle\CRUD\Controller\ApiController;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
|
||||
class OpeningApiController extends ApiController
|
||||
{
|
||||
protected function customizeQuery(string $action, Request $request, $qb): void
|
||||
{
|
||||
$qb->where($qb->expr()->gt('e.noActiveAfter', ':now'))
|
||||
->orWhere($qb->expr()->isNull('e.noActiveAfter'));
|
||||
$qb->setParameter('now', new \DateTime('now'));
|
||||
}
|
||||
}
|
@@ -39,22 +39,16 @@ use Chill\MainBundle\Search\SearchProvider;
|
||||
use Chill\PersonBundle\Repository\PersonRepository;
|
||||
use Chill\PersonBundle\Config\ConfigPersonAltNamesHelper;
|
||||
use Symfony\Component\Validator\Validator\ValidatorInterface;
|
||||
use Doctrine\ORM\EntityManagerInterface;
|
||||
|
||||
/**
|
||||
* Class PersonController
|
||||
*
|
||||
* @package Chill\PersonBundle\Controller
|
||||
*/
|
||||
class PersonController extends AbstractController
|
||||
final class PersonController extends AbstractController
|
||||
{
|
||||
/**
|
||||
*
|
||||
* @var SimilarPersonMatcher
|
||||
*/
|
||||
protected $similarPersonMatcher;
|
||||
|
||||
/**
|
||||
*
|
||||
* @var TranslatorInterface
|
||||
*/
|
||||
protected $translator;
|
||||
@@ -65,35 +59,39 @@ class PersonController extends AbstractController
|
||||
protected $eventDispatcher;
|
||||
|
||||
/**
|
||||
*
|
||||
* @var PersonRepository;
|
||||
*/
|
||||
protected $personRepository;
|
||||
|
||||
/**
|
||||
*
|
||||
* @var ConfigPersonAltNamesHelper
|
||||
*/
|
||||
protected $configPersonAltNameHelper;
|
||||
|
||||
/**
|
||||
* @var EntityManagerInterface
|
||||
*/
|
||||
private $em;
|
||||
|
||||
/**
|
||||
* @var \Psr\Log\LoggerInterface
|
||||
*/
|
||||
private $logger;
|
||||
|
||||
|
||||
/**
|
||||
* @var ValidatorInterface
|
||||
*/
|
||||
private $validator;
|
||||
|
||||
public function __construct(
|
||||
public function __construct(
|
||||
SimilarPersonMatcher $similarPersonMatcher,
|
||||
TranslatorInterface $translator,
|
||||
EventDispatcherInterface $eventDispatcher,
|
||||
PersonRepository $personRepository,
|
||||
ConfigPersonAltNamesHelper $configPersonAltNameHelper,
|
||||
LoggerInterface $logger,
|
||||
ValidatorInterface $validator
|
||||
ValidatorInterface $validator,
|
||||
EntityManagerInterface $em
|
||||
) {
|
||||
$this->similarPersonMatcher = $similarPersonMatcher;
|
||||
$this->translator = $translator;
|
||||
@@ -102,14 +100,14 @@ class PersonController extends AbstractController
|
||||
$this->personRepository = $personRepository;
|
||||
$this->logger = $logger;
|
||||
$this->validator = $validator;
|
||||
$this->em = $em;
|
||||
}
|
||||
|
||||
public function getCFGroup()
|
||||
{
|
||||
$cFGroup = null;
|
||||
|
||||
$em = $this->getDoctrine()->getManager();
|
||||
$cFDefaultGroup = $em->getRepository("ChillCustomFieldsBundle:CustomFieldsDefaultGroup")
|
||||
$cFDefaultGroup = $this->em->getRepository("ChillCustomFieldsBundle:CustomFieldsDefaultGroup")
|
||||
->findOneByEntity("Chill\PersonBundle\Entity\Person");
|
||||
|
||||
if($cFDefaultGroup) {
|
||||
@@ -198,8 +196,7 @@ class PersonController extends AbstractController
|
||||
->trans('The person data has been updated')
|
||||
);
|
||||
|
||||
$em = $this->getDoctrine()->getManager();
|
||||
$em->flush();
|
||||
$this->em->flush();
|
||||
|
||||
$url = $this->generateUrl('chill_person_view', array(
|
||||
'person_id' => $person->getId()
|
||||
@@ -343,6 +340,8 @@ class PersonController extends AbstractController
|
||||
$this->logger->info('Person created without errors');
|
||||
}
|
||||
|
||||
$this->em->persist($person);
|
||||
|
||||
$alternatePersons = $this->similarPersonMatcher
|
||||
->matchPerson($person);
|
||||
|
||||
@@ -391,11 +390,9 @@ class PersonController extends AbstractController
|
||||
'You are not allowed to create this person');
|
||||
|
||||
if ($errors->count() === 0) {
|
||||
$em = $this->getDoctrine()->getManager();
|
||||
$this->em->persist($person);
|
||||
|
||||
$em->persist($person);
|
||||
|
||||
$em->flush();
|
||||
$this->em->flush();
|
||||
|
||||
return $this->redirect($this->generateUrl('chill_person_general_edit',
|
||||
array('person_id' => $person->getId())));
|
||||
|
@@ -0,0 +1,88 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* Chill is a software for social workers
|
||||
*
|
||||
* Copyright (C) 2014-2015, Champs Libres Cooperative SCRLFS,
|
||||
* <http://www.champs-libres.coop>, <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\DataFixtures\ORM;
|
||||
|
||||
use Doctrine\Common\DataFixtures\AbstractFixture;
|
||||
use Doctrine\Common\DataFixtures\OrderedFixtureInterface;
|
||||
use Doctrine\Persistence\ObjectManager;
|
||||
use Symfony\Component\DependencyInjection\ContainerAwareInterface;
|
||||
|
||||
use Chill\PersonBundle\Entity\AccompanyingPeriod;
|
||||
use Chill\PersonBundle\Entity\Person;
|
||||
|
||||
/**
|
||||
* Description of LoadAccompanyingPeriod
|
||||
*
|
||||
* @author Champs-Libres Coop
|
||||
*/
|
||||
class LoadAccompanyingPeriod extends AbstractFixture implements OrderedFixtureInterface, ContainerAwareInterface
|
||||
{
|
||||
use \Symfony\Component\DependencyInjection\ContainerAwareTrait;
|
||||
|
||||
|
||||
public const ACCOMPANYING_PERIOD = 'parcours 1';
|
||||
|
||||
public function getOrder()
|
||||
{
|
||||
return 10004;
|
||||
}
|
||||
|
||||
public static $references = array();
|
||||
|
||||
public function load(ObjectManager $manager)
|
||||
{
|
||||
|
||||
$centerA = $this->getReference('centerA');
|
||||
$centerAId = $centerA->getId();
|
||||
|
||||
$personIds = $this->container->get('doctrine.orm.entity_manager')
|
||||
->createQueryBuilder()
|
||||
->select('p.id')
|
||||
->from('ChillPersonBundle:Person', 'p')
|
||||
->where('p.center = :centerAId')
|
||||
->orderBy('p.id', 'ASC')
|
||||
->setParameter('centerAId', $centerAId)
|
||||
->getQuery()
|
||||
->getScalarResult();
|
||||
|
||||
$openingDate = new \DateTime('2020-04-01');
|
||||
|
||||
$person1 = $manager->getRepository(Person::class)->find($personIds[0]);
|
||||
$person2 = $manager->getRepository(Person::class)->find($personIds[1]);
|
||||
|
||||
$socialScope = $this->getReference('scope_social');
|
||||
|
||||
$a = new AccompanyingPeriod($openingDate);
|
||||
$a->addPerson($person1);
|
||||
$a->addPerson($person2);
|
||||
$a->addScope($socialScope);
|
||||
$a->setStep(AccompanyingPeriod::STEP_CONFIRMED);
|
||||
|
||||
$manager->persist($a);
|
||||
|
||||
$this->addReference(self::ACCOMPANYING_PERIOD, $a);
|
||||
echo "Adding one AccompanyingPeriod\n";
|
||||
|
||||
$manager->flush();
|
||||
}
|
||||
}
|
@@ -0,0 +1,62 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* Chill is a software for social workers
|
||||
*
|
||||
* Copyright (C) 2014-2015, Champs Libres Cooperative SCRLFS,
|
||||
* <http://www.champs-libres.coop>, <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\DataFixtures\ORM;
|
||||
|
||||
use Doctrine\Common\DataFixtures\AbstractFixture;
|
||||
use Doctrine\Common\DataFixtures\OrderedFixtureInterface;
|
||||
use Doctrine\Persistence\ObjectManager;
|
||||
|
||||
use Chill\PersonBundle\Entity\AccompanyingPeriod\Origin;
|
||||
|
||||
/**
|
||||
* Description of LoadAccompanyingPeriodOrigin
|
||||
*
|
||||
* @author Champs-Libres Coop
|
||||
*/
|
||||
class LoadAccompanyingPeriodOrigin extends AbstractFixture implements OrderedFixtureInterface
|
||||
{
|
||||
|
||||
public const ACCOMPANYING_PERIOD_ORIGIN = 'accompanying_period_origin';
|
||||
|
||||
public function getOrder()
|
||||
{
|
||||
return 10005;
|
||||
}
|
||||
|
||||
private $phoneCall = ['en' => 'phone call', 'fr' => 'appel téléphonique'];
|
||||
|
||||
public static $references = array();
|
||||
|
||||
public function load(ObjectManager $manager)
|
||||
{
|
||||
$o = new Origin();
|
||||
$o->setLabel(json_encode($this->phoneCall));
|
||||
|
||||
$manager->persist($o);
|
||||
|
||||
$this->addReference(self::ACCOMPANYING_PERIOD_ORIGIN, $o);
|
||||
echo "Adding one AccompanyingPeriod Origin\n";
|
||||
|
||||
$manager->flush();
|
||||
}
|
||||
}
|
@@ -29,6 +29,7 @@ use Chill\PersonBundle\Entity\Person;
|
||||
use Symfony\Component\DependencyInjection\ContainerAwareInterface;
|
||||
use Chill\MainBundle\DataFixtures\ORM\LoadPostalCodes;
|
||||
use Chill\MainBundle\Entity\Address;
|
||||
use Chill\MainBundle\Doctrine\Model\Point;
|
||||
|
||||
/**
|
||||
* Load people into database
|
||||
@@ -37,17 +38,17 @@ use Chill\MainBundle\Entity\Address;
|
||||
* @author Marc Ducobu <marc@champs-libres.coop>
|
||||
*/
|
||||
class LoadPeople extends AbstractFixture implements OrderedFixtureInterface, ContainerAwareInterface
|
||||
{
|
||||
|
||||
{
|
||||
|
||||
use \Symfony\Component\DependencyInjection\ContainerAwareTrait;
|
||||
|
||||
|
||||
protected $faker;
|
||||
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->faker = \Faker\Factory::create('fr_FR');
|
||||
}
|
||||
|
||||
|
||||
public function prepare()
|
||||
{
|
||||
//prepare days, month, years
|
||||
@@ -56,57 +57,57 @@ class LoadPeople extends AbstractFixture implements OrderedFixtureInterface, Con
|
||||
$this->years[] = $y;
|
||||
$y = $y +1;
|
||||
} while ($y >= 1990);
|
||||
|
||||
|
||||
$m = 1;
|
||||
do {
|
||||
$this->month[] = $m;
|
||||
$m = $m +1;
|
||||
} while ($m >= 12);
|
||||
|
||||
|
||||
$d = 1;
|
||||
do {
|
||||
$this->day[] = $d;
|
||||
$d = $d + 1;
|
||||
} while ($d <= 28);
|
||||
}
|
||||
|
||||
|
||||
public function getOrder()
|
||||
{
|
||||
return 10000;
|
||||
}
|
||||
|
||||
|
||||
public function load(ObjectManager $manager)
|
||||
{
|
||||
$this->loadRandPeople($manager);
|
||||
$this->loadExpectedPeople($manager);
|
||||
|
||||
|
||||
$manager->flush();
|
||||
}
|
||||
|
||||
|
||||
public function loadExpectedPeople(ObjectManager $manager)
|
||||
{
|
||||
echo "loading expected people...\n";
|
||||
|
||||
|
||||
foreach ($this->peoples as $person) {
|
||||
$this->addAPerson($this->fillWithDefault($person), $manager);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public function loadRandPeople(ObjectManager $manager)
|
||||
{
|
||||
echo "loading rand people...\n";
|
||||
|
||||
|
||||
$this->prepare();
|
||||
|
||||
|
||||
$chooseLastNameOrTri = array('tri', 'tri', 'name', 'tri');
|
||||
|
||||
|
||||
$i = 0;
|
||||
|
||||
|
||||
do {
|
||||
$i++;
|
||||
|
||||
|
||||
$sex = $this->genders[array_rand($this->genders)];
|
||||
|
||||
|
||||
if ($chooseLastNameOrTri[array_rand($chooseLastNameOrTri)] === 'tri' ) {
|
||||
$length = rand(2, 3);
|
||||
$lastName = '';
|
||||
@@ -117,13 +118,13 @@ class LoadPeople extends AbstractFixture implements OrderedFixtureInterface, Con
|
||||
} else {
|
||||
$lastName = $this->lastNames[array_rand($this->lastNames)];
|
||||
}
|
||||
|
||||
|
||||
if ($sex === Person::MALE_GENDER) {
|
||||
$firstName = $this->firstNamesMale[array_rand($this->firstNamesMale)];
|
||||
} else {
|
||||
$firstName = $this->firstNamesFemale[array_rand($this->firstNamesFemale)];
|
||||
}
|
||||
|
||||
|
||||
// add an address on 80% of the created people
|
||||
if (rand(0,100) < 80) {
|
||||
$address = $this->getRandomAddress();
|
||||
@@ -137,7 +138,7 @@ class LoadPeople extends AbstractFixture implements OrderedFixtureInterface, Con
|
||||
} else {
|
||||
$address = null;
|
||||
}
|
||||
|
||||
|
||||
$person = array(
|
||||
'FirstName' => $firstName,
|
||||
'LastName' => $lastName,
|
||||
@@ -147,15 +148,15 @@ class LoadPeople extends AbstractFixture implements OrderedFixtureInterface, Con
|
||||
'Address' => $address,
|
||||
'maritalStatus' => $this->maritalStatusRef[array_rand($this->maritalStatusRef)]
|
||||
);
|
||||
|
||||
|
||||
$this->addAPerson($this->fillWithDefault($person), $manager);
|
||||
|
||||
|
||||
} while ($i <= 100);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* fill a person array with default value
|
||||
*
|
||||
*
|
||||
* @param string[] $specific
|
||||
*/
|
||||
private function fillWithDefault(array $specific)
|
||||
@@ -171,10 +172,10 @@ class LoadPeople extends AbstractFixture implements OrderedFixtureInterface, Con
|
||||
'Address' => null
|
||||
), $specific);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* create a new person from array data
|
||||
*
|
||||
*
|
||||
* @param array $person
|
||||
* @param ObjectManager $manager
|
||||
* @throws \Exception
|
||||
@@ -200,35 +201,51 @@ class LoadPeople extends AbstractFixture implements OrderedFixtureInterface, Con
|
||||
$this->addAccompanyingPeriods($p, $value, $manager);
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
//try to add the data using the setSomething function,
|
||||
// if not possible, fallback to addSomething function
|
||||
if (method_exists($p, 'set'.$key)) {
|
||||
call_user_func(array($p, 'set'.$key), $value);
|
||||
} elseif (method_exists($p, 'add'.$key)) {
|
||||
// if we have a "addSomething", we may have multiple items to add
|
||||
// so, we set the value in an array if it is not an array, and
|
||||
// so, we set the value in an array if it is not an array, and
|
||||
// will call the function addSomething multiple times
|
||||
if (!is_array($value)) {
|
||||
$value = array($value);
|
||||
}
|
||||
|
||||
|
||||
foreach($value as $v) {
|
||||
if ($v !== NULL) {
|
||||
call_user_func(array($p, 'add'.$key), $v);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
$manager->persist($p);
|
||||
echo "add person'".$p->__toString()."'\n";
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Creata a random address
|
||||
*
|
||||
* Create a random point
|
||||
*
|
||||
* @return Point
|
||||
*/
|
||||
private function getRandomPoint()
|
||||
{
|
||||
$lonBrussels = 4.35243;
|
||||
$latBrussels = 50.84676;
|
||||
$lon = $lonBrussels + 0.01 * rand(-5, 5);
|
||||
$lat = $latBrussels + 0.01 * rand(-5, 5);
|
||||
return Point::fromLonLat($lon, $lat);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Create a random address
|
||||
*
|
||||
* @return Address
|
||||
*/
|
||||
private function getRandomAddress()
|
||||
@@ -238,13 +255,16 @@ class LoadPeople extends AbstractFixture implements OrderedFixtureInterface, Con
|
||||
->setStreetAddress2(
|
||||
rand(0,9) > 5 ? $this->faker->streetAddress : ''
|
||||
)
|
||||
->setPoint(
|
||||
rand(0,9) > 5 ? $this->getRandomPoint() : NULL
|
||||
)
|
||||
->setPostcode($this->getReference(
|
||||
LoadPostalCodes::$refs[array_rand(LoadPostalCodes::$refs)]
|
||||
))
|
||||
->setValidFrom($this->faker->dateTimeBetween('-5 years'))
|
||||
;
|
||||
}
|
||||
|
||||
|
||||
private function getCountry($countryCode)
|
||||
{
|
||||
if ($countryCode === NULL) {
|
||||
@@ -257,30 +277,30 @@ class LoadPeople extends AbstractFixture implements OrderedFixtureInterface, Con
|
||||
|
||||
private $maritalStatusRef = ['ms_single', 'ms_married', 'ms_widow', 'ms_separat',
|
||||
'ms_divorce', 'ms_legalco', 'ms_unknown'];
|
||||
|
||||
|
||||
private $firstNamesMale = array("Jean", "Mohamed", "Alfred", "Robert", "Justin", "Brian",
|
||||
"Compère", "Jean-de-Dieu", "Charles", "Pierre", "Luc", "Mathieu", "Alain", "Etienne", "Eric",
|
||||
"Corentin", "Gaston", "Spirou", "Fantasio", "Mahmadou", "Mohamidou", "Vursuv", "Youssef" );
|
||||
|
||||
|
||||
private $firstNamesFemale = array("Svedana", "Sevlatina", "Irène", "Marcelle",
|
||||
"Corentine", "Alfonsine", "Caroline", "Solange", "Gostine", "Fatoumata", "Nicole",
|
||||
"Groseille", "Chana", "Oxana", "Ivana", "Julie", "Tina", "Adèle" );
|
||||
|
||||
|
||||
private $lastNames = array("Diallo", "Bah", "Gaillot", "Martin");
|
||||
|
||||
|
||||
private $lastNamesTrigrams = array("fas", "tré", "hu", 'blart', 'van', 'der', 'lin', 'den',
|
||||
'ta', 'mi', 'net', 'gna', 'bol', 'sac', 'ré', 'jo', 'du', 'pont', 'cas', 'tor', 'rob', 'al',
|
||||
'ma', 'gone', 'car',"fu", "ka", "lot", "no", "va", "du", "bu", "su", "jau", "tte", 'sir',
|
||||
"lo", 'to', "cho", "car", 'mo','zu', 'qi', 'mu');
|
||||
|
||||
|
||||
private $genders = array(Person::MALE_GENDER, Person::FEMALE_GENDER);
|
||||
|
||||
|
||||
private $years = array();
|
||||
|
||||
|
||||
private $month = array();
|
||||
|
||||
|
||||
private $day = array();
|
||||
|
||||
|
||||
private $peoples = array(
|
||||
array(
|
||||
'LastName' => "Depardieu",
|
||||
@@ -362,21 +382,21 @@ class LoadPeople extends AbstractFixture implements OrderedFixtureInterface, Con
|
||||
'maritalStatus' => 'ms_legalco'
|
||||
),
|
||||
);
|
||||
|
||||
|
||||
|
||||
|
||||
private function addAccompanyingPeriods(Person $person, array $periods, ObjectManager $manager)
|
||||
{
|
||||
foreach ($periods as $period) {
|
||||
|
||||
|
||||
echo "adding new past Accompanying Period..\n";
|
||||
|
||||
|
||||
/** @var AccompanyingPeriod $accompanyingPeriod */
|
||||
$accompanyingPeriod = new AccompanyingPeriod(new \DateTime($period['from']));
|
||||
$accompanyingPeriod
|
||||
->setClosingDate(new \DateTime($period['to']))
|
||||
->setRemark($period['remark'])
|
||||
;
|
||||
|
||||
|
||||
$person->addAccompanyingPeriod($accompanyingPeriod);
|
||||
}
|
||||
}
|
||||
|
@@ -25,6 +25,7 @@ use Doctrine\Persistence\ObjectManager;
|
||||
use Chill\MainBundle\DataFixtures\ORM\LoadPermissionsGroup;
|
||||
use Chill\MainBundle\Entity\RoleScope;
|
||||
use Chill\PersonBundle\Security\Authorization\PersonVoter;
|
||||
use Chill\PersonBundle\Security\Authorization\AccompanyingPeriodVoter;
|
||||
|
||||
/**
|
||||
* Add a role CHILL_PERSON_UPDATE & CHILL_PERSON_CREATE for all groups except administrative,
|
||||
@@ -44,6 +45,7 @@ class LoadPersonACL extends AbstractFixture implements OrderedFixtureInterface
|
||||
{
|
||||
foreach (LoadPermissionsGroup::$refs as $permissionsGroupRef) {
|
||||
$permissionsGroup = $this->getReference($permissionsGroupRef);
|
||||
$scopeSocial = $this->getReference('scope_social');
|
||||
|
||||
//create permission group
|
||||
switch ($permissionsGroup->getName()) {
|
||||
@@ -51,6 +53,12 @@ class LoadPersonACL extends AbstractFixture implements OrderedFixtureInterface
|
||||
case 'direction':
|
||||
printf("Adding CHILL_PERSON_UPDATE & CHILL_PERSON_CREATE to %s permission group \n", $permissionsGroup->getName());
|
||||
|
||||
$permissionsGroup->addRoleScope(
|
||||
(new RoleScope())
|
||||
->setRole(AccompanyingPeriodVoter::SEE)
|
||||
->setScope($scopeSocial)
|
||||
);
|
||||
|
||||
$roleScopeUpdate = (new RoleScope())
|
||||
->setRole('CHILL_PERSON_UPDATE')
|
||||
->setScope(null);
|
||||
|
@@ -28,6 +28,7 @@ use Chill\MainBundle\DependencyInjection\MissingBundleException;
|
||||
use Chill\PersonBundle\Security\Authorization\PersonVoter;
|
||||
use Chill\MainBundle\Security\Authorization\ChillExportVoter;
|
||||
use Chill\PersonBundle\Doctrine\DQL\AddressPart;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
|
||||
/**
|
||||
* Class ChillPersonExtension
|
||||
@@ -38,7 +39,7 @@ use Chill\PersonBundle\Doctrine\DQL\AddressPart;
|
||||
*/
|
||||
class ChillPersonExtension extends Extension implements PrependExtensionInterface
|
||||
{
|
||||
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
* @param array $configs
|
||||
@@ -49,14 +50,14 @@ class ChillPersonExtension extends Extension implements PrependExtensionInterfac
|
||||
{
|
||||
$configuration = new Configuration();
|
||||
$config = $this->processConfiguration($configuration, $configs);
|
||||
|
||||
|
||||
// set configuration for validation
|
||||
$container->setParameter('chill_person.validation.birtdate_not_before',
|
||||
$config['validation']['birthdate_not_after']);
|
||||
|
||||
|
||||
$this->handlePersonFieldsParameters($container, $config['person_fields']);
|
||||
$this->handleAccompanyingPeriodsFieldsParameters($container, $config['accompanying_periods_fields']);
|
||||
|
||||
|
||||
$container->setParameter('chill_person.allow_multiple_simultaneous_accompanying_periods',
|
||||
$config['allow_multiple_simultaneous_accompanying_periods']);
|
||||
|
||||
@@ -75,19 +76,21 @@ class ChillPersonExtension extends Extension implements PrependExtensionInterfac
|
||||
$loader->load('services/repository.yaml');
|
||||
$loader->load('services/templating.yaml');
|
||||
$loader->load('services/alt_names.yaml');
|
||||
|
||||
$loader->load('services/serializer.yaml');
|
||||
$loader->load('services/security.yaml');
|
||||
|
||||
// load service advanced search only if configure
|
||||
if ($config['search']['search_by_phone'] != 'never') {
|
||||
$loader->load('services/search_by_phone.yaml');
|
||||
$container->setParameter('chill_person.search.search_by_phone',
|
||||
$config['search']['search_by_phone']);
|
||||
}
|
||||
|
||||
|
||||
if ($container->getParameter('chill_person.accompanying_period') !== 'hidden') {
|
||||
$loader->load('services/exports_accompanying_period.yaml');
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param ContainerBuilder $container
|
||||
* @param $config
|
||||
@@ -97,9 +100,9 @@ class ChillPersonExtension extends Extension implements PrependExtensionInterfac
|
||||
if (array_key_exists('enabled', $config)) {
|
||||
unset($config['enabled']);
|
||||
}
|
||||
|
||||
|
||||
$container->setParameter('chill_person.person_fields', $config);
|
||||
|
||||
|
||||
foreach ($config as $key => $value) {
|
||||
switch($key) {
|
||||
case 'accompanying_period':
|
||||
@@ -111,7 +114,7 @@ class ChillPersonExtension extends Extension implements PrependExtensionInterfac
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param ContainerBuilder $container
|
||||
* @param $config
|
||||
@@ -119,7 +122,7 @@ class ChillPersonExtension extends Extension implements PrependExtensionInterfac
|
||||
private function handleAccompanyingPeriodsFieldsParameters(ContainerBuilder $container, $config)
|
||||
{
|
||||
$container->setParameter('chill_person.accompanying_period_fields', $config);
|
||||
|
||||
|
||||
foreach ($config as $key => $value) {
|
||||
switch($key) {
|
||||
case 'enabled':
|
||||
@@ -130,7 +133,7 @@ class ChillPersonExtension extends Extension implements PrependExtensionInterfac
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param ContainerBuilder $container
|
||||
* @throws MissingBundleException
|
||||
@@ -150,7 +153,7 @@ class ChillPersonExtension extends Extension implements PrependExtensionInterfac
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param ContainerBuilder $container
|
||||
* @throws MissingBundleException
|
||||
@@ -161,7 +164,7 @@ class ChillPersonExtension extends Extension implements PrependExtensionInterfac
|
||||
$this->prependHomepageWidget($container);
|
||||
$this->prependDoctrineDQL($container);
|
||||
$this->prependCruds($container);
|
||||
|
||||
|
||||
//add person_fields parameter as global
|
||||
$chillPersonConfig = $container->getExtensionConfig($this->getAlias());
|
||||
$config = $this->processConfiguration(new Configuration(), $chillPersonConfig);
|
||||
@@ -179,7 +182,7 @@ class ChillPersonExtension extends Extension implements PrependExtensionInterfac
|
||||
$container->prependExtensionConfig('twig', $twigConfig);
|
||||
|
||||
$this-> declarePersonAsCustomizable($container);
|
||||
|
||||
|
||||
//declare routes for person bundle
|
||||
$container->prependExtensionConfig('chill_main', array(
|
||||
'routing' => array(
|
||||
@@ -189,7 +192,7 @@ class ChillPersonExtension extends Extension implements PrependExtensionInterfac
|
||||
)
|
||||
));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Add a widget "add a person" on the homepage, automatically
|
||||
*
|
||||
@@ -208,7 +211,7 @@ class ChillPersonExtension extends Extension implements PrependExtensionInterfac
|
||||
)
|
||||
));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Add role hierarchy.
|
||||
*
|
||||
@@ -225,7 +228,7 @@ class ChillPersonExtension extends Extension implements PrependExtensionInterfac
|
||||
)
|
||||
));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Add DQL function linked with person
|
||||
*
|
||||
@@ -234,7 +237,7 @@ class ChillPersonExtension extends Extension implements PrependExtensionInterfac
|
||||
protected function prependDoctrineDQL(ContainerBuilder $container)
|
||||
{
|
||||
//add DQL function to ORM (default entity_manager)
|
||||
|
||||
|
||||
$container->prependExtensionConfig('doctrine', array(
|
||||
'orm' => array(
|
||||
'dql' => array(
|
||||
@@ -257,7 +260,7 @@ class ChillPersonExtension extends Extension implements PrependExtensionInterfac
|
||||
)
|
||||
));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param ContainerBuilder $container
|
||||
*/
|
||||
@@ -306,6 +309,55 @@ class ChillPersonExtension extends Extension implements PrependExtensionInterfac
|
||||
'template' => '@ChillPerson/MaritalStatus/edit.html.twig',
|
||||
]
|
||||
]
|
||||
],
|
||||
],
|
||||
'apis' => [
|
||||
[
|
||||
'class' => \Chill\PersonBundle\Entity\AccompanyingPeriod::class,
|
||||
'name' => 'accompanying_course',
|
||||
'base_path' => '/api/1.0/person/accompanying-course',
|
||||
'controller' => \Chill\PersonBundle\Controller\AccompanyingCourseApiController::class,
|
||||
'actions' => [
|
||||
'_entity' => [
|
||||
'roles' => [
|
||||
Request::METHOD_GET => \Chill\PersonBundle\Security\Authorization\AccompanyingPeriodVoter::SEE
|
||||
]
|
||||
],
|
||||
'participation' => [
|
||||
'methods' => [
|
||||
Request::METHOD_POST => true,
|
||||
Request::METHOD_DELETE => true,
|
||||
Request::METHOD_GET => false,
|
||||
Request::METHOD_HEAD => false,
|
||||
],
|
||||
'roles' => [
|
||||
Request::METHOD_POST => \Chill\PersonBundle\Security\Authorization\AccompanyingPeriodVoter::SEE,
|
||||
Request::METHOD_DELETE=> \Chill\PersonBundle\Security\Authorization\AccompanyingPeriodVoter::SEE
|
||||
]
|
||||
]
|
||||
|
||||
]
|
||||
],
|
||||
[
|
||||
'class' => \Chill\PersonBundle\Entity\AccompanyingPeriod\Origin::class,
|
||||
'name' => 'accompanying_period_origin',
|
||||
'base_path' => '/api/1.0/person/accompanying-period/origin',
|
||||
'controller' => \Chill\PersonBundle\Controller\OpeningApiController::class,
|
||||
'base_role' => 'ROLE_USER',
|
||||
'actions' => [
|
||||
'_index' => [
|
||||
'methods' => [
|
||||
Request::METHOD_GET => true,
|
||||
Request::METHOD_HEAD => true
|
||||
],
|
||||
],
|
||||
'_entity' => [
|
||||
'methods' => [
|
||||
Request::METHOD_GET => true,
|
||||
Request::METHOD_HEAD => true
|
||||
]
|
||||
],
|
||||
]
|
||||
]
|
||||
]
|
||||
]);
|
||||
|
@@ -103,7 +103,7 @@ class AccompanyingPeriod
|
||||
* @ORM\Column(type="text")
|
||||
*/
|
||||
private $remark = '';
|
||||
|
||||
|
||||
/**
|
||||
* @var Collection
|
||||
*
|
||||
@@ -112,16 +112,16 @@ class AccompanyingPeriod
|
||||
* )
|
||||
*/
|
||||
private $comments;
|
||||
|
||||
|
||||
/**
|
||||
* @var Collection
|
||||
*
|
||||
* @ORM\OneToMany(targetEntity=AccompanyingPeriodParticipation::class,
|
||||
* mappedBy="accompanyingPeriod",
|
||||
* cascade={"persist", "remove", "merge", "detach"})
|
||||
* cascade={"persist", "refresh", "remove", "merge", "detach"})
|
||||
*/
|
||||
private $participations;
|
||||
|
||||
|
||||
/**
|
||||
* @var AccompanyingPeriod\ClosingMotive
|
||||
*
|
||||
@@ -130,19 +130,19 @@ class AccompanyingPeriod
|
||||
* @ORM\JoinColumn(nullable=true)
|
||||
*/
|
||||
private $closingMotive = null;
|
||||
|
||||
|
||||
/**
|
||||
* @ORM\ManyToOne(targetEntity=User::class)
|
||||
* @ORM\JoinColumn(nullable=true)
|
||||
*/
|
||||
private $user;
|
||||
|
||||
|
||||
/**
|
||||
* @ORM\ManyToOne(targetEntity=User::class)
|
||||
* @ORM\JoinColumn(nullable=true)
|
||||
*/
|
||||
private $createdBy;
|
||||
|
||||
|
||||
/**
|
||||
* @var string
|
||||
* @ORM\Column(type="string", length=32, nullable=true)
|
||||
@@ -154,7 +154,7 @@ class AccompanyingPeriod
|
||||
* @ORM\JoinColumn(nullable=true)
|
||||
*/
|
||||
private $origin;
|
||||
|
||||
|
||||
/**
|
||||
* @var string
|
||||
* @ORM\Column(type="string", nullable=true)
|
||||
@@ -214,7 +214,7 @@ class AccompanyingPeriod
|
||||
* )
|
||||
*/
|
||||
private $resources;
|
||||
|
||||
|
||||
/**
|
||||
* AccompanyingPeriod constructor.
|
||||
*
|
||||
@@ -246,7 +246,7 @@ class AccompanyingPeriod
|
||||
public function setOpeningDate($openingDate)
|
||||
{
|
||||
$this->openingDate = $openingDate;
|
||||
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
@@ -272,7 +272,7 @@ class AccompanyingPeriod
|
||||
public function setClosingDate($closingDate)
|
||||
{
|
||||
$this->closingDate = $closingDate;
|
||||
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
@@ -285,7 +285,7 @@ class AccompanyingPeriod
|
||||
{
|
||||
return $this->closingDate;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return boolean
|
||||
*/
|
||||
@@ -298,43 +298,43 @@ class AccompanyingPeriod
|
||||
if ($this->getClosingDate() === null) {
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
public function setRemark(string $remark): self
|
||||
{
|
||||
if ($remark === null) {
|
||||
$remark = '';
|
||||
}
|
||||
|
||||
|
||||
$this->remark = $remark;
|
||||
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
|
||||
public function getRemark(): string
|
||||
{
|
||||
return $this->remark;
|
||||
}
|
||||
|
||||
|
||||
public function getComments(): Collection
|
||||
{
|
||||
return $this->comments;
|
||||
}
|
||||
|
||||
|
||||
public function addComment(Comment $comment): self
|
||||
{
|
||||
$this->comments[] = $comment;
|
||||
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
|
||||
public function removeComment(Comment $comment): void
|
||||
{
|
||||
$this->comments->removeElement($comment);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get Participations Collection
|
||||
*/
|
||||
@@ -342,67 +342,85 @@ class AccompanyingPeriod
|
||||
{
|
||||
return $this->participations;
|
||||
}
|
||||
|
||||
/**
|
||||
* This private function scan Participations Collection,
|
||||
* searching for a given Person
|
||||
*/
|
||||
private function participationsContainsPerson(Person $person): ?AccompanyingPeriodParticipation
|
||||
{
|
||||
foreach ($this->participations as $participation) {
|
||||
/** @var AccompanyingPeriodParticipation $participation */
|
||||
if ($person === $participation->getPerson()) {
|
||||
return $participation;
|
||||
}}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* This public function is the same but return only true or false
|
||||
* Get the participation containing a person
|
||||
*/
|
||||
public function getParticipationsContainsPerson(Person $person): Collection
|
||||
{
|
||||
return $this->getParticipations($person)->filter(
|
||||
function(AccompanyingPeriodParticipation $participation) use ($person) {
|
||||
if ($person === $participation->getPerson()) {
|
||||
return $participation;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the opened participation containing a person
|
||||
*
|
||||
* "Open" means that the closed date is NULL
|
||||
*/
|
||||
public function getOpenParticipationContainsPerson(Person $person): ?AccompanyingPeriodParticipation
|
||||
{
|
||||
$collection = $this->getParticipationsContainsPerson($person)->filter(
|
||||
function(AccompanyingPeriodParticipation $participation) use ($person) {
|
||||
if (NULL === $participation->getEndDate()) {
|
||||
return $participation;
|
||||
}
|
||||
});
|
||||
|
||||
return $collection->count() > 0 ? $collection->first() : NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if the accompanying period contains a person.
|
||||
*
|
||||
* **Note**: this participation can be opened or not.
|
||||
*/
|
||||
public function containsPerson(Person $person): bool
|
||||
{
|
||||
return ($this->participationsContainsPerson($person) === null) ? false : true;
|
||||
return $this->getParticipationsContainsPerson($person)->count() > 0;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Add Person
|
||||
*/
|
||||
public function addPerson(Person $person = null): self
|
||||
public function addPerson(Person $person = null): AccompanyingPeriodParticipation
|
||||
{
|
||||
$participation = new AccompanyingPeriodParticipation($this, $person);
|
||||
$this->participations[] = $participation;
|
||||
|
||||
return $this;
|
||||
|
||||
return $participation;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Remove Person
|
||||
*/
|
||||
public function removePerson(Person $person): void
|
||||
public function removePerson(Person $person): ?AccompanyingPeriodParticipation
|
||||
{
|
||||
$participation = $this->participationsContainsPerson($person);
|
||||
|
||||
if (! null === $participation) {
|
||||
$participation = $this->getOpenParticipationContainsPerson($person);
|
||||
|
||||
if ($participation instanceof AccompanyingPeriodParticipation) {
|
||||
$participation->setEndDate(new \DateTimeImmutable('now'));
|
||||
$this->participations->removeElement($participation);
|
||||
}
|
||||
|
||||
return $participation;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
public function getClosingMotive(): ?ClosingMotive
|
||||
{
|
||||
return $this->closingMotive;
|
||||
}
|
||||
|
||||
|
||||
public function setClosingMotive(ClosingMotive $closingMotive = null): self
|
||||
{
|
||||
$this->closingMotive = $closingMotive;
|
||||
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* If the period can be reopened.
|
||||
*
|
||||
@@ -414,7 +432,7 @@ class AccompanyingPeriod
|
||||
if ($this->isOpen() === true) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
$participation = $this->participationsContainsPerson($person);
|
||||
if (!null === $participation)
|
||||
{
|
||||
@@ -422,10 +440,10 @@ class AccompanyingPeriod
|
||||
$periods = $person->getAccompanyingPeriodsOrdered();
|
||||
return end($periods) === $this;
|
||||
}
|
||||
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*/
|
||||
public function reOpen(): void
|
||||
@@ -442,14 +460,14 @@ class AccompanyingPeriod
|
||||
if ($this->isOpen()) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
if (! $this->isClosingAfterOpening()) {
|
||||
$context->buildViolation('The date of closing is before the date of opening')
|
||||
->atPath('dateClosing')
|
||||
->addViolation();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns true if the closing date is after the opening date.
|
||||
*
|
||||
@@ -467,16 +485,16 @@ class AccompanyingPeriod
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
function getUser(): ?User
|
||||
{
|
||||
return $this->user;
|
||||
}
|
||||
|
||||
|
||||
function setUser(User $user): self
|
||||
{
|
||||
$this->user = $user;
|
||||
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
@@ -484,38 +502,38 @@ class AccompanyingPeriod
|
||||
{
|
||||
return $this->origin;
|
||||
}
|
||||
|
||||
|
||||
public function setOrigin(Origin $origin): self
|
||||
{
|
||||
$this->origin = $origin;
|
||||
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
|
||||
public function getRequestorPerson(): ?Person
|
||||
{
|
||||
return $this->requestorPerson;
|
||||
}
|
||||
|
||||
|
||||
public function setRequestorPerson(Person $requestorPerson): self
|
||||
{
|
||||
$this->requestorPerson = ($this->requestorThirdParty === null) ? $requestorPerson : null;
|
||||
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
|
||||
public function getRequestorThirdParty(): ?ThirdParty
|
||||
{
|
||||
return $this->requestorThirdParty;
|
||||
}
|
||||
|
||||
|
||||
public function setRequestorThirdParty(ThirdParty $requestorThirdParty): self
|
||||
{
|
||||
$this->requestorThirdParty = ($this->requestorPerson === null) ? $requestorThirdParty : null;
|
||||
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return Person|ThirdParty
|
||||
*/
|
||||
@@ -523,48 +541,48 @@ class AccompanyingPeriod
|
||||
{
|
||||
return $this->requestorPerson ?? $this->requestorThirdParty;
|
||||
}
|
||||
|
||||
|
||||
public function isRequestorAnonymous(): bool
|
||||
{
|
||||
return $this->requestorAnonymous;
|
||||
}
|
||||
|
||||
|
||||
public function setRequestorAnonymous(bool $requestorAnonymous): self
|
||||
{
|
||||
$this->requestorAnonymous = $requestorAnonymous;
|
||||
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
|
||||
public function isEmergency(): bool
|
||||
{
|
||||
return $this->emergency;
|
||||
}
|
||||
|
||||
|
||||
public function setEmergency(bool $emergency): self
|
||||
{
|
||||
$this->emergency = $emergency;
|
||||
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
|
||||
public function isConfidential(): bool
|
||||
{
|
||||
return $this->confidential;
|
||||
}
|
||||
|
||||
|
||||
public function setConfidential(bool $confidential): self
|
||||
{
|
||||
$this->confidential = $confidential;
|
||||
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
|
||||
public function getCreatedBy(): ?User
|
||||
{
|
||||
return $this->createdBy;
|
||||
}
|
||||
|
||||
|
||||
public function setCreatedBy(User $createdBy): self
|
||||
{
|
||||
$this->createdBy = $createdBy;
|
||||
@@ -576,11 +594,11 @@ class AccompanyingPeriod
|
||||
{
|
||||
return $this->step;
|
||||
}
|
||||
|
||||
|
||||
public function setStep(string $step): self
|
||||
{
|
||||
$this->step = $step;
|
||||
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
@@ -588,45 +606,57 @@ class AccompanyingPeriod
|
||||
{
|
||||
return $this->intensity;
|
||||
}
|
||||
|
||||
|
||||
public function setIntensity(string $intensity): self
|
||||
{
|
||||
$this->intensity = $intensity;
|
||||
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
|
||||
public function getScopes(): Collection
|
||||
{
|
||||
return $this->scopes;
|
||||
}
|
||||
|
||||
|
||||
public function addScope(Scope $scope): self
|
||||
{
|
||||
$this->scopes[] = $scope;
|
||||
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
|
||||
public function removeScope(Scope $scope): void
|
||||
{
|
||||
$this->scopes->removeElement($scope);
|
||||
}
|
||||
|
||||
|
||||
public function getResources(): Collection
|
||||
{
|
||||
return $this->resources;
|
||||
}
|
||||
|
||||
|
||||
public function addResource(Resource $resource): self
|
||||
{
|
||||
$this->resources[] = $resource;
|
||||
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
|
||||
public function removeResource(Resource $resource): void
|
||||
{
|
||||
$this->resources->removeElement($resource);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a list of all persons which are participating to this course
|
||||
*/
|
||||
public function getPersons(): Collection
|
||||
{
|
||||
return $this->participations->map(
|
||||
function(AccompanyingPeriodParticipation $participation) {
|
||||
return $participation->getPerson();
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@@ -0,0 +1,309 @@
|
||||
<?php
|
||||
|
||||
namespace Chill\PersonBundle\Entity\AccompanyingPeriod;
|
||||
|
||||
use Chill\PersonBundle\Entity\SocialWork\Result;
|
||||
use Chill\PersonBundle\Entity\SocialWork\SocialAction;
|
||||
use Chill\PersonBundle\Repository\AccompanyingPeriod\AccompanyingPeriodWorkRepository;
|
||||
use Chill\MainBundle\Entity\User;
|
||||
use Chill\PersonBundle\Entity\AccompanyingPeriod;
|
||||
use Chill\ThirdPartyBundle\Entity\ThirdParty;
|
||||
use Doctrine\Common\Collections\ArrayCollection;
|
||||
use Doctrine\Common\Collections\Collection;
|
||||
use Doctrine\ORM\Mapping as ORM;
|
||||
|
||||
/**
|
||||
* @ORM\Entity(repositoryClass=AccompanyingPeriodWorkRepository::class)
|
||||
* @ORM\Table(name="chill_person_accompanying_period_work")
|
||||
*/
|
||||
class AccompanyingPeriodWork
|
||||
{
|
||||
/**
|
||||
* @ORM\Id
|
||||
* @ORM\GeneratedValue
|
||||
* @ORM\Column(type="integer")
|
||||
*/
|
||||
private $id;
|
||||
|
||||
/**
|
||||
* @ORM\Column(type="text")
|
||||
*/
|
||||
private $note;
|
||||
|
||||
/**
|
||||
* @ORM\ManyToOne(targetEntity=AccompanyingPeriod::class)
|
||||
*/
|
||||
private $accompanyingPeriod;
|
||||
|
||||
/**
|
||||
* @ORM\ManyToOne(targetEntity=SocialAction::class)
|
||||
*/
|
||||
private $socialAction;
|
||||
|
||||
/**
|
||||
* @ORM\Column(type="datetime")
|
||||
*/
|
||||
private $createdAt;
|
||||
|
||||
/**
|
||||
* @ORM\ManyToOne(targetEntity=User::class)
|
||||
* @ORM\JoinColumn(nullable=false)
|
||||
*/
|
||||
private $createdBy;
|
||||
|
||||
/**
|
||||
* @ORM\Column(type="datetime")
|
||||
*/
|
||||
private $startDate;
|
||||
|
||||
/**
|
||||
* @ORM\Column(type="datetime")
|
||||
*/
|
||||
private $endDate;
|
||||
|
||||
/**
|
||||
* @ORM\ManyToOne(targetEntity=ThirdParty::class)
|
||||
*
|
||||
* In schema : traitant
|
||||
*/
|
||||
private $handlingThierParty;
|
||||
|
||||
/**
|
||||
* @ORM\Column(type="boolean")
|
||||
*/
|
||||
private $createdAutomatically;
|
||||
|
||||
/**
|
||||
* @ORM\Column(type="text")
|
||||
*/
|
||||
private $createdAutomaticallyReason;
|
||||
|
||||
/**
|
||||
* @ORM\OneToMany(targetEntity=AccompanyingPeriodWorkGoal::class, mappedBy="accompanyingPeriodWork")
|
||||
*/
|
||||
private $goals;
|
||||
|
||||
/**
|
||||
* @ORM\ManyToMany(targetEntity=Result::class, inversedBy="accompanyingPeriodWorks")
|
||||
* @ORM\JoinTable(name="chill_person_accompanying_period_work_result")
|
||||
*/
|
||||
private $results;
|
||||
|
||||
/**
|
||||
* @ORM\ManyToMany(targetEntity=ThirdParty::class)
|
||||
* @ORM\JoinTable(name="chill_person_accompanying_period_work_third_party")
|
||||
*
|
||||
* In schema : intervenants
|
||||
*/
|
||||
private $thirdParties;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->goals = new ArrayCollection();
|
||||
$this->results = new ArrayCollection();
|
||||
$this->thirdParties = new ArrayCollection();
|
||||
}
|
||||
|
||||
public function getId(): ?int
|
||||
{
|
||||
return $this->id;
|
||||
}
|
||||
|
||||
public function getNote(): ?string
|
||||
{
|
||||
return $this->note;
|
||||
}
|
||||
|
||||
public function setNote(string $note): self
|
||||
{
|
||||
$this->note = $note;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getAccompanyingPeriod(): ?AccompanyingPeriod
|
||||
{
|
||||
return $this->accompanyingPeriod;
|
||||
}
|
||||
|
||||
public function setAccompanyingPeriod(?AccompanyingPeriod $accompanyingPeriod): self
|
||||
{
|
||||
$this->accompanyingPeriod = $accompanyingPeriod;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getSocialAction(): ?SocialAction
|
||||
{
|
||||
return $this->socialAction;
|
||||
}
|
||||
|
||||
public function setSocialAction(?SocialAction $socialAction): self
|
||||
{
|
||||
$this->socialAction = $socialAction;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getCreatedAt(): ?\DateTimeInterface
|
||||
{
|
||||
return $this->createdAt;
|
||||
}
|
||||
|
||||
public function setCreatedAt(\DateTimeInterface $createdAt): self
|
||||
{
|
||||
$this->createdAt = $createdAt;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getCreatedBy(): ?User
|
||||
{
|
||||
return $this->createdBy;
|
||||
}
|
||||
|
||||
public function setCreatedBy(?User $createdBy): self
|
||||
{
|
||||
$this->createdBy = $createdBy;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getStartDate(): ?\DateTimeInterface
|
||||
{
|
||||
return $this->startDate;
|
||||
}
|
||||
|
||||
public function setStartDate(\DateTimeInterface $startDate): self
|
||||
{
|
||||
$this->startDate = $startDate;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getEndDate(): ?\DateTimeInterface
|
||||
{
|
||||
return $this->endDate;
|
||||
}
|
||||
|
||||
public function setEndDate(\DateTimeInterface $endDate): self
|
||||
{
|
||||
$this->endDate = $endDate;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getHandlingThierParty(): ?ThirdParty
|
||||
{
|
||||
return $this->handlingThierParty;
|
||||
}
|
||||
|
||||
public function setHandlingThierParty(?ThirdParty $handlingThierParty): self
|
||||
{
|
||||
$this->handlingThierParty = $handlingThierParty;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getCreatedAutomatically(): ?bool
|
||||
{
|
||||
return $this->createdAutomatically;
|
||||
}
|
||||
|
||||
public function setCreatedAutomatically(bool $createdAutomatically): self
|
||||
{
|
||||
$this->createdAutomatically = $createdAutomatically;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getCreatedAutomaticallyReason(): ?string
|
||||
{
|
||||
return $this->createdAutomaticallyReason;
|
||||
}
|
||||
|
||||
public function setCreatedAutomaticallyReason(string $createdAutomaticallyReason): self
|
||||
{
|
||||
$this->createdAutomaticallyReason = $createdAutomaticallyReason;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Collection|AccompanyingPeriodWorkGoal[]
|
||||
*/
|
||||
public function getGoals(): Collection
|
||||
{
|
||||
return $this->goals;
|
||||
}
|
||||
|
||||
public function addGoal(AccompanyingPeriodWorkGoal $goal): self
|
||||
{
|
||||
if (!$this->goals->contains($goal)) {
|
||||
$this->goals[] = $goal;
|
||||
$goal->setAccompanyingPeriodWork2($this);
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function removeGoal(AccompanyingPeriodWorkGoal $goal): self
|
||||
{
|
||||
if ($this->goals->removeElement($goal)) {
|
||||
// set the owning side to null (unless already changed)
|
||||
if ($goal->getAccompanyingPeriodWork2() === $this) {
|
||||
$goal->setAccompanyingPeriodWork2(null);
|
||||
}
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Collection|Result[]
|
||||
*/
|
||||
public function getResults(): Collection
|
||||
{
|
||||
return $this->results;
|
||||
}
|
||||
|
||||
public function addResult(Result $result): self
|
||||
{
|
||||
if (!$this->results->contains($result)) {
|
||||
$this->results[] = $result;
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function removeResult(Result $result): self
|
||||
{
|
||||
$this->results->removeElement($result);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Collection|ThirdParty[]
|
||||
*/
|
||||
public function getThirdParties(): Collection
|
||||
{
|
||||
return $this->thirdParties;
|
||||
}
|
||||
|
||||
public function addThirdParty(ThirdParty $thirdParty): self
|
||||
{
|
||||
if (!$this->thirdParties->contains($thirdParty)) {
|
||||
$this->thirdParties[] = $thirdParty;
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function removeThirdParty(ThirdParty $thirdParty): self
|
||||
{
|
||||
$this->thirdParties->removeElement($thirdParty);
|
||||
|
||||
return $this;
|
||||
}
|
||||
}
|
@@ -0,0 +1,115 @@
|
||||
<?php
|
||||
|
||||
namespace Chill\PersonBundle\Entity\AccompanyingPeriod;
|
||||
|
||||
use Chill\PersonBundle\Entity\SocialWork\Goal;
|
||||
use Chill\PersonBundle\Entity\SocialWork\Result;
|
||||
use Chill\PersonBundle\Repository\AccompanyingPeriod\AccompanyingPeriodWorkGoalRepository;
|
||||
use Doctrine\Common\Collections\ArrayCollection;
|
||||
use Doctrine\Common\Collections\Collection;
|
||||
use Doctrine\ORM\Mapping as ORM;
|
||||
|
||||
/**
|
||||
* @ORM\Entity(repositoryClass=AccompanyingPeriodWorkGoalRepository::class)
|
||||
* @ORM\Table(name="chill_person_accompanying_period_work_goal")
|
||||
*/
|
||||
class AccompanyingPeriodWorkGoal
|
||||
{
|
||||
/**
|
||||
* @ORM\Id
|
||||
* @ORM\GeneratedValue
|
||||
* @ORM\Column(type="integer")
|
||||
*/
|
||||
private $id;
|
||||
|
||||
/**
|
||||
* @ORM\Column(type="text")
|
||||
*/
|
||||
private $note;
|
||||
|
||||
/**
|
||||
* @ORM\ManyToOne(targetEntity=AccompanyingPeriodWork::class, inversedBy="goals")
|
||||
*/
|
||||
private $accompanyingPeriodWork;
|
||||
|
||||
/**
|
||||
* @ORM\ManyToOne(targetEntity=Goal::class)
|
||||
*/
|
||||
private $goal;
|
||||
|
||||
/**
|
||||
* @ORM\ManyToMany(targetEntity=Result::class, inversedBy="accompanyingPeriodWorkGoals")
|
||||
* @ORM\JoinTable(name="chill_person_accompanying_period_work_goal_result")
|
||||
*/
|
||||
private $results;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->results = new ArrayCollection();
|
||||
}
|
||||
|
||||
public function getId(): ?int
|
||||
{
|
||||
return $this->id;
|
||||
}
|
||||
|
||||
public function getNote(): ?string
|
||||
{
|
||||
return $this->note;
|
||||
}
|
||||
|
||||
public function setNote(string $note): self
|
||||
{
|
||||
$this->note = $note;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getAccompanyingPeriodWork(): ?AccompanyingPeriodWork
|
||||
{
|
||||
return $this->accompanyingPeriodWork;
|
||||
}
|
||||
|
||||
public function setAccompanyingPeriodWork(?AccompanyingPeriodWork $accompanyingPeriodWork): self
|
||||
{
|
||||
$this->accompanyingPeriodWork = $accompanyingPeriodWork;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getGoal(): ?Goal
|
||||
{
|
||||
return $this->goal;
|
||||
}
|
||||
|
||||
public function setGoal(?Goal $goal): self
|
||||
{
|
||||
$this->goal = $goal;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Collection|Result[]
|
||||
*/
|
||||
public function getResults(): Collection
|
||||
{
|
||||
return $this->results;
|
||||
}
|
||||
|
||||
public function addResult(Result $result): self
|
||||
{
|
||||
if (!$this->results->contains($result)) {
|
||||
$this->results[] = $result;
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function removeResult(Result $result): self
|
||||
{
|
||||
$this->results->removeElement($result);
|
||||
|
||||
return $this;
|
||||
}
|
||||
}
|
@@ -22,7 +22,7 @@
|
||||
|
||||
namespace Chill\PersonBundle\Entity\AccompanyingPeriod;
|
||||
|
||||
use Chill\PersonBundle\Entity\AccompanyingPeriod\OriginRepository;
|
||||
use Chill\PersonBundle\Repository\AccompanyingPeriod\OriginRepository;
|
||||
use Doctrine\ORM\Mapping as ORM;
|
||||
|
||||
/**
|
||||
@@ -53,7 +53,7 @@ class Origin
|
||||
return $this->id;
|
||||
}
|
||||
|
||||
public function getLabel(): ?string
|
||||
public function getLabel()
|
||||
{
|
||||
return $this->label;
|
||||
}
|
||||
|
70
src/Bundle/ChillPersonBundle/Entity/Household/Household.php
Normal file
70
src/Bundle/ChillPersonBundle/Entity/Household/Household.php
Normal file
@@ -0,0 +1,70 @@
|
||||
<?php
|
||||
|
||||
namespace Chill\PersonBundle\Entity\Household;
|
||||
|
||||
use Chill\PersonBundle\Repository\Household\HouseholdRepository;
|
||||
use Doctrine\ORM\Mapping as ORM;
|
||||
use Doctrine\Common\Collections\Collection;
|
||||
use Chill\MainBundle\Entity\Address;
|
||||
|
||||
/**
|
||||
* @ORM\Entity(repositoryClass=HouseholdRepository::class)
|
||||
*/
|
||||
class Household
|
||||
{
|
||||
/**
|
||||
* @ORM\Id
|
||||
* @ORM\GeneratedValue
|
||||
* @ORM\Column(type="integer")
|
||||
*/
|
||||
private $id;
|
||||
|
||||
public function getId(): ?int
|
||||
{
|
||||
return $this->id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Addresses
|
||||
* @var Collection
|
||||
*
|
||||
* @ORM\ManyToMany(
|
||||
* targetEntity="Chill\MainBundle\Entity\Address",
|
||||
* cascade={"persist", "remove", "merge", "detach"})
|
||||
* @ORM\JoinTable(name="chill_person_household_to_addresses")
|
||||
* @ORM\OrderBy({"validFrom" = "DESC"})
|
||||
*/
|
||||
private $addresses;
|
||||
|
||||
|
||||
/**
|
||||
* @param Address $address
|
||||
* @return $this
|
||||
*/
|
||||
public function addAddress(Address $address)
|
||||
{
|
||||
$this->addresses[] = $address;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Address $address
|
||||
*/
|
||||
public function removeAddress(Address $address)
|
||||
{
|
||||
$this->addresses->removeElement($address);
|
||||
}
|
||||
|
||||
/**
|
||||
* By default, the addresses are ordered by date, descending (the most
|
||||
* recent first)
|
||||
*
|
||||
* @return \Chill\MainBundle\Entity\Address[]
|
||||
*/
|
||||
public function getAddresses()
|
||||
{
|
||||
return $this->addresses;
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,153 @@
|
||||
<?php
|
||||
|
||||
namespace Chill\PersonBundle\Entity\Household;
|
||||
|
||||
use Doctrine\ORM\Mapping as ORM;
|
||||
use Chill\PersonBundle\Repository\Household\HouseholdMembersRepository;
|
||||
use Chill\PersonBundle\Entity\Person;
|
||||
use Chill\PersonBundle\Entity\Household\Household;
|
||||
|
||||
/**
|
||||
* @ORM\Entity(repositoryClass=HouseholdMembersRepository::class)
|
||||
*/
|
||||
class HouseholdMembers
|
||||
{
|
||||
/**
|
||||
* @ORM\Id
|
||||
* @ORM\GeneratedValue
|
||||
* @ORM\Column(type="integer")
|
||||
*/
|
||||
private $id;
|
||||
|
||||
/**
|
||||
* @ORM\Column(type="string", length=255, nullable=true)
|
||||
*/
|
||||
private $position;
|
||||
|
||||
/**
|
||||
* @ORM\Column(type="date")
|
||||
*/
|
||||
private $startDate;
|
||||
|
||||
/**
|
||||
* @ORM\Column(type="date")
|
||||
*/
|
||||
private $endDate;
|
||||
|
||||
/**
|
||||
* @ORM\Column(type="string", length=255, nullable=true)
|
||||
*/
|
||||
private $comment;
|
||||
|
||||
/**
|
||||
* @ORM\Column(type="boolean")
|
||||
*/
|
||||
private $sharedHousehold;
|
||||
|
||||
/**
|
||||
*
|
||||
* @var Person
|
||||
* @ORM\ManyToOne(
|
||||
* targetEntity="\Chill\PersonBundle\Entity\Person"
|
||||
* )
|
||||
*/
|
||||
private $person;
|
||||
|
||||
/**
|
||||
*
|
||||
* @var Household
|
||||
* @ORM\ManyToOne(
|
||||
* targetEntity="\Chill\PersonBundle\Entity\Household\Household"
|
||||
* )
|
||||
*/
|
||||
private $household;
|
||||
|
||||
public function getId(): ?int
|
||||
{
|
||||
return $this->id;
|
||||
}
|
||||
|
||||
public function getPosition(): ?string
|
||||
{
|
||||
return $this->position;
|
||||
}
|
||||
|
||||
public function setPosition(?string $position): self
|
||||
{
|
||||
$this->position = $position;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getStartDate(): ?\DateTimeInterface
|
||||
{
|
||||
return $this->startDate;
|
||||
}
|
||||
|
||||
public function setStartDate(\DateTimeInterface $startDate): self
|
||||
{
|
||||
$this->startDate = $startDate;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getEndDate(): ?\DateTimeInterface
|
||||
{
|
||||
return $this->endDate;
|
||||
}
|
||||
|
||||
public function setEndDate(\DateTimeInterface $endDate): self
|
||||
{
|
||||
$this->endDate = $endDate;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getComment(): ?string
|
||||
{
|
||||
return $this->comment;
|
||||
}
|
||||
|
||||
public function setComment(?string $comment): self
|
||||
{
|
||||
$this->comment = $comment;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getSharedHousehold(): ?bool
|
||||
{
|
||||
return $this->sharedHousehold;
|
||||
}
|
||||
|
||||
public function setSharedHousehold(bool $sharedHousehold): self
|
||||
{
|
||||
$this->sharedHousehold = $sharedHousehold;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getPerson(): ?Person
|
||||
{
|
||||
return $this->person;
|
||||
}
|
||||
|
||||
public function setPerson(?Person $person): self
|
||||
{
|
||||
$this->person = $person;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getHousehold(): ?Household
|
||||
{
|
||||
return $this->household;
|
||||
}
|
||||
|
||||
public function setHousehold(?Household $household): self
|
||||
{
|
||||
$this->household = $household;
|
||||
|
||||
return $this;
|
||||
}
|
||||
}
|
@@ -22,15 +22,17 @@ namespace Chill\PersonBundle\Entity;
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
use Doctrine\ORM\Mapping as ORM;
|
||||
use Doctrine\Common\Collections\Collection;
|
||||
use Doctrine\Common\Collections\ArrayCollection;
|
||||
use Doctrine\Common\Collections\Criteria;
|
||||
use ArrayIterator;
|
||||
use Chill\MainBundle\Entity\Center;
|
||||
use Chill\MainBundle\Entity\Country;
|
||||
use Chill\PersonBundle\Entity\MaritalStatus;
|
||||
use Chill\MainBundle\Entity\HasCenterInterface;
|
||||
use Chill\MainBundle\Entity\Address;
|
||||
use DateTime;
|
||||
use Doctrine\ORM\Mapping as ORM;
|
||||
use Doctrine\Common\Collections\Collection;
|
||||
use Doctrine\Common\Collections\ArrayCollection;
|
||||
use Doctrine\Common\Collections\Criteria;
|
||||
use Symfony\Component\Validator\Context\ExecutionContextInterface;
|
||||
|
||||
/**
|
||||
@@ -388,7 +390,7 @@ class Person implements HasCenterInterface
|
||||
*
|
||||
* @deprecated since 1.1 use `getOpenedAccompanyingPeriod instead
|
||||
*/
|
||||
public function getCurrentAccompanyingPeriod() : AccompanyingPeriod
|
||||
public function getCurrentAccompanyingPeriod() : ?AccompanyingPeriod
|
||||
{
|
||||
return $this->getOpenedAccompanyingPeriod();
|
||||
}
|
||||
@@ -1008,32 +1010,28 @@ class Person implements HasCenterInterface
|
||||
/**
|
||||
* By default, the addresses are ordered by date, descending (the most
|
||||
* recent first)
|
||||
*
|
||||
* @return \Chill\MainBundle\Entity\Address[]
|
||||
*/
|
||||
public function getAddresses()
|
||||
public function getAddresses(): Collection
|
||||
{
|
||||
return $this->addresses;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param \DateTime|null $date
|
||||
* @return null
|
||||
*/
|
||||
public function getLastAddress(\DateTime $date = null)
|
||||
public function getLastAddress(DateTime $from = null)
|
||||
{
|
||||
if ($date === null) {
|
||||
$date = new \DateTime('now');
|
||||
}
|
||||
$from ??= new DateTime('now');
|
||||
|
||||
$addresses = $this->getAddresses();
|
||||
/** @var ArrayIterator $addressesIterator */
|
||||
$addressesIterator = $this->getAddresses()
|
||||
->filter(static fn (Address $address): bool => $address->getValidFrom() <= $from)
|
||||
->getIterator();
|
||||
|
||||
if ($addresses == null) {
|
||||
$addressesIterator->uasort(
|
||||
static fn (Address $left, Address $right): int => $right->getValidFrom() <=> $left->getValidFrom()
|
||||
);
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
return $addresses->first();
|
||||
return [] === ($addresses = iterator_to_array($addressesIterator)) ?
|
||||
null :
|
||||
current($addresses);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@@ -0,0 +1,93 @@
|
||||
<?php
|
||||
|
||||
namespace Chill\PersonBundle\Entity\SocialWork;
|
||||
|
||||
use Chill\PersonBundle\Repository\SocialWork\EvaluationRepository;
|
||||
use Doctrine\ORM\Mapping as ORM;
|
||||
|
||||
/**
|
||||
* @ORM\Entity(repositoryClass=EvaluationRepository::class)
|
||||
* @ORM\Table(name="chill_person_social_work_evaluation")
|
||||
*/
|
||||
class Evaluation
|
||||
{
|
||||
/**
|
||||
* @ORM\Id
|
||||
* @ORM\GeneratedValue
|
||||
* @ORM\Column(type="integer")
|
||||
*/
|
||||
private $id;
|
||||
|
||||
/**
|
||||
* @ORM\Column(type="json")
|
||||
*/
|
||||
private $title = [];
|
||||
|
||||
/**
|
||||
* @ORM\Column(type="dateinterval")
|
||||
*/
|
||||
private $delay;
|
||||
|
||||
/**
|
||||
* @ORM\Column(type="dateinterval")
|
||||
*/
|
||||
private $notificationDelay;
|
||||
|
||||
/**
|
||||
* @ORM\ManyToOne(targetEntity=SocialAction::class)
|
||||
*/
|
||||
private $socialAction;
|
||||
|
||||
public function getId(): ?int
|
||||
{
|
||||
return $this->id;
|
||||
}
|
||||
|
||||
public function getTitle(): array
|
||||
{
|
||||
return $this->title;
|
||||
}
|
||||
|
||||
public function setTitle(array $title): self
|
||||
{
|
||||
$this->title = $title;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getDelay(): ?\DateInterval
|
||||
{
|
||||
return $this->delay;
|
||||
}
|
||||
|
||||
public function setDelay(\DateInterval $delay): self
|
||||
{
|
||||
$this->delay = $delay;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getNotificationDelay(): ?\DateInterval
|
||||
{
|
||||
return $this->notificationDelay;
|
||||
}
|
||||
|
||||
public function setNotificationDelay(\DateInterval $notificationDelay): self
|
||||
{
|
||||
$this->notificationDelay = $notificationDelay;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getSocialAction(): ?SocialAction
|
||||
{
|
||||
return $this->socialAction;
|
||||
}
|
||||
|
||||
public function setSocialAction(?SocialAction $socialAction): self
|
||||
{
|
||||
$this->socialAction = $socialAction;
|
||||
|
||||
return $this;
|
||||
}
|
||||
}
|
121
src/Bundle/ChillPersonBundle/Entity/SocialWork/Goal.php
Normal file
121
src/Bundle/ChillPersonBundle/Entity/SocialWork/Goal.php
Normal file
@@ -0,0 +1,121 @@
|
||||
<?php
|
||||
|
||||
namespace Chill\PersonBundle\Entity\SocialWork;
|
||||
|
||||
use Chill\PersonBundle\Repository\SocialWork\GoalRepository;
|
||||
use Doctrine\Common\Collections\ArrayCollection;
|
||||
use Doctrine\Common\Collections\Collection;
|
||||
use Doctrine\ORM\Mapping as ORM;
|
||||
|
||||
/**
|
||||
* @ORM\Entity(repositoryClass=GoalRepository::class)
|
||||
* @ORM\Table(name="chill_person_social_work_goal")
|
||||
*/
|
||||
class Goal
|
||||
{
|
||||
/**
|
||||
* @ORM\Id
|
||||
* @ORM\GeneratedValue
|
||||
* @ORM\Column(type="integer")
|
||||
*/
|
||||
private $id;
|
||||
|
||||
/**
|
||||
* @ORM\Column(type="json")
|
||||
*/
|
||||
private $title = [];
|
||||
|
||||
/**
|
||||
* @ORM\Column(type="datetime", nullable=true)
|
||||
*/
|
||||
private $desactivationDate;
|
||||
|
||||
/**
|
||||
* @ORM\ManyToMany(targetEntity=SocialAction::class, mappedBy="goals")
|
||||
*/
|
||||
private $socialActions;
|
||||
|
||||
/**
|
||||
* @ORM\ManyToMany(targetEntity=Result::class, inversedBy="goals")
|
||||
* @ORM\JoinTable(name="chill_person_social_work_goal_result")
|
||||
*/
|
||||
private $results;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->socialActions = new ArrayCollection();
|
||||
$this->results = new ArrayCollection();
|
||||
}
|
||||
|
||||
public function getTitle(): array
|
||||
{
|
||||
return $this->title;
|
||||
}
|
||||
|
||||
public function setTitle(array $title): self
|
||||
{
|
||||
$this->title = $title;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getDesactivationDate(): ?\DateTimeInterface
|
||||
{
|
||||
return $this->desactivationDate;
|
||||
}
|
||||
|
||||
public function setDesactivationDate(?\DateTimeInterface $desactivationDate): self
|
||||
{
|
||||
$this->desactivationDate = $desactivationDate;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Collection|SocialAction[]
|
||||
*/
|
||||
public function getSocialActions(): Collection
|
||||
{
|
||||
return $this->socialActions;
|
||||
}
|
||||
|
||||
public function addSocialAction(SocialAction $socialAction): self
|
||||
{
|
||||
if (!$this->socialActions->contains($socialAction)) {
|
||||
$this->socialActions[] = $socialAction;
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function removeSocialAction(SocialAction $socialAction): self
|
||||
{
|
||||
$this->socialActions->removeElement($socialAction);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Collection|Result[]
|
||||
*/
|
||||
public function getResults(): Collection
|
||||
{
|
||||
return $this->results;
|
||||
}
|
||||
|
||||
public function addResult(Result $result): self
|
||||
{
|
||||
if (!$this->results->contains($result)) {
|
||||
$this->results[] = $result;
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function removeResult(Result $result): self
|
||||
{
|
||||
$this->results->removeElement($result);
|
||||
|
||||
return $this;
|
||||
}
|
||||
}
|
187
src/Bundle/ChillPersonBundle/Entity/SocialWork/Result.php
Normal file
187
src/Bundle/ChillPersonBundle/Entity/SocialWork/Result.php
Normal file
@@ -0,0 +1,187 @@
|
||||
<?php
|
||||
|
||||
namespace Chill\PersonBundle\Entity\SocialWork;
|
||||
|
||||
use Chill\PersonBundle\Entity\AccompanyingPeriod\AccompanyingPeriodWork;
|
||||
use Chill\PersonBundle\Entity\AccompanyingPeriod\AccompanyingPeriodWorkGoal;
|
||||
use Chill\PersonBundle\Repository\SocialWork\ResultRepository;
|
||||
use Doctrine\Common\Collections\ArrayCollection;
|
||||
use Doctrine\Common\Collections\Collection;
|
||||
use Doctrine\ORM\Mapping as ORM;
|
||||
|
||||
/**
|
||||
* @ORM\Entity(repositoryClass=ResultRepository::class)
|
||||
* @ORM\Table(name="chill_person_social_work_result")
|
||||
*/
|
||||
class Result
|
||||
{
|
||||
/**
|
||||
* @ORM\Id
|
||||
* @ORM\GeneratedValue
|
||||
* @ORM\Column(type="integer")
|
||||
*/
|
||||
private $id;
|
||||
|
||||
/**
|
||||
* @ORM\Column(type="json")
|
||||
*/
|
||||
private $title = [];
|
||||
|
||||
/**
|
||||
* @ORM\Column(type="datetime", nullable=true)
|
||||
*/
|
||||
private $desactivationDate;
|
||||
|
||||
/**
|
||||
* @ORM\ManyToMany(targetEntity=SocialAction::class, mappedBy="results")
|
||||
*/
|
||||
private $socialActions;
|
||||
|
||||
/**
|
||||
* @ORM\ManyToMany(targetEntity=Goal::class, mappedBy="results")
|
||||
*/
|
||||
private $goals;
|
||||
|
||||
/**
|
||||
* @ORM\ManyToMany(targetEntity=AccompanyingPeriodWork::class, mappedBy="results")
|
||||
*/
|
||||
private $accompanyingPeriodWorks;
|
||||
|
||||
/**
|
||||
* @ORM\ManyToMany(targetEntity=AccompanyingPeriodWorkGoal::class, mappedBy="results")
|
||||
*/
|
||||
private $accompanyingPeriodWorkGoals;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->socialActions = new ArrayCollection();
|
||||
$this->goals = new ArrayCollection();
|
||||
$this->accompanyingPeriodWorks = new ArrayCollection();
|
||||
$this->accompanyingPeriodWorkGoals = new ArrayCollection();
|
||||
}
|
||||
|
||||
public function getId(): ?int
|
||||
{
|
||||
return $this->id;
|
||||
}
|
||||
|
||||
public function getTitle(): array
|
||||
{
|
||||
return $this->title;
|
||||
}
|
||||
|
||||
public function setTitle(array $title): self
|
||||
{
|
||||
$this->title = $title;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getDesactivationDate(): ?\DateTimeInterface
|
||||
{
|
||||
return $this->desactivationDate;
|
||||
}
|
||||
|
||||
public function setDesactivationDate(?\DateTimeInterface $desactivationDate): self
|
||||
{
|
||||
$this->desactivationDate = $desactivationDate;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Collection|SocialAction[]
|
||||
*/
|
||||
public function getSocialActions(): Collection
|
||||
{
|
||||
return $this->socialActions;
|
||||
}
|
||||
|
||||
public function addSocialAction(SocialAction $socialAction): self
|
||||
{
|
||||
if (!$this->socialActions->contains($socialAction)) {
|
||||
$this->socialActions[] = $socialAction;
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function removeSocialAction(SocialAction $socialAction): self
|
||||
{
|
||||
$this->socialActions->removeElement($socialAction);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Collection|Goal[]
|
||||
*/
|
||||
public function getGoals(): Collection
|
||||
{
|
||||
return $this->goals;
|
||||
}
|
||||
|
||||
public function addGoal(Goal $goal): self
|
||||
{
|
||||
if (!$this->goals->contains($goal)) {
|
||||
$this->goals[] = $goal;
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function removeGoal(Goal $goal): self
|
||||
{
|
||||
$this->goals->removeElement($goal);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Collection|AccompanyingPeriodWork[]
|
||||
*/
|
||||
public function getAccompanyingPeriodWorks(): Collection
|
||||
{
|
||||
return $this->accompanyingPeriodWorks;
|
||||
}
|
||||
|
||||
public function addAccompanyingPeriodWork(AccompanyingPeriodWork $accompanyingPeriod): self
|
||||
{
|
||||
if (!$this->accompanyingPeriodWorks->contains($accompanyingPeriod)) {
|
||||
$this->accompanyingPeriodWorks[] = $accompanyingPeriod;
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function removeAccompanyingPeriodWork(AccompanyingPeriodWork $accompanyingPeriod): self
|
||||
{
|
||||
$this->accompanyingPeriodWorks->removeElement($accompanyingPeriod);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Collection|AccompanyingPeriodWorkGoal[]
|
||||
*/
|
||||
public function getAccompanyingPeriodWorkGoals(): Collection
|
||||
{
|
||||
return $this->accompanyingPeriodWorkGoals;
|
||||
}
|
||||
|
||||
public function addAccompanyingPeriodWorkGoal(AccompanyingPeriodWorkGoal $accompanyingPeriodWorkGoal): self
|
||||
{
|
||||
if (!$this->accompanyingPeriodWorkGoals->contains($accompanyingPeriodWorkGoal)) {
|
||||
$this->accompanyingPeriodWorkGoals[] = $accompanyingPeriodWorkGoal;
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function removeAccompanyingPeriodWorkGoal(AccompanyingPeriodWorkGoal $accompanyingPeriodWorkGoal): self
|
||||
{
|
||||
$this->accompanyingPeriodWorkGoals->removeElement($accompanyingPeriodWorkGoal);
|
||||
|
||||
return $this;
|
||||
}
|
||||
}
|
214
src/Bundle/ChillPersonBundle/Entity/SocialWork/SocialAction.php
Normal file
214
src/Bundle/ChillPersonBundle/Entity/SocialWork/SocialAction.php
Normal file
@@ -0,0 +1,214 @@
|
||||
<?php
|
||||
|
||||
namespace Chill\PersonBundle\Entity\SocialWork;
|
||||
|
||||
use Chill\PersonBundle\Repository\SocialWork\SocialActionRepository;
|
||||
use Doctrine\Common\Collections\ArrayCollection;
|
||||
use Doctrine\Common\Collections\Collection;
|
||||
use Doctrine\ORM\Mapping as ORM;
|
||||
|
||||
/**
|
||||
* @ORM\Entity(repositoryClass=SocialActionRepository::class)
|
||||
* @ORM\Table(name="chill_person_social_action")
|
||||
*/
|
||||
class SocialAction
|
||||
{
|
||||
/**
|
||||
* @ORM\Id
|
||||
* @ORM\GeneratedValue
|
||||
* @ORM\Column(type="integer")
|
||||
*/
|
||||
private $id;
|
||||
|
||||
/**
|
||||
* @ORM\Column(type="datetime", nullable=true)
|
||||
*/
|
||||
private $desactivationDate;
|
||||
|
||||
/**
|
||||
* @ORM\ManyToOne(targetEntity=SocialIssue::class, inversedBy="socialActions")
|
||||
*/
|
||||
private $issue;
|
||||
|
||||
/**
|
||||
* @ORM\ManyToOne(targetEntity=SocialAction::class, inversedBy="children")
|
||||
*/
|
||||
private $parent;
|
||||
|
||||
/**
|
||||
* @ORM\OneToMany(targetEntity=SocialAction::class, mappedBy="parent")
|
||||
*/
|
||||
private $children;
|
||||
|
||||
/**
|
||||
* @ORM\Column(type="dateinterval")
|
||||
*/
|
||||
private $defaultNotificationDelay;
|
||||
|
||||
/**
|
||||
* @ORM\Column(type="json")
|
||||
*/
|
||||
private $title = [];
|
||||
|
||||
/**
|
||||
* @ORM\ManyToMany(targetEntity=Goal::class, inversedBy="socialActions")
|
||||
* @ORM\JoinTable(name="chill_person_social_action_goal")
|
||||
*/
|
||||
private $goals;
|
||||
|
||||
/**
|
||||
* @ORM\ManyToMany(targetEntity=Result::class, inversedBy="socialActions")
|
||||
* @ORM\JoinTable(name="chill_person_social_action_result")
|
||||
*/
|
||||
private $results;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->children = new ArrayCollection();
|
||||
$this->goals = new ArrayCollection();
|
||||
$this->results = new ArrayCollection();
|
||||
}
|
||||
|
||||
public function getId(): ?int
|
||||
{
|
||||
return $this->id;
|
||||
}
|
||||
|
||||
public function getDesactivationDate(): ?\DateTimeInterface
|
||||
{
|
||||
return $this->desactivationDate;
|
||||
}
|
||||
|
||||
public function setDesactivationDate(?\DateTimeInterface $desactivationDate): self
|
||||
{
|
||||
$this->desactivationDate = $desactivationDate;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getIssue(): ?SocialIssue
|
||||
{
|
||||
return $this->issue;
|
||||
}
|
||||
|
||||
public function setIssue(?SocialIssue $issue): self
|
||||
{
|
||||
$this->issue = $issue;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getParent(): ?self
|
||||
{
|
||||
return $this->parent;
|
||||
}
|
||||
|
||||
public function setParent(?self $parent): self
|
||||
{
|
||||
$this->parent = $parent;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Collection|self[]
|
||||
*/
|
||||
public function getChildren(): Collection
|
||||
{
|
||||
return $this->children;
|
||||
}
|
||||
|
||||
public function addChild(self $child): self
|
||||
{
|
||||
if (!$this->children->contains($child)) {
|
||||
$this->children[] = $child;
|
||||
$child->setParent($this);
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function removeChild(self $child): self
|
||||
{
|
||||
if ($this->children->removeElement($child)) {
|
||||
// set the owning side to null (unless already changed)
|
||||
if ($child->getParent() === $this) {
|
||||
$child->setParent(null);
|
||||
}
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getDefaultNotificationDelay(): ?\DateInterval
|
||||
{
|
||||
return $this->defaultNotificationDelay;
|
||||
}
|
||||
|
||||
public function setDefaultNotificationDelay(\DateInterval $defaultNotificationDelay): self
|
||||
{
|
||||
$this->defaultNotificationDelay = $defaultNotificationDelay;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getTitle(): array
|
||||
{
|
||||
return $this->title;
|
||||
}
|
||||
|
||||
public function setTitle(array $title): self
|
||||
{
|
||||
$this->title = $title;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Collection|Goal[]
|
||||
*/
|
||||
public function getGoals(): Collection
|
||||
{
|
||||
return $this->goals;
|
||||
}
|
||||
|
||||
public function addGoal(Goal $goal): self
|
||||
{
|
||||
if (!$this->goals->contains($goal)) {
|
||||
$this->goals[] = $goal;
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function removeGoal(Goal $goal): self
|
||||
{
|
||||
$this->goals->removeElement($goal);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Collection|Result[]
|
||||
*/
|
||||
public function getResults(): Collection
|
||||
{
|
||||
return $this->results;
|
||||
}
|
||||
|
||||
public function addResult(Result $result): self
|
||||
{
|
||||
if (!$this->results->contains($result)) {
|
||||
$this->results[] = $result;
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function removeResult(Result $result): self
|
||||
{
|
||||
$this->results->removeElement($result);
|
||||
|
||||
return $this;
|
||||
}
|
||||
}
|
154
src/Bundle/ChillPersonBundle/Entity/SocialWork/SocialIssue.php
Normal file
154
src/Bundle/ChillPersonBundle/Entity/SocialWork/SocialIssue.php
Normal file
@@ -0,0 +1,154 @@
|
||||
<?php
|
||||
namespace Chill\PersonBundle\Entity\SocialWork;
|
||||
|
||||
|
||||
use Chill\PersonBundle\Repository\SocialWork\SocialIssueRepository;
|
||||
use Doctrine\Common\Collections\ArrayCollection;
|
||||
use Doctrine\Common\Collections\Collection;
|
||||
use Doctrine\ORM\Mapping as ORM;
|
||||
|
||||
/**
|
||||
* @ORM\Entity(repositoryClass=SocialIssueRepository::class)
|
||||
* @ORM\Table(name="chill_person_social_issue")
|
||||
*/
|
||||
class SocialIssue
|
||||
{
|
||||
/**
|
||||
* @ORM\Id
|
||||
* @ORM\GeneratedValue
|
||||
* @ORM\Column(type="integer")
|
||||
*/
|
||||
private $id;
|
||||
|
||||
/**
|
||||
* @ORM\ManyToOne(targetEntity=SocialIssue::class, inversedBy="children")
|
||||
*/
|
||||
private $parent;
|
||||
|
||||
/**
|
||||
* @ORM\OneToMany(targetEntity=SocialIssue::class, mappedBy="parent")
|
||||
*/
|
||||
private $children;
|
||||
|
||||
/**
|
||||
* @ORM\Column(type="datetime", nullable=true)
|
||||
*/
|
||||
private $desactivationDate;
|
||||
|
||||
/**
|
||||
* @ORM\Column(type="json")
|
||||
*/
|
||||
private $title = [];
|
||||
|
||||
/**
|
||||
* @ORM\OneToMany(targetEntity=SocialAction::class, mappedBy="issue")
|
||||
*/
|
||||
private $socialActions;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->children = new ArrayCollection();
|
||||
$this->socialActions = new ArrayCollection();
|
||||
}
|
||||
|
||||
public function getId(): ?int
|
||||
{
|
||||
return $this->id;
|
||||
}
|
||||
|
||||
public function getParent(): ?self
|
||||
{
|
||||
return $this->parent;
|
||||
}
|
||||
|
||||
public function setParent(?self $parent): self
|
||||
{
|
||||
$this->parent = $parent;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Collection|self[]
|
||||
*/
|
||||
public function getChildren(): Collection
|
||||
{
|
||||
return $this->children;
|
||||
}
|
||||
|
||||
public function addChild(self $child): self
|
||||
{
|
||||
if (!$this->children->contains($child)) {
|
||||
$this->children[] = $child;
|
||||
$child->setParent($this);
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function removeChild(self $child): self
|
||||
{
|
||||
if ($this->children->removeElement($child)) {
|
||||
// set the owning side to null (unless already changed)
|
||||
if ($child->getParent() === $this) {
|
||||
$child->setParent(null);
|
||||
}
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getDesactivationDate(): ?\DateTimeInterface
|
||||
{
|
||||
return $this->desactivationDate;
|
||||
}
|
||||
|
||||
public function setDesactivationDate(?\DateTimeInterface $desactivationDate): self
|
||||
{
|
||||
$this->desactivationDate = $desactivationDate;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getTitle(): array
|
||||
{
|
||||
return $this->title;
|
||||
}
|
||||
|
||||
public function setTitle(array $title): self
|
||||
{
|
||||
$this->title = $title;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Collection|SocialAction[]
|
||||
*/
|
||||
public function getSocialActions(): Collection
|
||||
{
|
||||
return $this->socialActions;
|
||||
}
|
||||
|
||||
public function addSocialAction(SocialAction $socialAction): self
|
||||
{
|
||||
if (!$this->socialActions->contains($socialAction)) {
|
||||
$this->socialActions[] = $socialAction;
|
||||
$socialAction->setSocialIssue($this);
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function removeSocialAction(SocialAction $socialAction): self
|
||||
{
|
||||
if ($this->socialActions->removeElement($socialAction)) {
|
||||
// set the owning side to null (unless already changed)
|
||||
if ($socialAction->getSocialIssue() === $this) {
|
||||
$socialAction->setSocialIssue(null);
|
||||
}
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
}
|
@@ -0,0 +1,52 @@
|
||||
<?php
|
||||
|
||||
namespace Chill\PersonBundle\Privacy;
|
||||
|
||||
/*
|
||||
* Chill is a software for social workers
|
||||
*
|
||||
* Copyright (C) 2014-2015, Champs Libres Cooperative SCRLFS,
|
||||
* <http://www.champs-libres.coop>, <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/>.
|
||||
*/
|
||||
|
||||
use Symfony\Component\EventDispatcher\Event;
|
||||
use Chill\PersonBundle\Entity\Person;
|
||||
use Chill\PersonBundle\Entity\AccompanyingPeriod;
|
||||
|
||||
class AccompanyingPeriodPrivacyEvent extends Event
|
||||
{
|
||||
public const ACCOMPANYING_PERIOD_PRIVACY_EVENT = 'chill_person.accompanying_period_privacy_event';
|
||||
|
||||
protected AccompanyingPeriod $period;
|
||||
|
||||
protected array $args;
|
||||
|
||||
public function __construct($period, $args = [])
|
||||
{
|
||||
$this->period = $period;
|
||||
$this->args = $args;
|
||||
}
|
||||
|
||||
public function getPeriod(): AccompanyingPeriod
|
||||
{
|
||||
return $this->period;
|
||||
}
|
||||
|
||||
public function getArgs(): array
|
||||
{
|
||||
return $this->args;
|
||||
}
|
||||
}
|
@@ -26,20 +26,21 @@ use Psr\Log\LoggerInterface;
|
||||
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
|
||||
use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface;
|
||||
use Chill\PersonBundle\Entity\Person;
|
||||
use Chill\PersonBundle\Privacy\AccompanyingPeriodPrivacyEvent;
|
||||
|
||||
class PrivacyEventSubscriber implements EventSubscriberInterface
|
||||
{
|
||||
|
||||
|
||||
/**
|
||||
* @var LoggerInterface
|
||||
*/
|
||||
protected $logger;
|
||||
|
||||
|
||||
/**
|
||||
* @var TokenStorageInterface
|
||||
*/
|
||||
protected $token;
|
||||
|
||||
|
||||
/**
|
||||
* PrivacyEventSubscriber constructor.
|
||||
*
|
||||
@@ -50,40 +51,64 @@ class PrivacyEventSubscriber implements EventSubscriberInterface
|
||||
$this->logger = $logger;
|
||||
$this->token = $token;
|
||||
}
|
||||
|
||||
|
||||
public static function getSubscribedEvents()
|
||||
{
|
||||
return array(PrivacyEvent::PERSON_PRIVACY_EVENT => array(
|
||||
array('onPrivacyEvent')
|
||||
));
|
||||
return [
|
||||
PrivacyEvent::PERSON_PRIVACY_EVENT => [
|
||||
['onPrivacyEvent']
|
||||
],
|
||||
AccompanyingPeriodPrivacyEvent::ACCOMPANYING_PERIOD_PRIVACY_EVENT => [
|
||||
['onAccompanyingPeriodPrivacyEvent']
|
||||
]
|
||||
];
|
||||
}
|
||||
|
||||
|
||||
public function onAccompanyingPeriodPrivacyEvent(AccompanyingPeriodPrivacyEvent $event)
|
||||
{
|
||||
$involved = $this->getInvolved();
|
||||
$involved['period_id'] = $event->getPeriod()->getId();
|
||||
$involved['persons'] = $event->getPeriod()->getPersons()
|
||||
->map(function(Person $p) { return $p->getId(); })
|
||||
->toArray();
|
||||
|
||||
$this->logger->notice(
|
||||
"[Privacy Event] An accompanying period has been viewed",
|
||||
array_merge($involved, $event->getArgs())
|
||||
);
|
||||
}
|
||||
|
||||
public function onPrivacyEvent(PrivacyEvent $event)
|
||||
{
|
||||
$persons = array();
|
||||
|
||||
$persons = [];
|
||||
|
||||
if ($event->hasPersons() === true) {
|
||||
foreach ($event->getPersons() as $person) {
|
||||
$persons[] = $person->getId();
|
||||
}
|
||||
}
|
||||
|
||||
$involved = array(
|
||||
'by_user' => $this->token->getToken()->getUser()->getUsername(),
|
||||
'by_user_id' => $this->token->getToken()->getUser()->getId(),
|
||||
'person_id' => $event->getPerson()->getId(),
|
||||
);
|
||||
|
||||
$involved = $this->getInvolved();
|
||||
$involved['person_id'] = $event->getPerson()->getId();
|
||||
|
||||
if ($event->hasPersons()) {
|
||||
$involved['persons'] = \array_map(
|
||||
function(Person $p) { return $p->getId(); },
|
||||
function(Person $p) { return $p->getId(); },
|
||||
$event->getPersons()
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
$this->logger->notice(
|
||||
"[Privacy Event] A Person Folder has been viewed",
|
||||
array_merge($involved, $event->getArgs())
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
protected function getInvolved(): array
|
||||
{
|
||||
return [
|
||||
'by_user' => $this->token->getToken()->getUser()->getUsername(),
|
||||
'by_user_id' => $this->token->getToken()->getUser()->getId(),
|
||||
];
|
||||
}
|
||||
}
|
||||
|
@@ -0,0 +1,21 @@
|
||||
<?php
|
||||
|
||||
namespace Chill\PersonBundle\Repository\AccompanyingPeriod;
|
||||
|
||||
use Chill\PersonBundle\Entity\AccompanyingPeriod\AccompanyingPeriodWorkGoal;
|
||||
use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository;
|
||||
use Doctrine\Persistence\ManagerRegistry;
|
||||
|
||||
/**
|
||||
* @method AccompanyingPeriodWorkGoal|null find($id, $lockMode = null, $lockVersion = null)
|
||||
* @method AccompanyingPeriodWorkGoal|null findOneBy(array $criteria, array $orderBy = null)
|
||||
* @method AccompanyingPeriodWorkGoal[] findAll()
|
||||
* @method AccompanyingPeriodWorkGoal[] findBy(array $criteria, array $orderBy = null, $limit = null, $offset = null)
|
||||
*/
|
||||
class AccompanyingPeriodWorkGoalRepository extends ServiceEntityRepository
|
||||
{
|
||||
public function __construct(ManagerRegistry $registry)
|
||||
{
|
||||
parent::__construct($registry, AccompanyingPeriodWorkGoal::class);
|
||||
}
|
||||
}
|
@@ -0,0 +1,21 @@
|
||||
<?php
|
||||
|
||||
namespace Chill\PersonBundle\Repository\AccompanyingPeriod;
|
||||
|
||||
use Chill\PersonBundle\Entity\AccompanyingPeriod\AccompanyingPeriodWork;
|
||||
use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository;
|
||||
use Doctrine\Persistence\ManagerRegistry;
|
||||
|
||||
/**
|
||||
* @method AccompanyingPeriodWork|null find($id, $lockMode = null, $lockVersion = null)
|
||||
* @method AccompanyingPeriodWork|null findOneBy(array $criteria, array $orderBy = null)
|
||||
* @method AccompanyingPeriodWork[] findAll()
|
||||
* @method AccompanyingPeriodWork[] findBy(array $criteria, array $orderBy = null, $limit = null, $offset = null)
|
||||
*/
|
||||
class AccompanyingPeriodWorkRepository extends ServiceEntityRepository
|
||||
{
|
||||
public function __construct(ManagerRegistry $registry)
|
||||
{
|
||||
parent::__construct($registry, AccompanyingPeriodWork::class);
|
||||
}
|
||||
}
|
@@ -23,6 +23,7 @@
|
||||
namespace Chill\PersonBundle\Repository;
|
||||
|
||||
use Chill\PersonBundle\Entity\AccompanyingPeriod;
|
||||
use Chill\PersonBundle\Entity\Person;
|
||||
use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository;
|
||||
use Doctrine\Persistence\ManagerRegistry;
|
||||
|
||||
@@ -38,5 +39,4 @@ class AccompanyingPeriodRepository extends ServiceEntityRepository
|
||||
{
|
||||
parent::__construct($registry, AccompanyingPeriod::class);
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -0,0 +1,50 @@
|
||||
<?php
|
||||
|
||||
namespace Chill\PersonBundle\Repository\Household;
|
||||
|
||||
use Chill\PersonBundle\Entity\Household\HouseholdMembers;
|
||||
use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository;
|
||||
use Doctrine\Persistence\ManagerRegistry;
|
||||
|
||||
/**
|
||||
* @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)
|
||||
*/
|
||||
class HouseholdMembersRepository extends ServiceEntityRepository
|
||||
{
|
||||
public function __construct(ManagerRegistry $registry)
|
||||
{
|
||||
parent::__construct($registry, 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()
|
||||
;
|
||||
}
|
||||
*/
|
||||
}
|
@@ -0,0 +1,50 @@
|
||||
<?php
|
||||
|
||||
namespace Chill\PersonBundle\Repository\Household;
|
||||
|
||||
use Chill\PersonBundle\Entity\Household\Household;
|
||||
use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository;
|
||||
use Doctrine\Persistence\ManagerRegistry;
|
||||
|
||||
/**
|
||||
* @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)
|
||||
*/
|
||||
class HouseholdRepository extends ServiceEntityRepository
|
||||
{
|
||||
public function __construct(ManagerRegistry $registry)
|
||||
{
|
||||
parent::__construct($registry, 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()
|
||||
;
|
||||
}
|
||||
*/
|
||||
}
|
@@ -0,0 +1,21 @@
|
||||
<?php
|
||||
|
||||
namespace Chill\PersonBundle\Repository\SocialWork;
|
||||
|
||||
use Chill\PersonBundle\Entity\SocialWork\Evaluation;
|
||||
use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository;
|
||||
use Doctrine\Persistence\ManagerRegistry;
|
||||
|
||||
/**
|
||||
* @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)
|
||||
*/
|
||||
class EvaluationRepository extends ServiceEntityRepository
|
||||
{
|
||||
public function __construct(ManagerRegistry $registry)
|
||||
{
|
||||
parent::__construct($registry, Evaluation::class);
|
||||
}
|
||||
}
|
@@ -0,0 +1,21 @@
|
||||
<?php
|
||||
|
||||
namespace Chill\PersonBundle\Repository\SocialWork;
|
||||
|
||||
use Chill\PersonBundle\Entity\SocialWork\Goal;
|
||||
use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository;
|
||||
use Doctrine\Persistence\ManagerRegistry;
|
||||
|
||||
/**
|
||||
* @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)
|
||||
*/
|
||||
class GoalRepository extends ServiceEntityRepository
|
||||
{
|
||||
public function __construct(ManagerRegistry $registry)
|
||||
{
|
||||
parent::__construct($registry, Goal::class);
|
||||
}
|
||||
}
|
@@ -0,0 +1,21 @@
|
||||
<?php
|
||||
|
||||
namespace Chill\PersonBundle\Repository\SocialWork;
|
||||
|
||||
use Chill\PersonBundle\Entity\SocialWork\Result;
|
||||
use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository;
|
||||
use Doctrine\Persistence\ManagerRegistry;
|
||||
|
||||
/**
|
||||
* @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)
|
||||
*/
|
||||
class ResultRepository extends ServiceEntityRepository
|
||||
{
|
||||
public function __construct(ManagerRegistry $registry)
|
||||
{
|
||||
parent::__construct($registry, Result::class);
|
||||
}
|
||||
}
|
@@ -0,0 +1,21 @@
|
||||
<?php
|
||||
|
||||
namespace Chill\PersonBundle\Repository\SocialWork;
|
||||
|
||||
use Chill\PersonBundle\Entity\SocialWork\SocialAction;
|
||||
use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository;
|
||||
use Doctrine\Persistence\ManagerRegistry;
|
||||
|
||||
/**
|
||||
* @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)
|
||||
*/
|
||||
class SocialActionRepository extends ServiceEntityRepository
|
||||
{
|
||||
public function __construct(ManagerRegistry $registry)
|
||||
{
|
||||
parent::__construct($registry, SocialAction::class);
|
||||
}
|
||||
}
|
@@ -0,0 +1,21 @@
|
||||
<?php
|
||||
|
||||
namespace Chill\PersonBundle\Repository\SocialWork;
|
||||
|
||||
use Chill\PersonBundle\Entity\SocialWork\SocialIssue;
|
||||
use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository;
|
||||
use Doctrine\Persistence\ManagerRegistry;
|
||||
|
||||
/**
|
||||
* @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)
|
||||
*/
|
||||
class SocialIssueRepository extends ServiceEntityRepository
|
||||
{
|
||||
public function __construct(ManagerRegistry $registry)
|
||||
{
|
||||
parent::__construct($registry, SocialIssue::class);
|
||||
}
|
||||
}
|
@@ -1,45 +0,0 @@
|
||||
<template>
|
||||
<accompanying-course v-bind:accompanying_course="accompanying_course"/>
|
||||
<persons-associated v-bind:persons_associated="accompanying_course.persons"/>
|
||||
<requestor v-bind:accompanying_course="accompanying_course"/>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import AccompanyingCourse from './components/AccompanyingCourse.vue';
|
||||
import PersonsAssociated from './components/PersonsAssociated.vue';
|
||||
import Requestor from './components/Requestor.vue';
|
||||
|
||||
export default {
|
||||
name: 'App',
|
||||
components: {
|
||||
AccompanyingCourse,
|
||||
PersonsAssociated,
|
||||
Requestor
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
accompanying_course: {}
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
accompanyingCourseId() {
|
||||
return window.accompanyingCourseId;
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
async getAccompanyingCourse() {
|
||||
let data_;
|
||||
return fetch(`/fr/api/parcours/${accompanyingCourseId}/show`)
|
||||
.then(response => response.json())
|
||||
.then(data => {
|
||||
this.$data.accompanying_course = data;
|
||||
});
|
||||
}
|
||||
},
|
||||
async mounted() {
|
||||
await this.getAccompanyingCourse();
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped></style>
|
@@ -1,26 +0,0 @@
|
||||
<template>
|
||||
<div class="vue-component">
|
||||
<h3>Parcours</h3>
|
||||
<dl>
|
||||
<dt>id</dt>
|
||||
<dd>{{ accompanying_course.id }}</dd>
|
||||
<dt>opening_date</dt>
|
||||
<dd>{{ accompanying_course.opening_date }}</dd>
|
||||
<dt>closing_date</dt>
|
||||
<dd>{{ accompanying_course.closing_date }}</dd>
|
||||
<dt>remark</dt>
|
||||
<dd>{{ accompanying_course.remark }}</dd>
|
||||
<dt>closing_motive</dt>
|
||||
<dd>{{ accompanying_course.closing_motive }}</dd>
|
||||
</dl>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: 'AccompanyingCourse',
|
||||
props: {
|
||||
accompanying_course: Object
|
||||
}
|
||||
}
|
||||
</script>
|
@@ -1,25 +0,0 @@
|
||||
<template>
|
||||
<tr>
|
||||
<td>{{ person.firstname }}</td>
|
||||
<td>{{ person.lastname }}</td>
|
||||
<td>{{ person.startdate }}</td>
|
||||
<td>{{ person.enddate }}</td>
|
||||
<td>
|
||||
<ul class="record_actions">
|
||||
<li><button class="sc-button bt-show"></button></li>
|
||||
<li><button class="sc-button bt-update"></button></li>
|
||||
<li><button class="sc-button bt-delete" @click.prevent="$emit('remove', person)"></button></li>
|
||||
</ul>
|
||||
</td>
|
||||
</tr>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: 'PersonItem',
|
||||
props: {
|
||||
person: { type: Object, required: true }
|
||||
},
|
||||
emits: ['remove']
|
||||
}
|
||||
</script>
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user