Compare commits

..

16 Commits

Author SHA1 Message Date
915a2e7284 Merge remote-tracking branch 'origin/dune-risky' into dune-risky 2021-07-13 16:59:38 +02:00
cb99074d1f fix custom field wich could not be saved 2021-07-13 16:58:17 +02:00
cfd9f1bab1 replace call to entity by class FQDN 2021-06-02 00:46:55 +02:00
358410cde1 Remove dead code 2021-05-26 19:44:58 +00:00
06c74ed5ed add menu into section 2021-05-26 21:14:42 +02:00
25c986cc61 fix rendering for timeline entries in center context 2021-05-26 18:10:51 +02:00
cad8174333 apply timelineSingleQuery on events 2021-05-26 18:05:02 +02:00
75c586fbf8 fix documentation for timeline 2021-05-26 17:58:58 +02:00
2cb9dfc250 add tasks to global timeline 2021-05-26 17:50:54 +02:00
5350a09951 apply timeline for report 2021-05-25 19:07:09 +02:00
9b1a66c992 fix query in timeline in activity and person bundle 2021-05-25 09:48:19 +02:00
74541f360b fix activity timeline using TimelineSingleQuery 2021-05-24 20:26:33 +02:00
ea477a9842 add accompanying period opening/closing to global timeline 2021-05-17 13:24:50 +02:00
73653744d7 Prepare for deprecation of class Role, and add method to filter centers 2021-05-17 13:23:58 +02:00
c3ef8d112c first impl for global timeline: apply on activities 2021-05-14 16:25:56 +02:00
Pol Dellaiera
8c98f2cf6e Update .gitignore file. 2021-05-07 09:04:29 +02:00
451 changed files with 30383 additions and 1921 deletions

3
.gitignore vendored
View File

@@ -1,8 +1,8 @@
.composer/* .composer/*
composer.phar composer.phar
composer.lock composer.lock
docs/build/ docs/build/
.php_cs.cache
###> symfony/framework-bundle ### ###> symfony/framework-bundle ###
/.env.local /.env.local
@@ -19,3 +19,4 @@ docs/build/
/phpunit.xml /phpunit.xml
.phpunit.result.cache .phpunit.result.cache
###< phpunit/phpunit ### ###< phpunit/phpunit ###

View File

@@ -13,7 +13,7 @@
"Chill\\EventBundle\\": "src/Bundle/ChillEventBundle", "Chill\\EventBundle\\": "src/Bundle/ChillEventBundle",
"Chill\\FamilyMemberBundle\\": "src/Bundle/ChillFamilyMemberBundle", "Chill\\FamilyMemberBundle\\": "src/Bundle/ChillFamilyMemberBundle",
"Chill\\MainBundle\\": "src/Bundle/ChillMainBundle", "Chill\\MainBundle\\": "src/Bundle/ChillMainBundle",
"Chill\\PersonBundle\\": "src/Bundle/ChillPersonBundle/src", "Chill\\PersonBundle\\": "src/Bundle/ChillPersonBundle",
"Chill\\ReportBundle\\": "src/Bundle/ChillReportBundle", "Chill\\ReportBundle\\": "src/Bundle/ChillReportBundle",
"Chill\\TaskBundle\\": "src/Bundle/ChillTaskBundle", "Chill\\TaskBundle\\": "src/Bundle/ChillTaskBundle",
"Chill\\ThirdPartyBundle\\": "src/Bundle/ChillThirdPartyBundle" "Chill\\ThirdPartyBundle\\": "src/Bundle/ChillThirdPartyBundle"

View File

@@ -97,7 +97,7 @@ The has the following signature :
* *
* @param string $context * @param string $context
* @param mixed[] $args the argument to the context. * @param mixed[] $args the argument to the context.
* @return string[] * @return TimelineSingleQuery
* @throw \LogicException if the context is not supported * @throw \LogicException if the context is not supported
*/ */
public function fetchQuery($context, array $args); public function fetchQuery($context, array $args);
@@ -163,18 +163,16 @@ The has the following signature :
The `fetchQuery` function The `fetchQuery` function
^^^^^^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^
The fetchQuery function help to build the UNION query to gather events. This function should return an associative array MUST have the following key : The fetchQuery function help to build the UNION query to gather events. This function should return an instance of :code:`TimelineSingleQuery`. For you convenience, this object may be build using an associative array with the following keys:
* `id` : the name of the id column * `id` : the name of the id column
* `type`: a string to indicate the type * `type`: a string to indicate the type
* `date`: the name of the datetime column, used to order entities by date * `date`: the name of the datetime column, used to order entities by date
* `FROM` (in capital) : the FROM clause. May contains JOIN instructions * `FROM`: the FROM clause. May contains JOIN instructions
* `WHERE`: the WHERE clause;
* `parameters`: the parameters to pass to the query
Those key are optional: The parameters should be replaced into the query by :code:`?`. They will be replaced into the query using prepared statements.
* `WHERE` (in capital) : the WHERE clause.
Where relevant, the data must be quoted to avoid SQL injection.
`$context` and `$args` are defined by the bundle which will call the timeline rendering. You may use them to build a different query depending on this context. `$context` and `$args` are defined by the bundle which will call the timeline rendering. You may use them to build a different query depending on this context.
@@ -186,6 +184,15 @@ For instance, if the context is `'person'`, the args will be this array :
'person' => $person //a \Chill\PersonBundle\Entity\Person entity 'person' => $person //a \Chill\PersonBundle\Entity\Person entity
); );
For the context :code:`center`, the args will be:
.. code-block:: php
array(
'centers' => [ ] // an array of \Chill\MainBundle\Entity\Center entities
);
You should find in the bundle documentation which contexts are arguments the bundle defines. You should find in the bundle documentation which contexts are arguments the bundle defines.
.. note:: .. note::
@@ -199,13 +206,12 @@ Example of an implementation :
namespace Chill\ReportBundle\Timeline; namespace Chill\ReportBundle\Timeline;
use Chill\MainBundle\Timeline\TimelineProviderInterface; use Chill\MainBundle\Timeline\TimelineProviderInterface;
use Chill\MainBundle\Timeline\TimelineSingleQuery;
use Doctrine\ORM\EntityManager; use Doctrine\ORM\EntityManager;
/** /**
* Provide report for inclusion in timeline * Provide report for inclusion in timeline
* *
* @author Julien Fastré <julien.fastre@champs-libres.coop>
* @author Champs Libres <info@champs-libres.coop>
*/ */
class TimelineReportProvider implements TimelineProviderInterface class TimelineReportProvider implements TimelineProviderInterface
{ {
@@ -227,16 +233,17 @@ Example of an implementation :
$metadata = $this->em->getClassMetadata('ChillReportBundle:Report'); $metadata = $this->em->getClassMetadata('ChillReportBundle:Report');
return array( return TimelineSingleQuery::fromArray([
'id' => $metadata->getColumnName('id'), 'id' => $metadata->getColumnName('id'),
'type' => 'report', 'type' => 'report',
'date' => $metadata->getColumnName('date'), 'date' => $metadata->getColumnName('date'),
'FROM' => $metadata->getTableName(), 'FROM' => $metadata->getTableName(),
'WHERE' => sprintf('%s = %d', 'WHERE' => sprintf('%s = ?',
$metadata $metadata
->getAssociationMapping('person')['joinColumns'][0]['name'], ->getAssociationMapping('person')['joinColumns'][0]['name'])
$args['person']->getId()) )
); 'parameters' => [ $args['person']->getId() ]
]);
} }
//.... //....

View File

@@ -38,7 +38,7 @@ use Chill\MainBundle\Validator\Constraints\Entity\UserCircleConsistency;
* Class Activity * Class Activity
* *
* @package Chill\ActivityBundle\Entity * @package Chill\ActivityBundle\Entity
* @ORM\Entity() * @ORM\Entity(repositoryClass="Chill\ActivityBundle\Repository\ActivityRepository")
* @ORM\Table(name="activity") * @ORM\Table(name="activity")
* @ORM\HasLifecycleCallbacks() * @ORM\HasLifecycleCallbacks()
* @UserCircleConsistency( * @UserCircleConsistency(

View File

@@ -0,0 +1,169 @@
<?php
/*
* Chill is a software for social workers
*
* Copyright (C) 2021, 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\ActivityBundle\Repository;
use Chill\ActivityBundle\Entity\Activity;
use Chill\PersonBundle\Entity\Person;
use Chill\ActivityBundle\Repository\ActivityRepository;
use Chill\ActivityBundle\Security\Authorization\ActivityVoter;
use Chill\MainBundle\Entity\Scope;
use Doctrine\ORM\QueryBuilder;
use Doctrine\ORM\Query\Expr\Orx;
use Chill\MainBundle\Security\Authorization\AuthorizationHelper;
use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface;
use Symfony\Component\Security\Core\Role\Role;
use Doctrine\ORM\EntityManagerInterface;
final class ActivityACLAwareRepository
{
private AuthorizationHelper $authorizationHelper;
private TokenStorageInterface $tokenStorage;
private ActivityRepository $repository;
private EntityManagerInterface $em;
public function __construct(
AuthorizationHelper $authorizationHelper,
TokenStorageInterface $tokenStorage,
ActivityRepository $repository,
EntityManagerInterface $em
) {
$this->authorizationHelper = $authorizationHelper;
$this->tokenStorage = $tokenStorage;
$this->repository = $repository;
$this->em = $em;
}
public function queryTimelineIndexer(string $context, array $args = []): array
{
$metadataActivity = $this->em->getClassMetadata(Activity::class);
$from = $this->getFromClauseCenter($args);
[$where, $parameters] = $this->getWhereClause($context, $args);
return [
'id' => $metadataActivity->getTableName()
.'.'.$metadataActivity->getColumnName('id'),
'type' => 'activity',
'date' => $metadataActivity->getTableName()
.'.'.$metadataActivity->getColumnName('date'),
'FROM' => $from,
'WHERE' => $where,
'parameters' => $parameters
];
}
private function getFromClauseCenter(array $args): string
{
$metadataActivity = $this->em->getClassMetadata(Activity::class);
$metadataPerson = $this->em->getClassMetadata(Person::class);
$associationMapping = $metadataActivity->getAssociationMapping('person');
return $metadataActivity->getTableName().' JOIN '
.$metadataPerson->getTableName().' ON '
.$metadataPerson->getTableName().'.'.
$associationMapping['joinColumns'][0]['referencedColumnName']
.' = '
.$associationMapping['joinColumns'][0]['name']
;
}
private function getWhereClause(string $context, array $args): array
{
$where = '';
$parameters = [];
$metadataActivity = $this->em->getClassMetadata(Activity::class);
$metadataPerson = $this->em->getClassMetadata(Person::class);
$activityToPerson = $metadataActivity->getAssociationMapping('person')['joinColumns'][0]['name'];
$activityToScope = $metadataActivity->getAssociationMapping('scope')['joinColumns'][0]['name'];
$personToCenter = $metadataPerson->getAssociationMapping('center')['joinColumns'][0]['name'];
// acls:
$role = new Role(ActivityVoter::SEE);
$reachableCenters = $this->authorizationHelper->getReachableCenters($this->tokenStorage->getToken()->getUser(),
$role);
if (count($reachableCenters) === 0) {
// insert a dummy condition
return 'FALSE = TRUE';
}
if ($context === 'person') {
// we start with activities having the person_id linked to person
$where .= sprintf('%s = ? AND ', $activityToPerson);
$parameters[] = $person->getId();
}
// we add acl (reachable center and scopes)
$where .= '('; // first loop for the for centers
$centersI = 0; // like centers#i
foreach ($reachableCenters as $center) {
// we pass if not in centers
if (!\in_array($center, $args['centers'])) {
continue;
}
// we get all the reachable scopes for this center
$reachableScopes = $this->authorizationHelper->getReachableScopes($this->tokenStorage->getToken()->getUser(), $role, $center);
// we get the ids for those scopes
$reachablesScopesId = array_map(
function(Scope $scope) { return $scope->getId(); },
$reachableScopes
);
// if not the first center
if ($centersI > 0) {
$where .= ') OR (';
}
// condition for the center
$where .= sprintf(' %s.%s = ? ', $metadataPerson->getTableName(), $personToCenter);
$parameters[] = $center->getId();
// begin loop for scopes
$where .= ' AND (';
$scopesI = 0; //like scope#i
foreach ($reachablesScopesId as $scopeId) {
if ($scopesI > 0) {
$where .= ' OR ';
}
$where .= sprintf(' %s.%s = ? ', $metadataActivity->getTableName(), $activityToScope);
$parameters[] = $scopeId;
$scopesI ++;
}
// close loop for scopes
$where .= ') ';
$centersI++;
}
// close loop for centers
$where .= ')';
return [$where, $parameters];
}
}

View File

@@ -0,0 +1,42 @@
<?php
/*
* Chill is a software for social workers
*
* Copyright (C) 2021, 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\ActivityBundle\Repository;
use Chill\ActivityBundle\Entity\Activity;
use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository;
use Doctrine\Persistence\ManagerRegistry;
/**
* @method AccompanyingPeriodParticipation|null find($id, $lockMode = null, $lockVersion = null)
* @method AccompanyingPeriodParticipation|null findOneBy(array $criteria, array $orderBy = null)
* @method AccompanyingPeriodParticipation[] findAll()
* @method AccompanyingPeriodParticipation[] findBy(array $criteria, array $orderBy = null, $limit = null, $offset = null)
*/
class ActivityRepository extends ServiceEntityRepository
{
public function __construct(ManagerRegistry $registry)
{
parent::__construct($registry, Activity::class);
}
}

View File

@@ -1,11 +1,11 @@
{% import 'ChillActivityBundle:ActivityReason:macro.html.twig' as m %} {% import 'ChillActivityBundle:ActivityReason:macro.html.twig' as m %}
<div> <div>
<h3>{{ activity.date|format_date('long') }}<span class="activity"> / {{ 'Activity'|trans }}</span></h3> <h3>{{ activity.date|format_date('long') }}<span class="activity"> / {{ 'Activity'|trans }}</span>{% if 'person' != context %} / {{ activity.person|chill_entity_render_box({'addLink': true}) }}{% endif %}</h3>
<div class="statement"> <div class="statement">
<span class="statement">{{ '%user% has done an %activity_type%'|trans( <span class="statement">{{ '%user% has done an %activity_type%'|trans(
{ {
'%user%' : user, '%user%' : activity.user,
'%activity_type%': activity.type.name|localize_translatable_string, '%activity_type%': activity.type.name|localize_translatable_string,
'%date%' : activity.date|format_date('long') } '%date%' : activity.date|format_date('long') }
) }}</span> ) }}</span>
@@ -29,13 +29,13 @@
<ul class="record_actions"> <ul class="record_actions">
<li> <li>
<a href="{{ path('chill_activity_activity_show', { 'person_id': person.id, 'id': activity.id} ) }}" class="sc-button bt-view"> <a href="{{ path('chill_activity_activity_show', { 'person_id': activity.person.id, 'id': activity.id} ) }}" class="sc-button bt-view">
{{ 'Show the activity'|trans }} {{ 'Show the activity'|trans }}
</a> </a>
</li> </li>
{% if is_granted('CHILL_ACTIVITY_UPDATE', activity) %} {% if is_granted('CHILL_ACTIVITY_UPDATE', activity) %}
<li> <li>
<a href="{{ path('chill_activity_activity_edit', { 'person_id': person.id, 'id': activity.id} ) }}" class="sc-button bt-edit"> <a href="{{ path('chill_activity_activity_edit', { 'person_id': activity.person.id, 'id': activity.id} ) }}" class="sc-button bt-edit">
{{ 'Edit the activity'|trans }} {{ 'Edit the activity'|trans }}
</a> </a>
</li> </li>

View File

@@ -21,6 +21,7 @@
namespace Chill\ActivityBundle\Timeline; namespace Chill\ActivityBundle\Timeline;
use Chill\MainBundle\Timeline\TimelineProviderInterface; use Chill\MainBundle\Timeline\TimelineProviderInterface;
use Chill\ActivityBundle\Repository\ActivityACLAwareRepository;
use Doctrine\ORM\EntityManager; use Doctrine\ORM\EntityManager;
use Chill\MainBundle\Security\Authorization\AuthorizationHelper; use Chill\MainBundle\Security\Authorization\AuthorizationHelper;
use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface; use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface;
@@ -28,13 +29,13 @@ use Symfony\Component\Security\Core\Role\Role;
use Doctrine\ORM\Mapping\ClassMetadata; use Doctrine\ORM\Mapping\ClassMetadata;
use Chill\PersonBundle\Entity\Person; use Chill\PersonBundle\Entity\Person;
use Chill\MainBundle\Entity\Scope; use Chill\MainBundle\Entity\Scope;
use Chill\ActivityBundle\Entity\Activity;
use Chill\MainBundle\Timeline\TimelineSingleQuery;
/** /**
* Provide activity for inclusion in timeline * Provide activity for inclusion in timeline
* *
* @author Julien Fastré <julien.fastre@champs-libres.coop> */
* @author Champs Libres <info@champs-libres.coop>
*/
class TimelineActivityProvider implements TimelineProviderInterface class TimelineActivityProvider implements TimelineProviderInterface
{ {
@@ -55,6 +56,10 @@ class TimelineActivityProvider implements TimelineProviderInterface
* @var \Chill\MainBundle\Entity\User * @var \Chill\MainBundle\Entity\User
*/ */
protected $user; protected $user;
protected ActivityACLAwareRepository $aclAwareRepository;
private const SUPPORTED_CONTEXTS = [ 'center', 'person'];
/** /**
* TimelineActivityProvider constructor. * TimelineActivityProvider constructor.
@@ -66,11 +71,13 @@ class TimelineActivityProvider implements TimelineProviderInterface
public function __construct( public function __construct(
EntityManager $em, EntityManager $em,
AuthorizationHelper $helper, AuthorizationHelper $helper,
TokenStorageInterface $storage TokenStorageInterface $storage,
ActivityACLAwareRepository $aclAwareRepository
) )
{ {
$this->em = $em; $this->em = $em;
$this->helper = $helper; $this->helper = $helper;
$this->aclAwareRepository = $aclAwareRepository;
if (!$storage->getToken()->getUser() instanceof \Chill\MainBundle\Entity\User) if (!$storage->getToken()->getUser() instanceof \Chill\MainBundle\Entity\User)
{ {
@@ -86,67 +93,69 @@ class TimelineActivityProvider implements TimelineProviderInterface
*/ */
public function fetchQuery($context, array $args) public function fetchQuery($context, array $args)
{ {
$this->checkContext($context); if ('center' === $context) {
return TimelineSingleQuery::fromArray($this->aclAwareRepository
->queryTimelineIndexer($context, $args));
}
$metadataActivity = $this->em->getClassMetadata('ChillActivityBundle:Activity'); $metadataActivity = $this->em->getClassMetadata(Activity::class);
$metadataPerson = $this->em->getClassMetadata('ChillPersonBundle:Person');
[$where, $parameters] = $this->getWhereClauseForPerson($args['person']);
return array( return TimelineSingleQuery::fromArray([
'id' => $metadataActivity->getTableName() 'id' => $metadataActivity->getTableName()
.'.'.$metadataActivity->getColumnName('id'), .'.'.$metadataActivity->getColumnName('id'),
'type' => 'activity', 'type' => 'activity',
'date' => $metadataActivity->getTableName() 'date' => $metadataActivity->getTableName()
.'.'.$metadataActivity->getColumnName('date'), .'.'.$metadataActivity->getColumnName('date'),
'FROM' => $this->getFromClause($metadataActivity, $metadataPerson), 'FROM' => $this->getFromClausePerson($args['person']),
'WHERE' => $this->getWhereClause($metadataActivity, $metadataPerson, 'WHERE' => $where,
$args['person']) 'parameters' => $parameters
); ]);
} }
private function getWhereClause(ClassMetadata $metadataActivity, private function getWhereClauseForPerson(Person $person)
ClassMetadata $metadataPerson, Person $person)
{ {
$role = new Role('CHILL_ACTIVITY_SEE'); $parameters = [];
$reachableCenters = $this->helper->getReachableCenters($this->user, $metadataActivity = $this->em->getClassMetadata(Activity::class);
$role);
$associationMapping = $metadataActivity->getAssociationMapping('person'); $associationMapping = $metadataActivity->getAssociationMapping('person');
$role = new Role('CHILL_ACTIVITY_SEE');
if (count($reachableCenters) === 0) { $reachableScopes = $this->helper->getReachableScopes($this->user,
return 'FALSE = TRUE'; $role, $person->getCenter());
$whereClause = sprintf(' {activity.person_id} = ? AND {activity.scope_id} IN ({scopes_ids}) ');
$scopes_ids = [];
// first parameter: activity.person_id
$parameters[] = $person->getId();
// loop on reachable scopes
foreach ($reachableScopes as $scope) {
if (\in_array($scope->getId(), $scopes_ids)) {
continue;
}
$scopes_ids[] = '?';
$parameters[] = $scope->getId();
} }
// we start with activities having the person_id linked to person return [
// (currently only context "person" is supported) \strtr(
$whereClause = sprintf('%s = %d', $whereClause,
$associationMapping['joinColumns'][0]['name'], [
$person->getId()); '{activity.person_id}' => $associationMapping['joinColumns'][0]['name'],
'{activity.scope_id}' => $metadataActivity->getTableName().'.'.
// we add acl (reachable center and scopes)
$centerAndScopeLines = array();
foreach ($reachableCenters as $center) {
$reachablesScopesId = array_map(
function(Scope $scope) { return $scope->getId(); },
$this->helper->getReachableScopes($this->user, $role,
$person->getCenter())
);
$centerAndScopeLines[] = sprintf('(%s = %d AND %s IN (%s))',
$metadataPerson->getTableName().'.'.
$metadataPerson->getAssociationMapping('center')['joinColumns'][0]['name'],
$center->getId(),
$metadataActivity->getTableName().'.'.
$metadataActivity->getAssociationMapping('scope')['joinColumns'][0]['name'], $metadataActivity->getAssociationMapping('scope')['joinColumns'][0]['name'],
implode(',', $reachablesScopesId)); '{scopes_ids}' => \implode(", ", $scopes_ids)
,
} ]
$whereClause .= ' AND ('.implode(' OR ', $centerAndScopeLines).')'; ),
$parameters
return $whereClause; ];
} }
private function getFromClause(ClassMetadata $metadataActivity, private function getFromClausePerson()
ClassMetadata $metadataPerson)
{ {
$metadataActivity = $this->em->getClassMetadata(Activity::class);
$metadataPerson = $this->em->getClassMetadata(Person::class);
$associationMapping = $metadataActivity->getAssociationMapping('person'); $associationMapping = $metadataActivity->getAssociationMapping('person');
return $metadataActivity->getTableName().' JOIN ' return $metadataActivity->getTableName().' JOIN '
@@ -157,14 +166,14 @@ class TimelineActivityProvider implements TimelineProviderInterface
.$associationMapping['joinColumns'][0]['name'] .$associationMapping['joinColumns'][0]['name']
; ;
} }
/** /**
* *
* {@inheritDoc} * {@inheritDoc}
*/ */
public function getEntities(array $ids) public function getEntities(array $ids)
{ {
$activities = $this->em->getRepository('ChillActivityBundle:Activity') $activities = $this->em->getRepository(Activity::class)
->findBy(array('id' => $ids)); ->findBy(array('id' => $ids));
$result = array(); $result = array();
@@ -183,14 +192,13 @@ class TimelineActivityProvider implements TimelineProviderInterface
{ {
$this->checkContext($context); $this->checkContext($context);
return array( return [
'template' => 'ChillActivityBundle:Timeline:activity_person_context.html.twig', 'template' => 'ChillActivityBundle:Timeline:activity_person_context.html.twig',
'template_data' => array( 'template_data' => [
'activity' => $entity, 'activity' => $entity,
'person' => $args['person'], 'context' => $context
'user' => $entity->getUser() ]
) ];
);
} }
/** /**
@@ -210,7 +218,7 @@ class TimelineActivityProvider implements TimelineProviderInterface
*/ */
private function checkContext($context) private function checkContext($context)
{ {
if ($context !== 'person') { if (FALSE === \in_array($context, self::SUPPORTED_CONTEXTS)) {
throw new \LogicException("The context '$context' is not " throw new \LogicException("The context '$context' is not "
. "supported. Currently only 'person' is supported"); . "supported. Currently only 'person' is supported");
} }

View File

@@ -22,6 +22,8 @@ services:
- '@doctrine.orm.entity_manager' - '@doctrine.orm.entity_manager'
- '@chill.main.security.authorization.helper' - '@chill.main.security.authorization.helper'
- '@security.token_storage' - '@security.token_storage'
- '@Chill\ActivityBundle\Repository\ActivityACLAwareRepository'
public: true public: true
tags: tags:
- { name: chill.timeline, context: 'person' } - { name: chill.timeline, context: 'person' }
- { name: chill.timeline, context: 'center' }

View File

@@ -1,18 +1,32 @@
---
services: services:
chill_activity.repository.activity_type: chill_activity.repository.activity_type:
class: Doctrine\ORM\EntityRepository class: Doctrine\ORM\EntityRepository
factory: ['@doctrine.orm.entity_manager', getRepository] factory: ['@doctrine.orm.entity_manager', getRepository]
arguments: arguments:
- 'Chill\ActivityBundle\Entity\ActivityType' - 'Chill\ActivityBundle\Entity\ActivityType'
chill_activity.repository.reason: chill_activity.repository.reason:
class: Doctrine\ORM\EntityRepository class: Doctrine\ORM\EntityRepository
factory: ['@doctrine.orm.entity_manager', getRepository] factory: ['@doctrine.orm.entity_manager', getRepository]
arguments: arguments:
- 'Chill\ActivityBundle\Entity\ActivityReason' - 'Chill\ActivityBundle\Entity\ActivityReason'
chill_activity.repository.reason_category: chill_activity.repository.reason_category:
class: Doctrine\ORM\EntityRepository class: Doctrine\ORM\EntityRepository
factory: ['@doctrine.orm.entity_manager', getRepository] factory: ['@doctrine.orm.entity_manager', getRepository]
arguments: arguments:
- 'Chill\ActivityBundle\Entity\ActivityReasonCategory' - 'Chill\ActivityBundle\Entity\ActivityReasonCategory'
Chill\ActivityBundle\Repository\ActivityRepository:
tags: [doctrine.repository_service]
arguments:
- '@Doctrine\Persistence\ManagerRegistry'
Chill\ActivityBundle\Repository\ActivityACLAwareRepository:
arguments:
$tokenStorage: '@Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface'
$authorizationHelper: '@Chill\MainBundle\Security\Authorization\AuthorizationHelper'
$repository: '@Chill\ActivityBundle\Repository\ActivityRepository'
$em: '@Doctrine\ORM\EntityManagerInterface'

View File

@@ -22,13 +22,12 @@ class ChoiceWithOtherType extends AbstractType
*/ */
public function buildForm(FormBuilderInterface $builder, array $options) public function buildForm(FormBuilderInterface $builder, array $options)
{ {
//add an 'other' entry in choices array //add an 'other' entry in choices array
$options['choices'][$this->otherValueLabel] = '_other'; $options['choices'][$this->otherValueLabel] = '_other';
//ChoiceWithOther must always be expanded //ChoiceWithOther must always be expanded
$options['expanded'] = true; $options['expanded'] = true;
// adding a default value for choice // adding a default value for choice
$options['empty_data'] = null; $options['empty_data'] = $options['multiple'] ? [] : null;
$builder $builder
->add('_other', TextType::class, array('required' => false)) ->add('_other', TextType::class, array('required' => false))

View File

@@ -23,6 +23,7 @@ namespace Chill\EventBundle\Timeline;
use Chill\EventBundle\Entity\Event; use Chill\EventBundle\Entity\Event;
use Chill\MainBundle\Entity\Scope; use Chill\MainBundle\Entity\Scope;
use Chill\MainBundle\Timeline\TimelineProviderInterface; use Chill\MainBundle\Timeline\TimelineProviderInterface;
use Chill\MainBundle\Timeline\TimelineSingleQuery;
use Doctrine\ORM\EntityManager; use Doctrine\ORM\EntityManager;
use Chill\MainBundle\Security\Authorization\AuthorizationHelper; use Chill\MainBundle\Security\Authorization\AuthorizationHelper;
use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface; use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface;
@@ -88,13 +89,14 @@ class TimelineEventProvider implements TimelineProviderInterface
$metadataParticipation = $this->em->getClassMetadata('ChillEventBundle:Participation'); $metadataParticipation = $this->em->getClassMetadata('ChillEventBundle:Participation');
$metadataPerson = $this->em->getClassMetadata('ChillPersonBundle:Person'); $metadataPerson = $this->em->getClassMetadata('ChillPersonBundle:Person');
$query = array( $query = TimelineSingleQuery::fromArray([
'id' => $metadataEvent->getTableName().'.'.$metadataEvent->getColumnName('id'), 'id' => $metadataEvent->getTableName().'.'.$metadataEvent->getColumnName('id'),
'type' => 'event', 'type' => 'event',
'date' => $metadataEvent->getTableName().'.'.$metadataEvent->getColumnName('date'), 'date' => $metadataEvent->getTableName().'.'.$metadataEvent->getColumnName('date'),
'FROM' => $this->getFromClause($metadataEvent, $metadataParticipation, $metadataPerson), 'FROM' => $this->getFromClause($metadataEvent, $metadataParticipation, $metadataPerson),
'WHERE' => $this->getWhereClause($metadataEvent, $metadataParticipation, $metadataPerson, $args['person']) 'WHERE' => $this->getWhereClause($metadataEvent, $metadataParticipation, $metadataPerson, $args['person']),
); 'parameters' => []
]);
return $query; return $query;
} }
@@ -238,4 +240,4 @@ class TimelineEventProvider implements TimelineProviderInterface
); );
} }
} }

View File

@@ -0,0 +1,91 @@
<?php
/*
* 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\Controller;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpFoundation\Request;
use Chill\MainBundle\Timeline\TimelineBuilder;
use Chill\MainBundle\Pagination\PaginatorFactory;
use Chill\PersonBundle\Security\Authorization\PersonVoter;
use Chill\MainBundle\Security\Authorization\AuthorizationHelper;
use Symfony\Component\Security\Core\Role\Role;
use Symfony\Component\Routing\Annotation\Route;
use Symfony\Component\Security\Core\Security;
class TimelineCenterController extends AbstractController
{
protected TimelineBuilder $timelineBuilder;
protected PaginatorFactory $paginatorFactory;
private Security $security;
public function __construct(
TimelineBuilder $timelineBuilder,
PaginatorFactory $paginatorFactory,
Security $security
) {
$this->timelineBuilder = $timelineBuilder;
$this->paginatorFactory = $paginatorFactory;
$this->security = $security;
}
/**
* @Route("/{_locale}/center/timeline",
* name="chill_center_timeline",
* methods={"GET"}
* )
*/
public function centerAction(Request $request)
{
// collect reachable center for each group
$user = $this->security->getUser();
$centers = [];
foreach ($user->getGroupCenters() as $group) {
$centers[] = $group->getCenter();
}
if (0 === count($centers)) {
throw $this->createNotFoundException();
}
$nbItems = $this->timelineBuilder->countItems('center',
[ 'centers' => $centers ]
);
$paginator = $this->paginatorFactory->create($nbItems);
return $this->render('@ChillMain/Timeline/index.html.twig', array
(
'timeline' => $this->timelineBuilder->getTimelineHTML(
'center',
[ 'centers' => $centers ],
$paginator->getCurrentPage()->getFirstItemNumber(),
$paginator->getItemsPerPage()
),
'nb_items' => $nbItems,
'paginator' => $paginator
)
);
}
}

View File

@@ -0,0 +1,7 @@
<div class="timeline">
{% for result in results %}
<div class="timeline-item {% if loop.index0 is even %}even{% else %}odd{% endif %}">
{% include result.template with result.template_data %}
</div>
{% endfor %}
</div>

View File

@@ -1,7 +1,15 @@
<div class="timeline"> {% extends "@ChillMain/layout.html.twig" %}
{% for result in results %}
<div class="timeline-item {% if loop.index0 is even %}even{% else %}odd{% endif %}"> {% block content %}
{% include result.template with result.template_data %} <div id="container content">
</div> <div class="grid-8 centered">
{% endfor %} <h1>{{ 'Global timeline'|trans }}</h1>
</div>
{{ timeline|raw }}
{% if nb_items > paginator.getItemsPerPage %}
{{ chill_pagination(paginator) }}
{% endif %}
</div>
</div>
{% endblock content %}

View File

@@ -68,6 +68,14 @@ class SectionMenuBuilder implements LocalMenuBuilderInterface
'icons' => ['home'], 'icons' => ['home'],
'order' => 0 'order' => 0
]); ]);
$menu->addChild($this->translator->trans('Global timeline'), [
'route' => 'chill_center_timeline',
])
->setExtras([
'order' => 10
]
);
if ($this->authorizationChecker->isGranted(ChillExportVoter::EXPORT)) { if ($this->authorizationChecker->isGranted(ChillExportVoter::EXPORT)) {
$menu->addChild($this->translator->trans('Export Menu'), [ $menu->addChild($this->translator->trans('Export Menu'), [

View File

@@ -32,34 +32,34 @@ use Chill\MainBundle\Entity\GroupCenter;
use Chill\MainBundle\Entity\RoleScope; use Chill\MainBundle\Entity\RoleScope;
/** /**
* Helper for authorizations. * Helper for authorizations.
* *
* Provides methods for user and entities information. * Provides methods for user and entities information.
* *
* @author Julien Fastré <julien.fastre@champs-libres.coop> * @author Julien Fastré <julien.fastre@champs-libres.coop>
*/ */
class AuthorizationHelper implements AuthorizationHelperInterface class AuthorizationHelper
{ {
/** /**
* *
* @var RoleHierarchyInterface * @var RoleHierarchyInterface
*/ */
protected $roleHierarchy; protected $roleHierarchy;
/** /**
* The role in a hierarchy, given by the parameter * The role in a hierarchy, given by the parameter
* `security.role_hierarchy.roles` from the container. * `security.role_hierarchy.roles` from the container.
* *
* @var string[] * @var string[]
*/ */
protected $hierarchy; protected $hierarchy;
/** /**
* *
* @var EntityManagerInterface * @var EntityManagerInterface
*/ */
protected $em; protected $em;
public function __construct( public function __construct(
RoleHierarchyInterface $roleHierarchy, RoleHierarchyInterface $roleHierarchy,
$hierarchy, $hierarchy,
@@ -69,10 +69,10 @@ class AuthorizationHelper implements AuthorizationHelperInterface
$this->hierarchy = $hierarchy; $this->hierarchy = $hierarchy;
$this->em = $em; $this->em = $em;
} }
/** /**
* Determines if a user is active on this center * Determines if a user is active on this center
* *
* @param User $user * @param User $user
* @param Center $center * @param Center $center
* @return bool * @return bool
@@ -81,21 +81,21 @@ class AuthorizationHelper implements AuthorizationHelperInterface
{ {
foreach ($user->getGroupCenters() as $groupCenter) { foreach ($user->getGroupCenters() as $groupCenter) {
if ($center->getId() === $groupCenter->getCenter()->getId()) { if ($center->getId() === $groupCenter->getCenter()->getId()) {
return true; return true;
} }
} }
return false; return false;
} }
/** /**
* *
* Determines if the user has access to the given entity. * Determines if the user has access to the given entity.
* *
* if the entity implements Chill\MainBundle\Entity\HasScopeInterface, * if the entity implements Chill\MainBundle\Entity\HasScopeInterface,
* the scope is taken into account. * the scope is taken into account.
* *
* @param User $user * @param User $user
* @param HasCenterInterface $entity the entity may also implement HasScopeInterface * @param HasCenterInterface $entity the entity may also implement HasScopeInterface
* @param string|Role $attribute * @param string|Role $attribute
@@ -103,15 +103,13 @@ class AuthorizationHelper implements AuthorizationHelperInterface
*/ */
public function userHasAccess(User $user, HasCenterInterface $entity, $attribute) public function userHasAccess(User $user, HasCenterInterface $entity, $attribute)
{ {
$center = $entity->getCenter(); $center = $entity->getCenter();
if (!$this->userCanReachCenter($user, $center)) { if (!$this->userCanReachCenter($user, $center)) {
return false; return false;
} }
$role = ($attribute instanceof Role) ? $attribute : new Role($attribute);
foreach ($user->getGroupCenters() as $groupCenter){ foreach ($user->getGroupCenters() as $groupCenter){
//filter on center //filter on center
if ($groupCenter->getCenter()->getId() === $entity->getCenter()->getId()) { if ($groupCenter->getCenter()->getId() === $entity->getCenter()->getId()) {
@@ -119,8 +117,7 @@ class AuthorizationHelper implements AuthorizationHelperInterface
//iterate on roleScopes //iterate on roleScopes
foreach($permissionGroup->getRoleScopes() as $roleScope) { foreach($permissionGroup->getRoleScopes() as $roleScope) {
//check that the role allow to reach the required role //check that the role allow to reach the required role
if ($this->isRoleReached($role, if ($this->isRoleReached($attribute, $roleScope->getRole())) {
new Role($roleScope->getRole()))){
//if yes, we have a right on something... //if yes, we have a right on something...
// perform check on scope if necessary // perform check on scope if necessary
if ($entity instanceof HasScopeInterface) { if ($entity instanceof HasScopeInterface) {
@@ -137,33 +134,35 @@ class AuthorizationHelper implements AuthorizationHelperInterface
} }
} }
} }
} }
} }
return false; return false;
} }
/** /**
* Get reachable Centers for the given user, role, * Get reachable Centers for the given user, role,
* and optionnaly Scope * and optionnaly Scope
* *
* @param User $user * @param User $user
* @param Role $role * @param string|Role $role
* @param null|Scope $scope * @param null|Scope $scope
* @return Center[] * @return Center[]
*/ */
public function getReachableCenters(User $user, Role $role, Scope $scope = null) public function getReachableCenters(User $user, $role, Scope $scope = null)
{ {
if ($role instanceof Role) {
$role = $role->getRole();
}
$centers = array(); $centers = array();
foreach ($user->getGroupCenters() as $groupCenter){ foreach ($user->getGroupCenters() as $groupCenter){
$permissionGroup = $groupCenter->getPermissionsGroup(); $permissionGroup = $groupCenter->getPermissionsGroup();
//iterate on roleScopes //iterate on roleScopes
foreach($permissionGroup->getRoleScopes() as $roleScope) { foreach($permissionGroup->getRoleScopes() as $roleScope) {
//check that the role is in the reachable roles //check that the role is in the reachable roles
if ($this->isRoleReached($role, if ($this->isRoleReached($role, $roleScope->getRole())) {
new Role($roleScope->getRole()))) {
if ($scope === null) { if ($scope === null) {
$centers[] = $groupCenter->getCenter(); $centers[] = $groupCenter->getCenter();
break 1; break 1;
@@ -171,19 +170,43 @@ class AuthorizationHelper implements AuthorizationHelperInterface
if ($scope->getId() == $roleScope->getScope()->getId()){ if ($scope->getId() == $roleScope->getScope()->getId()){
$centers[] = $groupCenter->getCenter(); $centers[] = $groupCenter->getCenter();
break 1; break 1;
} }
} }
} }
} }
} }
return $centers; return $centers;
} }
/** /**
* Return all reachable scope for a given user, center and role * Filter an array of centers, return only center which are reachable
* *
* @param User $user The user
* @param array $centers a list of centers which are going to be filtered
* @param string|Center $role
*/
public function filterReachableCenters(User $user, array $centers, $role): array
{
$results = [];
if ($role instanceof Role) {
$role = $role->getRole();
}
foreach ($centers as $center) {
if ($this->userCanReachCenter($user, $center, $role)) {
$results[] = $center;
}
}
return $results;
}
/**
* Return all reachable scope for a given user, center and role
*
* @deprecated Use getReachableCircles * @deprecated Use getReachableCircles
* *
* @param User $user * @param User $user
@@ -191,23 +214,30 @@ class AuthorizationHelper implements AuthorizationHelperInterface
* @param Center $center * @param Center $center
* @return Scope[] * @return Scope[]
*/ */
public function getReachableScopes(User $user, Role $role, Center $center) public function getReachableScopes(User $user, $role, Center $center)
{ {
if ($role instanceof Role) {
$role = $role->getRole();
}
return $this->getReachableCircles($user, $role, $center); return $this->getReachableCircles($user, $role, $center);
} }
/** /**
* Return all reachable circle for a given user, center and role * Return all reachable circle for a given user, center and role
* *
* @param User $user * @param User $user
* @param Role $role * @param string|Role $role
* @param Center $center * @param Center $center
* @return Scope[] * @return Scope[]
*/ */
public function getReachableCircles(User $user, Role $role, Center $center) public function getReachableCircles(User $user, $role, Center $center)
{ {
if ($role instanceof Role) {
$role = $role->getRole();
}
$scopes = array(); $scopes = array();
foreach ($user->getGroupCenters() as $groupCenter){ foreach ($user->getGroupCenters() as $groupCenter){
if ($center->getId() === $groupCenter->getCenter()->getId()) { if ($center->getId() === $groupCenter->getCenter()->getId()) {
//iterate on permissionGroup //iterate on permissionGroup
@@ -215,20 +245,18 @@ class AuthorizationHelper implements AuthorizationHelperInterface
//iterate on roleScopes //iterate on roleScopes
foreach($permissionGroup->getRoleScopes() as $roleScope) { foreach($permissionGroup->getRoleScopes() as $roleScope) {
//check that the role is in the reachable roles //check that the role is in the reachable roles
if ($this->isRoleReached($role, if ($this->isRoleReached($role, $roleScope->getRole())) {
new Role($roleScope->getRole()))) {
$scopes[] = $roleScope->getScope(); $scopes[] = $roleScope->getScope();
} }
} }
} }
} }
return $scopes; return $scopes;
} }
/** /**
* *
* @param Role $role * @param Role $role
* @param Center $center * @param Center $center
* @param Scope $circle * @param Scope $circle
@@ -239,7 +267,7 @@ class AuthorizationHelper implements AuthorizationHelperInterface
$parents = $this->getParentRoles($role); $parents = $this->getParentRoles($role);
$parents[] = $role; $parents[] = $role;
$parentRolesString = \array_map(function(Role $r) { return $r->getRole(); }, $parents); $parentRolesString = \array_map(function(Role $r) { return $r->getRole(); }, $parents);
$qb = $this->em->createQueryBuilder(); $qb = $this->em->createQueryBuilder();
$qb $qb
->select('u') ->select('u')
@@ -250,37 +278,37 @@ class AuthorizationHelper implements AuthorizationHelperInterface
->where('gc.center = :center') ->where('gc.center = :center')
->andWhere($qb->expr()->in('rs.role', $parentRolesString)) ->andWhere($qb->expr()->in('rs.role', $parentRolesString))
; ;
$qb->setParameter('center', $center); $qb->setParameter('center', $center);
if ($circle !== null) { if ($circle !== null) {
$qb->andWhere('rs.scope = :circle') $qb->andWhere('rs.scope = :circle')
->setParameter('circle', $circle) ->setParameter('circle', $circle)
; ;
} }
return $qb->getQuery()->getResult(); return $qb->getQuery()->getResult();
} }
/** /**
* Test if a parent role may give access to a given child role * Test if a parent role may give access to a given child role
* *
* @param Role $childRole The role we want to test if he is reachable * @param Role $childRole The role we want to test if he is reachable
* @param Role $parentRole The role which should give access to $childRole * @param Role $parentRole The role which should give access to $childRole
* @return boolean true if the child role is granted by parent role * @return boolean true if the child role is granted by parent role
*/ */
protected function isRoleReached(Role $childRole, Role $parentRole) protected function isRoleReached($childRole, $parentRole)
{ {
$reachableRoles = $this->roleHierarchy $reachableRoles = $this->roleHierarchy
->getReachableRoles([$parentRole]); ->getReachableRoleNames([$parentRole]);
return in_array($childRole, $reachableRoles); return in_array($childRole, $reachableRoles);
} }
/** /**
* Return all the role which give access to the given role. Only the role * Return all the role which give access to the given role. Only the role
* which are registered into Chill are taken into account. * which are registered into Chill are taken into account.
* *
* @param Role $role * @param Role $role
* @return Role[] the role which give access to the given $role * @return Role[] the role which give access to the given $role
*/ */
@@ -291,18 +319,18 @@ class AuthorizationHelper implements AuthorizationHelperInterface
$roles = \array_map( $roles = \array_map(
function($string) { function($string) {
return new Role($string); return new Role($string);
}, },
\array_keys($this->hierarchy) \array_keys($this->hierarchy)
); );
foreach ($roles as $r) { foreach ($roles as $r) {
$childRoles = $this->roleHierarchy->getReachableRoleNames([$r->getRole()]); $childRoles = $this->roleHierarchy->getReachableRoleNames([$r->getRole()]);
if (\in_array($role, $childRoles)) { if (\in_array($role, $childRoles)) {
$parentRoles[] = $r; $parentRoles[] = $r;
} }
} }
return $parentRoles; return $parentRoles;
} }
} }

View File

@@ -1,87 +0,0 @@
<?php
namespace Chill\MainBundle\Security\Authorization;
use Chill\MainBundle\Entity\User;
use Chill\MainBundle\Entity\Center;
use Chill\MainBundle\Entity\HasCenterInterface;
use Symfony\Component\Security\Core\Role\Role;
use Chill\MainBundle\Entity\Scope;
interface AuthorizationHelperInterface
{
/**
* Determines if a user is active on this center
*
* @param User $user
* @param Center $center
* @return bool
*/
public function userCanReachCenter(User $user, Center $center);
/**
*
* Determines if the user has access to the given entity.
*
* if the entity implements Chill\MainBundle\Entity\HasScopeInterface,
* the scope is taken into account.
*
* @param User $user
* @param HasCenterInterface $entity the entity may also implement HasScopeInterface
* @param string|Role $attribute
* @return boolean true if the user has access
*/
public function userHasAccess(User $user, HasCenterInterface $entity, $attribute);
/**
* Get reachable Centers for the given user, role,
* and optionnaly Scope
*
* @param User $user
* @param Role $role
* @param null|Scope $scope
* @return Center[]
*/
public function getReachableCenters(User $user, Role $role, Scope $scope = null);
/**
* Return all reachable scope for a given user, center and role
*
* @deprecated Use getReachableCircles
*
* @param User $user
* @param Role $role
* @param Center $center
* @return Scope[]
*/
public function getReachableScopes(User $user, Role $role, Center $center);
/**
* Return all reachable circle for a given user, center and role
*
* @param User $user
* @param Role $role
* @param Center $center
* @return Scope[]
*/
public function getReachableCircles(User $user, Role $role, Center $center);
/**
*
* @param Role $role
* @param Center $center
* @param Scope $circle
* @return Users
*/
public function findUsersReaching(Role $role, Center $center, Scope $circle = null);
/**
* Return all the role which give access to the given role. Only the role
* which are registered into Chill are taken into account.
*
* @param Role $role
* @return Role[] the role which give access to the given $role
*/
public function getParentRoles(Role $role);
}

View File

@@ -2,7 +2,7 @@
/* /*
* Chill is a software for social workers * Chill is a software for social workers
* *
* Copyright (C) 2014-2019, Champs Libres Cooperative SCRLFS, * Copyright (C) 2014-2019, Champs Libres Cooperative SCRLFS,
* <http://www.champs-libres.coop> * <http://www.champs-libres.coop>
* *
* This program is free software: you can redistribute it and/or modify * This program is free software: you can redistribute it and/or modify
@@ -28,18 +28,18 @@ use Twig\TwigFilter;
* *
* @package Chill\MainBundle\Templating\Entity * @package Chill\MainBundle\Templating\Entity
*/ */
class ChillEntityRenderExtension extends AbstractExtension implements ChillEntityRenderExtensionInterface class ChillEntityRenderExtension extends AbstractExtension
{ {
/** /**
* @var ChillEntityRenderInterface * @var ChillEntityRenderInterface
*/ */
protected $renders = []; protected $renders = [];
/** /**
* @var ChillEntityRender * @var ChillEntityRender
*/ */
protected $defaultRender; protected $defaultRender;
/** /**
* ChillEntityRenderExtension constructor. * ChillEntityRenderExtension constructor.
*/ */
@@ -47,7 +47,7 @@ class ChillEntityRenderExtension extends AbstractExtension implements ChillEntit
{ {
$this->defaultRender = new ChillEntityRender(); $this->defaultRender = new ChillEntityRender();
} }
/** /**
* @return array|TwigFilter[] * @return array|TwigFilter[]
*/ */
@@ -62,7 +62,7 @@ class ChillEntityRenderExtension extends AbstractExtension implements ChillEntit
]) ])
]; ];
} }
/** /**
* @param $entity * @param $entity
* @param array $options * @param array $options
@@ -76,7 +76,7 @@ class ChillEntityRenderExtension extends AbstractExtension implements ChillEntit
return $this->getRender($entity, $options) return $this->getRender($entity, $options)
->renderString($entity, $options); ->renderString($entity, $options);
} }
/** /**
* @param $entity * @param $entity
* @param array $options * @param array $options
@@ -90,7 +90,7 @@ class ChillEntityRenderExtension extends AbstractExtension implements ChillEntit
return $this->getRender($entity, $options) return $this->getRender($entity, $options)
->renderBox($entity, $options); ->renderBox($entity, $options);
} }
/** /**
* @param ChillEntityRenderInterface $render * @param ChillEntityRenderInterface $render
*/ */
@@ -98,7 +98,7 @@ class ChillEntityRenderExtension extends AbstractExtension implements ChillEntit
{ {
$this->renders[] = $render; $this->renders[] = $render;
} }
/** /**
* @param $entity * @param $entity
* @param $options * @param $options

View File

@@ -1,33 +0,0 @@
<?php
namespace Chill\MainBundle\Templating\Entity;
use Twig\Extension\ExtensionInterface;
use Twig\TwigFilter;
interface ChillEntityRenderExtensionInterface extends ExtensionInterface
{
/**
* @return array|TwigFilter[]
*/
public function getFilters();
/**
* @param $entity
* @param array $options
* @return string
*/
public function renderString($entity, array $options = []): string;
/**
* @param $entity
* @param array $options
* @return string
*/
public function renderBox($entity, array $options = []): string;
/**
* @param ChillEntityRenderInterface $render
*/
public function addRender(ChillEntityRenderInterface $render);
}

View File

@@ -23,36 +23,36 @@ use Symfony\Component\HttpFoundation\RequestStack;
use Symfony\Component\Translation\Translator; use Symfony\Component\Translation\Translator;
/** /**
* *
* This helper helps to find the string in current locale from translatable_strings * This helper helps to find the string in current locale from translatable_strings
* *
* @author Julien Fastré <julien.fastre@champs-libres.coop> * @author Julien Fastré <julien.fastre@champs-libres.coop>
* *
*/ */
class TranslatableStringHelper implements TranslatableStringHelperInterface class TranslatableStringHelper
{ {
/** /**
* *
* @var RequestStack * @var RequestStack
*/ */
private $requestStack; private $requestStack;
private $fallbackLocales; private $fallbackLocales;
public function __construct(RequestStack $requestStack, Translator $translator) public function __construct(RequestStack $requestStack, Translator $translator)
{ {
$this->requestStack = $requestStack; $this->requestStack = $requestStack;
$this->fallbackLocales = $translator->getFallbackLocales(); $this->fallbackLocales = $translator->getFallbackLocales();
} }
/** /**
* return the string in current locale if it exists. * return the string in current locale if it exists.
* *
* If it does not exists; return the name in the first language available. * If it does not exists; return the name in the first language available.
* *
* Return a blank string if any strings are available. * Return a blank string if any strings are available.
* Return NULL if $translatableString is NULL * Return NULL if $translatableString is NULL
* *
* @param array $translatableStrings * @param array $translatableStrings
* @return string * @return string
*/ */
@@ -61,32 +61,32 @@ class TranslatableStringHelper implements TranslatableStringHelperInterface
if (NULL === $translatableStrings) { if (NULL === $translatableStrings) {
return NULL; return NULL;
} }
$language = $this->requestStack->getCurrentRequest()->getLocale(); $language = $this->requestStack->getCurrentRequest()->getLocale();
if (isset($translatableStrings[$language])) { if (isset($translatableStrings[$language])) {
return $translatableStrings[$language]; return $translatableStrings[$language];
} else { } else {
foreach ($this->fallbackLocales as $locale) { foreach ($this->fallbackLocales as $locale) {
if (array_key_exists($locale, $translatableStrings)) { if (array_key_exists($locale, $translatableStrings)) {
return $translatableStrings[$locale]; return $translatableStrings[$locale];
} }
} }
} }
// no fallback translation... trying the first available // no fallback translation... trying the first available
$langs = array_keys($translatableStrings); $langs = array_keys($translatableStrings);
if (count($langs) === 0) { if (count($langs) === 0) {
return ''; return '';
} }
return $translatableStrings[$langs[0]]; return $translatableStrings[$langs[0]];
} }
} }

View File

@@ -1,19 +0,0 @@
<?php
namespace Chill\MainBundle\Templating;
interface TranslatableStringHelperInterface
{
/**
* return the string in current locale if it exists.
*
* If it does not exists; return the name in the first language available.
*
* Return a blank string if any strings are available.
* Return NULL if $translatableString is NULL
*
* @param array $translatableStrings
* @return string
*/
public function localize(array $translatableStrings);
}

View File

@@ -23,46 +23,46 @@ use Doctrine\ORM\Query\ResultSetMapping;
use Doctrine\DBAL\Types\Type; use Doctrine\DBAL\Types\Type;
use Doctrine\ORM\EntityManagerInterface; use Doctrine\ORM\EntityManagerInterface;
use Symfony\Component\DependencyInjection\ContainerAwareInterface; use Symfony\Component\DependencyInjection\ContainerAwareInterface;
use Doctrine\ORM\Query;
use Doctrine\ORM\NativeQuery;
/** /**
* Build timeline * Build timeline
*
* @author Julien Fastré <julien.fastre@champs-libres.coop>
*/ */
class TimelineBuilder implements ContainerAwareInterface, TimelineBuilderInterface class TimelineBuilder implements ContainerAwareInterface
{ {
use \Symfony\Component\DependencyInjection\ContainerAwareTrait; use \Symfony\Component\DependencyInjection\ContainerAwareTrait;
/** /**
* *
* @var \Doctrine\ORM\EntityManagerInterface * @var \Doctrine\ORM\EntityManagerInterface
*/ */
private $em; private $em;
/** /**
* Record provider * Record provider
* *
* This array has the structure `[ 'service id' => $service ]` * This array has the structure `[ 'service id' => $service ]`
* *
* @var TimelineProviderInterface[] * @var TimelineProviderInterface[]
*/ */
private $providers = []; private $providers = [];
/** /**
* Record provider and their context * Record provider and their context
* *
* This array has the structure `[ 'context' => [ 'service id' ] ]` * This array has the structure `[ 'context' => [ 'service id' ] ]`
* *
* @var array * @var array
*/ */
private $providersByContext = []; private $providersByContext = [];
public function __construct(EntityManagerInterface $em) public function __construct(EntityManagerInterface $em)
{ {
$this->em = $em; $this->em = $em;
} }
/** /**
* return an HTML string with timeline * return an HTML string with timeline
* *
@@ -78,19 +78,19 @@ class TimelineBuilder implements ContainerAwareInterface, TimelineBuilderInterfa
*/ */
public function getTimelineHTML($context, array $args, $firstItem = 0, $number = 20) public function getTimelineHTML($context, array $args, $firstItem = 0, $number = 20)
{ {
$union = $this->buildUnionQuery($context, $args); list($union, $parameters) = $this->buildUnionQuery($context, $args);
//add ORDER BY clause and LIMIT //add ORDER BY clause and LIMIT
$query = $union . sprintf(' ORDER BY date DESC LIMIT %d OFFSET %d', $query = $union . sprintf(' ORDER BY date DESC LIMIT %d OFFSET %d',
$number, $firstItem); $number, $firstItem);
// run query and handle results // run query and handle results
$fetched = $this->runUnionQuery($query); $fetched = $this->runUnionQuery($query, $parameters);
$entitiesByKey = $this->getEntities($fetched, $context); $entitiesByKey = $this->getEntities($fetched, $context);
return $this->render($fetched, $entitiesByKey, $context, $args); return $this->render($fetched, $entitiesByKey, $context, $args);
} }
/** /**
* Return the number of items for the given context and args * Return the number of items for the given context and args
* *
@@ -100,18 +100,20 @@ class TimelineBuilder implements ContainerAwareInterface, TimelineBuilderInterfa
*/ */
public function countItems($context, array $args) public function countItems($context, array $args)
{ {
$union = $this->buildUnionQuery($context, $args);
// embed the union query inside a count query
$count = sprintf('SELECT COUNT(sq.id) AS total FROM (%s) as sq', $union);
$rsm = (new ResultSetMapping()) $rsm = (new ResultSetMapping())
->addScalarResult('total', 'total', Type::INTEGER); ->addScalarResult('total', 'total', Type::INTEGER);
return $this->em->createNativeQuery($count, $rsm) list($select, $parameters) = $this->buildUnionQuery($context, $args);
->getSingleScalarResult();
}
// embed the union query inside a count query
$countQuery = sprintf('SELECT COUNT(sq.id) AS total FROM (%s) as sq', $select);
$nq = $this->em->createNativeQuery($countQuery, $rsm);
$nq->setParameters($parameters);
return $nq->getSingleScalarResult();
}
/** /**
* add a provider id * add a provider id
* *
@@ -125,7 +127,7 @@ class TimelineBuilder implements ContainerAwareInterface, TimelineBuilderInterfa
$this->providersByContext[$context][] = $id; $this->providersByContext[$context][] = $id;
$this->providers[$id] = $provider; $this->providers[$id] = $provider;
} }
/** /**
* Get providers by context * Get providers by context
* *
@@ -139,55 +141,74 @@ class TimelineBuilder implements ContainerAwareInterface, TimelineBuilderInterfa
throw new \LogicException(sprintf('No builders have been defined for "%s"' throw new \LogicException(sprintf('No builders have been defined for "%s"'
. ' context', $context)); . ' context', $context));
} }
$providers = []; $providers = [];
foreach($this->providersByContext[$context] as $providerId) { foreach($this->providersByContext[$context] as $providerId) {
$providers[] = $this->providers[$providerId]; $providers[] = $this->providers[$providerId];
} }
return $providers; return $providers;
} }
/** /**
* build the UNION query with all providers * build the UNION query with all providers
* *
* @uses self::buildSelectQuery to build individual SELECT queries * @uses self::buildSelectQuery to build individual SELECT queries
* *
* @param string $context
* @param mixed $args
* @param int $page
* @param int $number
* @return string
* @throws \LogicException if no builder have been defined for this context * @throws \LogicException if no builder have been defined for this context
* @return array, where first element is the query, the second one an array with the parameters
*/ */
private function buildUnionQuery($context, array $args) private function buildUnionQuery(string $context, array $args): array
{ {
//append SELECT queries with UNION keyword between them //append SELECT queries with UNION keyword between them
$union = ''; $union = '';
foreach($this->getProvidersByContext($context) as $provider) { $parameters = [];
$select = $this->buildSelectQuery($provider, $context, $args);
$append = ($union === '') ? $select : ' UNION '.$select;
$union .= $append;
}
return $union; foreach($this->getProvidersByContext($context) as $provider) {
$data = $provider->fetchQuery($context, $args);
list($select, $selectParameters) = $this->buildSelectQuery($data);
$append = empty($union) ? $select : ' UNION '.$select;
$union .= $append;
$parameters = array_merge($parameters, $selectParameters);
}
return [$union, $parameters];
} }
/**
* Hack to replace the arbitrary "AS" statement in DQL
* into proper SQL query
* TODO remove
private function replaceASInDQL(string $dql): string
{
$pattern = '/^(SELECT\s+[a-zA-Z0-9\_\.\']{1,}\s+)(AS [a-z0-9\_]{1,})(\s{0,},\s{0,}[a-zA-Z0-9\_\.\']{1,}\s+)(AS [a-z0-9\_]{1,})(\s{0,},\s{0,}[a-zA-Z0-9\_\.\']{1,}\s+)(AS [a-z0-9\_]{1,})(\s+FROM.*)/';
$replacements = '${1} AS id ${3} AS type ${5} AS date ${7}';
$s = \preg_replace($pattern, $replacements, $dql, 1);
if (NULL === $s) {
throw new \RuntimeException('Could not replace the "AS" statement produced by '.
'DQL with normal SQL AS: '.$dql);
}
return $s;
}
*/
/** /**
* return the SQL SELECT query as a string, * return the SQL SELECT query as a string,
* *
* @uses TimelineProfiderInterface::fetchQuery use the fetchQuery function * @return array: first parameter is the sql string, second an array with parameters
* @param \Chill\MainBundle\Timeline\TimelineProviderInterface $provider
* @param string $context
* @param mixed[] $args
* @return string
*/ */
private function buildSelectQuery(TimelineProviderInterface $provider, $context, array $args) private function buildSelectQuery($data): array
{ {
$data = $provider->fetchQuery($context, $args); return [$data->buildSql(), $data->getParameters()];
return sprintf( // dead code
$parameters = [];
$sql = sprintf(
'SELECT %s AS id, ' 'SELECT %s AS id, '
. '%s AS "date", ' . '%s AS "date", '
. "'%s' AS type " . "'%s' AS type "
@@ -197,26 +218,30 @@ class TimelineBuilder implements ContainerAwareInterface, TimelineBuilderInterfa
$data['date'], $data['date'],
$data['type'], $data['type'],
$data['FROM'], $data['FROM'],
$data['WHERE']); is_string($data['WHERE']) ? $data['WHERE'] : $data['WHERE'][0]
} );
return [$sql, $data['WHERE'][1]];
}
/** /**
* run the UNION query and return result as an array * run the UNION query and return result as an array
* *
* @param string $query * @return array an array with the results
* @return array
*/ */
private function runUnionQuery($query) private function runUnionQuery(string $query, array $parameters): array
{ {
$resultSetMapping = (new ResultSetMapping()) $resultSetMapping = (new ResultSetMapping())
->addScalarResult('id', 'id') ->addScalarResult('id', 'id')
->addScalarResult('type', 'type') ->addScalarResult('type', 'type')
->addScalarResult('date', 'date'); ->addScalarResult('date', 'date');
return $this->em->createNativeQuery($query, $resultSetMapping) return $this->em->createNativeQuery($query, $resultSetMapping)
->getArrayResult(); ->setParameters($parameters)
->getArrayResult();
} }
/** /**
* *
* @param array $queriedIds * @param array $queriedIds
@@ -227,11 +252,11 @@ class TimelineBuilder implements ContainerAwareInterface, TimelineBuilderInterfa
{ {
//gather entities by type to pass all id with same type to the TimelineProvider. //gather entities by type to pass all id with same type to the TimelineProvider.
$idsByType = array(); $idsByType = array();
foreach($queriedIds as $result) { foreach($queriedIds as $result) {
$idsByType[$result['type']][] = $result['id']; $idsByType[$result['type']][] = $result['id'];
} }
//fetch entities from providers //fetch entities from providers
$entitiesByType = array(); $entitiesByType = array();
foreach ($idsByType as $type => $ids) { foreach ($idsByType as $type => $ids) {
@@ -243,10 +268,10 @@ class TimelineBuilder implements ContainerAwareInterface, TimelineBuilderInterfa
} }
} }
} }
return $entitiesByType; return $entitiesByType;
} }
/** /**
* render the timeline as HTML * render the timeline as HTML
* *
@@ -269,17 +294,17 @@ class TimelineBuilder implements ContainerAwareInterface, TimelineBuilderInterfa
$timelineEntry['date'] = new \DateTime($result['date']); $timelineEntry['date'] = new \DateTime($result['date']);
$timelineEntry['template'] = $data['template']; $timelineEntry['template'] = $data['template'];
$timelineEntry['template_data'] = $data['template_data']; $timelineEntry['template_data'] = $data['template_data'];
$timelineEntries[] = $timelineEntry; $timelineEntries[] = $timelineEntry;
} }
return $this->container->get('templating') return $this->container->get('templating')
->render('@ChillMain/Timeline/index.html.twig', array( ->render('@ChillMain/Timeline/chain_timelines.html.twig', array(
'results' => $timelineEntries 'results' => $timelineEntries
)); ));
} }
/** /**
* get the template data from the provider for the given entity, by type. * get the template data from the provider for the given entity, by type.
* *

View File

@@ -1,24 +0,0 @@
<?php
/*
* 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\Timeline;
interface TimelineBuilderInterface
{
}

View File

@@ -0,0 +1,155 @@
<?php
namespace Chill\MainBundle\Timeline;
class TimelineSingleQuery
{
private ?string $id;
private ?string $date;
private ?string $key;
private ?string $from;
private ?string $where;
private array $parameters = [];
private bool $distinct = false;
public function __construct(
string $id = null,
string $date = null,
string $key = null,
string $from = null,
string $where = null,
array $parameters = []
) {
$this->id = $id;
$this->date = $date;
$this->key = $key;
$this->from = $from;
$this->where = $where;
$this->parameters = $parameters;
}
public static function fromArray(array $a)
{
return new TimelineSingleQuery(
$a['id'] ?? null,
$a['date'] ?? null,
$a['type'] ?? $a['key'] ?? null,
$a['FROM'] ?? $a['from'] ?? null,
$a['WHERE'] ?? $a['where'] ?? null,
$a['parameters'] ?? null);
}
public function getId(): string
{
return $this->id;
}
public function setId(string $id): self
{
$this->id = $id;
return $this;
}
public function getDate(): string
{
return $this->date;
}
public function setDate(string $date): self
{
$this->date = $date;
return $this;
}
public function getKey(): string
{
return $this->key;
}
public function setKey(string $key): self
{
$this->key = $key;
return $this;
}
public function getFrom(): string
{
return $this->from;
}
public function setFrom(string $from): self
{
$this->from = $from;
return $this;
}
public function getWhere(): string
{
return $this->where;
}
public function setWhere(string $where): self
{
$this->where = $where;
return $this;
}
public function getParameters(): array
{
return $this->parameters;
}
public function setParameters(array $parameters): self
{
$this->parameters = $parameters;
return $this;
}
public function setDistinct(bool $distinct): self
{
$this->distinct = $distinct;
return $this;
}
public function isDistinct(): bool
{
return $this->distinct;
}
public function buildSql(): string
{
$parameters = [];
$sql = \strtr(
'SELECT {distinct} {id} AS id, '
. '{date} AS "date", '
. "'{key}' AS type "
. 'FROM {from} '
. 'WHERE {where}',
[
'{distinct}' => $this->distinct ? 'DISTINCT' : '',
'{id}' => $this->getId(),
'{date}' => $this->getDate(),
'{key}' => $this->getKey(),
'{from}' => $this->getFrom(),
'{where}' => $this->getWhere(),
]
);
return $sql;
}
}

View File

@@ -1,3 +1,7 @@
chill_main_controllers:
resource: '../Controller/'
type: annotation
chill_main_admin_permissionsgroup: chill_main_admin_permissionsgroup:
resource: "@ChillMainBundle/config/routes/permissionsgroup.yaml" resource: "@ChillMainBundle/config/routes/permissionsgroup.yaml"
prefix: "{_locale}/admin/permissionsgroup" prefix: "{_locale}/admin/permissionsgroup"

View File

@@ -10,7 +10,6 @@ services:
- "@translator.default" - "@translator.default"
Chill\MainBundle\Templating\TranslatableStringHelper: '@chill.main.helper.translatable_string' Chill\MainBundle\Templating\TranslatableStringHelper: '@chill.main.helper.translatable_string'
Chill\MainBundle\Templating\TranslatableStringHelperInterface: Chill\MainBundle\Templating\TranslatableStringHelper
chill.main.twig.translatable_string: chill.main.twig.translatable_string:
class: Chill\MainBundle\Templating\TranslatableStringTwig class: Chill\MainBundle\Templating\TranslatableStringTwig
@@ -20,14 +19,14 @@ services:
- [ setContainer, ["@service_container"]] - [ setContainer, ["@service_container"]]
tags: tags:
- { name: twig.extension } - { name: twig.extension }
chill.main.twig.widget: chill.main.twig.widget:
class: Chill\MainBundle\Templating\Widget\WidgetRenderingTwig class: Chill\MainBundle\Templating\Widget\WidgetRenderingTwig
arguments: arguments:
- "@event_dispatcher" - "@event_dispatcher"
tags: tags:
- { name: twig.extension } - { name: twig.extension }
chill.main.twig.csv_cell: chill.main.twig.csv_cell:
class: Chill\MainBundle\Templating\CSVCellTwig class: Chill\MainBundle\Templating\CSVCellTwig
tags: tags:

View File

@@ -1,4 +1,4 @@
services: services:
chill.main.security.authorization.helper: chill.main.security.authorization.helper:
class: Chill\MainBundle\Security\Authorization\AuthorizationHelper class: Chill\MainBundle\Security\Authorization\AuthorizationHelper
arguments: arguments:
@@ -6,48 +6,47 @@ services:
$hierarchy: "%security.role_hierarchy.roles%" $hierarchy: "%security.role_hierarchy.roles%"
$em: '@Doctrine\ORM\EntityManagerInterface' $em: '@Doctrine\ORM\EntityManagerInterface'
Chill\MainBundle\Security\Authorization\AuthorizationHelper: '@chill.main.security.authorization.helper' Chill\MainBundle\Security\Authorization\AuthorizationHelper: '@chill.main.security.authorization.helper'
Chill\MainBundle\Security\Authorization\AuthorizationHelperInterface: Chill\MainBundle\Security\Authorization\AuthorizationHelper
chill.main.role_provider: chill.main.role_provider:
class: Chill\MainBundle\Security\RoleProvider class: Chill\MainBundle\Security\RoleProvider
chill.main.user_provider: chill.main.user_provider:
class: Chill\MainBundle\Security\UserProvider\UserProvider class: Chill\MainBundle\Security\UserProvider\UserProvider
arguments: arguments:
$em: '@Doctrine\ORM\EntityManagerInterface' $em: '@Doctrine\ORM\EntityManagerInterface'
Chill\MainBundle\Security\Authorization\ChillExportVoter: Chill\MainBundle\Security\Authorization\ChillExportVoter:
arguments: arguments:
$authorizationHelper: '@Chill\MainBundle\Security\Authorization\AuthorizationHelper' $authorizationHelper: '@Chill\MainBundle\Security\Authorization\AuthorizationHelper'
tags: tags:
- { name: security.voter } - { name: security.voter }
Chill\MainBundle\Security\PasswordRecover\TokenManager: Chill\MainBundle\Security\PasswordRecover\TokenManager:
arguments: arguments:
$secret: '%kernel.secret%' $secret: '%kernel.secret%'
$logger: '@Psr\Log\LoggerInterface' $logger: '@Psr\Log\LoggerInterface'
Chill\MainBundle\Security\PasswordRecover\RecoverPasswordHelper: Chill\MainBundle\Security\PasswordRecover\RecoverPasswordHelper:
arguments: arguments:
$tokenManager: '@Chill\MainBundle\Security\PasswordRecover\TokenManager' $tokenManager: '@Chill\MainBundle\Security\PasswordRecover\TokenManager'
$urlGenerator: '@Symfony\Component\Routing\Generator\UrlGeneratorInterface' $urlGenerator: '@Symfony\Component\Routing\Generator\UrlGeneratorInterface'
$mailer: '@Chill\MainBundle\Notification\Mailer' $mailer: '@Chill\MainBundle\Notification\Mailer'
$routeParameters: "%chill_main.notifications%" $routeParameters: "%chill_main.notifications%"
Chill\MainBundle\Security\PasswordRecover\PasswordRecoverEventSubscriber: Chill\MainBundle\Security\PasswordRecover\PasswordRecoverEventSubscriber:
arguments: arguments:
$locker: '@Chill\MainBundle\Security\PasswordRecover\PasswordRecoverLocker' $locker: '@Chill\MainBundle\Security\PasswordRecover\PasswordRecoverLocker'
tags: tags:
- { name: kernel.event_subscriber } - { name: kernel.event_subscriber }
Chill\MainBundle\Security\PasswordRecover\PasswordRecoverLocker: Chill\MainBundle\Security\PasswordRecover\PasswordRecoverLocker:
arguments: arguments:
$chillRedis: '@Chill\MainBundle\Redis\ChillRedis' $chillRedis: '@Chill\MainBundle\Redis\ChillRedis'
$logger: '@Psr\Log\LoggerInterface' $logger: '@Psr\Log\LoggerInterface'
Chill\MainBundle\Security\PasswordRecover\PasswordRecoverVoter: Chill\MainBundle\Security\PasswordRecover\PasswordRecoverVoter:
arguments: arguments:
$locker: '@Chill\MainBundle\Security\PasswordRecover\PasswordRecoverLocker' $locker: '@Chill\MainBundle\Security\PasswordRecover\PasswordRecoverLocker'
$requestStack: '@Symfony\Component\HttpFoundation\RequestStack' $requestStack: '@Symfony\Component\HttpFoundation\RequestStack'
tags: tags:
- { name: security.voter } - { name: security.voter }

View File

@@ -30,7 +30,6 @@ services:
Chill\MainBundle\Templating\Entity\ChillEntityRenderExtension: Chill\MainBundle\Templating\Entity\ChillEntityRenderExtension:
tags: tags:
- { name: twig.extension } - { name: twig.extension }
Chill\MainBundle\Templating\Entity\ChillEntityRenderExtensionInterface: Chill\MainBundle\Templating\Entity\ChillEntityRenderExtension
Chill\MainBundle\Templating\Entity\CommentRender: Chill\MainBundle\Templating\Entity\CommentRender:
arguments: arguments:
@@ -38,7 +37,7 @@ services:
- '@Symfony\Component\Templating\EngineInterface' - '@Symfony\Component\Templating\EngineInterface'
tags: tags:
- { name: 'chill.render_entity' } - { name: 'chill.render_entity' }
Chill\MainBundle\Templating\ChillMarkdownRenderExtension: Chill\MainBundle\Templating\ChillMarkdownRenderExtension:
tags: tags:
- { name: twig.extension } - { name: twig.extension }

View File

@@ -5,5 +5,6 @@ services:
- "@doctrine.orm.entity_manager" - "@doctrine.orm.entity_manager"
calls: calls:
- [ setContainer, ["@service_container"]] - [ setContainer, ["@service_container"]]
# alias:
Chill\MainBundle\Timeline\TimelineBuilder: '@chill_main.timeline_builder'
Chill\MainBundle\Timeline\TimelineBuilderInterface: "@chill_main.timeline_builder"

View File

@@ -46,6 +46,11 @@ Back to the list: Retour à la liste
#interval #interval
Years: Années Years: Années
# misc date
Since %date%: Depuis le %date%
since %date%: depuis le %date%
Until %date%: Jusqu'au %date%
until %date%: jusqu'au %date%
#elements used in software #elements used in software
centers: centres centers: centres
Centers: Centres Centers: Centres
@@ -78,6 +83,9 @@ Results %start%-%end% of %total%: Résultats %start%-%end% sur %total%
See all results: Voir tous les résultats See all results: Voir tous les résultats
Advanced search: Recherche avancée Advanced search: Recherche avancée
# timeline
Global timeline: Historique global
#admin #admin
Create: Créer Create: Créer
show: voir show: voir

View File

@@ -17,57 +17,57 @@
*/ */
namespace Chill\PersonBundle\Actions; namespace Chill\PersonBundle\Actions;
use Symfony\Contracts\EventDispatcher\Event; use Symfony\Component\EventDispatcher\Event;
/** /**
* Event triggered when an entity attached to a person is removed. * Event triggered when an entity attached to a person is removed.
* *
* *
*/ */
class ActionEvent implements Event class ActionEvent extends Event
{ {
const DELETE = 'CHILL_PERSON.DELETE_ASSOCIATED_ENTITY'; const DELETE = 'CHILL_PERSON.DELETE_ASSOCIATED_ENTITY';
const MOVE = 'CHILL_PERSON.MOVE_ASSOCIATED_ENTITY'; const MOVE = 'CHILL_PERSON.MOVE_ASSOCIATED_ENTITY';
/** /**
* *
* @var int * @var int
*/ */
protected $personId; protected $personId;
/** /**
* the FQDN class name as recorded in doctrine * the FQDN class name as recorded in doctrine
* *
* @var string * @var string
*/ */
protected $entity; protected $entity;
/** /**
* an array of key value data to describe the movement * an array of key value data to describe the movement
* *
* @var array * @var array
*/ */
protected $metadata; protected $metadata;
/** /**
* the sql statement * the sql statement
* *
* @var string * @var string
*/ */
protected $sqlStatement; protected $sqlStatement;
/** /**
* *
* @var string[] * @var string[]
*/ */
protected $preSql = []; protected $preSql = [];
/** /**
* *
* @var string[] * @var string[]
*/ */
protected $postSql = []; protected $postSql = [];
public function __construct($personId, $entity, $sqlStatement, $metadata = []) public function __construct($personId, $entity, $sqlStatement, $metadata = [])
{ {
$this->personId = $personId; $this->personId = $personId;
@@ -77,7 +77,7 @@ class ActionEvent implements Event
} }
/** /**
* *
* @return string[] * @return string[]
*/ */
public function getPreSql(): array public function getPreSql(): array
@@ -86,7 +86,7 @@ class ActionEvent implements Event
} }
/** /**
* *
* @return string[] * @return string[]
*/ */
public function getPostSql(): array public function getPostSql(): array
@@ -105,7 +105,7 @@ class ActionEvent implements Event
/** /**
* Add Sql which will be executed **after** the delete statement * Add Sql which will be executed **after** the delete statement
* *
* @param type $postSql * @param type $postSql
* @return $this * @return $this
*/ */
@@ -122,22 +122,22 @@ class ActionEvent implements Event
/** /**
* get the entity name, as recorded in doctrine * get the entity name, as recorded in doctrine
* *
* @return string * @return string
*/ */
public function getEntity(): string public function getEntity(): string
{ {
return $this->entity; return $this->entity;
} }
public function getSqlStatement() public function getSqlStatement()
{ {
return $this->sqlStatement; return $this->sqlStatement;
} }
public function getMetadata() public function getMetadata()
{ {
return $this->metadata; return $this->metadata;
} }
} }

View File

@@ -5,10 +5,10 @@ namespace Chill\PersonBundle\Config;
/** /**
* Give help to interact with the config for alt names * Give help to interact with the config for alt names
* *
* *
*/ */
class ConfigPersonAltNamesHelper implements ConfigPersonAltNamesHelperInterface class ConfigPersonAltNamesHelper
{ {
/** /**
* the raw config, directly from the container parameter * the raw config, directly from the container parameter
@@ -16,32 +16,32 @@ class ConfigPersonAltNamesHelper implements ConfigPersonAltNamesHelperInterface
* @var array * @var array
*/ */
private $config = []; private $config = [];
public function __construct($config) public function __construct($config)
{ {
$this->config = $config; $this->config = $config;
} }
/** /**
* Return true if at least one alt name is configured * Return true if at least one alt name is configured
* *
* @return bool * @return bool
*/ */
public function hasAltNames(): bool public function hasAltNames(): bool
{ {
return count($this->config) > 0; return count($this->config) > 0;
} }
/** /**
* get the choices as key => values * get the choices as key => values
* *
* @return array * @return array
*/ */
public function getChoices(): array public function getChoices(): array
{ {
$choices = []; $choices = [];
foreach ($this->config as $entry) { foreach ($this->config as $entry) {
$labels = $entry['labels']; $labels = $entry['labels'];
$lang = false; $lang = false;
$label = false; $label = false;
@@ -50,11 +50,11 @@ class ConfigPersonAltNamesHelper implements ConfigPersonAltNamesHelperInterface
if (key($labels) === 'lang') { if (key($labels) === 'lang') {
$lang = current($labels); $lang = current($labels);
} }
if (key($labels) === 'label') { if (key($labels) === 'label') {
$label = current($labels); $label = current($labels);
} }
if ($lang !== FALSE && $label !== FALSE) { if ($lang !== FALSE && $label !== FALSE) {
$choices[$entry['key']][$lang] = $label; $choices[$entry['key']][$lang] = $label;
$lang = false; $lang = false;
@@ -63,7 +63,7 @@ class ConfigPersonAltNamesHelper implements ConfigPersonAltNamesHelperInterface
$cur = next($labels); $cur = next($labels);
} }
} }
return $choices; return $choices;
} }

View File

@@ -26,7 +26,7 @@ use Chill\PersonBundle\Privacy\PrivacyEvent;
use Doctrine\DBAL\Exception; use Doctrine\DBAL\Exception;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController; use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Chill\PersonBundle\Entity\Person; use Chill\PersonBundle\Entity\Person;
use Chill\PersonBundle\Form\Type\AccompanyingPeriodType; use Chill\PersonBundle\Form\AccompanyingPeriodType;
use Chill\PersonBundle\Entity\AccompanyingPeriod; use Chill\PersonBundle\Entity\AccompanyingPeriod;
use Doctrine\Common\Collections\Criteria; use Doctrine\Common\Collections\Criteria;
use Chill\PersonBundle\Security\Authorization\PersonVoter; use Chill\PersonBundle\Security\Authorization\PersonVoter;
@@ -47,12 +47,12 @@ class AccompanyingPeriodController extends AbstractController
* @var EventDispatcherInterface * @var EventDispatcherInterface
*/ */
protected $eventDispatcher; protected $eventDispatcher;
/** /**
* @var ValidatorInterface * @var ValidatorInterface
*/ */
protected $validator; protected $validator;
/** /**
* AccompanyingPeriodController constructor. * AccompanyingPeriodController constructor.
* *
@@ -64,17 +64,11 @@ class AccompanyingPeriodController extends AbstractController
$this->eventDispatcher = $eventDispatcher; $this->eventDispatcher = $eventDispatcher;
$this->validator = $validator; $this->validator = $validator;
} }
/**
* @Route(
* name="chill_person_accompanying_period_list",
* path="/{_locale}/person/{person_id}/accompanying-period"
* )
*/
public function listAction(int $person_id): Response public function listAction(int $person_id): Response
{ {
$person = $this->_getPerson($person_id); $person = $this->_getPerson($person_id);
$event = new PrivacyEvent($person, [ $event = new PrivacyEvent($person, [
'element_class' => AccompanyingPeriod::class, 'element_class' => AccompanyingPeriod::class,
'action' => 'list' 'action' => 'list'
@@ -86,13 +80,7 @@ class AccompanyingPeriodController extends AbstractController
'person' => $person 'person' => $person
]); ]);
} }
/**
* @Route(
* name="chill_person_accompanying_period_create",
* path="/{_locale}/person/{person_id}/accompanying-period/create"
* )
*/
public function createAction(int $person_id, Request $request): Response public function createAction(int $person_id, Request $request): Response
{ {
$person = $this->_getPerson($person_id); $person = $this->_getPerson($person_id);
@@ -102,17 +90,17 @@ class AccompanyingPeriodController extends AbstractController
$accompanyingPeriod = new AccompanyingPeriod(new \DateTime('now')); $accompanyingPeriod = new AccompanyingPeriod(new \DateTime('now'));
$accompanyingPeriod->setClosingDate(new \DateTime('now')); $accompanyingPeriod->setClosingDate(new \DateTime('now'));
$accompanyingPeriod->addPerson($person); $accompanyingPeriod->addPerson($person);
//or $person->addAccompanyingPeriod($accompanyingPeriod); //or $person->addAccompanyingPeriod($accompanyingPeriod);
$form = $this->createForm( $form = $this->createForm(
AccompanyingPeriodType::class, AccompanyingPeriodType::class,
$accompanyingPeriod, [ $accompanyingPeriod, [
'period_action' => 'create', 'period_action' => 'create',
'center' => $person->getCenter() 'center' => $person->getCenter()
]); ]);
if ($request->getMethod() === 'POST') { if ($request->getMethod() === 'POST') {
$form->handleRequest($request); $form->handleRequest($request);
$errors = $this->_validatePerson($person); $errors = $this->_validatePerson($person);
@@ -132,7 +120,7 @@ class AccompanyingPeriodController extends AbstractController
$this->generateUrl('chill_person_accompanying_period_list', [ $this->generateUrl('chill_person_accompanying_period_list', [
'person_id' => $person->getId() 'person_id' => $person->getId()
])); ]));
} else { } else {
$flashBag->add('error', $this->get('translator') $flashBag->add('error', $this->get('translator')
->trans('Error! Period not created!')); ->trans('Error! Period not created!'));
@@ -149,12 +137,9 @@ class AccompanyingPeriodController extends AbstractController
'accompanying_period' => $accompanyingPeriod 'accompanying_period' => $accompanyingPeriod
]); ]);
} }
/** /**
* @Route( * @throws Exception
* name="chill_person_accompanying_period_update",
* path="/{_locale}/person/{person_id}/accompanying-period/{period_id}/update"
* )
*/ */
public function updateAction(int $person_id, int $period_id, Request $request): Response public function updateAction(int $person_id, int $period_id, Request $request): Response
{ {
@@ -169,7 +154,7 @@ class AccompanyingPeriodController extends AbstractController
/** @var Person $person */ /** @var Person $person */
$person = $this->_getPerson($person_id); $person = $this->_getPerson($person_id);
// CHECK // CHECK
if (! $accompanyingPeriod->containsPerson($person)) { if (! $accompanyingPeriod->containsPerson($person)) {
throw new Exception("Accompanying period " . $period_id . " does not contain person " . $person_id); throw new Exception("Accompanying period " . $period_id . " does not contain person " . $person_id);
@@ -191,7 +176,7 @@ class AccompanyingPeriodController extends AbstractController
if ($form->isValid(['Default', 'closed']) if ($form->isValid(['Default', 'closed'])
&& count($errors) === 0) { && count($errors) === 0) {
$em->flush(); $em->flush();
$flashBag->add('success', $flashBag->add('success',
@@ -201,9 +186,9 @@ class AccompanyingPeriodController extends AbstractController
$this->generateUrl('chill_person_accompanying_period_list', [ $this->generateUrl('chill_person_accompanying_period_list', [
'person_id' => $person->getId() 'person_id' => $person->getId()
])); ]));
} else { } else {
$flashBag->add('error', $this->get('translator') $flashBag->add('error', $this->get('translator')
->trans('Error when updating the period')); ->trans('Error when updating the period'));
@@ -219,22 +204,19 @@ class AccompanyingPeriodController extends AbstractController
'accompanying_period' => $accompanyingPeriod 'accompanying_period' => $accompanyingPeriod
]); ]);
} }
/** /**
* @Route( * @throws \Exception
* name="chill_person_accompanying_period_close",
* path="/{_locale}/person/{person_id}/accompanying-period/close"
* )
*/ */
public function closeAction(int $person_id, Request $request): Response public function closeAction(int $person_id, Request $request): Response
{ {
$person = $this->_getPerson($person_id); $person = $this->_getPerson($person_id);
$this->denyAccessUnlessGranted(PersonVoter::UPDATE, $person, 'You are not allowed to update this person'); $this->denyAccessUnlessGranted(PersonVoter::UPDATE, $person, 'You are not allowed to update this person');
if ($person->isOpen() === false) { if ($person->isOpen() === false) {
$this->get('session')->getFlashBag() $this->get('session')->getFlashBag()
->add('error', $this->get('translator') ->add('error', $this->get('translator')
->trans('Beware period is closed', ['%name%' => $person->__toString()] ->trans('Beware period is closed', ['%name%' => $person->__toString()]
@@ -247,7 +229,7 @@ class AccompanyingPeriodController extends AbstractController
} }
$current = $person->getCurrentAccompanyingPeriod(); $current = $person->getCurrentAccompanyingPeriod();
$form = $this->createForm(AccompanyingPeriodType::class, $current, [ $form = $this->createForm(AccompanyingPeriodType::class, $current, [
'period_action' => 'close', 'period_action' => 'close',
'center' => $person->getCenter() 'center' => $person->getCenter()
@@ -274,7 +256,7 @@ class AccompanyingPeriodController extends AbstractController
'person_id' => $person->getId() 'person_id' => $person->getId()
]) ])
); );
} else { } else {
$this->get('session')->getFlashBag() $this->get('session')->getFlashBag()
->add('error', $this->get('translator') ->add('error', $this->get('translator')
@@ -285,7 +267,7 @@ class AccompanyingPeriodController extends AbstractController
->add('info', $error->getMessage()); ->add('info', $error->getMessage());
} }
} }
} else { //if form is not valid } else { //if form is not valid
$this->get('session')->getFlashBag() $this->get('session')->getFlashBag()
->add('error', ->add('error',
@@ -306,7 +288,7 @@ class AccompanyingPeriodController extends AbstractController
'accompanying_period' => $current 'accompanying_period' => $current
]); ]);
} }
private function _validatePerson(Person $person): ConstraintViolationListInterface private function _validatePerson(Person $person): ConstraintViolationListInterface
{ {
$errors = $this->validator->validate($person, null, $errors = $this->validator->validate($person, null,
@@ -314,10 +296,10 @@ class AccompanyingPeriodController extends AbstractController
// Can be disabled with config // Can be disabled with config
if (false === $this->container->getParameter('chill_person.allow_multiple_simultaneous_accompanying_periods')) { if (false === $this->container->getParameter('chill_person.allow_multiple_simultaneous_accompanying_periods')) {
$errors_accompanying_period = $this->validator->validate($person, null, $errors_accompanying_period = $this->validator->validate($person, null,
['accompanying_period_consistent']); ['accompanying_period_consistent']);
foreach($errors_accompanying_period as $error ) { foreach($errors_accompanying_period as $error ) {
$errors->add($error); $errors->add($error);
} }
@@ -325,13 +307,7 @@ class AccompanyingPeriodController extends AbstractController
return $errors; return $errors;
} }
/**
* @Route(
* name="chill_person_accompanying_period_open",
* path="/{_locale}/person/{person_id}/accompanying-period/open"
* )
*/
public function openAction(int $person_id, Request $request): Response public function openAction(int $person_id, Request $request): Response
{ {
$person = $this->_getPerson($person_id); $person = $this->_getPerson($person_id);
@@ -408,13 +384,7 @@ class AccompanyingPeriodController extends AbstractController
'accompanying_period' => $accompanyingPeriod 'accompanying_period' => $accompanyingPeriod
]); ]);
} }
/**
* @Route(
* name="chill_person_accompanying_period_re_open",
* path="/{_locale}/person/{person_id}/accompanying-period/re-open"
* )
*/
public function reOpenAction(int $person_id, int $period_id, Request $request): Response public function reOpenAction(int $person_id, int $period_id, Request $request): Response
{ {
/** @var Person $person */ /** @var Person $person */
@@ -447,13 +417,13 @@ class AccompanyingPeriodController extends AbstractController
return $this->redirectToRoute('chill_person_accompanying_period_list', [ return $this->redirectToRoute('chill_person_accompanying_period_list', [
'person_id' => $person->getId() 'person_id' => $person->getId()
]); ]);
} elseif ($confirm === false && $period->canBeReOpened($person)) { } elseif ($confirm === false && $period->canBeReOpened($person)) {
return $this->render('ChillPersonBundle:AccompanyingPeriod:re_open.html.twig', [ return $this->render('ChillPersonBundle:AccompanyingPeriod:re_open.html.twig', [
'period' => $period, 'period' => $period,
'person' => $person 'person' => $person
]); ]);
} else { } else {
return (new Response()) return (new Response())
->setStatusCode(Response::HTTP_BAD_REQUEST) ->setStatusCode(Response::HTTP_BAD_REQUEST)

View File

@@ -13,29 +13,16 @@ use Symfony\Component\Routing\Annotation\Route;
class AdminController extends AbstractController class AdminController extends AbstractController
{ {
/** /**
* @Route( * @param $_locale
* name="chill_person_admin", * @return \Symfony\Component\HttpFoundation\Response
* path="/{_locale}/admin/person"
* )
*/ */
public function indexAction($_locale) public function indexAction($_locale)
{ {
return $this->render('ChillPersonBundle:Admin:layout.html.twig', []); return $this->render('ChillPersonBundle:Admin:layout.html.twig', []);
} }
/** /**
* @Route( * @return \Symfony\Component\HttpFoundation\RedirectResponse
* name="chill_person_admin_redirect_to_admin_index",
* path="/{_locale}/admin/person_redirect_to_main",
* options={
* menus={
* admin_person={
* order="0",
* label="Main admin menu"
* }
* }
* }
* )
*/ */
public function redirectToAdminIndexAction() public function redirectToAdminIndexAction()
{ {

View File

@@ -30,7 +30,6 @@ use Chill\MainBundle\Entity\Address;
use Doctrine\Common\Collections\Criteria; use Doctrine\Common\Collections\Criteria;
use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\Validator\Validator\ValidatorInterface; use Symfony\Component\Validator\Validator\ValidatorInterface;
use Symfony\Component\Routing\Annotation\Route;
/** /**
* Class PersonAddressController * Class PersonAddressController
@@ -46,7 +45,7 @@ class PersonAddressController extends AbstractController
* @var ValidatorInterface * @var ValidatorInterface
*/ */
protected $validator; protected $validator;
/** /**
* PersonAddressController constructor. * PersonAddressController constructor.
* *
@@ -56,13 +55,7 @@ class PersonAddressController extends AbstractController
{ {
$this->validator = $validator; $this->validator = $validator;
} }
/**
* @Route(
* name="chill_person_address_list",
* path="/{_locale}/person/{person_id}/address/list"
* )
*/
public function listAction($person_id) public function listAction($person_id)
{ {
$person = $this->getDoctrine()->getManager() $person = $this->getDoctrine()->getManager()
@@ -85,13 +78,6 @@ class PersonAddressController extends AbstractController
)); ));
} }
/**
* @Route(
* name="chill_person_address_create",
* path="/{_locale}/person/{person_id}/address/create",
* methods={"POST"}
* )
*/
public function newAction($person_id) public function newAction($person_id)
{ {
$person = $this->getDoctrine()->getManager() $person = $this->getDoctrine()->getManager()
@@ -119,12 +105,6 @@ class PersonAddressController extends AbstractController
)); ));
} }
/**
* @Route(
* name="chill_person_address_new",
* path="/{_locale}/person/{person_id}/address/new"
* )
*/
public function createAction($person_id, Request $request) public function createAction($person_id, Request $request)
{ {
$person = $this->getDoctrine()->getManager() $person = $this->getDoctrine()->getManager()
@@ -181,12 +161,6 @@ class PersonAddressController extends AbstractController
)); ));
} }
/**
* @Route(
* name="chill_person_address_edit",
* path="/{_locale}/person/{person_id}/address/{address_id}/edit"
* )
*/
public function editAction($person_id, $address_id) public function editAction($person_id, $address_id)
{ {
$person = $this->getDoctrine()->getManager() $person = $this->getDoctrine()->getManager()
@@ -215,12 +189,6 @@ class PersonAddressController extends AbstractController
)); ));
} }
/**
* @Route(
* name="chill_person_address_update",
* path="/{_locale}/person/{person_id}/address/{address_id}/update"
* )
*/
public function updateAction($person_id, $address_id, Request $request) public function updateAction($person_id, $address_id, Request $request)
{ {
$person = $this->getDoctrine()->getManager() $person = $this->getDoctrine()->getManager()

View File

@@ -34,14 +34,12 @@ use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Security\Core\Role\Role; use Symfony\Component\Security\Core\Role\Role;
use Chill\PersonBundle\Security\Authorization\PersonVoter; use Chill\PersonBundle\Security\Authorization\PersonVoter;
use Chill\PersonBundle\Search\SimilarPersonMatcher; use Chill\PersonBundle\Search\SimilarPersonMatcher;
use Symfony\Component\Translation\TranslatorInterface;
use Chill\MainBundle\Search\SearchProvider; use Chill\MainBundle\Search\SearchProvider;
use Chill\PersonBundle\Repository\PersonRepository; use Chill\PersonBundle\Repository\PersonRepository;
use Chill\PersonBundle\Config\ConfigPersonAltNamesHelper; use Chill\PersonBundle\Config\ConfigPersonAltNamesHelper;
use Chill\PersonBundle\Repository\PersonNotDuplicateRepository;
use Symfony\Component\Validator\Validator\ValidatorInterface; use Symfony\Component\Validator\Validator\ValidatorInterface;
use Doctrine\ORM\EntityManagerInterface; use Doctrine\ORM\EntityManagerInterface;
use Symfony\Component\Routing\Annotation\Route;
use Symfony\Contracts\Translation\TranslatorInterface;
final class PersonController extends AbstractController final class PersonController extends AbstractController
{ {
@@ -119,12 +117,6 @@ final class PersonController extends AbstractController
return $cFGroup; return $cFGroup;
} }
/**
* @Route(
* name="chill_person_view",
* path="/{_locale}/person/{person_id}/general"
* )
*/
public function viewAction($person_id) public function viewAction($person_id)
{ {
$person = $this->_getPerson($person_id); $person = $this->_getPerson($person_id);
@@ -148,12 +140,6 @@ final class PersonController extends AbstractController
)); ));
} }
/**
* @Route(
* name="chill_person_general_edit",
* path="/{_locale}/person/{person_id}/general/edit"
* )
*/
public function editAction($person_id) public function editAction($person_id)
{ {
$person = $this->_getPerson($person_id); $person = $this->_getPerson($person_id);
@@ -177,13 +163,7 @@ final class PersonController extends AbstractController
array('person' => $person, 'form' => $form->createView())); array('person' => $person, 'form' => $form->createView()));
} }
/** public function updateAction($person_id, Request $request)
* @Route(
* name="chill_person_general_update",
* path="/{_locale}/person/{person_id}/general/update"
* )
*/
public function updateAction($person_id, Request $request, TranslatorInterface $translator)
{ {
$person = $this->_getPerson($person_id); $person = $this->_getPerson($person_id);
@@ -212,7 +192,7 @@ final class PersonController extends AbstractController
$this->get('session')->getFlashBag() $this->get('session')->getFlashBag()
->add('success', ->add('success',
$translator $this->get('translator')
->trans('The person data has been updated') ->trans('The person data has been updated')
); );
@@ -226,12 +206,6 @@ final class PersonController extends AbstractController
} }
} }
/**
* @Route(
* name="chill_person_new",
* path="/{_locale}/person/new"
* )
*/
public function newAction() public function newAction()
{ {
// this is a dummy default center. // this is a dummy default center.
@@ -316,13 +290,7 @@ final class PersonController extends AbstractController
return $errors; return $errors;
} }
/** public function reviewAction(Request $request)
* @Route(
* name="chill_person_review",
* path="/{_locale}/person/review"
* )
*/
public function reviewAction(Request $request, PersonNotDuplicateRepository $personNotDuplicateRepository)
{ {
if ($request->getMethod() !== 'POST') { if ($request->getMethod() !== 'POST') {
$r = new Response("You must send something to review the creation of a new Person"); $r = new Response("You must send something to review the creation of a new Person");
@@ -374,7 +342,8 @@ final class PersonController extends AbstractController
$this->em->persist($person); $this->em->persist($person);
$alternatePersons = $this->similarPersonMatcher->matchPerson($person, $personNotDuplicateRepository); $alternatePersons = $this->similarPersonMatcher
->matchPerson($person);
if (count($alternatePersons) === 0) { if (count($alternatePersons) === 0) {
return $this->forward('ChillPersonBundle:Person:create'); return $this->forward('ChillPersonBundle:Person:create');
@@ -398,12 +367,6 @@ final class PersonController extends AbstractController
'form' => $form->createView())); 'form' => $form->createView()));
} }
/**
* @Route(
* name="chill_person_create",
* path="/{_locale}/person/create"
* )
*/
public function createAction(Request $request) public function createAction(Request $request)
{ {

View File

@@ -12,17 +12,16 @@ use Chill\PersonBundle\Privacy\PrivacyEvent;
use Chill\PersonBundle\Repository\PersonRepository; use Chill\PersonBundle\Repository\PersonRepository;
use Chill\PersonBundle\Search\SimilarPersonMatcher; use Chill\PersonBundle\Search\SimilarPersonMatcher;
use http\Exception\InvalidArgumentException; use http\Exception\InvalidArgumentException;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Symfony\Component\EventDispatcher\EventDispatcherInterface; use Symfony\Component\EventDispatcher\EventDispatcherInterface;
use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\Translation\TranslatorInterface; use Symfony\Component\Translation\TranslatorInterface;
use Chill\ActivityBundle\Entity\Activity; use Chill\ActivityBundle\Entity\Activity;
use Chill\DocStoreBundle\Entity\PersonDocument; use Chill\DocStoreBundle\Entity\PersonDocument;
use Chill\EventBundle\Entity\Participation; use Chill\EventBundle\Entity\Participation;
use Chill\PersonBundle\Repository\PersonNotDuplicateRepository;
use Chill\TaskBundle\Entity\SingleTask; use Chill\TaskBundle\Entity\SingleTask;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
class PersonDuplicateController extends AbstractController class PersonDuplicateController extends Controller
{ {
/** /**
* @var \Chill\PersonBundle\Search\SimilarPersonMatcher * @var \Chill\PersonBundle\Search\SimilarPersonMatcher
@@ -63,13 +62,7 @@ class PersonDuplicateController extends AbstractController
$this->eventDispatcher = $eventDispatcher; $this->eventDispatcher = $eventDispatcher;
} }
/** public function viewAction($person_id)
* @Route(
* name="chill_person_duplicate_view",
* path="/{_locale}/person/{person_id}/duplicate/view"
* )
*/
public function viewAction($person_id, PersonNotDuplicateRepository $personNotDuplicateRepository)
{ {
$person = $this->_getPerson($person_id); $person = $this->_getPerson($person_id);
if ($person === null) { if ($person === null) {
@@ -83,7 +76,8 @@ class PersonDuplicateController extends AbstractController
$duplicatePersons = $this->similarPersonMatcher-> $duplicatePersons = $this->similarPersonMatcher->
matchPerson($person, 0.5, SimilarPersonMatcher::SIMILAR_SEARCH_ORDER_BY_ALPHABETICAL); matchPerson($person, 0.5, SimilarPersonMatcher::SIMILAR_SEARCH_ORDER_BY_ALPHABETICAL);
$notDuplicatePersons = $personNotDuplicateRepository->findNotDuplicatePerson($person); $notDuplicatePersons = $this->getDoctrine()->getRepository(PersonNotDuplicate::class)
->findNotDuplicatePerson($person);
return $this->render('ChillPersonBundle:PersonDuplicate:view.html.twig', [ return $this->render('ChillPersonBundle:PersonDuplicate:view.html.twig', [
'person' => $person, 'person' => $person,
@@ -92,12 +86,6 @@ class PersonDuplicateController extends AbstractController
]); ]);
} }
/**
* @Route(
* name="chill_person_duplicate_confirm",
* path="/{_locale}/person/{person1_id}/duplicate/{person2_id}/confirm"
* )
*/
public function confirmAction($person1_id, $person2_id, Request $request) public function confirmAction($person1_id, $person2_id, Request $request)
{ {
if ($person1_id === $person2_id) { if ($person1_id === $person2_id) {
@@ -109,7 +97,7 @@ class PersonDuplicateController extends AbstractController
$person1->counters = $this->_getCounters($person1_id); $person1->counters = $this->_getCounters($person1_id);
$person2->counters = $this->_getCounters($person2_id); $person2->counters = $this->_getCounters($person2_id);
if ($person1 === null) { if ($person1 === null) {
throw $this->createNotFoundException("Person with id $person1_id not" throw $this->createNotFoundException("Person with id $person1_id not"
. " found on this server"); . " found on this server");
@@ -155,12 +143,6 @@ class PersonDuplicateController extends AbstractController
]); ]);
} }
/**
* @Route(
* name="chill_person_duplicate_not_duplicate",
* path="/{_locale}/person/{person1_id}/duplicate/{person2_id}/not-duplicate"
* )
*/
public function notDuplicateAction($person1_id, $person2_id) public function notDuplicateAction($person1_id, $person2_id)
{ {
[$person1, $person2] = $this->_getPersonsByPriority($person1_id, $person2_id); [$person1, $person2] = $this->_getPersonsByPriority($person1_id, $person2_id);
@@ -184,12 +166,6 @@ class PersonDuplicateController extends AbstractController
return $this->redirectToRoute('chill_person_duplicate_view', ['person_id' => $person1->getId()]); return $this->redirectToRoute('chill_person_duplicate_view', ['person_id' => $person1->getId()]);
} }
/**
* @Route(
* name="chill_person_remove_duplicate_not_duplicate",
* path="/{_locale}/person/{person1_id}/duplicate/{person2_id}/remove-not-duplicate"
* )
*/
public function removeNotDuplicateAction($person1_id, $person2_id) public function removeNotDuplicateAction($person1_id, $person2_id)
{ {
[$person1, $person2] = $this->_getPersonsByPriority($person1_id, $person2_id); [$person1, $person2] = $this->_getPersonsByPriority($person1_id, $person2_id);
@@ -208,12 +184,6 @@ class PersonDuplicateController extends AbstractController
return $this->redirectToRoute('chill_person_duplicate_view', ['person_id' => $person1->getId()]); return $this->redirectToRoute('chill_person_duplicate_view', ['person_id' => $person1->getId()]);
} }
/**
* @Route(
* name="chill_person_find_manually_duplicate",
* path="/{_locale}/person/{person_id}/find-manually"
* )
*/
public function findManuallyDuplicateAction($person_id, Request $request) public function findManuallyDuplicateAction($person_id, Request $request)
{ {
$person = $this->_getPerson($person_id); $person = $this->_getPerson($person_id);
@@ -294,17 +264,17 @@ class PersonDuplicateController extends AbstractController
return [$person1, $person2]; return [$person1, $person2];
} }
private function _getCounters($id): ?array private function _getCounters($id): ?array
{ {
$em = $this->getDoctrine()->getManager(); $em = $this->getDoctrine()->getManager();
$nb_activity = $em->getRepository(Activity::class)->findBy(['person'=>$id]); $nb_activity = $em->getRepository(Activity::class)->findBy(['person'=>$id]);
$nb_document = $em->getRepository(PersonDocument::class)->findBy(['person'=>$id]); $nb_document = $em->getRepository(PersonDocument::class)->findBy(['person'=>$id]);
$nb_event = $em->getRepository(Participation::class)->findBy(['person'=>$id]); $nb_event = $em->getRepository(Participation::class)->findBy(['person'=>$id]);
$nb_task = $em->getRepository(SingleTask::class)->countByParameters(['person'=>$id]); $nb_task = $em->getRepository(SingleTask::class)->countByParameters(['person'=>$id]);
$person = $em->getRepository(Person::class)->findOneBy(['id'=>$id]); $person = $em->getRepository(Person::class)->findOneBy(['id'=>$id]);
return [ return [
'nb_activity' => count($nb_activity), 'nb_activity' => count($nb_activity),
'nb_document' => count($nb_document), 'nb_document' => count($nb_document),

View File

@@ -26,36 +26,19 @@ use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Request;
use Chill\MainBundle\Timeline\TimelineBuilder; use Chill\MainBundle\Timeline\TimelineBuilder;
use Chill\MainBundle\Pagination\PaginatorFactory; use Chill\MainBundle\Pagination\PaginatorFactory;
use Chill\MainBundle\Timeline\TimelineBuilderInterface;
use Chill\PersonBundle\Security\Authorization\PersonVoter; use Chill\PersonBundle\Security\Authorization\PersonVoter;
use Symfony\Component\Routing\Annotation\Route; use Chill\MainBundle\Security\Authorization\AuthorizationHelper;
use Symfony\Component\Security\Core\Role\Role;
/**
* Class TimelinePersonController
*
* @package Chill\PersonBundle\Controller
* @author Julien Fastré <julien.fastre@champs-libres.coop>
*/
class TimelinePersonController extends AbstractController class TimelinePersonController extends AbstractController
{ {
/** protected EventDispatcherInterface $eventDispatcher;
* @var EventDispatcherInterface
*/ protected TimelineBuilder $timelineBuilder;
protected $eventDispatcher;
protected PaginatorFactory $paginatorFactory;
/**
*
* @var TimelineBuilderInterface
*/
protected $timelineBuilder;
/**
*
* @var PaginatorFactory
*/
protected $paginatorFactory;
/** /**
* TimelinePersonController constructor. * TimelinePersonController constructor.
* *
@@ -63,28 +46,17 @@ class TimelinePersonController extends AbstractController
*/ */
public function __construct( public function __construct(
EventDispatcherInterface $eventDispatcher, EventDispatcherInterface $eventDispatcher,
TimelineBuilderInterface $timelineBuilder, TimelineBuilder $timelineBuilder,
PaginatorFactory $paginatorFactory PaginatorFactory $paginatorFactory,
AuthorizationHelper $authorizationHelper
) { ) {
$this->eventDispatcher = $eventDispatcher; $this->eventDispatcher = $eventDispatcher;
$this->timelineBuilder = $timelineBuilder; $this->timelineBuilder = $timelineBuilder;
$this->paginatorFactory = $paginatorFactory; $this->paginatorFactory = $paginatorFactory;
$this->authorizationHelper = $authorizationHelper;
} }
/**
* @Route(
* name="chill_person_timeline",
* path="/{_locale}/person/{person_id}/timeline",
* options={
* menus={
* person={
* order="60",
* label="Timeline"
* }
* }
* }
* )
*/
public function personAction(Request $request, $person_id) public function personAction(Request $request, $person_id)
{ {
$person = $this->getDoctrine() $person = $this->getDoctrine()
@@ -94,22 +66,22 @@ class TimelinePersonController extends AbstractController
if ($person === NULL) { if ($person === NULL) {
throw $this->createNotFoundException(); throw $this->createNotFoundException();
} }
$this->denyAccessUnlessGranted(PersonVoter::SEE, $person); $this->denyAccessUnlessGranted(PersonVoter::SEE, $person);
$nbItems = $this->timelineBuilder->countItems('person', $nbItems = $this->timelineBuilder->countItems('person',
[ 'person' => $person ] [ 'person' => $person ]
); );
$paginator = $this->paginatorFactory->create($nbItems); $paginator = $this->paginatorFactory->create($nbItems);
$event = new PrivacyEvent($person, array('action' => 'timeline')); $event = new PrivacyEvent($person, array('action' => 'timeline'));
$this->eventDispatcher->dispatch(PrivacyEvent::PERSON_PRIVACY_EVENT, $event); $this->eventDispatcher->dispatch(PrivacyEvent::PERSON_PRIVACY_EVENT, $event);
return $this->render('ChillPersonBundle:Timeline:index.html.twig', array return $this->render('ChillPersonBundle:Timeline:index.html.twig', array
( (
'timeline' => $this->timelineBuilder->getTimelineHTML( 'timeline' => $this->timelineBuilder->getTimelineHTML(
'person', 'person',
array('person' => $person), array('person' => $person),
$paginator->getCurrentPage()->getFirstItemNumber(), $paginator->getCurrentPage()->getFirstItemNumber(),
$paginator->getItemsPerPage() $paginator->getItemsPerPage()

View File

@@ -60,14 +60,20 @@ class ChillPersonExtension extends Extension implements PrependExtensionInterfac
$container->setParameter('chill_person.allow_multiple_simultaneous_accompanying_periods', $container->setParameter('chill_person.allow_multiple_simultaneous_accompanying_periods',
$config['allow_multiple_simultaneous_accompanying_periods']); $config['allow_multiple_simultaneous_accompanying_periods']);
$loader = new Loader\YamlFileLoader($container, new FileLocator(dirname(__DIR__, 2).'/config')); $loader = new Loader\YamlFileLoader($container, new FileLocator(__DIR__.'/../config'));
$loader->load('services.yaml'); $loader->load('services.yaml');
$loader->load('services/widgets.yaml'); $loader->load('services/widgets.yaml');
$loader->load('services/exports.yaml'); $loader->load('services/exports.yaml');
$loader->load('services/fixtures.yaml'); $loader->load('services/fixtures.yaml');
$loader->load('services/controller.yaml');
$loader->load('services/search.yaml'); $loader->load('services/search.yaml');
$loader->load('services/menu.yaml');
$loader->load('services/privacyEvent.yaml');
$loader->load('services/command.yaml'); $loader->load('services/command.yaml');
$loader->load('services/actions.yaml');
$loader->load('services/form.yaml'); $loader->load('services/form.yaml');
$loader->load('services/repository.yaml');
$loader->load('services/templating.yaml');
$loader->load('services/alt_names.yaml'); $loader->load('services/alt_names.yaml');
$loader->load('services/serializer.yaml'); $loader->load('services/serializer.yaml');
@@ -179,7 +185,7 @@ class ChillPersonExtension extends Extension implements PrependExtensionInterfac
$container->prependExtensionConfig('chill_main', array( $container->prependExtensionConfig('chill_main', array(
'routing' => array( 'routing' => array(
'resources' => array( 'resources' => array(
dirname(__DIR__, 2) . '/config/routes.yaml' '@ChillPersonBundle/config/routes.yaml'
) )
) )
)); ));

View File

@@ -37,43 +37,43 @@ use Chill\MainBundle\Entity\User;
/** /**
* AccompanyingPeriod Class * AccompanyingPeriod Class
* *
* @ORM\Entity * @ORM\Entity(repositoryClass="Chill\PersonBundle\Repository\AccompanyingPeriodRepository")
* @ORM\Table(name="chill_person_accompanying_period") * @ORM\Table(name="chill_person_accompanying_period")
*/ */
class AccompanyingPeriod class AccompanyingPeriod
{ {
/** /**
* Mark an accompanying period as "occasional" * Mark an accompanying period as "occasional"
* *
* used in INTENSITY * used in INTENSITY
*/ */
public const INTENSITY_OCCASIONAL = 'occasional'; public const INTENSITY_OCCASIONAL = 'occasional';
/** /**
* Mark an accompanying period as "regular" * Mark an accompanying period as "regular"
* *
* used in INTENSITY * used in INTENSITY
*/ */
public const INTENSITY_REGULAR = 'regular'; public const INTENSITY_REGULAR = 'regular';
public const INTENSITIES = [self::INTENSITY_OCCASIONAL, self::INTENSITY_REGULAR]; public const INTENSITIES = [self::INTENSITY_OCCASIONAL, self::INTENSITY_REGULAR];
/** /**
* Mark an accompanying period as "draft". * Mark an accompanying period as "draft".
* *
* This means that the accompanying period is not yet * This means that the accompanying period is not yet
* confirmed by the creator * confirmed by the creator
*/ */
public const STEP_DRAFT = 'DRAFT'; public const STEP_DRAFT = 'DRAFT';
/** /**
* Mark an accompanying period as "confirmed". * Mark an accompanying period as "confirmed".
* *
* This means that the accompanying period **is** * This means that the accompanying period **is**
* confirmed by the creator * confirmed by the creator
*/ */
public const STEP_CONFIRMED = 'CONFIRMED'; public const STEP_CONFIRMED = 'CONFIRMED';
/** /**
* @var integer * @var integer
* *
@@ -148,7 +148,7 @@ class AccompanyingPeriod
* @ORM\Column(type="string", length=32, nullable=true) * @ORM\Column(type="string", length=32, nullable=true)
*/ */
private $step = self::STEP_DRAFT; private $step = self::STEP_DRAFT;
/** /**
* @ORM\ManyToOne(targetEntity=Origin::class) * @ORM\ManyToOne(targetEntity=Origin::class)
* @ORM\JoinColumn(nullable=true) * @ORM\JoinColumn(nullable=true)
@@ -302,13 +302,9 @@ class AccompanyingPeriod
return false; return false;
} }
public function setRemark(string $remark): self public function setRemark(string $remark = null): self
{ {
if ($remark === null) { $this->remark = (string) $remark;
$remark = '';
}
$this->remark = $remark;
return $this; return $this;
} }

View File

@@ -4,6 +4,7 @@ namespace Chill\PersonBundle\Entity\AccompanyingPeriod;
use Chill\PersonBundle\Entity\SocialWork\Result; use Chill\PersonBundle\Entity\SocialWork\Result;
use Chill\PersonBundle\Entity\SocialWork\SocialAction; use Chill\PersonBundle\Entity\SocialWork\SocialAction;
use Chill\PersonBundle\Repository\AccompanyingPeriod\AccompanyingPeriodWorkRepository;
use Chill\MainBundle\Entity\User; use Chill\MainBundle\Entity\User;
use Chill\PersonBundle\Entity\AccompanyingPeriod; use Chill\PersonBundle\Entity\AccompanyingPeriod;
use Chill\ThirdPartyBundle\Entity\ThirdParty; use Chill\ThirdPartyBundle\Entity\ThirdParty;
@@ -12,7 +13,7 @@ use Doctrine\Common\Collections\Collection;
use Doctrine\ORM\Mapping as ORM; use Doctrine\ORM\Mapping as ORM;
/** /**
* @ORM\Entity * @ORM\Entity(repositoryClass=AccompanyingPeriodWorkRepository::class)
* @ORM\Table(name="chill_person_accompanying_period_work") * @ORM\Table(name="chill_person_accompanying_period_work")
*/ */
class AccompanyingPeriodWork class AccompanyingPeriodWork

View File

@@ -4,12 +4,13 @@ namespace Chill\PersonBundle\Entity\AccompanyingPeriod;
use Chill\PersonBundle\Entity\SocialWork\Goal; use Chill\PersonBundle\Entity\SocialWork\Goal;
use Chill\PersonBundle\Entity\SocialWork\Result; use Chill\PersonBundle\Entity\SocialWork\Result;
use Chill\PersonBundle\Repository\AccompanyingPeriod\AccompanyingPeriodWorkGoalRepository;
use Doctrine\Common\Collections\ArrayCollection; use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\Common\Collections\Collection; use Doctrine\Common\Collections\Collection;
use Doctrine\ORM\Mapping as ORM; use Doctrine\ORM\Mapping as ORM;
/** /**
* @ORM\Entity * @ORM\Entity(repositoryClass=AccompanyingPeriodWorkGoalRepository::class)
* @ORM\Table(name="chill_person_accompanying_period_work_goal") * @ORM\Table(name="chill_person_accompanying_period_work_goal")
*/ */
class AccompanyingPeriodWorkGoal class AccompanyingPeriodWorkGoal

View File

@@ -29,7 +29,8 @@ use Doctrine\Common\Collections\ArrayCollection;
/** /**
* ClosingMotive give an explanation why we closed the Accompanying period * ClosingMotive give an explanation why we closed the Accompanying period
* *
* @ORM\Entity * @ORM\Entity(
* repositoryClass="Chill\PersonBundle\Repository\AccompanyingPeriod\ClosingMotiveRepository")
* @ORM\Table(name="chill_person_accompanying_period_closingmotive") * @ORM\Table(name="chill_person_accompanying_period_closingmotive")
*/ */
class ClosingMotive class ClosingMotive
@@ -49,14 +50,14 @@ class ClosingMotive
* @ORM\Column(type="json") * @ORM\Column(type="json")
*/ */
private $name; private $name;
/** /**
* @var boolean * @var boolean
* *
* @ORM\Column(type="boolean") * @ORM\Column(type="boolean")
*/ */
private $active = true; private $active = true;
/** /**
* @var self * @var self
* *
@@ -65,7 +66,7 @@ class ClosingMotive
* inversedBy="children") * inversedBy="children")
*/ */
private $parent = null; private $parent = null;
/** /**
* Child Accompanying periods * Child Accompanying periods
* @var Collection * @var Collection
@@ -75,15 +76,15 @@ class ClosingMotive
* mappedBy="parent") * mappedBy="parent")
*/ */
private $children; private $children;
/** /**
* @var float * @var float
* *
* @ORM\Column(type="float") * @ORM\Column(type="float")
*/ */
private $ordering = 0.0; private $ordering = 0.0;
/** /**
* ClosingMotive constructor. * ClosingMotive constructor.
*/ */
@@ -91,7 +92,7 @@ class ClosingMotive
{ {
$this->children = new ArrayCollection(); $this->children = new ArrayCollection();
} }
/** /**
* Get id * Get id
* *
@@ -125,7 +126,7 @@ class ClosingMotive
{ {
return $this->name; return $this->name;
} }
/** /**
* @return bool * @return bool
*/ */
@@ -133,7 +134,7 @@ class ClosingMotive
{ {
return $this->active; return $this->active;
} }
/** /**
* @param bool $active * @param bool $active
* @return $this * @return $this
@@ -141,16 +142,16 @@ class ClosingMotive
public function setActive(bool $active) public function setActive(bool $active)
{ {
$this->active = $active; $this->active = $active;
if ($this->active === FALSE) { if ($this->active === FALSE) {
foreach ($this->getChildren() as $child) { foreach ($this->getChildren() as $child) {
$child->setActive(FALSE); $child->setActive(FALSE);
} }
} }
return $this; return $this;
} }
/** /**
* @return ClosingMotive * @return ClosingMotive
*/ */
@@ -158,7 +159,7 @@ class ClosingMotive
{ {
return $this->parent; return $this->parent;
} }
/** /**
* @return Collection * @return Collection
*/ */
@@ -166,7 +167,7 @@ class ClosingMotive
{ {
return $this->children; return $this->children;
} }
/** /**
* @param ClosingMotive|null $parent * @param ClosingMotive|null $parent
* @return ClosingMotive * @return ClosingMotive
@@ -174,14 +175,14 @@ class ClosingMotive
public function setParent(?ClosingMotive $parent): ClosingMotive public function setParent(?ClosingMotive $parent): ClosingMotive
{ {
$this->parent = $parent; $this->parent = $parent;
if (NULL !== $parent) { if (NULL !== $parent) {
//$parent->addChildren($this); //$parent->addChildren($this);
} }
return $this; return $this;
} }
/** /**
* @param Collection $children * @param Collection $children
* @return ClosingMotive * @return ClosingMotive
@@ -189,10 +190,10 @@ class ClosingMotive
public function setChildren(Collection $children): ClosingMotive public function setChildren(Collection $children): ClosingMotive
{ {
$this->children = $children; $this->children = $children;
return $this; return $this;
} }
/** /**
* @param ClosingMotive $child * @param ClosingMotive $child
* @return ClosingMotive * @return ClosingMotive
@@ -202,13 +203,13 @@ class ClosingMotive
if ($this->children->contains($child)) { if ($this->children->contains($child)) {
return $this; return $this;
} }
$this->children->add($child); $this->children->add($child);
$child->setParent($this); $child->setParent($this);
return $this; return $this;
} }
/** /**
* @param ClosingMotive $child * @param ClosingMotive $child
* @return ClosingMotive * @return ClosingMotive
@@ -218,10 +219,10 @@ class ClosingMotive
if ($this->children->removeElement($child)) { if ($this->children->removeElement($child)) {
$child->setParent(null); $child->setParent(null);
} }
return $this; return $this;
} }
/** /**
* @return float * @return float
*/ */
@@ -229,7 +230,7 @@ class ClosingMotive
{ {
return $this->ordering; return $this->ordering;
} }
/** /**
* @param float $ordering * @param float $ordering
* @return $this * @return $this
@@ -237,10 +238,10 @@ class ClosingMotive
public function setOrdering(float $ordering) public function setOrdering(float $ordering)
{ {
$this->ordering = $ordering; $this->ordering = $ordering;
return $this; return $this;
} }
/** /**
* @return bool * @return bool
*/ */
@@ -248,7 +249,7 @@ class ClosingMotive
{ {
return $this->parent !== null; return $this->parent !== null;
} }
/** /**
* @return bool * @return bool
*/ */
@@ -256,7 +257,7 @@ class ClosingMotive
{ {
return $this->children->count() > 0; return $this->children->count() > 0;
} }
/** /**
* @return bool * @return bool
*/ */
@@ -264,7 +265,7 @@ class ClosingMotive
{ {
return $this->children->count() === 0; return $this->children->count() === 0;
} }
/** /**
* @return bool * @return bool
*/ */

View File

@@ -22,12 +22,13 @@
namespace Chill\PersonBundle\Entity\AccompanyingPeriod; namespace Chill\PersonBundle\Entity\AccompanyingPeriod;
use Chill\PersonBundle\Repository\AccompanyingPeriod\CommentRepository;
use Chill\MainBundle\Entity\User; use Chill\MainBundle\Entity\User;
use Chill\PersonBundle\Entity\AccompanyingPeriod; use Chill\PersonBundle\Entity\AccompanyingPeriod;
use Doctrine\ORM\Mapping as ORM; use Doctrine\ORM\Mapping as ORM;
/** /**
* @ORM\Entity * @ORM\Entity(repositoryClass=CommentRepository::class)
* @ORM\Table(name="chill_person_accompanying_period_comment") * @ORM\Table(name="chill_person_accompanying_period_comment")
*/ */
class Comment class Comment

View File

@@ -22,10 +22,11 @@
namespace Chill\PersonBundle\Entity\AccompanyingPeriod; namespace Chill\PersonBundle\Entity\AccompanyingPeriod;
use Chill\PersonBundle\Entity\AccompanyingPeriod\OriginRepository;
use Doctrine\ORM\Mapping as ORM; use Doctrine\ORM\Mapping as ORM;
/** /**
* @ORM\Entity * @ORM\Entity(repositoryClass=OriginRepository::class)
* @ORM\Table(name="chill_person_accompanying_period_origin") * @ORM\Table(name="chill_person_accompanying_period_origin")
*/ */
class Origin class Origin

View File

@@ -22,6 +22,7 @@
namespace Chill\PersonBundle\Entity\AccompanyingPeriod; namespace Chill\PersonBundle\Entity\AccompanyingPeriod;
use Chill\PersonBundle\Repository\AccompanyingPeriod\ResourceRepository;
use Chill\PersonBundle\Entity\AccompanyingPeriod; use Chill\PersonBundle\Entity\AccompanyingPeriod;
use Chill\PersonBundle\Entity\AccompanyingPeriod\Comment; use Chill\PersonBundle\Entity\AccompanyingPeriod\Comment;
use Chill\PersonBundle\Entity\Person; use Chill\PersonBundle\Entity\Person;
@@ -29,7 +30,7 @@ use Chill\ThirdPartyBundle\Entity\ThirdParty;
use Doctrine\ORM\Mapping as ORM; use Doctrine\ORM\Mapping as ORM;
/** /**
* @ORM\Entity * @ORM\Entity(repositoryClass=ResourceRepository::class)
* @ORM\Table(name="chill_person_accompanying_period_resource") * @ORM\Table(name="chill_person_accompanying_period_resource")
*/ */
class Resource class Resource
@@ -120,7 +121,7 @@ class Resource
return $this; return $this;
} }
/** /**
* @return Person|ThirdParty * @return Person|ThirdParty
*/ */

View File

@@ -22,6 +22,7 @@
namespace Chill\PersonBundle\Entity; namespace Chill\PersonBundle\Entity;
use Chill\PersonBundle\Repository\AccompanyingPeriodParticipationRepository;
use Chill\PersonBundle\Entity\AccompanyingPeriod; use Chill\PersonBundle\Entity\AccompanyingPeriod;
use Chill\PersonBundle\Entity\Person; use Chill\PersonBundle\Entity\Person;
use Doctrine\ORM\Mapping as ORM; use Doctrine\ORM\Mapping as ORM;
@@ -30,7 +31,7 @@ use Doctrine\ORM\Mapping as ORM;
* AccompanyingPeriodParticipation Class * AccompanyingPeriodParticipation Class
* *
* @package Chill\PersonBundle\Entity * @package Chill\PersonBundle\Entity
* @ORM\Entity * @ORM\Entity(repositoryClass=AccompanyingPeriodParticipationRepository::class)
* @ORM\Table(name="chill_person_accompanying_period_participation") * @ORM\Table(name="chill_person_accompanying_period_participation")
*/ */
class AccompanyingPeriodParticipation class AccompanyingPeriodParticipation
@@ -41,83 +42,83 @@ class AccompanyingPeriodParticipation
* @ORM\Column(type="integer") * @ORM\Column(type="integer")
*/ */
private $id; private $id;
/** /**
* @ORM\ManyToOne(targetEntity=Person::class, inversedBy="accompanyingPeriodParticipations") * @ORM\ManyToOne(targetEntity=Person::class, inversedBy="accompanyingPeriodParticipations")
* @ORM\JoinColumn(name="person_id", referencedColumnName="id", nullable=false) * @ORM\JoinColumn(name="person_id", referencedColumnName="id", nullable=false)
*/ */
private $person; private $person;
/** /**
* @ORM\ManyToOne(targetEntity=AccompanyingPeriod::class, inversedBy="participations", cascade={"persist"}) * @ORM\ManyToOne(targetEntity=AccompanyingPeriod::class, inversedBy="participations", cascade={"persist"})
* @ORM\JoinColumn(name="accompanyingperiod_id", referencedColumnName="id", nullable=false) * @ORM\JoinColumn(name="accompanyingperiod_id", referencedColumnName="id", nullable=false)
*/ */
private $accompanyingPeriod; private $accompanyingPeriod;
/** /**
* @ORM\Column(type="date", nullable=false) * @ORM\Column(type="date", nullable=false)
*/ */
private $startDate; private $startDate;
/** /**
* @ORM\Column(type="date", nullable=true) * @ORM\Column(type="date", nullable=true)
*/ */
private $endDate = null; private $endDate = null;
public function __construct(AccompanyingPeriod $accompanyingPeriod, Person $person) public function __construct(AccompanyingPeriod $accompanyingPeriod, Person $person)
{ {
$this->startDate = new \DateTimeImmutable('now'); $this->startDate = new \DateTimeImmutable('now');
$this->accompanyingPeriod = $accompanyingPeriod; $this->accompanyingPeriod = $accompanyingPeriod;
$this->person = $person; $this->person = $person;
} }
public function getId(): ?int public function getId(): ?int
{ {
return $this->id; return $this->id;
} }
public function getPerson(): ?Person public function getPerson(): ?Person
{ {
return $this->person; return $this->person;
} }
public function setPerson(?Person $person): self public function setPerson(?Person $person): self
{ {
$this->person = $person; $this->person = $person;
return $this; return $this;
} }
public function getAccompanyingPeriod(): ?AccompanyingPeriod public function getAccompanyingPeriod(): ?AccompanyingPeriod
{ {
return $this->accompanyingPeriod; return $this->accompanyingPeriod;
} }
public function setAccompanyingPeriod(?AccompanyingPeriod $accompanyingPeriod): self public function setAccompanyingPeriod(?AccompanyingPeriod $accompanyingPeriod): self
{ {
$this->accompanyingPeriod = $accompanyingPeriod; $this->accompanyingPeriod = $accompanyingPeriod;
return $this; return $this;
} }
public function getStartDate(): ?\DateTimeInterface public function getStartDate(): ?\DateTimeInterface
{ {
return $this->startDate; return $this->startDate;
} }
/* /*
* public function setStartDate(\DateTimeInterface $startDate): self { $this->startDate = $startDate; return $this; } * public function setStartDate(\DateTimeInterface $startDate): self { $this->startDate = $startDate; return $this; }
*/ */
public function getEndDate(): ?\DateTimeInterface public function getEndDate(): ?\DateTimeInterface
{ {
return $this->endDate; return $this->endDate;
} }
public function setEndDate(?\DateTimeInterface $endDate): self public function setEndDate(?\DateTimeInterface $endDate): self
{ {
$this->endDate = $endDate; $this->endDate = $endDate;
return $this; return $this;
} }
} }

View File

@@ -25,7 +25,7 @@ use Doctrine\ORM\Mapping as ORM;
/** /**
* MaritalStatus * MaritalStatus
* *
* @ORM\Entity * @ORM\Entity()
* @ORM\Table(name="chill_person_marital_status") * @ORM\Table(name="chill_person_marital_status")
* @ORM\HasLifecycleCallbacks() * @ORM\HasLifecycleCallbacks()
*/ */
@@ -48,7 +48,7 @@ class MaritalStatus
/** /**
* Get id * Get id
* *
* @return string * @return string
*/ */
public function getId() public function getId()
{ {
@@ -57,7 +57,7 @@ class MaritalStatus
/** /**
* Set id * Set id
* *
* @param string $id * @param string $id
* @return MaritalStatus * @return MaritalStatus
*/ */
@@ -76,17 +76,17 @@ class MaritalStatus
public function setName($name) public function setName($name)
{ {
$this->name = $name; $this->name = $name;
return $this; return $this;
} }
/** /**
* Get name * Get name
* *
* @return string array * @return string array
*/ */
public function getName() public function getName()
{ {
return $this->name; return $this->name;
} }
} }

View File

@@ -38,7 +38,7 @@ use Symfony\Component\Validator\Context\ExecutionContextInterface;
/** /**
* Person Class * Person Class
* *
* @ORM\Entity * @ORM\Entity(repositoryClass="Chill\PersonBundle\Repository\PersonRepository")
* @ORM\Table(name="chill_person_person", * @ORM\Table(name="chill_person_person",
* indexes={@ORM\Index( * indexes={@ORM\Index(
* name="person_names", * name="person_names",
@@ -287,7 +287,7 @@ class Person implements HasCenterInterface
$this->open(new AccompanyingPeriod($opening)); $this->open(new AccompanyingPeriod($opening));
} }
/** /**
* This private function scan accompanyingPeriodParticipations Collection, * This private function scan accompanyingPeriodParticipations Collection,
* searching for a given AccompanyingPeriod * searching for a given AccompanyingPeriod
@@ -299,10 +299,10 @@ class Person implements HasCenterInterface
if ($accompanyingPeriod === $participation->getAccompanyingPeriod()) { if ($accompanyingPeriod === $participation->getAccompanyingPeriod()) {
return $participation; return $participation;
}} }}
return null; return null;
} }
/** /**
* This public function is the same but return only true or false * This public function is the same but return only true or false
*/ */
@@ -310,7 +310,7 @@ class Person implements HasCenterInterface
{ {
return ($this->participationsContainAccompanyingPeriod($accompanyingPeriod)) ? false : true; return ($this->participationsContainAccompanyingPeriod($accompanyingPeriod)) ? false : true;
} }
/** /**
* Add AccompanyingPeriodParticipation * Add AccompanyingPeriodParticipation
* *
@@ -320,7 +320,7 @@ class Person implements HasCenterInterface
{ {
$participation = new AccompanyingPeriodParticipation($accompanyingPeriod, $this); $participation = new AccompanyingPeriodParticipation($accompanyingPeriod, $this);
$this->accompanyingPeriodParticipations->add($participation); $this->accompanyingPeriodParticipations->add($participation);
return $this; return $this;
} }
@@ -330,7 +330,7 @@ class Person implements HasCenterInterface
public function removeAccompanyingPeriod(AccompanyingPeriod $accompanyingPeriod) : void public function removeAccompanyingPeriod(AccompanyingPeriod $accompanyingPeriod) : void
{ {
$participation = $this->participationsContainAccompanyingPeriod($accompanyingPeriod); $participation = $this->participationsContainAccompanyingPeriod($accompanyingPeriod);
if (! null === $participation) { if (! null === $participation) {
$participation->setEndDate(\DateTimeImmutable::class); $participation->setEndDate(\DateTimeImmutable::class);
$this->accompanyingPeriodParticipations->removeElement($participation); $this->accompanyingPeriodParticipations->removeElement($participation);
@@ -408,7 +408,7 @@ class Person implements HasCenterInterface
} }
return $accompanyingPeriods; return $accompanyingPeriods;
} }
/** /**
* Get AccompanyingPeriodParticipations Collection * Get AccompanyingPeriodParticipations Collection
*/ */
@@ -1140,12 +1140,12 @@ class Person implements HasCenterInterface
return true; return true;
} }
public function getFullnameCanonical() : string public function getFullnameCanonical() : string
{ {
return $this->fullnameCanonical; return $this->fullnameCanonical;
} }
public function setFullnameCanonical($fullnameCanonical) : Person public function setFullnameCanonical($fullnameCanonical) : Person
{ {
$this->fullnameCanonical = $fullnameCanonical; $this->fullnameCanonical = $fullnameCanonical;

View File

@@ -8,7 +8,7 @@ use Doctrine\ORM\Mapping as ORM;
* PersonAltName * PersonAltName
* *
* @ORM\Table(name="chill_person_alt_name") * @ORM\Table(name="chill_person_alt_name")
* @ORM\Entity * @ORM\Entity(repositoryClass="Chill\PersonBundle\Repository\PersonAltNameRepository")
*/ */
class PersonAltName class PersonAltName
{ {
@@ -34,7 +34,7 @@ class PersonAltName
* @ORM\Column(name="label", type="text") * @ORM\Column(name="label", type="text")
*/ */
private $label; private $label;
/** /**
* @var Person * @var Person
* *
@@ -45,7 +45,7 @@ class PersonAltName
*/ */
private $person; private $person;
/** /**
* Get id. * Get id.
* *
@@ -103,7 +103,7 @@ class PersonAltName
{ {
return $this->label; return $this->label;
} }
/** /**
* @return Person * @return Person
*/ */
@@ -111,7 +111,7 @@ class PersonAltName
{ {
return $this->person; return $this->person;
} }
/** /**
* @param Person|null $person * @param Person|null $person
* @return $this * @return $this
@@ -119,7 +119,7 @@ class PersonAltName
public function setPerson(?Person $person = null) public function setPerson(?Person $person = null)
{ {
$this->person = $person; $this->person = $person;
return $this; return $this;
} }
} }

View File

@@ -9,7 +9,7 @@ use Chill\MainBundle\Entity\User;
* PersonNotDuplicate * PersonNotDuplicate
* *
* @ORM\Table(name="chill_person_not_duplicate") * @ORM\Table(name="chill_person_not_duplicate")
* @ORM\Entity * @ORM\Entity(repositoryClass="Chill\PersonBundle\Repository\PersonNotDuplicateRepository")
*/ */
class PersonNotDuplicate class PersonNotDuplicate
{ {

View File

@@ -8,7 +8,7 @@ use Doctrine\ORM\Mapping as ORM;
/** /**
* Person Phones * Person Phones
* *
* @ORM\Entity * @ORM\Entity()
* @ORM\Table(name="chill_person_phone") * @ORM\Table(name="chill_person_phone")
*/ */
class PersonPhone class PersonPhone
@@ -107,7 +107,7 @@ class PersonPhone
{ {
$this->date = $date; $this->date = $date;
} }
public function isEmpty(): bool public function isEmpty(): bool
{ {
return empty($this->getDescription()) && empty($this->getPhonenumber()); return empty($this->getDescription()) && empty($this->getPhonenumber());

View File

@@ -2,10 +2,11 @@
namespace Chill\PersonBundle\Entity\SocialWork; namespace Chill\PersonBundle\Entity\SocialWork;
use Chill\PersonBundle\Repository\SocialWork\EvaluationRepository;
use Doctrine\ORM\Mapping as ORM; use Doctrine\ORM\Mapping as ORM;
/** /**
* @ORM\Entity * @ORM\Entity(repositoryClass=EvaluationRepository::class)
* @ORM\Table(name="chill_person_social_work_evaluation") * @ORM\Table(name="chill_person_social_work_evaluation")
*/ */
class Evaluation class Evaluation

View File

@@ -2,12 +2,13 @@
namespace Chill\PersonBundle\Entity\SocialWork; namespace Chill\PersonBundle\Entity\SocialWork;
use Chill\PersonBundle\Repository\SocialWork\GoalRepository;
use Doctrine\Common\Collections\ArrayCollection; use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\Common\Collections\Collection; use Doctrine\Common\Collections\Collection;
use Doctrine\ORM\Mapping as ORM; use Doctrine\ORM\Mapping as ORM;
/** /**
* @ORM\Entity * @ORM\Entity(repositoryClass=GoalRepository::class)
* @ORM\Table(name="chill_person_social_work_goal") * @ORM\Table(name="chill_person_social_work_goal")
*/ */
class Goal class Goal

View File

@@ -4,12 +4,13 @@ namespace Chill\PersonBundle\Entity\SocialWork;
use Chill\PersonBundle\Entity\AccompanyingPeriod\AccompanyingPeriodWork; use Chill\PersonBundle\Entity\AccompanyingPeriod\AccompanyingPeriodWork;
use Chill\PersonBundle\Entity\AccompanyingPeriod\AccompanyingPeriodWorkGoal; use Chill\PersonBundle\Entity\AccompanyingPeriod\AccompanyingPeriodWorkGoal;
use Chill\PersonBundle\Repository\SocialWork\ResultRepository;
use Doctrine\Common\Collections\ArrayCollection; use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\Common\Collections\Collection; use Doctrine\Common\Collections\Collection;
use Doctrine\ORM\Mapping as ORM; use Doctrine\ORM\Mapping as ORM;
/** /**
* @ORM\Entity * @ORM\Entity(repositoryClass=ResultRepository::class)
* @ORM\Table(name="chill_person_social_work_result") * @ORM\Table(name="chill_person_social_work_result")
*/ */
class Result class Result

View File

@@ -2,12 +2,13 @@
namespace Chill\PersonBundle\Entity\SocialWork; namespace Chill\PersonBundle\Entity\SocialWork;
use Chill\PersonBundle\Repository\SocialWork\SocialActionRepository;
use Doctrine\Common\Collections\ArrayCollection; use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\Common\Collections\Collection; use Doctrine\Common\Collections\Collection;
use Doctrine\ORM\Mapping as ORM; use Doctrine\ORM\Mapping as ORM;
/** /**
* @ORM\Entity * @ORM\Entity(repositoryClass=SocialActionRepository::class)
* @ORM\Table(name="chill_person_social_action") * @ORM\Table(name="chill_person_social_action")
*/ */
class SocialAction class SocialAction

View File

@@ -1,12 +1,14 @@
<?php <?php
namespace Chill\PersonBundle\Entity\SocialWork; namespace Chill\PersonBundle\Entity\SocialWork;
use Chill\PersonBundle\Repository\SocialWork\SocialIssueRepository;
use Doctrine\Common\Collections\ArrayCollection; use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\Common\Collections\Collection; use Doctrine\Common\Collections\Collection;
use Doctrine\ORM\Mapping as ORM; use Doctrine\ORM\Mapping as ORM;
/** /**
* @ORM\Entity * @ORM\Entity(repositoryClass=SocialIssueRepository::class)
* @ORM\Table(name="chill_person_social_issue") * @ORM\Table(name="chill_person_social_issue")
*/ */
class SocialIssue class SocialIssue

Some files were not shown because too many files have changed in this diff Show More