Compare commits

..

6 Commits

Author SHA1 Message Date
Pol Dellaiera
ee4e0b86fd ci: Autofix code style. 2021-05-07 22:39:37 +02:00
Pol Dellaiera
ce4cbe3b8d Fix syntax errors. 2021-05-07 21:59:49 +02:00
Pol Dellaiera
c5b8b6345d Upgrade drupol/php-conventions to v5. 2021-05-07 21:59:49 +02:00
8b51bfbaf5 force type for connection parameter 2021-05-07 21:59:49 +02:00
Pol Dellaiera
f6cf0dba2f chore: Add/update static files. 2021-05-07 21:59:49 +02:00
Pol Dellaiera
0625afecdd chore: Update composer.json 2021-05-07 19:43:46 +02:00
2041 changed files with 76519 additions and 114097 deletions

View File

@@ -7,7 +7,6 @@ charset = utf-8
end_of_line = LF end_of_line = LF
insert_final_newline = true insert_final_newline = true
trim_trailing_whitespace = true trim_trailing_whitespace = true
indent_size = 4
[*.{php,html,twig}] [*.{php,html,twig}]
indent_style = space indent_style = space

View File

@@ -5,23 +5,20 @@ image: registry.gitlab.com/chill-projet/chill-app/php-base-image:7.4
cache: cache:
paths: paths:
- tests/app/vendor/ - tests/app/vendor/
- .composer
before_script: before_script:
# add extensions to postgres # add extensions to postgres
- PGPASSWORD=$POSTGRES_PASSWORD psql -U $POSTGRES_USER -h db -c "CREATE EXTENSION IF NOT EXISTS unaccent; CREATE EXTENSION IF NOT EXISTS pg_trgm;" - PGPASSWORD=$POSTGRES_PASSWORD psql -U $POSTGRES_USER -h db -c "CREATE EXTENSION IF NOT EXISTS unaccent; CREATE EXTENSION IF NOT EXISTS pg_trgm;"
# Install and run Composer # Install and run Composer
- mkdir -p $COMPOSER_HOME
- curl -sS https://getcomposer.org/installer | php - curl -sS https://getcomposer.org/installer | php
- php -d memory_limit=2G composer.phar install - php composer.phar install
- php tests/app/bin/console doctrine:migrations:migrate -n - php tests/app/bin/console doctrine:migrations:migrate -n
- php -d memory_limit=2G tests/app/bin/console doctrine:fixtures:load -n - php tests/app/bin/console doctrine:fixtures:load -n
- echo "before_script finished"
# Bring in any services we need http://docs.gitlab.com/ee/ci/docker/using_docker_images.html#what-is-a-service # Bring in any services we need http://docs.gitlab.com/ee/ci/docker/using_docker_images.html#what-is-a-service
# See http://docs.gitlab.com/ee/ci/services/README.html for examples. # See http://docs.gitlab.com/ee/ci/services/README.html for examples.
services: services:
- name: postgis/postgis:12-3.1-alpine - name: postgres:12
alias: db alias: db
- name: redis - name: redis
alias: redis alias: redis
@@ -36,13 +33,9 @@ variables:
REDIS_HOST: redis REDIS_HOST: redis
REDIS_PORT: 6379 REDIS_PORT: 6379
REDIS_URL: redis://redis:6379 REDIS_URL: redis://redis:6379
# change vendor dir to make the app install into tests/apps
COMPOSER_VENDOR_DIR: tests/app/vendor
# cache some composer data
COMPOSER_HOME: .composer
# Run our tests # Run our tests
test: test:
script: script:
- php -d memory_limit=3G bin/phpunit --colors=never - bin/phpunit --colors=never

71
.php-cs-fixer.dist.php Normal file
View File

@@ -0,0 +1,71 @@
<?php
/**
* Chill is a software for social workers.
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*
* @see https://www.champs-libres.coop/
*/
declare(strict_types=1);
use drupol\PhpCsFixerConfigsPhp\Config\Php7;
use PhpCsFixer\RuleSet\RuleSetDescriptionInterface;
use PhpCsFixer\RuleSet\RuleSets;
require __DIR__ . '/vendor/autoload.php';
$vendorDirectory = dirname((new ReflectionClass(Php7::class))->getFileName(), 5);
$config = require $vendorDirectory . '/drupol/php-conventions/config/php73/php_cs_fixer.config.php';
$config
->getFinder()
->ignoreDotFiles(false);
$rules = $config->getRules();
$riskyRules = array_reduce(
array_filter(
RuleSets::getSetDefinitions(),
static function (RuleSetDescriptionInterface $ruleset): bool {
return $ruleset->isRisky();
}
),
static function (array $carry, RuleSetDescriptionInterface $ruleSetDescription): array {
return array_merge($carry, array_keys($ruleSetDescription->getRules()));
},
[]
);
$rules['header_comment']['header'] = trim(file_get_contents(__DIR__ . '/resource/header.txt'));
// Remove properties containing the word 'risky'.
// Remove custom risky properties
$rules = array_filter(
array_filter(
array_diff_key(
$rules,
array_flip($riskyRules)
),
static function (string $property): bool {
return false === strpos(strtolower($property), 'risky');
},
ARRAY_FILTER_USE_KEY
),
static function (string $property): bool {
return false === in_array(
$property,
[
'static_lambda',
'ordered_interfaces',
'psr4',
]
);
},
ARRAY_FILTER_USE_KEY
);
return $config->setRules($rules);

View File

@@ -1,45 +0,0 @@
# Changelog
All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to
* [Semantic Versioning](https://semver.org/spec/v2.0.0.html) for stable releases;
* date versioning for test releases
## Unreleased
* Address: zoom on postal code geometry + fix origin of manually entered postal code
* [Aside activity] Fixes for aside activity
* categories with child
* fast creation buttons
* add ordering for types
## Test releases
### test release 2021-10-04
* [Household editor][UI] Update how household suggestion and addresses are picked;
* [AddAddress] Handle address suggestion;
* [CenterType][Create a person] when overriding the ACL rules, allow to show a PickCenterType
when no centers are reachable by the default ACL.
* [Household] Show comment event if no address are associated with the household;
* [Person results] Add requestor into search results:
* a badge "requestor" is shown into search results;
* periods where the person is only requestor (without participating) are also shown;
Issues:
* https://gitlab.com/champs-libres/departement-de-la-vendee/accent-suivi-developpement/-/issues/13
* https://gitlab.com/champs-libres/departement-de-la-vendee/chill/-/issues/199
* [Person form] "accept sms" not required:
https://gitlab.com/champs-libres/departement-de-la-vendee/accent-suivi-developpement/-/issues/37
https://gitlab.com/champs-libres/departement-de-la-vendee/chill/-/issues/221
* On-The-Fly modale works for showing, editing and creating person and thirdparty ;
* AccompanyingCourse Resume page: list associated persons by household, see household when hover, and show on-the-fly modale when clicking on person ;

View File

@@ -629,12 +629,12 @@ to attach them to the start of each source file to most effectively
state the exclusion of warranty; and each file should have at least state the exclusion of warranty; and each file should have at least
the "copyright" line and a pointer to where the full notice is found. the "copyright" line and a pointer to where the full notice is found.
chill-bundles <one line to give the program's name and a brief idea of what it does.>
Copyright (C) 2021 Chill Project Copyright (C) <year> <name of author>
This program is free software: you can redistribute it and/or modify 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 it under the terms of the GNU Affero General Public License as published by
by the Free Software Foundation, either version 3 of the License, or the Free Software Foundation, either version 3 of the License, or
(at your option) any later version. (at your option) any later version.
This program is distributed in the hope that it will be useful, This program is distributed in the hope that it will be useful,

View File

@@ -1,72 +1,9 @@
{ {
"name": "chill-project/chill-bundles", "name": "chill-project/chill-bundles",
"license": "AGPL-3.0-only",
"type": "library", "type": "library",
"description": "Most used bundles for chill-project", "description": "Most used bundles for chill-project",
"keywords": [ "keywords": ["chill", "social worker"],
"chill",
"social worker"
],
"license": "AGPL-3.0-only",
"require": {
"champs-libres/async-uploader-bundle": "dev-sf4",
"champs-libres/wopi-bundle": "dev-master",
"composer/package-versions-deprecated": "^1.10",
"doctrine/doctrine-bundle": "^2.1",
"doctrine/doctrine-migrations-bundle": "^3.0",
"doctrine/orm": "^2.7",
"erusev/parsedown": "^1.7",
"graylog2/gelf-php": "^1.5",
"knplabs/knp-menu": "^3.1",
"knplabs/knp-menu-bundle": "^3.0",
"knplabs/knp-time-bundle": "^1.12",
"league/csv": "^9.7.1",
"nyholm/psr7": "^1.4",
"phpoffice/phpspreadsheet": "^1.16",
"ramsey/uuid-doctrine": "^1.7",
"sensio/framework-extra-bundle": "^5.5",
"symfony/asset": "4.*",
"symfony/browser-kit": "^5.2",
"symfony/css-selector": "^5.2",
"symfony/expression-language": "4.*",
"symfony/form": "4.*",
"symfony/intl": "4.*",
"symfony/mime": "^4 || ^5",
"symfony/monolog-bundle": "^3.5",
"symfony/security-bundle": "4.*",
"symfony/serializer": "^5.2",
"symfony/swiftmailer-bundle": "^3.5",
"symfony/templating": "4.*",
"symfony/translation": "4.*",
"symfony/twig-bundle": "^4.4",
"symfony/validator": "4.*",
"symfony/webpack-encore-bundle": "^1.11",
"symfony/workflow": "4.*",
"symfony/yaml": "4.*",
"twig/extra-bundle": "^2.12 || ^3.0",
"twig/intl-extra": "^3.0",
"twig/markdown-extra": "^3.3",
"twig/twig": "^2.12 || ^3.0"
},
"conflict": {
"symfony/symfony": "*"
},
"require-dev": {
"doctrine/doctrine-fixtures-bundle": "^3.3",
"fakerphp/faker": "^1.13",
"nelmio/alice": "^3.8",
"phpunit/phpunit": "^7.0",
"symfony/debug-bundle": "^5.1",
"symfony/dotenv": "^5.1",
"symfony/maker-bundle": "^1.20",
"symfony/phpunit-bridge": "^5.2",
"symfony/stopwatch": "^5.1",
"symfony/var-dumper": "4.*",
"symfony/web-profiler-bundle": "^5.0"
},
"config": {
"bin-dir": "bin",
"vendor-dir": "tests/app/vendor"
},
"autoload": { "autoload": {
"psr-4": { "psr-4": {
"Chill\\ActivityBundle\\": "src/Bundle/ChillActivityBundle", "Chill\\ActivityBundle\\": "src/Bundle/ChillActivityBundle",
@@ -79,24 +16,73 @@
"Chill\\PersonBundle\\": "src/Bundle/ChillPersonBundle", "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"
"Chill\\AsideActivityBundle\\": "src/Bundle/ChillAsideActivityBundle/src",
"Chill\\DocGeneratorBundle\\": "src/Bundle/ChillDocGeneratorBundle",
"Chill\\CalendarBundle\\": "src/Bundle/ChillCalendarBundle",
"Chill\\WopiBundle\\": "src/Bundle/ChillWopiBundle/src"
} }
}, },
"autoload-dev": { "autoload-dev": {
"psr-4": { "psr-4": {
"App\\": "tests/app/src/" "App\\": "tests/app/src/"
} }
}, },
"minimum-stability": "dev", "require": {
"prefer-stable": true, "champs-libres/async-uploader-bundle": "dev-sf4",
"graylog2/gelf-php": "^1.5",
"symfony/form": "4.*",
"symfony/twig-bundle": "^4.4",
"twig/extra-bundle": "^2.12|^3.0",
"twig/twig": "^2.12|^3.0",
"composer/package-versions-deprecated": "^1.10",
"doctrine/doctrine-bundle": "^2.1",
"doctrine/doctrine-migrations-bundle": "^3.0",
"doctrine/orm": "^2.7",
"symfony/asset": "4.*",
"symfony/monolog-bundle": "^3.5",
"symfony/security-bundle": "4.*",
"symfony/translation": "4.*",
"symfony/validator": "4.*",
"sensio/framework-extra-bundle": "^5.5",
"symfony/yaml": "4.*",
"symfony/webpack-encore-bundle": "^1.11",
"knplabs/knp-menu": "^3.1",
"knplabs/knp-menu-bundle": "^3.0",
"symfony/templating": "4.*",
"twig/intl-extra": "^3.0",
"symfony/workflow": "4.*",
"symfony/expression-language": "4.*",
"knplabs/knp-time-bundle": "^1.12",
"symfony/intl": "4.*",
"symfony/swiftmailer-bundle": "^3.5",
"league/csv": "^9.6",
"phpoffice/phpspreadsheet": "^1.16",
"symfony/browser-kit": "^5.2",
"symfony/css-selector": "^5.2",
"twig/markdown-extra": "^3.3",
"erusev/parsedown": "^1.7",
"symfony/serializer": "^5.2"
},
"conflict": {
"symfony/symfony": "*"
},
"require-dev": {
"drupol/php-conventions": "5.*",
"fakerphp/faker": "^1.13",
"phpunit/phpunit": "^7.0",
"symfony/dotenv": "^5.1",
"symfony/maker-bundle": "^1.20",
"doctrine/doctrine-fixtures-bundle": "^3.3",
"symfony/stopwatch": "^5.1",
"symfony/web-profiler-bundle": "^5.0",
"symfony/var-dumper": "4.*",
"symfony/debug-bundle": "^5.1",
"symfony/phpunit-bridge": "^5.2"
},
"scripts": { "scripts": {
"auto-scripts": { "auto-scripts": {
"cache:clear": "symfony-cmd", "cache:clear": "symfony-cmd",
"assets:install %PUBLIC_DIR%": "symfony-cmd" "assets:install %PUBLIC_DIR%": "symfony-cmd"
} }
},
"config": {
"bin-dir": "bin"
} }
} }

View File

@@ -1,123 +1,124 @@
<?php <?php
/**
* Chill is a software for social workers
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/
namespace Chill\PersonBundle\Export\Filter; namespace Chill\PersonBundle\Export\Filter;
use Chill\MainBundle\Export\ExportElementValidatedInterface;
use Chill\MainBundle\Export\FilterInterface; use Chill\MainBundle\Export\FilterInterface;
use DateTime;
use Doctrine\ORM\Query\Expr;
use Symfony\Component\Form\Extension\Core\Type\DateType; use Symfony\Component\Form\Extension\Core\Type\DateType;
use Symfony\Component\Validator\Context\ExecutionContextInterface; use Symfony\Component\Validator\Context\ExecutionContextInterface;
use Symfony\Component\Validator\Constraints;
use Symfony\Component\Form\FormEvent;
use Symfony\Component\Form\FormEvents;
use Doctrine\ORM\Query\Expr;
use Chill\MainBundle\Form\Type\Export\FilterType;
use Symfony\Component\Form\FormError;
use Chill\MainBundle\Export\ExportElementValidatedInterface;
class BirthdateFilter implements FilterInterface, ExportElementValidatedInterface class BirthdateFilter implements FilterInterface, ExportElementValidatedInterface
{ {
// add specific role for this filter // add specific role for this filter
public function addRole() public function addRole()
{ {
// we do not need any new role for this filter, so we return null // we do not need any new role for this filter, so we return null
return null; return null;
} }
// here, we alter the query created by Export
public function alterQuery(\Doctrine\ORM\QueryBuilder $qb, $data)
{
$where = $qb->getDQLPart('where');
// we create the clause here
$clause = $qb->expr()->between(
'person.birthdate',
':date_from',
':date_to'
);
// we have to take care **not to** remove previous clauses...
if ($where instanceof Expr\Andx) {
$where->add($clause);
} else {
$where = $qb->expr()->andX($clause);
}
$qb->add('where', $where);
// we add parameters from $data. $data contains the parameters from the form
$qb->setParameter('date_from', $data['date_from']);
$qb->setParameter('date_to', $data['date_to']);
}
// we give information on which type of export this filter applies // we give information on which type of export this filter applies
public function applyOn() public function applyOn()
{ {
return 'person'; return 'person';
} }
public function getTitle()
{
return 'Filter by person\'s birthdate';
}
// we build a form to collect some parameters from the users // we build a form to collect some parameters from the users
public function buildForm(\Symfony\Component\Form\FormBuilderInterface $builder) public function buildForm(\Symfony\Component\Form\FormBuilderInterface $builder)
{ {
$builder->add('date_from', DateType::class, array( $builder->add('date_from', DateType::class, [
'label' => "Born after this date", 'label' => 'Born after this date',
'data' => new \DateTime(), 'data' => new DateTime(),
'attr' => array('class' => 'datepicker'), 'attr' => ['class' => 'datepicker'],
'widget'=> 'single_text', 'widget' => 'single_text',
'format' => 'dd-MM-yyyy', 'format' => 'dd-MM-yyyy',
)); ]);
$builder->add('date_to', DateType::class, array( $builder->add('date_to', DateType::class, [
'label' => "Born before this date", 'label' => 'Born before this date',
'data' => new \DateTime(), 'data' => new DateTime(),
'attr' => array('class' => 'datepicker'), 'attr' => ['class' => 'datepicker'],
'widget'=> 'single_text', 'widget' => 'single_text',
'format' => 'dd-MM-yyyy', 'format' => 'dd-MM-yyyy',
)); ]);
}
// the form created above must be validated. The process of validation
// is executed here. This function is added by the interface
// `ExportElementValidatedInterface`, and can be ignore if there is
// no need for a validation
public function validateForm($data, ExecutionContextInterface $context)
{
$date_from = $data['date_from'];
$date_to = $data['date_to'];
if ($date_from === null) {
$context->buildViolation('The "date from" should not be empty')
//->atPath('date_from')
->addViolation();
}
if ($date_to === null) {
$context->buildViolation('The "date to" should not be empty')
//->atPath('date_to')
->addViolation();
}
if (
($date_from !== null && $date_to !== null)
&&
$date_from >= $date_to
) {
$context->buildViolation('The date "date to" should be after the '
. 'date given in "date from" field')
->addViolation();
}
}
// here, we alter the query created by Export
public function alterQuery(\Doctrine\ORM\QueryBuilder $qb, $data)
{
$where = $qb->getDQLPart('where');
// we create the clause here
$clause = $qb->expr()->between('person.birthdate', ':date_from',
':date_to');
// we have to take care **not to** remove previous clauses...
if ($where instanceof Expr\Andx) {
$where->add($clause);
} else {
$where = $qb->expr()->andX($clause);
}
$qb->add('where', $where);
// we add parameters from $data. $data contains the parameters from the form
$qb->setParameter('date_from', $data['date_from']);
$qb->setParameter('date_to', $data['date_to']);
} }
// here, we create a simple string which will describe the action of // here, we create a simple string which will describe the action of
// the filter in the Response // the filter in the Response
public function describeAction($data, $format = 'string') public function describeAction($data, $format = 'string')
{ {
return array('Filtered by person\'s birtdate: ' return ['Filtered by person\'s birtdate: '
. 'between %date_from% and %date_to%', array( . 'between %date_from% and %date_to%', [
'%date_from%' => $data['date_from']->format('d-m-Y'), '%date_from%' => $data['date_from']->format('d-m-Y'),
'%date_to%' => $data['date_to']->format('d-m-Y') '%date_to%' => $data['date_to']->format('d-m-Y'),
)); ], ];
} }
public function getTitle()
{
return 'Filter by person\'s birthdate';
}
// the form created above must be validated. The process of validation
// is executed here. This function is added by the interface
// `ExportElementValidatedInterface`, and can be ignore if there is
// no need for a validation
public function validateForm($data, ExecutionContextInterface $context)
{
$date_from = $data['date_from'];
$date_to = $data['date_to'];
if (null === $date_from) {
$context->buildViolation('The "date from" should not be empty')
//->atPath('date_from')
->addViolation();
}
if (null === $date_to) {
$context->buildViolation('The "date to" should not be empty')
//->atPath('date_to')
->addViolation();
}
if (
(null !== $date_from && null !== $date_to)
&& $date_from >= $date_to
) {
$context->buildViolation('The date "date to" should be after the '
. 'date given in "date from" field')
->addViolation();
}
}
} }

View File

@@ -1,118 +1,117 @@
<?php <?php
/**
* Chill is a software for social workers
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/
namespace Chill\PersonBundle\Export\Export; namespace Chill\PersonBundle\Export\Export;
use Chill\MainBundle\Export\ExportInterface; use Chill\MainBundle\Export\ExportInterface;
use Doctrine\ORM\QueryBuilder;
use Symfony\Component\Form\FormBuilderInterface;
use Doctrine\ORM\Query;
use Chill\PersonBundle\Security\Authorization\PersonVoter;
use Symfony\Component\Security\Core\Role\Role;
use Chill\PersonBundle\Export\Declarations;
use Chill\MainBundle\Export\FormatterInterface; use Chill\MainBundle\Export\FormatterInterface;
use Chill\PersonBundle\Export\Declarations;
use Chill\PersonBundle\Security\Authorization\PersonVoter;
use Doctrine\ORM\EntityManagerInterface; use Doctrine\ORM\EntityManagerInterface;
use Doctrine\ORM\Query;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\Security\Core\Role\Role;
/**
*
*
* @author Julien Fastré <julien.fastre@champs-libres.coop>
*/
class CountPerson implements ExportInterface class CountPerson implements ExportInterface
{ {
/** /**
*
* @var EntityManagerInterface * @var EntityManagerInterface
*/ */
protected $entityManager; protected $entityManager;
public function __construct( public function __construct(
EntityManagerInterface $em EntityManagerInterface $em
) ) {
{
$this->entityManager = $em; $this->entityManager = $em;
} }
public function getType() public function buildForm(FormBuilderInterface $builder)
{ {
return Declarations::PERSON_TYPE; // this export does not add any form
} }
public function getAllowedFormattersTypes()
{
return [FormatterInterface::TYPE_TABULAR];
}
public function getDescription() public function getDescription()
{ {
return "Count peoples by various parameters."; return 'Count peoples by various parameters.';
} }
public function getTitle() public function getLabels($key, array $values, $data)
{ {
return "Count peoples"; // the Closure which will be executed by the formatter.
return function ($value) {
switch ($value) {
case '_header':
// we have to process specifically the '_header' string,
// which will be used by the formatter to show a column title
return $this->getTitle();
default:
// for all value, we do not process them and return them
// immediatly
return $value;
}
};
} }
public function requiredRole()
{
return new Role(PersonVoter::STATS);
}
public function initiateQuery(array $requiredModifiers, array $acl, array $data = array())
{
// we gather all center the user choose.
$centers = array_map(function($el) { return $el['center']; }, $acl);
$qb = $this->entityManager->createQueryBuilder();
$qb->select('COUNT(person.id) AS export_result')
->from('ChillPersonBundle:Person', 'person')
->join('person.center', 'center')
->andWhere('center IN (:authorized_centers)')
->setParameter('authorized_centers', $centers);
;
return $qb;
}
public function getResult($qb, $data)
{
return $qb->getQuery()->getResult(Query::HYDRATE_SCALAR);
}
public function getQueryKeys($data) public function getQueryKeys($data)
{ {
// this array match the result keys in the query. We have only // this array match the result keys in the query. We have only
// one column. // one column.
return array('export_result'); return ['export_result'];
} }
public function getLabels($key, array $values, $data) public function getResult($qb, $data)
{ {
return $qb->getQuery()->getResult(Query::HYDRATE_SCALAR);
// the Closure which will be executed by the formatter.
return function($value) {
switch($value) {
case '_header':
// we have to process specifically the '_header' string,
// which will be used by the formatter to show a column title
return $this->getTitle();
default:
// for all value, we do not process them and return them
// immediatly
return $value;
};
} }
public function getAllowedFormattersTypes() public function getTitle()
{ {
return array(FormatterInterface::TYPE_TABULAR); return 'Count peoples';
} }
public function buildForm(FormBuilderInterface $builder) { public function getType()
// this export does not add any form {
return Declarations::PERSON_TYPE;
} }
public function initiateQuery(array $requiredModifiers, array $acl, array $data = [])
{
// we gather all center the user choose.
$centers = array_map(function ($el) {
return $el['center'];
}, $acl);
$qb = $this->entityManager->createQueryBuilder();
$qb->select('COUNT(person.id) AS export_result')
->from('ChillPersonBundle:Person', 'person')
->join('person.center', 'center')
->andWhere('center IN (:authorized_centers)')
->setParameter('authorized_centers', $centers);
return $qb;
}
public function requiredRole()
{
return new Role(PersonVoter::STATS);
}
public function supportsModifiers() public function supportsModifiers()
{ {
// explain the export manager which formatters and filters are allowed // explain the export manager which formatters and filters are allowed
return array(Declarations::PERSON_TYPE, Declarations::PERSON_IMPLIED_IN); return [Declarations::PERSON_TYPE, Declarations::PERSON_IMPLIED_IN];
} }
} }

View File

@@ -13,9 +13,6 @@ API
Chill provides a basic framework to build REST api. Chill provides a basic framework to build REST api.
Basic configuration
*******************
Configure a route Configure a route
================= =================
@@ -37,7 +34,7 @@ You can also:
* `How to create your custom normalizer <https://symfony.com/doc/current/serializer/custom_normalizer.html>`_ * `How to create your custom normalizer <https://symfony.com/doc/current/serializer/custom_normalizer.html>`_
Auto-loading the routes Auto-loading the routes
======================= ***********************
Ensure that those lines are present in your file `app/config/routing.yml`: Ensure that those lines are present in your file `app/config/routing.yml`:
@@ -50,7 +47,7 @@ Ensure that those lines are present in your file `app/config/routing.yml`:
Create your model Create your model
================= *****************
Create your model on the usual way: Create your model on the usual way:
@@ -90,7 +87,7 @@ Create your model on the usual way:
Configure api Configure api
============= *************
Configure the api using Yaml (see the full configuration: :ref:`api_full_configuration`): Configure the api using Yaml (see the full configuration: :ref:`api_full_configuration`):
@@ -174,7 +171,7 @@ Configure the api using Yaml (see the full configuration: :ref:`api_full_configu
} }
The :code:`_index` and :code:`_entity` action The :code:`_index` and :code:`_entity` action
********************************************* =============================================
The :code:`_index` and :code:`_entity` action are default actions: The :code:`_index` and :code:`_entity` action are default actions:
@@ -192,7 +189,7 @@ Entity:
Path: :code:`/api/1.0/person/accompanying-period/origin/{id}.{_format}` Path: :code:`/api/1.0/person/accompanying-period/origin/{id}.{_format}`
Role Role
**** ====
By default, the key `base_role` is used to check ACL. Take care of creating the :code:`Voter` required to take that into account. By default, the key `base_role` is used to check ACL. Take care of creating the :code:`Voter` required to take that into account.
@@ -219,7 +216,7 @@ You can also define a role for each method. In this case, this role is used for
HEAD: MY ROLE_SEE HEAD: MY ROLE_SEE
Customize the controller Customize the controller
************************ ========================
You can customize the controller by hooking into the default actions. Take care of extending :code:`Chill\MainBundle\CRUD\Controller\ApiController`. You can customize the controller by hooking into the default actions. Take care of extending :code:`Chill\MainBundle\CRUD\Controller\ApiController`.
@@ -267,7 +264,7 @@ And set your controller in configuration:
HEAD: true HEAD: true
Create your own actions Create your own actions
*********************** =======================
You can add your own actions: You can add your own actions:
@@ -364,297 +361,8 @@ Then, create the corresponding action into your controller:
} }
} }
Managing association
********************
ManyToOne association
=====================
In ManyToOne association, you can add associated entities using the :code:`PATCH` request. By default, the serializer deserialize entities only with their id and discriminator type, if any.
Example:
.. code-block:: bash
curl -X 'PATCH' \
'http://localhost:8001/api/1.0/person/accompanying-course/2668.json' \
-H 'accept: */*' \
-H 'Content-Type: application/json' \
# see the data sent to the server: \
-d '{
"type": "accompanying_period",
"id": 2668,
"origin": { "id": 11 }
}'
ManyToMany associations
=======================
In OneToMany association, you can easily create route for adding and removing entities, using :code:`POST` and :code:`DELETE` requests.
Prepare your entity, creating the methods :code:`addYourEntity` and :code:`removeYourEntity`:
.. code-block:: php
namespace Chill\PersonBundle\Entity;
use Chill\MainBundle\Entity\Scope;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\Common\Collections\Collection;
use Doctrine\ORM\Mapping as ORM;
use Symfony\Component\Serializer\Annotation\Groups;
use Symfony\Component\Serializer\Annotation\DiscriminatorMap;
/**
* AccompanyingPeriod Class
*
* @ORM\Entity
* @ORM\Table(name="chill_person_accompanying_period")
* @DiscriminatorMap(typeProperty="type", mapping={
* "accompanying_period"=AccompanyingPeriod::class
* })
*/
class AccompanyingPeriod
{
/**
* @var Collection
* @ORM\ManyToMany(
* targetEntity=Scope::class,
* cascade={}
* )
* @Groups({"read"})
*/
private $scopes;
public function addScope(Scope $scope): self
{
$this->scopes[] = $scope;
return $this;
}
public function removeScope(Scope $scope): void
{
$this->scopes->removeElement($scope);
}
Create your route into the configuration:
.. code-block:: yaml
chill_main:
apis:
-
class: Chill\PersonBundle\Entity\AccompanyingPeriod
name: accompanying_course
base_path: /api/1.0/person/accompanying-course
controller: Chill\PersonBundle\Controller\AccompanyingCourseApiController
actions:
scope:
methods:
POST: true
DELETE: true
GET: false
HEAD: false
PUT: false
PATCH: false
roles:
POST: CHILL_PERSON_ACCOMPANYING_PERIOD_SEE
DELETE: CHILL_PERSON_ACCOMPANYING_PERIOD_SEE
GET: null
HEAD: null
PUT: null
PATCH: null
controller_action: null
path: null
single-collection: single
This will create a new route, which will accept two methods: DELETE and POST:
.. code-block:: raw
+--------------+---------------------------------------------------------------------------------------+
| Property | Value |
+--------------+---------------------------------------------------------------------------------------+
| Route Name | chill_api_single_accompanying_course_scope |
| Path | /api/1.0/person/accompanying-course/{id}/scope.{_format} |
| Path Regex | {^/api/1\.0/person/accompanying\-course/(?P<id>[^/]++)/scope\.(?P<_format>[^/]++)$}sD |
| Host | ANY |
| Host Regex | |
| Scheme | ANY |
| Method | POST|DELETE |
| Requirements | {id}: \d+ |
| Class | Symfony\Component\Routing\Route |
| Defaults | _controller: csapi_accompanying_course_controller:scopeApi |
| Options | compiler_class: Symfony\Component\Routing\RouteCompiler |
+--------------+---------------------------------------------------------------------------------------+
Then, create the controller action. Call the method:
.. code-block:: php
namespace Chill\PersonBundle\Controller;
use Chill\MainBundle\CRUD\Controller\ApiController;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Chill\MainBundle\Entity\Scope;
class MyController extends ApiController
{
public function scopeApi($id, Request $request, string $_format): Response
{
return $this->addRemoveSomething('scope', $id, $request, $_format, 'scope', Scope::class, [ 'groups' => [ 'read' ] ]);
}
}
This will allow to add a scope by his id, and delete them.
Curl requests:
.. code-block:: bash
# add a scope with id 5
curl -X 'POST' \
'http://localhost:8001/api/1.0/person/accompanying-course/2868/scope.json' \
-H 'accept: */*' \
-H 'Content-Type: application/json' \
-d '{
"type": "scope",
"id": 5
}'
# remove a scope with id 5
curl -X 'DELETE' \
'http://localhost:8001/api/1.0/person/accompanying-course/2868/scope.json' \
-H 'accept: */*' \
-H 'Content-Type: application/json' \
-d '{
"id": 5,
"type": "scope"
}'
Deserializing an association where multiple types are allowed
=============================================================
Sometimes, multiples types are allowed as association to one entity:
.. code-block:: php
namespace Chill\PersonBundle\Entity\AccompanyingPeriod;
use Chill\PersonBundle\Entity\Person;
use Chill\ThirdPartyBundle\Entity\ThirdParty;
use Doctrine\ORM\Mapping as ORM;
class Resource
{
/**
* @ORM\ManyToOne(targetEntity=ThirdParty::class)
* @ORM\JoinColumn(nullable=true)
*/
private $thirdParty;
/**
* @ORM\ManyToOne(targetEntity=Person::class)
* @ORM\JoinColumn(nullable=true)
*/
private $person;
/**
*
* @param $resource Person|ThirdParty
*/
public function setResource($resource): self
{
// ...
}
/**
* @return ThirdParty|Person
* @Groups({"read", "write"})
*/
public function getResource()
{
return $this->person ?? $this->thirdParty;
}
}
This is not well taken into account by the Symfony serializer natively.
You must, then, create your own CustomNormalizer. You can help yourself using this:
.. code-block:: php
namespace Chill\PersonBundle\Serializer\Normalizer;
use Chill\PersonBundle\Entity\Person;
use Chill\ThirdPartyBundle\Entity\ThirdParty;
use Chill\PersonBundle\Entity\AccompanyingPeriod\Resource;
use Chill\PersonBundle\Repository\AccompanyingPeriod\ResourceRepository;
use Symfony\Component\Serializer\Normalizer\DenormalizerInterface;
use Symfony\Component\Serializer\Normalizer\DenormalizerAwareInterface;
use Symfony\Component\Serializer\Normalizer\DenormalizerAwareTrait;
use Symfony\Component\Serializer\Normalizer\ObjectToPopulateTrait;
use Symfony\Component\Serializer\Exception;
use Chill\MainBundle\Serializer\Normalizer\DiscriminatedObjectDenormalizer;
class AccompanyingPeriodResourceNormalizer implements DenormalizerInterface, DenormalizerAwareInterface
{
use DenormalizerAwareTrait;
use ObjectToPopulateTrait;
public function __construct(ResourceRepository $repository)
{
$this->repository = $repository;
}
public function denormalize($data, string $type, string $format = null, array $context = [])
{
// .. snipped for brevity
if ($resource === NULL) {
$resource = new Resource();
}
if (\array_key_exists('resource', $data)) {
$res = $this->denormalizer->denormalize(
$data['resource'],
// call for a "multiple type"
DiscriminatedObjectDenormalizer::TYPE,
$format,
// into the context, we add the list of allowed types:
[
DiscriminatedObjectDenormalizer::ALLOWED_TYPES =>
[
Person::class, ThirdParty::class
]
]
);
$resource->setResource($res);
}
return $resource;
}
public function supportsDenormalization($data, string $type, string $format = null)
{
return $type === Resource::class;
}
}
Serialization for collection Serialization for collection
**************************** ============================
A specific model has been defined for returning collection: A specific model has been defined for returning collection:
@@ -673,9 +381,8 @@ A specific model has been defined for returning collection:
} }
} }
Where this is relevant, this model should be re-used in custom controller actions.
In custom actions, this can be achieved quickly by assembling results into a :code:`Chill\MainBundle\Serializer\Model\Collection`. The pagination information is given by using :code:`Paginator` (see :ref:`Pagination <pagination-ref>`). This can be achieved quickly by assembling results into a :code:`Chill\MainBundle\Serializer\Model\Collection`. The pagination information is given by using :code:`Paginator` (see :ref:`Pagination <pagination-ref>`).
.. code-block:: php .. code-block:: php
@@ -693,11 +400,10 @@ In custom actions, this can be achieved quickly by assembling results into a :co
} }
} }
.. _api_full_configuration: .. _api_full_configuration:
Full configuration example Full configuration example
************************** ==========================
.. code-block:: yaml .. code-block:: yaml

View File

@@ -28,7 +28,7 @@ Then, render the pagination using the dedicated twig function.
.. code-block:: html+twig .. code-block:: html+twig
{% extends "@ChillPerson/Person/layout.html.twig" %} {% extends "ChillPersonBundle::layout.html.twig" %}
{% block title 'Item list'|trans %} {% block title 'Item list'|trans %}

View File

@@ -1,42 +1,48 @@
<?php <?php
/**
* Chill is a software for social workers
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/
namespace Chill\MyBundle\Controller; namespace Chill\MyBundle\Controller;
use Symfony\Bundle\FrameworkBundle\Controller\Controller; use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Symfony\Component\HttpFoundation\Request;
class ItemController extends Controller
class ItemController extends Controller { {
public function yourAction()
public function yourAction()
{ {
$em = $this->getDoctrine()->getManager(); $em = $this->getDoctrine()->getManager();
// first, get the number of total item are available // first, get the number of total item are available
$total = $em $total = $em
->createQuery("SELECT COUNT (item.id) FROM ChillMyBundle:Item item") ->createQuery('SELECT COUNT (item.id) FROM ChillMyBundle:Item item')
->getSingleScalarResult(); ->getSingleScalarResult();
// get the PaginatorFactory // get the PaginatorFactory
$paginatorFactory = $this->get('chill_main.paginator_factory'); $paginatorFactory = $this->get('chill_main.paginator_factory');
// create a pagination instance. This instance is only valid for // create a pagination instance. This instance is only valid for
// the current route and parameters // the current route and parameters
$paginator = $paginatorFactory->create($total); $paginator = $paginatorFactory->create($total);
// launch your query on item. Limit the query to the results // launch your query on item. Limit the query to the results
// for the current page using the paginator // for the current page using the paginator
$items = $em->createQuery("SELECT item FROM ChillMyBundle:Item item WHERE <your clause>") $items = $em->createQuery('SELECT item FROM ChillMyBundle:Item item WHERE <your clause>')
// use the paginator to get the first item number // use the paginator to get the first item number
->setFirstResult($paginator->getCurrentPage()->getFirstItemNumber()) ->setFirstResult($paginator->getCurrentPage()->getFirstItemNumber())
// use the paginator to get the number of items to display // use the paginator to get the number of items to display
->setMaxResults($paginator->getItemsPerPage()); ->setMaxResults($paginator->getItemsPerPage());
return $this->render('ChillMyBundle:Item:list.html.twig', array( return $this
'items' => $items, ->render(
'paginator' => $paginator 'ChillMyBundle:Item:list.html.twig',
); [
'items' => $items,
'paginator' => $paginator,
]
);
} }
} }

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 TimelineSingleQuery * @return string[]
* @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,16 +163,18 @@ 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 instance of :code:`TimelineSingleQuery`. For you convenience, this object may be build using an associative array with the following keys: The fetchQuery function help to build the UNION query to gather events. This function should return an associative array MUST have the following key :
* `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`: the FROM clause. May contains JOIN instructions * `FROM` (in capital) : the FROM clause. May contains JOIN instructions
* `WHERE`: the WHERE clause;
* `parameters`: the parameters to pass to the query
The parameters should be replaced into the query by :code:`?`. They will be replaced into the query using prepared statements. Those key are optional:
* `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.
@@ -184,15 +186,6 @@ 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::
@@ -206,12 +199,13 @@ 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
{ {
@@ -233,17 +227,16 @@ Example of an implementation :
$metadata = $this->em->getClassMetadata('ChillReportBundle:Report'); $metadata = $this->em->getClassMetadata('ChillReportBundle:Report');
return TimelineSingleQuery::fromArray([ return array(
'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 = ?', 'WHERE' => sprintf('%s = %d',
$metadata $metadata
->getAssociationMapping('person')['joinColumns'][0]['name']) ->getAssociationMapping('person')['joinColumns'][0]['name'],
) $args['person']->getId())
'parameters' => [ $args['person']->getId() ] );
]);
} }
//.... //....

View File

@@ -1,43 +1,51 @@
<?php <?php
/**
* Chill is a software for social workers
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/
namespace Chill\HealthBundle\Controller; namespace Chill\HealthBundle\Controller;
use Chill\HealthBundle\Security\Authorization\ConsultationVoter; use Chill\HealthBundle\Security\Authorization\ConsultationVoter;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Chill\PersonBundle\Security\Authorization\PersonVoter; use Chill\PersonBundle\Security\Authorization\PersonVoter;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Symfony\Component\Security\Core\Role\Role; use Symfony\Component\Security\Core\Role\Role;
class ConsultationController extends Controller class ConsultationController extends Controller
{ {
/** /**
*
* @param int $id personId * @param int $id personId
* @return \Symfony\Component\HttpFoundation\Response *
* @throws type * @throws type
*
* @return \Symfony\Component\HttpFoundation\Response
*/ */
public function listAction($id) public function listAction($id)
{ {
/* @var $person \Chill\PersonBundle\Entity\Person */ /* @var $person \Chill\PersonBundle\Entity\Person */
$person = $this->get('chill.person.repository.person') $person = $this->get('chill.person.repository.person')
->find($id); ->find($id);
if ($person === null) { if (null === $person) {
throw $this->createNotFoundException("The person is not found"); throw $this->createNotFoundException('The person is not found');
} }
$this->denyAccessUnlessGranted(PersonVoter::SEE, $person); $this->denyAccessUnlessGranted(PersonVoter::SEE, $person);
/* @var $authorizationHelper \Chill\MainBundle\Security\Authorization\AuthorizationHelper */ /* @var $authorizationHelper \Chill\MainBundle\Security\Authorization\AuthorizationHelper */
$authorizationHelper = $this->get('chill.main.security.' $authorizationHelper = $this->get('chill.main.security.'
. 'authorization.helper'); . 'authorization.helper');
$circles = $authorizationHelper->getReachableCircles( $circles = $authorizationHelper->getReachableCircles(
$this->getUser(), $this->getUser(),
new Role(ConsultationVoter::SEE), new Role(ConsultationVoter::SEE),
$person->getCenter() $person->getCenter()
); );
// create a query which take circles into account // create a query which take circles into account
$consultations = $this->getDoctrine()->getManager() $consultations = $this->getDoctrine()->getManager()
->createQuery('SELECT c FROM ChillHealthBundle:Consultation c ' ->createQuery('SELECT c FROM ChillHealthBundle:Consultation c '
. 'WHERE c.patient = :person AND c.circle IN(:circles) ' . 'WHERE c.patient = :person AND c.circle IN(:circles) '
@@ -45,11 +53,10 @@ class ConsultationController extends Controller
->setParameter('person', $person) ->setParameter('person', $person)
->setParameter('circles', $circles) ->setParameter('circles', $circles)
->getResult(); ->getResult();
return $this->render('ChillHealthBundle:Consultation:list.html.twig', array( return $this->render('ChillHealthBundle:Consultation:list.html.twig', [
'person' => $person, 'person' => $person,
'consultations' => $consultations 'consultations' => $consultations,
)); ]);
} }
} }

View File

@@ -149,7 +149,7 @@ It proposes a new block :
* where to display the admin content * where to display the admin content
@ChillPersonBundle/Person/layout.html.twig ChillPersonBundle::layout.html.twig
----------------------------------- -----------------------------------
This layout extend `ChillMainBundle::layoutWithVerticalMenu.html.twig` add the person details in the block `top_banner`, set the menu `person` as the vertical menu. This layout extend `ChillMainBundle::layoutWithVerticalMenu.html.twig` add the person details in the block `top_banner`, set the menu `person` as the vertical menu.

View File

@@ -1,64 +1,60 @@
<?php <?php
# Chill\MainBundle\DependencyInjection\Configuration.php
namespace Chill\MainBundle\DependencyInjection;
/**
* Chill is a software for social workers
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/
namespace Chill\MainBundle\DependencyInjection;
use Chill\MainBundle\DependencyInjection\Widget\AddWidgetConfigurationTrait;
use Symfony\Component\Config\Definition\Builder\TreeBuilder; use Symfony\Component\Config\Definition\Builder\TreeBuilder;
use Symfony\Component\Config\Definition\ConfigurationInterface; use Symfony\Component\Config\Definition\ConfigurationInterface;
use Chill\MainBundle\DependencyInjection\Widget\AddWidgetConfigurationTrait;
use Symfony\Component\DependencyInjection\ContainerBuilder; use Symfony\Component\DependencyInjection\ContainerBuilder;
/** /**
* Configure the main bundle * Configure the main bundle.
*/ */
class Configuration implements ConfigurationInterface class Configuration implements ConfigurationInterface
{ {
use AddWidgetConfigurationTrait;
use AddWidgetConfigurationTrait;
/**
*
* @var ContainerBuilder
*/
private $containerBuilder;
/**
public function __construct(array $widgetFactories = array(), * @var ContainerBuilder
ContainerBuilder $containerBuilder) */
{ private $containerBuilder;
// we register here widget factories (see below)
$this->setWidgetFactories($widgetFactories);
// we will need the container builder later...
$this->containerBuilder = $containerBuilder;
}
/**
* {@inheritDoc}
*/
public function getConfigTreeBuilder()
{
$treeBuilder = new TreeBuilder();
$rootNode = $treeBuilder->root('chill_main');
$rootNode public function __construct(
->children() array $widgetFactories = [],
ContainerBuilder $containerBuilder
) {
// we register here widget factories (see below)
$this->setWidgetFactories($widgetFactories);
// we will need the container builder later...
$this->containerBuilder = $containerBuilder;
}
// ... public function getConfigTreeBuilder()
{
$treeBuilder = new TreeBuilder();
$rootNode = $treeBuilder->root('chill_main');
->arrayNode('widgets') $rootNode
->canBeDisabled() ->children()
->children()
// we declare here all configuration for homepage place
->append($this->addWidgetsConfiguration('homepage', $this->containerBuilder))
->end() // end of widgets/children
->end() // end of widgets
->end() // end of root/children
->end() // end of root
;
return $treeBuilder;
}
}
// ...
->arrayNode('widgets')
->canBeDisabled()
->children()
// we declare here all configuration for homepage place
->append($this->addWidgetsConfiguration('homepage', $this->containerBuilder))
->end() // end of widgets/children
->end() // end of widgets
->end() // end of root/children
->end(); // end of root
return $treeBuilder;
}
}

View File

@@ -1,16 +1,17 @@
<?php <?php
#Chill\MainBundle\DependencyInjection\ChillMainExtension.php /**
* Chill is a software for social workers
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/
namespace Chill\MainBundle\DependencyInjection; namespace Chill\MainBundle\DependencyInjection;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\Config\FileLocator;
use Symfony\Component\HttpKernel\DependencyInjection\Extension;
use Symfony\Component\DependencyInjection\Loader;
use Symfony\Component\DependencyInjection\Extension\PrependExtensionInterface;
use Chill\MainBundle\DependencyInjection\Widget\Factory\WidgetFactoryInterface; use Chill\MainBundle\DependencyInjection\Widget\Factory\WidgetFactoryInterface;
use Chill\MainBundle\DependencyInjection\Configuration; use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\HttpKernel\DependencyInjection\Extension;
/** /**
* This class load config for chillMainExtension. * This class load config for chillMainExtension.
@@ -18,42 +19,42 @@ use Chill\MainBundle\DependencyInjection\Configuration;
class ChillMainExtension extends Extension implements Widget\HasWidgetFactoriesExtensionInterface class ChillMainExtension extends Extension implements Widget\HasWidgetFactoriesExtensionInterface
{ {
/** /**
* widget factory * widget factory.
* *
* @var WidgetFactoryInterface[] * @var WidgetFactoryInterface[]
*/ */
protected $widgetFactories = array(); protected $widgetFactories = [];
public function addWidgetFactory(WidgetFactoryInterface $factory) public function addWidgetFactory(WidgetFactoryInterface $factory)
{ {
$this->widgetFactories[] = $factory; $this->widgetFactories[] = $factory;
} }
public function getConfiguration(array $config, ContainerBuilder $container)
{
return new Configuration($this->widgetFactories, $container);
}
/** /**
*
* @return WidgetFactoryInterface[] * @return WidgetFactoryInterface[]
*/ */
public function getWidgetFactories() public function getWidgetFactories()
{ {
return $this->widgetFactories; return $this->widgetFactories;
} }
public function load(array $configs, ContainerBuilder $container) public function load(array $configs, ContainerBuilder $container)
{ {
// configuration for main bundle // configuration for main bundle
$configuration = $this->getConfiguration($configs, $container); $configuration = $this->getConfiguration($configs, $container);
$config = $this->processConfiguration($configuration, $configs); $config = $this->processConfiguration($configuration, $configs);
// add the key 'widget' without the key 'enable'
$container->setParameter('chill_main.widgets',
array('homepage' => $config['widgets']['homepage']));
// ... // add the key 'widget' without the key 'enable'
$container->setParameter(
'chill_main.widgets',
['homepage' => $config['widgets']['homepage']]
);
// ...
} }
public function getConfiguration(array $config, ContainerBuilder $container)
{
return new Configuration($this->widgetFactories, $container);
}
} }

View File

@@ -1,69 +1,71 @@
<?php <?php
# Chill/PersonBundle/Widget/PersonListWidgetFactory /**
* Chill is a software for social workers
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/
namespace Chill\PersonBundle\Widget; namespace Chill\PersonBundle\Widget;
use Chill\MainBundle\DependencyInjection\Widget\Factory\AbstractWidgetFactory; use Chill\MainBundle\DependencyInjection\Widget\Factory\AbstractWidgetFactory;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\Config\Definition\Builder\NodeBuilder; use Symfony\Component\Config\Definition\Builder\NodeBuilder;
use Symfony\Component\DependencyInjection\ContainerBuilder;
/** /**
* add configuration for the person_list widget. * add configuration for the person_list widget.
*/ */
class PersonListWidgetFactory extends AbstractWidgetFactory class PersonListWidgetFactory extends AbstractWidgetFactory
{ {
/* /*
* append the option to the configuration * append the option to the configuration
* see http://symfony.com/doc/current/components/config/definition.html * see http://symfony.com/doc/current/components/config/definition.html
* *
*/ */
public function configureOptions($place, NodeBuilder $node) public function configureOptions($place, NodeBuilder $node)
{ {
$node->booleanNode('only_active') $node->booleanNode('only_active')
->defaultTrue() ->defaultTrue()
->end(); ->end();
$node->integerNode('number_of_items') $node->integerNode('number_of_items')
->defaultValue(50) ->defaultValue(50)
->end(); ->end();
$node->scalarNode('filtering_class') $node->scalarNode('filtering_class')
->defaultNull() ->defaultNull()
->end(); ->end();
} }
/* /*
* return an array with the allowed places where the widget can be rendered * return an array with the allowed places where the widget can be rendered
* *
* @return string[] * @return string[]
*/ */
public function getAllowedPlaces() public function getAllowedPlaces()
{ {
return array('homepage'); return ['homepage'];
} }
/*
* return the widget alias
*
* @return string
*/
public function getWidgetAlias()
{
return 'person_list';
}
/* /*
* return the service id for the service which will render the widget. * return the service id for the service which will render the widget.
* *
* this service must implements `Chill\MainBundle\Templating\Widget\WidgetInterface` * this service must implements `Chill\MainBundle\Templating\Widget\WidgetInterface`
* *
* the service must exists in the container, and it is not required that the service * the service must exists in the container, and it is not required that the service
* has the `chill_main` tag. * has the `chill_main` tag.
*/ */
public function getServiceId(ContainerBuilder $containerBuilder, $place, $order, array $config) public function getServiceId(ContainerBuilder $containerBuilder, $place, $order, array $config)
{ {
return 'chill_person.widget.person_list'; return 'chill_person.widget.person_list';
} }
}
/*
* return the widget alias
*
* @return string
*/
public function getWidgetAlias()
{
return 'person_list';
}
}

View File

@@ -1,66 +1,71 @@
<?php <?php
# Chill/PersonBundle/Widget/PersonListWidget.php
/**
* Chill is a software for social workers
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/
namespace Chill\PersonBundle\Widget; namespace Chill\PersonBundle\Widget;
use Chill\MainBundle\Security\Authorization\AuthorizationHelper;
use Chill\MainBundle\Templating\Widget\WidgetInterface; use Chill\MainBundle\Templating\Widget\WidgetInterface;
use Chill\PersonBundle\Security\Authorization\PersonVoter;
use DateTime;
use Doctrine\DBAL\Types\Type;
use Doctrine\ORM\EntityManager;
use Doctrine\ORM\EntityRepository; use Doctrine\ORM\EntityRepository;
use Doctrine\ORM\Query\Expr; use Doctrine\ORM\Query\Expr;
use Doctrine\DBAL\Types\Type;
use Chill\MainBundle\Security\Authorization\AuthorizationHelper;
use Symfony\Component\Security\Core\User\UserInterface;
use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorage; use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorage;
use Chill\PersonBundle\Security\Authorization\PersonVoter;
use Symfony\Component\Security\Core\Role\Role; use Symfony\Component\Security\Core\Role\Role;
use Doctrine\ORM\EntityManager; use Symfony\Component\Security\Core\User\UserInterface;
use Twig_Environment;
/** /**
* add a widget with person list. * add a widget with person list.
* *
* The configuration is defined by `PersonListWidgetFactory` * The configuration is defined by `PersonListWidgetFactory`
*/ */
class PersonListWidget implements WidgetInterface class PersonListWidget implements WidgetInterface
{ {
/** /**
* Repository for persons * the authorization helper.
* *
* @var EntityRepository * @var AuthorizationHelper;
*/ */
protected $personRepository; protected $authorizationHelper;
/** /**
* The entity manager * The entity manager.
* *
* @var EntityManager * @var EntityManager
*/ */
protected $entityManager; protected $entityManager;
/**
* the authorization helper
*
* @var AuthorizationHelper;
*/
protected $authorizationHelper;
/** /**
* Repository for persons.
* *
* @var EntityRepository
*/
protected $personRepository;
/**
* @var TokenStorage * @var TokenStorage
*/ */
protected $tokenStorage; protected $tokenStorage;
/** /**
*
* @var UserInterface * @var UserInterface
*/ */
protected $user; protected $user;
public function __construct( public function __construct(
EntityRepository $personRepostory, EntityRepository $personRepostory,
EntityManager $em, EntityManager $em,
AuthorizationHelper $authorizationHelper, AuthorizationHelper $authorizationHelper,
TokenStorage $tokenStorage TokenStorage $tokenStorage
) { ) {
$this->personRepository = $personRepostory; $this->personRepository = $personRepostory;
$this->authorizationHelper = $authorizationHelper; $this->authorizationHelper = $authorizationHelper;
$this->tokenStorage = $tokenStorage; $this->tokenStorage = $tokenStorage;
@@ -68,27 +73,24 @@ class PersonListWidget implements WidgetInterface
} }
/** /**
*
* @param type $place * @param type $place
* @param array $context *
* @param array $config
* @return string * @return string
*/ */
public function render(\Twig_Environment $env, $place, array $context, array $config) public function render(Twig_Environment $env, $place, array $context, array $config)
{ {
$qb = $this->personRepository $qb = $this->personRepository
->createQueryBuilder('person'); ->createQueryBuilder('person');
// show only the person from the authorized centers // show only the person from the authorized centers
$and = $qb->expr()->andX(); $and = $qb->expr()->andX();
$centers = $this->authorizationHelper $centers = $this->authorizationHelper
->getReachableCenters($this->getUser(), new Role(PersonVoter::SEE)); ->getReachableCenters($this->getUser(), new Role(PersonVoter::SEE));
$and->add($qb->expr()->in('person.center', ':centers')); $and->add($qb->expr()->in('person.center', ':centers'));
$qb->setParameter('centers', $centers); $qb->setParameter('centers', $centers);
// add the "only active" where clause // add the "only active" where clause
if ($config['only_active'] === true) { if (true === $config['only_active']) {
$qb->join('person.accompanyingPeriods', 'ap'); $qb->join('person.accompanyingPeriods', 'ap');
$or = new Expr\Orx(); $or = new Expr\Orx();
// add the case where closingDate IS NULL // add the case where closingDate IS NULL
@@ -98,32 +100,30 @@ class PersonListWidget implements WidgetInterface
$or->add($andWhenClosingDateIsNull); $or->add($andWhenClosingDateIsNull);
// add the case when now is between opening date and closing date // add the case when now is between opening date and closing date
$or->add( $or->add(
(new Expr())->between(':now', 'ap.openingDate', 'ap.closingDate') (new Expr())->between(':now', 'ap.openingDate', 'ap.closingDate')
); );
$and->add($or); $and->add($or);
$qb->setParameter('now', new \DateTime(), Type::DATE); $qb->setParameter('now', new DateTime(), Type::DATE);
} }
// adding the where clause to the query // adding the where clause to the query
$qb->where($and); $qb->where($and);
$qb->setFirstResult(0)->setMaxResults($config['number_of_items']); $qb->setFirstResult(0)->setMaxResults($config['number_of_items']);
$persons = $qb->getQuery()->getResult(); $persons = $qb->getQuery()->getResult();
return $env->render( return $env->render(
'ChillPersonBundle:Widget:homepage_person_list.html.twig', 'ChillPersonBundle:Widget:homepage_person_list.html.twig',
array('persons' => $persons) ['persons' => $persons]
); );
} }
/** /**
*
* @return UserInterface * @return UserInterface
*/ */
private function getUser() private function getUser()
{ {
// return a user // return a user
} }
} }

View File

@@ -1,51 +1,46 @@
<?php <?php
# Chill/PersonBundle/DependencyInjection/ChillPersonExtension.php /**
* Chill is a software for social workers
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/
namespace Chill\PersonBundle\DependencyInjection; namespace Chill\PersonBundle\DependencyInjection;
use Symfony\Component\DependencyInjection\ContainerBuilder; use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\Config\FileLocator;
use Symfony\Component\HttpKernel\DependencyInjection\Extension;
use Symfony\Component\DependencyInjection\Loader;
use Symfony\Component\DependencyInjection\Extension\PrependExtensionInterface; use Symfony\Component\DependencyInjection\Extension\PrependExtensionInterface;
use Chill\MainBundle\DependencyInjection\MissingBundleException; use Symfony\Component\HttpKernel\DependencyInjection\Extension;
use Chill\PersonBundle\Security\Authorization\PersonVoter;
/** /**
* This is the class that loads and manages your bundle configuration * This is the class that loads and manages your bundle configuration.
* *
* To learn more see {@link http://symfony.com/doc/current/cookbook/bundles/extension.html} * To learn more see {@link http://symfony.com/doc/current/cookbook/bundles/extension.html}
*/ */
class ChillPersonExtension extends Extension implements PrependExtensionInterface class ChillPersonExtension extends Extension implements PrependExtensionInterface
{ {
/**
* {@inheritDoc}
*/
public function load(array $configs, ContainerBuilder $container) public function load(array $configs, ContainerBuilder $container)
{ {
// ... // ...
} }
/** /**
* * Add a widget "add a person" on the homepage, automatically.
* Add a widget "add a person" on the homepage, automatically *
*
* @param \Chill\PersonBundle\DependencyInjection\containerBuilder $container * @param \Chill\PersonBundle\DependencyInjection\containerBuilder $container
*/ */
public function prepend(ContainerBuilder $container) public function prepend(ContainerBuilder $container)
{ {
$container->prependExtensionConfig('chill_main', array( $container->prependExtensionConfig('chill_main', [
'widgets' => array( 'widgets' => [
'homepage' => array( 'homepage' => [
array( [
'widget_alias' => 'add_person', 'widget_alias' => 'add_person',
'order' => 2 'order' => 2,
) ],
) ],
) ],
)); ]);
} }
} }

View File

@@ -82,7 +82,7 @@ Chill will be available at ``http://localhost:8001.`` Currently, there isn't any
.. code-block:: bash .. code-block:: bash
docker-compose exec --user $(id -u) php bin/console doctrine:fixtures:load --purge-with-truncate docker-compose exec --user $(id -u) php bin/console doctrine:fixtures:load
There are several users available: There are several users available:

View File

@@ -2,8 +2,8 @@ imports:
- { resource: vendor/drupol/php-conventions/config/php73/grumphp.yml } - { resource: vendor/drupol/php-conventions/config/php73/grumphp.yml }
parameters: parameters:
tasks.license.holder: Champs-Libres tasks.phpcsfixer.config: .php-cs-fixer.dist.php
tasks.license.date_from: 2021
tasks.license.name: AGPL-3.0 tasks.license.name: AGPL-3.0
extra_tasks: tasks.license.holder: Champs-Libres
phpunit: ~ tasks.license.date_from: 2001
tasks.phpcsfixer.allow_risky: false

View File

@@ -1,3 +0,0 @@
add npm/yarn dependency in package.json :
"select2-bootstrap-theme": "0.1.0-beta.10",

View File

@@ -10,7 +10,7 @@
<php> <php>
<ini name="error_reporting" value="-1" /> <ini name="error_reporting" value="-1" />
<server name="APP_ENV" value="test" force="true" /> <server name="APP_ENV" value="test" force="true" />
<env name="SYMFONY_DEPRECATIONS_HELPER" value="weak" /> <env name="SYMFONY_DEPRECATIONS_HELPER" value="weak" />
<server name="SHELL_VERBOSITY" value="-1" /> <server name="SHELL_VERBOSITY" value="-1" />
</php> </php>
@@ -18,26 +18,12 @@
<testsuite name="MainBundle"> <testsuite name="MainBundle">
<directory suffix="Test.php">src/Bundle/ChillMainBundle/Tests/</directory> <directory suffix="Test.php">src/Bundle/ChillMainBundle/Tests/</directory>
</testsuite> </testsuite>
<!--
<testsuite name="PersonBundle"> <testsuite name="PersonBundle">
<directory suffix="Test.php">src/Bundle/ChillPersonBundle/Tests/</directory> <directory suffix="Test.php">src/Bundle/ChillPersonBundle/Tests/</directory>
<!-- test for export will be runned later -->
<exclude>src/Bundle/ChillPersonBundle/Tests/Export/*</exclude>
<!-- we are rewriting accompanying periods... Work in progress -->
<exclude>src/Bundle/ChillPersonBundle/Tests/Controller/AccompanyingPeriodControllerTest.php</exclude>
<!-- we are rewriting address, Work in progress -->
<exclude>src/Bundle/ChillPersonBundle/Tests/Controller/PersonAddressControllerTest.php</exclude>
<!-- find a solution to create multiple configs -->
<exclude>src/Bundle/ChillPersonBundle/Tests/Controller/PersonControllerUpdateWithHiddenFieldsTest.php</exclude>
<!-- temporarily removed, the time to find a fix -->
<exclude>src/Bundle/ChillPersonBundle/Tests/Controller/PersonDuplicateControllerViewTest.php</exclude>
</testsuite> </testsuite>
<testsuite name="AsideActivityBundle"> -->
<directory suffix="Test.php">src/Bundle/ChillAsideActivityBundle/src/Tests/</directory> </testsuites>
</testsuite>
<testsuite name="CalendarBundle">
<directory suffix="Test.php">src/Bundle/ChillCalendarBundle/Tests/</directory>
</testsuite>
</testsuites>
<listeners> <listeners>
<listener class="Symfony\Bridge\PhpUnit\SymfonyTestsListener" /> <listener class="Symfony\Bridge\PhpUnit\SymfonyTestsListener" />

5
resource/header.txt Normal file
View File

@@ -0,0 +1,5 @@
Chill is a software for social workers
For the full copyright and license information, please view
the LICENSE file that was distributed with this source code.

View File

@@ -1,5 +1,12 @@
<?php <?php
/**
* Chill is a software for social workers
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/
namespace Chill\ActivityBundle; namespace Chill\ActivityBundle;
use Symfony\Component\HttpKernel\Bundle\Bundle; use Symfony\Component\HttpKernel\Bundle\Bundle;

View File

@@ -1,546 +1,467 @@
<?php <?php
/* /**
* Chill is a software for social workers * Chill is a software for social workers
* *
* Copyright (C) 2014-2015, Champs Libres Cooperative SCRLFS, * For the full copyright and license information, please view
* <http://www.champs-libres.coop>, <info@champs-libres.coop> * the LICENSE file that was distributed with this source code.
*
* 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\Controller; namespace Chill\ActivityBundle\Controller;
use Chill\ActivityBundle\Repository\ActivityACLAwareRepository;
use Chill\ActivityBundle\Repository\ActivityACLAwareRepositoryInterface;
use Chill\ActivityBundle\Security\Authorization\ActivityVoter;
use Chill\MainBundle\Security\Authorization\AuthorizationHelper;
use Chill\PersonBundle\Entity\AccompanyingPeriod;
use Chill\PersonBundle\Entity\Person;
use Chill\PersonBundle\Privacy\PrivacyEvent;
use Psr\Log\LoggerInterface;
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
use Symfony\Component\Form\Form;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\Form\Extension\Core\Type\SubmitType;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Security\Core\Role\Role;
use Chill\ActivityBundle\Entity\Activity; use Chill\ActivityBundle\Entity\Activity;
use Chill\ActivityBundle\Form\ActivityType; use Chill\ActivityBundle\Form\ActivityType;
use Chill\MainBundle\Entity\Embeddable\CommentEmbeddable; use Chill\MainBundle\Security\Authorization\AuthorizationHelper;
use Symfony\Component\Serializer\SerializerInterface; use Chill\PersonBundle\Privacy\PrivacyEvent;
use DateTime;
use Psr\Log\LoggerInterface;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
use Symfony\Component\Form\Extension\Core\Type\SubmitType;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\Security\Core\Role\Role;
/** /**
* Class ActivityController * Class ActivityController.
*
* @package Chill\ActivityBundle\Controller
*/ */
class ActivityController extends AbstractController class ActivityController extends AbstractController
{ {
protected EventDispatcherInterface $eventDispatcher; /**
* @var AuthorizationHelper
*/
protected $authorizationHelper;
protected AuthorizationHelper $authorizationHelper; /**
* @var EventDispatcherInterface
*/
protected $eventDispatcher;
protected LoggerInterface $logger; /**
* @var LoggerInterface
protected SerializerInterface $serializer; */
protected $logger;
protected ActivityACLAwareRepositoryInterface $activityACLAwareRepository;
/**
* ActivityController constructor.
*/
public function __construct( public function __construct(
ActivityACLAwareRepositoryInterface $activityACLAwareRepository,
EventDispatcherInterface $eventDispatcher, EventDispatcherInterface $eventDispatcher,
AuthorizationHelper $authorizationHelper, AuthorizationHelper $authorizationHelper,
LoggerInterface $logger, LoggerInterface $logger
SerializerInterface $serializer
) { ) {
$this->activityACLAwareRepository = $activityACLAwareRepository;
$this->eventDispatcher = $eventDispatcher; $this->eventDispatcher = $eventDispatcher;
$this->authorizationHelper = $authorizationHelper; $this->authorizationHelper = $authorizationHelper;
$this->logger = $logger; $this->logger = $logger;
$this->serializer = $serializer;
} }
/** /**
* Lists all Activity entities. * Creates a new Activity entity.
*
* @param mixed $person_id
*/ */
public function listAction(Request $request): Response public function createAction($person_id, Request $request)
{ {
$em = $this->getDoctrine()->getManager(); $em = $this->getDoctrine()->getManager();
$view = null; $person = $em->getRepository('ChillPersonBundle:Person')->find($person_id);
// TODO: add pagination
[$person, $accompanyingPeriod] = $this->getEntity($request); if (null === $person) {
throw $this->createNotFoundException('person not found');
if ($person instanceof Person) {
$this->denyAccessUnlessGranted(ActivityVoter::SEE, $person);
$activities = $this->activityACLAwareRepository
->findByPerson($person, ActivityVoter::SEE, 0, null);
$event = new PrivacyEvent($person, array(
'element_class' => Activity::class,
'action' => 'list'
));
$this->eventDispatcher->dispatch(PrivacyEvent::PERSON_PRIVACY_EVENT, $event);
$view = 'ChillActivityBundle:Activity:listPerson.html.twig';
} elseif ($accompanyingPeriod instanceof AccompanyingPeriod) {
$this->denyAccessUnlessGranted(ActivityVoter::SEE, $accompanyingPeriod);
$activities = $this->activityACLAwareRepository
->findByAccompanyingPeriod($accompanyingPeriod, ActivityVoter::SEE);
$view = 'ChillActivityBundle:Activity:listAccompanyingCourse.html.twig';
} }
return $this->render($view, array( $this->denyAccessUnlessGranted('CHILL_PERSON_SEE', $person);
'activities' => $activities,
'person' => $person,
'accompanyingCourse' => $accompanyingPeriod,
));
}
public function selectTypeAction(Request $request): Response
{
$em = $this->getDoctrine()->getManager();
$view = null;
[$person, $accompanyingPeriod] = $this->getEntity($request);
if ($accompanyingPeriod instanceof AccompanyingPeriod) {
$view = 'ChillActivityBundle:Activity:selectTypeAccompanyingCourse.html.twig';
} elseif ($person instanceof Person) {
$view = 'ChillActivityBundle:Activity:selectTypePerson.html.twig';
}
$data = [];
$activityTypeCategories = $em->getRepository(\Chill\ActivityBundle\Entity\ActivityTypeCategory::class)
->findBy(['active' => true], ['ordering' => 'ASC']);
foreach ($activityTypeCategories as $activityTypeCategory) {
$activityTypes = $em->getRepository(\Chill\ActivityBundle\Entity\ActivityType::class)
->findBy(['active' => true, 'category' => $activityTypeCategory], ['ordering' => 'ASC']);
$data[] = [
'activityTypeCategory' => $activityTypeCategory,
'activityTypes' => $activityTypes,
];
}
if ($request->query->has('activityData')) {
$activityData = $request->query->get('activityData');
} else {
$activityData = [];
}
if ($view === null) {
throw $this->createNotFoundException('Template not found');
}
return $this->render($view, [
'person' => $person,
'accompanyingCourse' => $accompanyingPeriod,
'data' => $data,
'activityData' => $activityData
]);
}
public function newAction(Request $request): Response
{
$em = $this->getDoctrine()->getManager();
[$person, $accompanyingPeriod] = $this->getEntity($request);
if ($accompanyingPeriod instanceof AccompanyingPeriod) {
$view = 'ChillActivityBundle:Activity:newAccompanyingCourse.html.twig';
} elseif ($person instanceof Person) {
$view = 'ChillActivityBundle:Activity:newPerson.html.twig';
}
$activityType_id = $request->get('activityType_id', 0);
$activityType = $em->getRepository(\Chill\ActivityBundle\Entity\ActivityType::class)
->find($activityType_id);
$activityData = null;
if ($request->query->has('activityData')) {
$activityData = $request->query->get('activityData');
}
if (!$activityType instanceof \Chill\ActivityBundle\Entity\ActivityType ||
!$activityType->isActive()) {
$params = $this->buildParamsToUrl($person, $accompanyingPeriod);
if (null !== $activityData) {
$params['activityData'] = $activityData;
}
return $this->redirectToRoute('chill_activity_activity_select_type', $params);
}
$entity = new Activity(); $entity = new Activity();
$entity->setUser($this->getUser()); $entity->setPerson($person);
$form = $this->createCreateForm($entity, $person);
$form->handleRequest($request);
if ($person instanceof Person) { if ($form->isValid()) {
$entity->setPerson($person); $em = $this->getDoctrine()->getManager();
}
if ($accompanyingPeriod instanceof AccompanyingPeriod) { $this->denyAccessUnlessGranted(
$entity->setAccompanyingPeriod($accompanyingPeriod); 'CHILL_ACTIVITY_CREATE',
} $entity,
'creation of this activity not allowed'
);
$entity->setType($activityType);
$entity->setDate(new \DateTime('now'));
if ($request->query->has('activityData')) {
$activityData = $request->query->get('activityData');
if (array_key_exists('durationTime', $activityData)) {
$durationTimeInMinutes = $activityData['durationTime'];
$hours = floor($durationTimeInMinutes / 60);
$minutes = $durationTimeInMinutes % 60;
$duration = \DateTime::createFromFormat("H:i", $hours.':'.$minutes);
if ($duration) {
$entity->setDurationTime($duration);
}
}
if (array_key_exists('date', $activityData)) {
$date = \DateTime::createFromFormat('Y-m-d', $activityData['date']);
if ($date) {
$entity->setDate($date);
}
}
if (array_key_exists('personsId', $activityData)) {
foreach($activityData['personsId'] as $personId){
$concernedPerson = $em->getRepository(\Chill\PersonBundle\Entity\Person::class)->find($personId);
$entity->addPerson($concernedPerson);
}
}
if (array_key_exists('professionalsId', $activityData)) {
foreach($activityData['professionalsId'] as $professionalsId){
$professional = $em->getRepository(\Chill\ThirdPartyBundle\Entity\ThirdParty::class)->find($professionalsId);
$entity->addThirdParty($professional);
}
}
if (array_key_exists('comment', $activityData)) {
$comment = new CommentEmbeddable();
$comment->setComment($activityData['comment']);
$comment->setUserId($this->getUser()->getid());
$comment->setDate(new \DateTime('now'));
$entity->setComment($comment);
}
}
// TODO revoir le Voter de Activity pour tenir compte qu'une activité peut appartenir a une période
// $this->denyAccessUnlessGranted('CHILL_ACTIVITY_CREATE', $entity);
$form = $this->createForm(ActivityType::class, $entity, [
'center' => $entity->getCenter(),
'role' => new Role('CHILL_ACTIVITY_CREATE'),
'activityType' => $entity->getType(),
'accompanyingPeriod' => $accompanyingPeriod,
])->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
$em->persist($entity); $em->persist($entity);
$em->flush(); $em->flush();
$this->addFlash('success', $this->get('translator')->trans('Success : activity created!')); $this->get('session')
->getFlashBag()
->add(
'success',
$this->get('translator')
->trans('Success : activity created!')
);
$params = $this->buildParamsToUrl($person, $accompanyingPeriod); return $this->redirect(
$this->generateUrl(
$params['id'] = $entity->getId(); 'chill_activity_activity_show',
['id' => $entity->getId(), 'person_id' => $person_id]
return $this->redirectToRoute('chill_activity_activity_show', $params); )
);
} }
if ($view === null) { $this->get('session')
throw $this->createNotFoundException('Template not found'); ->getFlashBag()->add(
} 'danger',
$this->get('translator')
->trans('The form is not valid. The activity has not been created !')
);
$activity_array = $this->serializer->normalize($entity, 'json', ['groups' => 'read']); return $this->render('ChillActivityBundle:Activity:new.html.twig', [
return $this->render($view, [
'person' => $person,
'accompanyingCourse' => $accompanyingPeriod,
'entity' => $entity, 'entity' => $entity,
'form' => $form->createView(), 'form' => $form->createView(),
'activity_json' => $activity_array
]);
}
public function showAction(Request $request, $id): Response
{
$em = $this->getDoctrine()->getManager();
[$person, $accompanyingPeriod] = $this->getEntity($request);
if ($accompanyingPeriod instanceof AccompanyingPeriod) {
$view = 'ChillActivityBundle:Activity:showAccompanyingCourse.html.twig';
} elseif ($person instanceof Person) {
$view = 'ChillActivityBundle:Activity:showPerson.html.twig';
}
$entity = $em->getRepository('ChillActivityBundle:Activity')->find($id);
if (!$entity) {
throw $this->createNotFoundException('Unable to find Activity entity.');
}
if (null !== $accompanyingPeriod) {
$entity->personsAssociated = $entity->getPersonsAssociated();
$entity->personsNotAssociated = $entity->getPersonsNotAssociated();
}
// TODO revoir le Voter de Activity pour tenir compte qu'une activité peut appartenir a une période
// $this->denyAccessUnlessGranted('CHILL_ACTIVITY_SEE', $entity);
$deleteForm = $this->createDeleteForm($id, $person, $accompanyingPeriod);
// TODO
/*
$event = new PrivacyEvent($person, array(
'element_class' => Activity::class,
'element_id' => $entity->getId(),
'action' => 'show'
));
$this->eventDispatcher->dispatch(PrivacyEvent::PERSON_PRIVACY_EVENT, $event);
*/
if ($view === null) {
throw $this->createNotFoundException('Template not found');
}
return $this->render($view, array(
'person' => $person,
'accompanyingCourse' => $accompanyingPeriod,
'entity' => $entity,
'delete_form' => $deleteForm->createView(),
));
}
/**
* Displays a form to edit an existing Activity entity.
*
*/
public function editAction($id, Request $request): Response
{
$em = $this->getDoctrine()->getManager();
[$person, $accompanyingPeriod] = $this->getEntity($request);
if ($accompanyingPeriod instanceof AccompanyingPeriod) {
$view = 'ChillActivityBundle:Activity:editAccompanyingCourse.html.twig';
} elseif ($person instanceof Person) {
$view = 'ChillActivityBundle:Activity:editPerson.html.twig';
}
$entity = $em->getRepository('ChillActivityBundle:Activity')->find($id);
if (!$entity) {
throw $this->createNotFoundException('Unable to find Activity entity.');
}
// TODO
// $this->denyAccessUnlessGranted('CHILL_ACTIVITY_UPDATE', $entity);
$form = $this->createForm(ActivityType::class, $entity, [
'center' => $entity->getCenter(),
'role' => new Role('CHILL_ACTIVITY_UPDATE'),
'activityType' => $entity->getType(),
'accompanyingPeriod' => $accompanyingPeriod,
])->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
$em->persist($entity);
$em->flush();
$this->addFlash('success', $this->get('translator')->trans('Success : activity updated!'));
$params = $this->buildParamsToUrl($person, $accompanyingPeriod);
$params['id'] = $id;
return $this->redirectToRoute('chill_activity_activity_show', $params);
}
$deleteForm = $this->createDeleteForm($id, $person, $accompanyingPeriod);
/*
* TODO
$event = new PrivacyEvent($person, array(
'element_class' => Activity::class,
'element_id' => $entity->getId(),
'action' => 'edit'
));
$this->eventDispatcher->dispatch(PrivacyEvent::PERSON_PRIVACY_EVENT, $event);
*/
if ($view === null) {
throw $this->createNotFoundException('Template not found');
}
$activity_array = $this->serializer->normalize($entity, 'json', ['groups' => 'read']);
return $this->render($view, array(
'entity' => $entity,
'edit_form' => $form->createView(),
'delete_form' => $deleteForm->createView(),
'person' => $person, 'person' => $person,
'accompanyingCourse' => $accompanyingPeriod, ]);
'activity_json' => $activity_array
));
} }
/** /**
* Deletes a Activity entity. * Deletes a Activity entity.
* *
* @param mixed $id
* @param mixed $person_id
*/ */
public function deleteAction(Request $request, $id) public function deleteAction(Request $request, $id, $person_id)
{ {
$em = $this->getDoctrine()->getManager(); $em = $this->getDoctrine()->getManager();
[$person, $accompanyingPeriod] = $this->getEntity($request);
if ($accompanyingPeriod instanceof AccompanyingPeriod) {
$view = 'ChillActivityBundle:Activity:confirm_deleteAccompanyingCourse.html.twig';
} elseif ($person instanceof Person) {
$view = 'ChillActivityBundle:Activity:confirm_deletePerson.html.twig';
}
/* @var $activity Activity */ /* @var $activity Activity */
$activity = $em->getRepository('ChillActivityBundle:Activity')->find($id); $activity = $em->getRepository('ChillActivityBundle:Activity')
->find($id);
$person = $activity->getPerson();
if (!$activity) { if (!$activity) {
throw $this->createNotFoundException('Unable to find Activity entity.'); throw $this->createNotFoundException('Unable to find Activity entity.');
} }
// TODO $this->denyAccessUnlessGranted('CHILL_ACTIVITY_DELETE', $activity);
// $this->denyAccessUnlessGranted('CHILL_ACTIVITY_DELETE', $activity);
$form = $this->createDeleteForm($id, $person, $accompanyingPeriod); $form = $this->createDeleteForm($id, $person);
if ($request->getMethod() === Request::METHOD_DELETE) { if ($request->getMethod() === Request::METHOD_DELETE) {
$form->handleRequest($request); $form->handleRequest($request);
if ($form->isValid()) { if ($form->isValid()) {
$this->logger->notice('An activity has been removed', [
$this->logger->notice("An activity has been removed", array( 'by_user' => $this->getUser()->getUsername(),
'by_user' => $this->getUser()->getUsername(), 'activity_id' => $activity->getId(),
'activity_id' => $activity->getId(), 'person_id' => $activity->getPerson()->getId(),
'person_id' => $activity->getPerson() ? $activity->getPerson()->getId() : null, 'comment' => $activity->getComment()->getComment(),
'comment' => $activity->getComment()->getComment(), 'scope_id' => $activity->getScope()->getId(),
'scope_id' => $activity->getScope() ? $activity->getScope()->getId() : null, 'reasons_ids' => $activity->getReasons()
'reasons_ids' => $activity->getReasons() ->map(function ($ar) {
->map(function ($ar) { return $ar->getId(); }) return $ar->getId();
->toArray(), })
'type_id' => $activity->getType()->getId(), ->toArray(),
'duration' => $activity->getDurationTime() ? $activity->getDurationTime()->format('U') : null, 'type_id' => $activity->getType()->getId(),
'date' => $activity->getDate()->format('Y-m-d'), 'duration' => $activity->getDurationTime()->format('U'),
'attendee' => $activity->getAttendee() 'date' => $activity->getDate()->format('Y-m-d'),
)); 'attendee' => $activity->getAttendee(),
]);
$em->remove($activity); $em->remove($activity);
$em->flush(); $em->flush();
$this->addFlash('success', $this->get('translator') $this->addFlash('success', $this->get('translator')
->trans("The activity has been successfully removed.")); ->trans('The activity has been successfully removed.'));
$params = $this->buildParamsToUrl($person, $accompanyingPeriod); return $this->redirect($this->generateUrl(
return $this->redirectToRoute('chill_activity_activity_list', $params); 'chill_activity_activity_list',
[
'person_id' => $person_id,
]
));
} }
} }
if ($view === null) { return $this->render('ChillActivityBundle:Activity:confirm_delete.html.twig', [
throw $this->createNotFoundException('Template not found'); 'activity' => $activity,
'delete_form' => $form->createView(),
]);
}
/**
* Displays a form to edit an existing Activity entity.
*
* @param mixed $person_id
* @param mixed $id
*/
public function editAction($person_id, $id)
{
$em = $this->getDoctrine()->getManager();
$person = $em->getRepository('ChillPersonBundle:Person')->find($person_id);
if (!$person) {
throw $this->createNotFoundException('person not found');
} }
return $this->render($view, array( $this->denyAccessUnlessGranted('CHILL_PERSON_SEE', $person);
'activity' => $activity,
'delete_form' => $form->createView(), $entity = $em->getRepository('ChillActivityBundle:Activity')->find($id);
'person' => $person,
'accompanyingCourse' => $accompanyingPeriod, if (!$entity) {
)); throw $this->createNotFoundException('Unable to find Activity entity.');
}
$this->denyAccessUnlessGranted('CHILL_ACTIVITY_UPDATE', $entity);
$editForm = $this->createEditForm($entity);
$deleteForm = $this->createDeleteForm($id, $person);
$event = new PrivacyEvent($person, [
'element_class' => Activity::class,
'element_id' => $entity->getId(),
'action' => 'edit',
]);
$this->eventDispatcher->dispatch(PrivacyEvent::PERSON_PRIVACY_EVENT, $event);
return $this->render('ChillActivityBundle:Activity:edit.html.twig', [
'entity' => $entity,
'edit_form' => $editForm->createView(),
'delete_form' => $deleteForm->createView(),
'person' => $person,
]);
}
/**
* Lists all Activity entities.
*
* @param mixed $person_id
*/
public function listAction($person_id, Request $request)
{
$em = $this->getDoctrine()->getManager();
$person = $em->getRepository('ChillPersonBundle:Person')->find($person_id);
if (null === $person) {
throw $this->createNotFoundException('Person not found');
}
$this->denyAccessUnlessGranted('CHILL_PERSON_SEE', $person);
$reachableScopes = $this->authorizationHelper
->getReachableScopes(
$this->getUser(),
new Role('CHILL_ACTIVITY_SEE'),
$person->getCenter()
);
$activities = $em->getRepository('ChillActivityBundle:Activity')
->findBy(
['person' => $person, 'scope' => $reachableScopes],
['date' => 'DESC']
);
$event = new PrivacyEvent($person, [
'element_class' => Activity::class,
'action' => 'list',
]);
$this->eventDispatcher->dispatch(PrivacyEvent::PERSON_PRIVACY_EVENT, $event);
return $this->render('ChillActivityBundle:Activity:list.html.twig', [
'activities' => $activities,
'person' => $person,
]);
}
/**
* Displays a form to create a new Activity entity.
*
* @param mixed $person_id
*/
public function newAction($person_id)
{
$em = $this->getDoctrine()->getManager();
$person = $em->getRepository('ChillPersonBundle:Person')->find($person_id);
if (null === $person) {
throw $this->createNotFoundException('Person not found');
}
$this->denyAccessUnlessGranted('CHILL_PERSON_SEE', $person);
$entity = new Activity();
$entity->setUser($this->get('security.token_storage')->getToken()->getUser());
$entity->setPerson($person);
$entity->setDate(new DateTime('now'));
$this->denyAccessUnlessGranted('CHILL_ACTIVITY_CREATE', $entity);
$form = $this->createCreateForm($entity, $person);
return $this->render('ChillActivityBundle:Activity:new.html.twig', [
'person' => $person,
'entity' => $entity,
'form' => $form->createView(),
]);
}
/**
* Finds and displays a Activity entity.
*
* @param mixed $person_id
* @param mixed $id
*/
public function showAction($person_id, $id)
{
$em = $this->getDoctrine()->getManager();
$person = $em->getRepository('ChillPersonBundle:Person')->find($person_id);
if (!$person) {
throw $this->createNotFoundException('person not found');
}
$this->denyAccessUnlessGranted('CHILL_PERSON_SEE', $person);
$entity = $em->getRepository('ChillActivityBundle:Activity')->find($id);
if (!$entity) {
throw $this->createNotFoundException('Unable to find Activity entity.');
}
$this->denyAccessUnlessGranted('CHILL_ACTIVITY_SEE', $entity);
$deleteForm = $this->createDeleteForm($id, $person);
$event = new PrivacyEvent($person, [
'element_class' => Activity::class,
'element_id' => $entity->getId(),
'action' => 'show',
]);
$this->eventDispatcher->dispatch(PrivacyEvent::PERSON_PRIVACY_EVENT, $event);
return $this->render('ChillActivityBundle:Activity:show.html.twig', [
'person' => $person,
'entity' => $entity,
'delete_form' => $deleteForm->createView(),
]);
}
/**
* Edits an existing Activity entity.
*
* @param mixed $person_id
* @param mixed $id
*/
public function updateAction(Request $request, $person_id, $id)
{
$em = $this->getDoctrine()->getManager();
$person = $em->getRepository('ChillPersonBundle:Person')->find($person_id);
$entity = $em->getRepository('ChillActivityBundle:Activity')->find($id);
if (!$entity) {
throw $this->createNotFoundException('Unable to find Activity entity.');
}
$this->denyAccessUnlessGranted('CHILL_ACTIVITY_UPDATE', $entity);
$deleteForm = $this->createDeleteForm($id, $person);
$editForm = $this->createEditForm($entity);
$editForm->handleRequest($request);
$event = new PrivacyEvent($person, [
'element_class' => Activity::class,
'element_id' => $entity->getId(),
'action' => 'update',
]);
$this->eventDispatcher->dispatch(PrivacyEvent::PERSON_PRIVACY_EVENT, $event);
if ($editForm->isValid()) {
$em->flush();
$this->get('session')
->getFlashBag()
->add(
'success',
$this->get('translator')
->trans('Success : activity updated!')
);
return $this->redirect($this->generateUrl('chill_activity_activity_show', ['id' => $id, 'person_id' => $person_id]));
}
$this->get('session')
->getFlashBag()
->add(
'error',
$this->get('translator')
->trans('This form contains errors')
);
return $this->render('ChillActivityBundle:Activity:edit.html.twig', [
'person' => $entity->getPerson(),
'entity' => $entity,
'edit_form' => $editForm->createView(),
'delete_form' => $deleteForm->createView(),
]);
}
/**
* Creates a form to create a Activity entity.
*
* @param Activity $entity The entity
*
* @return \Symfony\Component\Form\Form The form
*/
private function createCreateForm(Activity $entity)
{
return $this->createForm(
ActivityType::class,
$entity,
[
'action' => $this->generateUrl('chill_activity_activity_create', [
'person_id' => $entity->getPerson()->getId(),
]),
'method' => 'POST',
'center' => $entity->getCenter(),
'role' => new Role('CHILL_ACTIVITY_CREATE'),
]
);
} }
/** /**
* Creates a form to delete a Activity entity by id. * Creates a form to delete a Activity entity by id.
*
* @param mixed $id The entity id
* @param mixed $person
*
* @return \Symfony\Component\Form\Form The form
*/ */
private function createDeleteForm(int $id, ?Person $person, ?AccompanyingPeriod $accompanyingPeriod): Form private function createDeleteForm($id, $person)
{ {
$params = $this->buildParamsToUrl($person, $accompanyingPeriod);
$params['id'] = $id;
return $this->createFormBuilder() return $this->createFormBuilder()
->setAction($this->generateUrl('chill_activity_activity_delete', $params)) ->setAction($this->generateUrl(
'chill_activity_activity_delete',
['id' => $id, 'person_id' => $person->getId()]
))
->setMethod('DELETE') ->setMethod('DELETE')
->add('submit', SubmitType::class, array('label' => 'Delete')) ->add('submit', SubmitType::class, ['label' => 'Delete'])
->getForm() ->getForm();
;
} }
private function getEntity(Request $request): array /**
* Creates a form to edit a Activity entity.
*
* @param Activity $entity The entity
*
* @return \Symfony\Component\Form\Form The form
*/
private function createEditForm(Activity $entity)
{ {
$em = $this->getDoctrine()->getManager(); return $this->createForm(ActivityType::class, $entity, [
$person = $accompanyingPeriod = null; 'action' => $this->generateUrl(
'chill_activity_activity_update',
if ($request->query->has('person_id')) { [
$person_id = $request->get('person_id'); 'id' => $entity->getId(),
$person = $em->getRepository(Person::class)->find($person_id); 'person_id' => $entity->getPerson()->getId(),
]
if ($person === null) { ),
throw $this->createNotFoundException('Person not found'); 'method' => 'PUT',
} 'center' => $entity->getCenter(),
'role' => new Role('CHILL_ACTIVITY_UPDATE'),
$this->denyAccessUnlessGranted('CHILL_PERSON_SEE', $person); ]);
} elseif ($request->query->has('accompanying_period_id')) {
$accompanying_period_id = $request->get('accompanying_period_id');
$accompanyingPeriod = $em->getRepository(AccompanyingPeriod::class)->find($accompanying_period_id);
if ($accompanyingPeriod === null) {
throw $this->createNotFoundException('Accompanying Period not found');
}
// TODO Add permission
// $this->denyAccessUnlessGranted('CHILL_PERSON_SEE', $person);
} else {
throw $this->createNotFoundException("Person or Accompanying Period not found");
}
return [
$person, $accompanyingPeriod
];
}
private function buildParamsToUrl(
?Person $person,
?AccompanyingPeriod $accompanyingPeriod
): array {
$params = [];
if ($person) {
$params['person_id'] = $person->getId();
}
if ($accompanyingPeriod) {
$params['accompanying_period_id'] = $accompanyingPeriod->getId();
}
return $params;
} }
} }

View File

@@ -1,38 +1,27 @@
<?php <?php
/**
* Chill is a software for social workers
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/
namespace Chill\ActivityBundle\Controller; namespace Chill\ActivityBundle\Controller;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\Form\Extension\Core\Type\SubmitType;
use Chill\ActivityBundle\Entity\ActivityReasonCategory; use Chill\ActivityBundle\Entity\ActivityReasonCategory;
use Chill\ActivityBundle\Form\ActivityReasonCategoryType; use Chill\ActivityBundle\Form\ActivityReasonCategoryType;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\Form\Extension\Core\Type\SubmitType;
use Symfony\Component\HttpFoundation\Request;
/** /**
* ActivityReasonCategory controller. * ActivityReasonCategory controller.
*
*/ */
class ActivityReasonCategoryController extends AbstractController class ActivityReasonCategoryController extends AbstractController
{ {
/**
* Lists all ActivityReasonCategory entities.
*
*/
public function indexAction()
{
$em = $this->getDoctrine()->getManager();
$entities = $em->getRepository('ChillActivityBundle:ActivityReasonCategory')->findAll();
return $this->render('ChillActivityBundle:ActivityReasonCategory:index.html.twig', array(
'entities' => $entities,
));
}
/** /**
* Creates a new ActivityReasonCategory entity. * Creates a new ActivityReasonCategory entity.
*
*/ */
public function createAction(Request $request) public function createAction(Request $request)
{ {
@@ -45,71 +34,19 @@ class ActivityReasonCategoryController extends AbstractController
$em->persist($entity); $em->persist($entity);
$em->flush(); $em->flush();
return $this->redirect($this->generateUrl('chill_activity_activityreasoncategory_show', array('id' => $entity->getId()))); return $this->redirect($this->generateUrl('chill_activity_activityreasoncategory_show', ['id' => $entity->getId()]));
} }
return $this->render('ChillActivityBundle:ActivityReasonCategory:new.html.twig', array( return $this->render('ChillActivityBundle:ActivityReasonCategory:new.html.twig', [
'entity' => $entity, 'entity' => $entity,
'form' => $form->createView(), 'form' => $form->createView(),
)); ]);
}
/**
* Creates a form to create a ActivityReasonCategory entity.
*
* @param ActivityReasonCategory $entity The entity
*
* @return \Symfony\Component\Form\Form The form
*/
private function createCreateForm(ActivityReasonCategory $entity)
{
$form = $this->createForm(ActivityReasonCategoryType::class, $entity, array(
'action' => $this->generateUrl('chill_activity_activityreasoncategory_create'),
'method' => 'POST',
));
$form->add('submit', SubmitType::class, array('label' => 'Create'));
return $form;
}
/**
* Displays a form to create a new ActivityReasonCategory entity.
*
*/
public function newAction()
{
$entity = new ActivityReasonCategory();
$form = $this->createCreateForm($entity);
return $this->render('ChillActivityBundle:ActivityReasonCategory:new.html.twig', array(
'entity' => $entity,
'form' => $form->createView(),
));
}
/**
* Finds and displays a ActivityReasonCategory entity.
*
*/
public function showAction($id)
{
$em = $this->getDoctrine()->getManager();
$entity = $em->getRepository('ChillActivityBundle:ActivityReasonCategory')->find($id);
if (!$entity) {
throw $this->createNotFoundException('Unable to find ActivityReasonCategory entity.');
}
return $this->render('ChillActivityBundle:ActivityReasonCategory:show.html.twig', array(
'entity' => $entity,
));
} }
/** /**
* Displays a form to edit an existing ActivityReasonCategory entity. * Displays a form to edit an existing ActivityReasonCategory entity.
* *
* @param mixed $id
*/ */
public function editAction($id) public function editAction($id)
{ {
@@ -123,33 +60,64 @@ class ActivityReasonCategoryController extends AbstractController
$editForm = $this->createEditForm($entity); $editForm = $this->createEditForm($entity);
return $this->render('ChillActivityBundle:ActivityReasonCategory:edit.html.twig', array( return $this->render('ChillActivityBundle:ActivityReasonCategory:edit.html.twig', [
'entity' => $entity, 'entity' => $entity,
'edit_form' => $editForm->createView(), 'edit_form' => $editForm->createView(),
)); ]);
} }
/** /**
* Creates a form to edit a ActivityReasonCategory entity. * Lists all ActivityReasonCategory entities.
* */
* @param ActivityReasonCategory $entity The entity public function indexAction()
*
* @return \Symfony\Component\Form\Form The form
*/
private function createEditForm(ActivityReasonCategory $entity)
{ {
$form = $this->createForm(ActivityReasonCategoryType::class, $entity, array( $em = $this->getDoctrine()->getManager();
'action' => $this->generateUrl('chill_activity_activityreasoncategory_update', array('id' => $entity->getId())),
'method' => 'PUT',
));
$form->add('submit', SubmitType::class, array('label' => 'Update')); $entities = $em->getRepository('ChillActivityBundle:ActivityReasonCategory')->findAll();
return $form; return $this->render('ChillActivityBundle:ActivityReasonCategory:index.html.twig', [
'entities' => $entities,
]);
} }
/**
* Displays a form to create a new ActivityReasonCategory entity.
*/
public function newAction()
{
$entity = new ActivityReasonCategory();
$form = $this->createCreateForm($entity);
return $this->render('ChillActivityBundle:ActivityReasonCategory:new.html.twig', [
'entity' => $entity,
'form' => $form->createView(),
]);
}
/**
* Finds and displays a ActivityReasonCategory entity.
*
* @param mixed $id
*/
public function showAction($id)
{
$em = $this->getDoctrine()->getManager();
$entity = $em->getRepository('ChillActivityBundle:ActivityReasonCategory')->find($id);
if (!$entity) {
throw $this->createNotFoundException('Unable to find ActivityReasonCategory entity.');
}
return $this->render('ChillActivityBundle:ActivityReasonCategory:show.html.twig', [
'entity' => $entity,
]);
}
/** /**
* Edits an existing ActivityReasonCategory entity. * Edits an existing ActivityReasonCategory entity.
* *
* @param mixed $id
*/ */
public function updateAction(Request $request, $id) public function updateAction(Request $request, $id)
{ {
@@ -167,12 +135,50 @@ class ActivityReasonCategoryController extends AbstractController
if ($editForm->isValid()) { if ($editForm->isValid()) {
$em->flush(); $em->flush();
return $this->redirect($this->generateUrl('chill_activity_activityreasoncategory_edit', array('id' => $id))); return $this->redirect($this->generateUrl('chill_activity_activityreasoncategory_edit', ['id' => $id]));
} }
return $this->render('ChillActivityBundle:ActivityReasonCategory:edit.html.twig', array( return $this->render('ChillActivityBundle:ActivityReasonCategory:edit.html.twig', [
'entity' => $entity, 'entity' => $entity,
'edit_form' => $editForm->createView(), 'edit_form' => $editForm->createView(),
)); ]);
}
/**
* Creates a form to create a ActivityReasonCategory entity.
*
* @param ActivityReasonCategory $entity The entity
*
* @return \Symfony\Component\Form\Form The form
*/
private function createCreateForm(ActivityReasonCategory $entity)
{
$form = $this->createForm(ActivityReasonCategoryType::class, $entity, [
'action' => $this->generateUrl('chill_activity_activityreasoncategory_create'),
'method' => 'POST',
]);
$form->add('submit', SubmitType::class, ['label' => 'Create']);
return $form;
}
/**
* Creates a form to edit a ActivityReasonCategory entity.
*
* @param ActivityReasonCategory $entity The entity
*
* @return \Symfony\Component\Form\Form The form
*/
private function createEditForm(ActivityReasonCategory $entity)
{
$form = $this->createForm(ActivityReasonCategoryType::class, $entity, [
'action' => $this->generateUrl('chill_activity_activityreasoncategory_update', ['id' => $entity->getId()]),
'method' => 'PUT',
]);
$form->add('submit', SubmitType::class, ['label' => 'Update']);
return $form;
} }
} }

View File

@@ -1,38 +1,27 @@
<?php <?php
/**
* Chill is a software for social workers
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/
namespace Chill\ActivityBundle\Controller; namespace Chill\ActivityBundle\Controller;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\Form\Extension\Core\Type\SubmitType;
use Chill\ActivityBundle\Entity\ActivityReason; use Chill\ActivityBundle\Entity\ActivityReason;
use Chill\ActivityBundle\Form\ActivityReasonType; use Chill\ActivityBundle\Form\ActivityReasonType;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\Form\Extension\Core\Type\SubmitType;
use Symfony\Component\HttpFoundation\Request;
/** /**
* ActivityReason controller. * ActivityReason controller.
*
*/ */
class ActivityReasonController extends AbstractController class ActivityReasonController extends AbstractController
{ {
/**
* Lists all ActivityReason entities.
*
*/
public function indexAction()
{
$em = $this->getDoctrine()->getManager();
$entities = $em->getRepository('ChillActivityBundle:ActivityReason')->findAll();
return $this->render('ChillActivityBundle:ActivityReason:index.html.twig', array(
'entities' => $entities,
));
}
/** /**
* Creates a new ActivityReason entity. * Creates a new ActivityReason entity.
*
*/ */
public function createAction(Request $request) public function createAction(Request $request)
{ {
@@ -45,71 +34,19 @@ class ActivityReasonController extends AbstractController
$em->persist($entity); $em->persist($entity);
$em->flush(); $em->flush();
return $this->redirect($this->generateUrl('chill_activity_activityreason', array('id' => $entity->getId()))); return $this->redirect($this->generateUrl('chill_activity_activityreason', ['id' => $entity->getId()]));
} }
return $this->render('ChillActivityBundle:ActivityReason:new.html.twig', array( return $this->render('ChillActivityBundle:ActivityReason:new.html.twig', [
'entity' => $entity, 'entity' => $entity,
'form' => $form->createView(), 'form' => $form->createView(),
)); ]);
}
/**
* Creates a form to create a ActivityReason entity.
*
* @param ActivityReason $entity The entity
*
* @return \Symfony\Component\Form\Form The form
*/
private function createCreateForm(ActivityReason $entity)
{
$form = $this->createForm(ActivityReasonType::class, $entity, array(
'action' => $this->generateUrl('chill_activity_activityreason_create'),
'method' => 'POST',
));
$form->add('submit', SubmitType::class, array('label' => 'Create'));
return $form;
}
/**
* Displays a form to create a new ActivityReason entity.
*
*/
public function newAction()
{
$entity = new ActivityReason();
$form = $this->createCreateForm($entity);
return $this->render('ChillActivityBundle:ActivityReason:new.html.twig', array(
'entity' => $entity,
'form' => $form->createView(),
));
}
/**
* Finds and displays a ActivityReason entity.
*
*/
public function showAction($id)
{
$em = $this->getDoctrine()->getManager();
$entity = $em->getRepository('ChillActivityBundle:ActivityReason')->find($id);
if (!$entity) {
throw $this->createNotFoundException('Unable to find ActivityReason entity.');
}
return $this->render('ChillActivityBundle:ActivityReason:show.html.twig', array(
'entity' => $entity,
));
} }
/** /**
* Displays a form to edit an existing ActivityReason entity. * Displays a form to edit an existing ActivityReason entity.
* *
* @param mixed $id
*/ */
public function editAction($id) public function editAction($id)
{ {
@@ -123,33 +60,64 @@ class ActivityReasonController extends AbstractController
$editForm = $this->createEditForm($entity); $editForm = $this->createEditForm($entity);
return $this->render('ChillActivityBundle:ActivityReason:edit.html.twig', array( return $this->render('ChillActivityBundle:ActivityReason:edit.html.twig', [
'entity' => $entity, 'entity' => $entity,
'edit_form' => $editForm->createView() 'edit_form' => $editForm->createView(),
)); ]);
} }
/** /**
* Creates a form to edit a ActivityReason entity. * Lists all ActivityReason entities.
* */
* @param ActivityReason $entity The entity public function indexAction()
*
* @return \Symfony\Component\Form\Form The form
*/
private function createEditForm(ActivityReason $entity)
{ {
$form = $this->createForm(ActivityReasonType::class, $entity, array( $em = $this->getDoctrine()->getManager();
'action' => $this->generateUrl('chill_activity_activityreason_update', array('id' => $entity->getId())),
'method' => 'PUT',
));
$form->add('submit', SubmitType::class, array('label' => 'Update')); $entities = $em->getRepository('ChillActivityBundle:ActivityReason')->findAll();
return $form; return $this->render('ChillActivityBundle:ActivityReason:index.html.twig', [
'entities' => $entities,
]);
} }
/**
* Displays a form to create a new ActivityReason entity.
*/
public function newAction()
{
$entity = new ActivityReason();
$form = $this->createCreateForm($entity);
return $this->render('ChillActivityBundle:ActivityReason:new.html.twig', [
'entity' => $entity,
'form' => $form->createView(),
]);
}
/**
* Finds and displays a ActivityReason entity.
*
* @param mixed $id
*/
public function showAction($id)
{
$em = $this->getDoctrine()->getManager();
$entity = $em->getRepository('ChillActivityBundle:ActivityReason')->find($id);
if (!$entity) {
throw $this->createNotFoundException('Unable to find ActivityReason entity.');
}
return $this->render('ChillActivityBundle:ActivityReason:show.html.twig', [
'entity' => $entity,
]);
}
/** /**
* Edits an existing ActivityReason entity. * Edits an existing ActivityReason entity.
* *
* @param mixed $id
*/ */
public function updateAction(Request $request, $id) public function updateAction(Request $request, $id)
{ {
@@ -167,12 +135,50 @@ class ActivityReasonController extends AbstractController
if ($editForm->isValid()) { if ($editForm->isValid()) {
$em->flush(); $em->flush();
return $this->redirect($this->generateUrl('chill_activity_activityreason', array('id' => $id))); return $this->redirect($this->generateUrl('chill_activity_activityreason', ['id' => $id]));
} }
return $this->render('ChillActivityBundle:ActivityReason:edit.html.twig', array( return $this->render('ChillActivityBundle:ActivityReason:edit.html.twig', [
'entity' => $entity, 'entity' => $entity,
'edit_form' => $editForm->createView() 'edit_form' => $editForm->createView(),
)); ]);
}
/**
* Creates a form to create a ActivityReason entity.
*
* @param ActivityReason $entity The entity
*
* @return \Symfony\Component\Form\Form The form
*/
private function createCreateForm(ActivityReason $entity)
{
$form = $this->createForm(ActivityReasonType::class, $entity, [
'action' => $this->generateUrl('chill_activity_activityreason_create'),
'method' => 'POST',
]);
$form->add('submit', SubmitType::class, ['label' => 'Create']);
return $form;
}
/**
* Creates a form to edit a ActivityReason entity.
*
* @param ActivityReason $entity The entity
*
* @return \Symfony\Component\Form\Form The form
*/
private function createEditForm(ActivityReason $entity)
{
$form = $this->createForm(ActivityReasonType::class, $entity, [
'action' => $this->generateUrl('chill_activity_activityreason_update', ['id' => $entity->getId()]),
'method' => 'PUT',
]);
$form->add('submit', SubmitType::class, ['label' => 'Update']);
return $form;
} }
} }

View File

@@ -0,0 +1,184 @@
<?php
/**
* Chill is a software for social workers
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/
namespace Chill\ActivityBundle\Controller;
use Chill\ActivityBundle\Entity\ActivityType;
use Chill\ActivityBundle\Form\ActivityTypeType;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\Form\Extension\Core\Type\SubmitType;
use Symfony\Component\HttpFoundation\Request;
/**
* Class ActivityTypeController.
*/
class ActivityTypeController extends AbstractController
{
/**
* Creates a new ActivityType entity.
*/
public function createAction(Request $request)
{
$entity = new ActivityType();
$form = $this->createCreateForm($entity);
$form->handleRequest($request);
if ($form->isValid()) {
$em = $this->getDoctrine()->getManager();
$em->persist($entity);
$em->flush();
return $this->redirect($this->generateUrl('chill_activity_activitytype_show', ['id' => $entity->getId()]));
}
return $this->render('ChillActivityBundle:ActivityType:new.html.twig', [
'entity' => $entity,
'form' => $form->createView(),
]);
}
/**
* Displays a form to edit an existing ActivityType entity.
*
* @param mixed $id
*/
public function editAction($id)
{
$em = $this->getDoctrine()->getManager();
$entity = $em->getRepository('ChillActivityBundle:ActivityType')->find($id);
if (!$entity) {
throw $this->createNotFoundException('Unable to find ActivityType entity.');
}
$editForm = $this->createEditForm($entity);
return $this->render('ChillActivityBundle:ActivityType:edit.html.twig', [
'entity' => $entity,
'edit_form' => $editForm->createView(),
]);
}
/**
* Lists all ActivityType entities.
*/
public function indexAction()
{
$em = $this->getDoctrine()->getManager();
$entities = $em->getRepository('ChillActivityBundle:ActivityType')->findAll();
return $this->render('ChillActivityBundle:ActivityType:index.html.twig', [
'entities' => $entities,
]);
}
/**
* Displays a form to create a new ActivityType entity.
*/
public function newAction()
{
$entity = new ActivityType();
$form = $this->createCreateForm($entity);
return $this->render('ChillActivityBundle:ActivityType:new.html.twig', [
'entity' => $entity,
'form' => $form->createView(),
]);
}
/**
* Finds and displays a ActivityType entity.
*
* @param mixed $id
*/
public function showAction($id)
{
$em = $this->getDoctrine()->getManager();
$entity = $em->getRepository('ChillActivityBundle:ActivityType')->find($id);
if (!$entity) {
throw $this->createNotFoundException('Unable to find ActivityType entity.');
}
return $this->render('ChillActivityBundle:ActivityType:show.html.twig', [
'entity' => $entity,
]);
}
/**
* Edits an existing ActivityType entity.
*
* @param mixed $id
*/
public function updateAction(Request $request, $id)
{
$em = $this->getDoctrine()->getManager();
$entity = $em->getRepository('ChillActivityBundle:ActivityType')->find($id);
if (!$entity) {
throw $this->createNotFoundException('Unable to find ActivityType entity.');
}
$editForm = $this->createEditForm($entity);
$editForm->handleRequest($request);
if ($editForm->isValid()) {
$em->flush();
return $this->redirect($this->generateUrl('chill_activity_activitytype_edit', ['id' => $id]));
}
return $this->render('ChillActivityBundle:ActivityType:edit.html.twig', [
'entity' => $entity,
'edit_form' => $editForm->createView(),
]);
}
/**
* Creates a form to create a ActivityType entity.
*
* @param ActivityType $entity The entity
*
* @return \Symfony\Component\Form\Form The form
*/
private function createCreateForm(ActivityType $entity)
{
$form = $this->createForm(ActivityTypeType::class, $entity, [
'action' => $this->generateUrl('chill_activity_activitytype_create'),
'method' => 'POST',
]);
$form->add('submit', SubmitType::class, ['label' => 'Create']);
return $form;
}
/**
* Creates a form to edit a ActivityType entity.
*
* @param ActivityType $entity The entity
*
* @return \Symfony\Component\Form\Form The form
*/
private function createEditForm(ActivityType $entity)
{
$form = $this->createForm(ActivityTypeType::class, $entity, [
'action' => $this->generateUrl('chill_activity_activitytype_update', ['id' => $entity->getId()]),
'method' => 'PUT',
]);
$form->add('submit', SubmitType::class, ['label' => 'Update']);
return $form;
}
}

View File

@@ -1,23 +0,0 @@
<?php
namespace Chill\ActivityBundle\Controller;
use Chill\MainBundle\CRUD\Controller\CRUDController;
use Chill\MainBundle\Pagination\PaginatorInterface;
use Symfony\Component\HttpFoundation\Request;
class AdminActivityPresenceController extends CRUDController
{
/**
* @param string $action
* @param \Doctrine\ORM\QueryBuilder|mixed $query
* @param Request $request
* @param PaginatorInterface $paginator
* @return \Doctrine\ORM\QueryBuilder|mixed
*/
protected function orderQuery(string $action, $query, Request $request, PaginatorInterface $paginator)
{
/** @var \Doctrine\ORM\QueryBuilder $query */
return $query->orderBy('e.id', 'ASC');
}
}

View File

@@ -1,23 +0,0 @@
<?php
namespace Chill\ActivityBundle\Controller;
use Chill\MainBundle\CRUD\Controller\CRUDController;
use Chill\MainBundle\Pagination\PaginatorInterface;
use Symfony\Component\HttpFoundation\Request;
class AdminActivityTypeCategoryController extends CRUDController
{
/**
* @param string $action
* @param \Doctrine\ORM\QueryBuilder|mixed $query
* @param Request $request
* @param PaginatorInterface $paginator
* @return \Doctrine\ORM\QueryBuilder|mixed
*/
protected function orderQuery(string $action, $query, Request $request, PaginatorInterface $paginator)
{
/** @var \Doctrine\ORM\QueryBuilder $query */
return $query->orderBy('e.ordering', 'ASC');
}
}

View File

@@ -1,23 +0,0 @@
<?php
namespace Chill\ActivityBundle\Controller;
use Chill\MainBundle\CRUD\Controller\CRUDController;
use Chill\MainBundle\Pagination\PaginatorInterface;
use Symfony\Component\HttpFoundation\Request;
class AdminActivityTypeController extends CRUDController
{
/**
* @param string $action
* @param \Doctrine\ORM\QueryBuilder|mixed $query
* @param Request $request
* @param PaginatorInterface $paginator
* @return \Doctrine\ORM\QueryBuilder|mixed
*/
protected function orderQuery(string $action, $query, Request $request, PaginatorInterface $paginator)
{
/** @var \Doctrine\ORM\QueryBuilder $query */
return $query->orderBy('e.ordering', 'ASC');
}
}

View File

@@ -1,33 +1,18 @@
<?php <?php
/* /**
* Chill is a software for social workers * Chill is a software for social workers
* Copyright (C) 2015 Champs Libres <info@champs-libres.coop>
* *
* This program is free software: you can redistribute it and/or modify * For the full copyright and license information, please view
* it under the terms of the GNU Affero General Public License as published by * the LICENSE file that was distributed with this source code.
* 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\Controller; namespace Chill\ActivityBundle\Controller;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController; use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
/** /**
* Controller for activity configuration * Controller for activity configuration.
*
* @author Julien Fastré <julien.fastre@champs-libres.coop>
* @author Champs Libres <info@champs-libres.coop>
*/ */
class AdminController extends AbstractController class AdminController extends AbstractController
{ {
@@ -35,7 +20,7 @@ class AdminController extends AbstractController
{ {
return $this->render('ChillActivityBundle:Admin:layout_activity.html.twig'); return $this->render('ChillActivityBundle:Admin:layout_activity.html.twig');
} }
public function redirectToAdminIndexAction() public function redirectToAdminIndexAction()
{ {
return $this->redirectToRoute('chill_main_admin_central'); return $this->redirectToRoute('chill_main_admin_central');

View File

@@ -1,42 +1,25 @@
<?php <?php
/* /**
* Chill is a software for social workers * Chill is a software for social workers
* *
* Copyright (C) 2014-2015, Champs Libres Cooperative SCRLFS, * For the full copyright and license information, please view
* <http://www.champs-libres.coop>, <info@champs-libres.coop> * the LICENSE file that was distributed with this source code.
*
* 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\DataFixtures\ORM; namespace Chill\ActivityBundle\DataFixtures\ORM;
use Chill\ActivityBundle\Entity\Activity;
use Chill\MainBundle\DataFixtures\ORM\LoadScopes;
use Chill\MainBundle\DataFixtures\ORM\LoadUsers;
use Doctrine\Common\DataFixtures\AbstractFixture; use Doctrine\Common\DataFixtures\AbstractFixture;
use Doctrine\Common\DataFixtures\OrderedFixtureInterface; use Doctrine\Common\DataFixtures\OrderedFixtureInterface;
use Doctrine\Persistence\ObjectManager; use Doctrine\Persistence\ObjectManager;
use Faker\Factory as FakerFactory; use Faker\Factory as FakerFactory;
use Chill\ActivityBundle\Entity\Activity;
use Chill\MainBundle\DataFixtures\ORM\LoadUsers;
use Chill\ActivityBundle\DataFixtures\ORM\LoadActivityReason;
use Chill\ActivityBundle\DataFixtures\ORM\LoadActivityType;
use Chill\MainBundle\DataFixtures\ORM\LoadScopes;
use Symfony\Component\DependencyInjection\ContainerAwareInterface; use Symfony\Component\DependencyInjection\ContainerAwareInterface;
/** /**
* Load reports into DB * Load reports into DB.
*
* @author Champs-Libres Coop
*/ */
class LoadActivity extends AbstractFixture implements OrderedFixtureInterface, ContainerAwareInterface class LoadActivity extends AbstractFixture implements OrderedFixtureInterface, ContainerAwareInterface
{ {
@@ -57,30 +40,48 @@ class LoadActivity extends AbstractFixture implements OrderedFixtureInterface, C
return 16400; return 16400;
} }
/** public function load(ObjectManager $manager)
* Return a random scope
*
* @return \Chill\MainBundle\Entity\Scope
*/
private function getRandomScope()
{ {
$scopeRef = LoadScopes::$references[array_rand(LoadScopes::$references)]; $persons = $this->container->get('doctrine.orm.entity_manager')
return $this->getReference($scopeRef); ->getRepository('ChillPersonBundle:Person')
->findAll();
foreach ($persons as $person) {
$activityNbr = rand(0, 3);
for ($i = 0; $i < $activityNbr; ++$i) {
echo 'Creating an activity type for : ' . $person . "\n";
$activity = $this->newRandomActivity($person);
$manager->persist($activity);
}
}
$manager->flush();
}
public function newRandomActivity($person)
{
$activity = (new Activity())
->setUser($this->getRandomUser())
->setPerson($person)
->setDate($this->faker->dateTimeThisYear())
->setDurationTime($this->faker->dateTime(36000))
->setType($this->getRandomActivityType())
->setScope($this->getRandomScope())
->setAttendee($this->faker->boolean());
$usedId = [];
for ($i = 0; rand(0, 4) > $i; ++$i) {
$reason = $this->getRandomActivityReason($usedId);
$usedId[] = $reason->getId();
$activity->addReason($reason);
}
return $activity;
} }
/** /**
* Return a random activityType * Return a random activityReason.
*
* @return \Chill\ActivityBundle\Entity\ActivityType
*/
private function getRandomActivityType()
{
$typeRef = LoadActivityType::$references[array_rand(LoadActivityType::$references)];
return $this->getReference($typeRef);
}
/**
* Return a random activityReason
* *
* @return \Chill\ActivityBundle\Entity\ActivityReason * @return \Chill\ActivityBundle\Entity\ActivityReason
*/ */
@@ -97,57 +98,38 @@ class LoadActivity extends AbstractFixture implements OrderedFixtureInterface, C
} }
/** /**
* Return a random user * Return a random activityType.
*
* @return \Chill\ActivityBundle\Entity\ActivityType
*/
private function getRandomActivityType()
{
$typeRef = LoadActivityType::$references[array_rand(LoadActivityType::$references)];
return $this->getReference($typeRef);
}
/**
* Return a random scope.
*
* @return \Chill\MainBundle\Entity\Scope
*/
private function getRandomScope()
{
$scopeRef = LoadScopes::$references[array_rand(LoadScopes::$references)];
return $this->getReference($scopeRef);
}
/**
* Return a random user.
* *
* @return \Chill\MainBundle\Entity\User * @return \Chill\MainBundle\Entity\User
*/ */
private function getRandomUser() private function getRandomUser()
{ {
$userRef = array_rand(LoadUsers::$refs); $userRef = array_rand(LoadUsers::$refs);
return $this->getReference($userRef); return $this->getReference($userRef);
} }
public function newRandomActivity($person)
{
$activity = (new Activity())
->setUser($this->getRandomUser())
->setPerson($person)
->setDate($this->faker->dateTimeThisYear())
->setDurationTime($this->faker->dateTime(36000))
->setType($this->getRandomActivityType())
->setScope($this->getRandomScope())
;
// ->setAttendee($this->faker->boolean())
$usedId = array();
for ($i = 0; $i < rand(0, 4); $i++) {
$reason = $this->getRandomActivityReason($usedId);
$usedId[] = $reason->getId();
$activity->addReason($reason);
}
return $activity;
}
public function load(ObjectManager $manager)
{
$persons = $this->container->get('doctrine.orm.entity_manager')
->getRepository('ChillPersonBundle:Person')
->findAll();
foreach($persons as $person) {
$activityNbr = rand(0,3);
$ref = 'activity_'.$person->getFullnameCanonical();
for($i = 0; $i < $activityNbr; $i ++) {
print "Creating an activity type for : ".$person." (ref: ".$ref.") \n";
$activity = $this->newRandomActivity($person);
$manager->persist($activity);
}
$this->setReference($ref, $activity);
}
$manager->flush();
}
} }

View File

@@ -1,39 +0,0 @@
<?php
namespace Chill\ActivityBundle\DataFixtures\ORM;
use Doctrine\Common\DataFixtures\AbstractFixture;
use Doctrine\Common\DataFixtures\DependentFixtureInterface;
use Chill\ActivityBundle\Entity\Activity;
use Chill\MainBundle\DataFixtures\ORM\LoadAbstractNotificationsTrait;
use Chill\ActivityBundle\DataFixtures\ORM\LoadActivity;
/**
* Load notififications into database
*/
class LoadActivityNotifications extends AbstractFixture implements DependentFixtureInterface
{
use LoadAbstractNotificationsTrait;
public $notifs = [
[
'message' => 'Hello !',
'entityClass' => Activity::class,
'entityRef' => 'activity_gerard depardieu',
'sender' => 'center a_social',
'addressees' => [
'center a_social',
'center a_administrative',
'center a_direction',
'multi_center'
],
]
];
public function getDependencies()
{
return [
LoadActivity::class,
];
}
}

View File

@@ -1,81 +1,66 @@
<?php <?php
/* /**
* Chill is a software for social workers * Chill is a software for social workers
* *
* Copyright (C) 2014-2015, Champs Libres Cooperative SCRLFS, * For the full copyright and license information, please view
* <http://www.champs-libres.coop>, <info@champs-libres.coop> * the LICENSE file that was distributed with this source code.
*
* 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\DataFixtures\ORM; namespace Chill\ActivityBundle\DataFixtures\ORM;
use Chill\ActivityBundle\Entity\ActivityReason;
use Doctrine\Common\DataFixtures\AbstractFixture; use Doctrine\Common\DataFixtures\AbstractFixture;
use Doctrine\Common\DataFixtures\OrderedFixtureInterface; use Doctrine\Common\DataFixtures\OrderedFixtureInterface;
use Doctrine\Persistence\ObjectManager; use Doctrine\Persistence\ObjectManager;
use Chill\ActivityBundle\Entity\ActivityReason;
/** /**
* Description of LoadActivityReason * Description of LoadActivityReason.
*
* @author Champs-Libres Coop
*/ */
class LoadActivityReason extends AbstractFixture implements OrderedFixtureInterface class LoadActivityReason extends AbstractFixture implements OrderedFixtureInterface
{ {
public static $references = [];
public function getOrder() public function getOrder()
{ {
return 16300; return 16300;
} }
public static $references = array();
public function load(ObjectManager $manager) public function load(ObjectManager $manager)
{ {
$reasons = [ $reasons = [
[ [
'name' => ['fr' => 'Recherche logement', 'en' => 'Housing research', 'nl' => 'Woning zoektoch'], 'name' => ['fr' => 'Recherche logement', 'en' => 'Housing research', 'nl' => 'Woning zoektoch'],
'category' => 'cat_Housing'], 'category' => 'cat_Housing', ],
[ [
'name' => ['fr' => 'Problème avec propriétaire', 'en' => 'Landlord problems', 'nl' => 'Huisbaas problemen'], 'name' => ['fr' => 'Problème avec propriétaire', 'en' => 'Landlord problems', 'nl' => 'Huisbaas problemen'],
'category' => 'cat_Housing'], 'category' => 'cat_Housing', ],
[ [
'name' => ['fr' => 'Retard de payement', 'en' => 'Payement problems', 'nl' => 'Betalings vertragingen'], 'name' => ['fr' => 'Retard de payement', 'en' => 'Payement problems', 'nl' => 'Betalings vertragingen'],
'category' => 'cat_Housing'], 'category' => 'cat_Housing', ],
[ [
'name' => ['fr' => 'Explication législation', 'en' => 'Legislation explanation', 'nl' => 'Legislative uitleg'], 'name' => ['fr' => 'Explication législation', 'en' => 'Legislation explanation', 'nl' => 'Legislative uitleg'],
'category' => 'cat_Unemployment procedure'], 'category' => 'cat_Unemployment procedure', ],
[ [
'name' => ['fr' => 'Coaching entretien d\'activation', 'en' => 'Interview coaching', 'nl' => 'Interview coaching'], 'name' => ['fr' => 'Coaching entretien d\'activation', 'en' => 'Interview coaching', 'nl' => 'Interview coaching'],
'category' => 'cat_Unemployment procedure'], 'category' => 'cat_Unemployment procedure', ],
[ [
'name' => ['fr' => 'Récupération des allocations', 'en' => 'Allowance recovery', 'nl' => 'Terugwinning van de uitkeringen'], 'name' => ['fr' => 'Récupération des allocations', 'en' => 'Allowance recovery', 'nl' => 'Terugwinning van de uitkeringen'],
'category' => 'cat_Unemployment procedure'] 'category' => 'cat_Unemployment procedure', ],
]; ];
foreach ($reasons as $r) { foreach ($reasons as $r) {
print "Creating activity reason : " . $r['name']['en'] . "\n"; echo 'Creating activity reason : ' . $r['name']['en'] . "\n";
$activityReason = (new ActivityReason()) $activityReason = (new ActivityReason())
->setName(($r['name'])) ->setName(($r['name']))
->setActive(true) ->setActive(true)
->setCategory($this->getReference($r['category'])); ->setCategory($this->getReference($r['category']));
$manager->persist($activityReason); $manager->persist($activityReason);
$reference = 'activity_reason_'.$r['name']['en']; $reference = 'activity_reason_' . $r['name']['en'];
$this->addReference($reference, $activityReason); $this->addReference($reference, $activityReason);
static::$references[] = $reference; static::$references[] = $reference;
} }
$manager->flush(); $manager->flush();
} }
} }

View File

@@ -1,35 +1,21 @@
<?php <?php
/* /**
* Chill is a software for social workers * Chill is a software for social workers
* *
* Copyright (C) 2014-2015, Champs Libres Cooperative SCRLFS, * For the full copyright and license information, please view
* <http://www.champs-libres.coop>, <info@champs-libres.coop> * the LICENSE file that was distributed with this source code.
*
* 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\DataFixtures\ORM; namespace Chill\ActivityBundle\DataFixtures\ORM;
use Chill\ActivityBundle\Entity\ActivityReasonCategory;
use Doctrine\Common\DataFixtures\AbstractFixture; use Doctrine\Common\DataFixtures\AbstractFixture;
use Doctrine\Common\DataFixtures\OrderedFixtureInterface; use Doctrine\Common\DataFixtures\OrderedFixtureInterface;
use Doctrine\Persistence\ObjectManager; use Doctrine\Persistence\ObjectManager;
use Chill\ActivityBundle\Entity\ActivityReasonCategory;
/** /**
* Description of LoadActivityReasonCategory * Description of LoadActivityReasonCategory.
*
* @author Champs-Libres Coop
*/ */
class LoadActivityReasonCategory extends AbstractFixture implements OrderedFixtureInterface class LoadActivityReasonCategory extends AbstractFixture implements OrderedFixtureInterface
{ {
@@ -37,27 +23,26 @@ class LoadActivityReasonCategory extends AbstractFixture implements OrderedFixtu
{ {
return 16200; return 16200;
} }
public function load(ObjectManager $manager) public function load(ObjectManager $manager)
{ {
$categs = [ $categs = [
['name' => ['name' => ['fr' => 'Logement', 'en' => 'Housing', 'nl' => 'Woning']],
['fr' => 'Logement', 'en' => 'Housing', 'nl' => 'Woning']], ['name' => ['fr' => 'Démarches chômage', 'en' => 'Unemployment procedure', 'nl' => 'Werkloosheid werkwijze']],
['name' =>
['fr' => 'Démarches chômage', 'en' => 'Unemployment procedure', 'nl' => 'Werkloosheid werkwijze']],
]; ];
foreach ($categs as $c) { foreach ($categs as $c) {
print "Creating activity reason category : " . $c['name']['en'] . "\n"; echo 'Creating activity reason category : ' . $c['name']['en'] . "\n";
$activityReasonCategory = (new ActivityReasonCategory()) $activityReasonCategory = (new ActivityReasonCategory())
->setName(($c['name'])) ->setName(($c['name']))
->setActive(true); ->setActive(true);
$manager->persist($activityReasonCategory); $manager->persist($activityReasonCategory);
$this->addReference( $this->addReference(
'cat_'.$c['name']['en'], 'cat_' . $c['name']['en'],
$activityReasonCategory); $activityReasonCategory
);
} }
$manager->flush(); $manager->flush();
} }
} }

View File

@@ -1,86 +1,45 @@
<?php <?php
/* /**
* Chill is a software for social workers * Chill is a software for social workers
* *
* Copyright (C) 2014-2015, Champs Libres Cooperative SCRLFS, * For the full copyright and license information, please view
* <http://www.champs-libres.coop>, <info@champs-libres.coop> * the LICENSE file that was distributed with this source code.
*
* 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\DataFixtures\ORM; namespace Chill\ActivityBundle\DataFixtures\ORM;
use Doctrine\Bundle\FixturesBundle\Fixture; use Chill\ActivityBundle\Entity\ActivityType;
use Doctrine\Common\DataFixtures\AbstractFixture;
use Doctrine\Common\DataFixtures\OrderedFixtureInterface; use Doctrine\Common\DataFixtures\OrderedFixtureInterface;
use Doctrine\Persistence\ObjectManager; use Doctrine\Persistence\ObjectManager;
use Chill\ActivityBundle\Entity\ActivityType;
/** /**
* Description of LoadActivityType * Description of LoadActivityType.
*
* @author Champs-Libres Coop
*/ */
class LoadActivityType extends Fixture implements OrderedFixtureInterface class LoadActivityType extends AbstractFixture implements OrderedFixtureInterface
{ {
public static $references = [];
public function getOrder() public function getOrder()
{ {
return 16100; return 16100;
} }
public static $references = array();
public function load(ObjectManager $manager) public function load(ObjectManager $manager)
{ {
$types = [ $types = [
# Exange ['name' => ['fr' => 'Appel téléphonique', 'en' => 'Telephone call', 'nl' => 'Telefoon appel']],
[ ['name' => ['fr' => 'Entretien', 'en' => 'Interview', 'nl' => 'Vraaggesprek']],
'name' => ['name' => ['fr' => 'Inspection', 'en' => 'Inspection', 'nl' => 'Inspectie']],
['fr' => 'Entretien physique avec l\'usager'],
'category' => 'exchange' ],
[
'name' =>
['fr' => 'Appel téléphonique', 'en' => 'Telephone call', 'nl' => 'Telefoon appel'],
'category' => 'exchange' ],
[
'name' =>
['fr' => 'Courriel', 'en' => 'Email', 'nl' => 'Email'],
'category' => 'exchange' ],
# Meeting
[
'name' =>
['fr' => 'Point technique encadrant'],
'category' => 'meeting' ],
[
'name' =>
['fr' => 'Réunion avec des partenaires'],
'category' => 'meeting' ],
[
'name' =>
['fr' => 'Commission pluridisciplinaire et pluri-institutionnelle'],
'category' => 'meeting' ],
]; ];
foreach ($types as $t) { foreach ($types as $t) {
print "Creating activity type : " . $t['name']['fr'] . " (cat:". $t['category'] . " \n"; echo 'Creating activity type : ' . $t['name']['en'] . "\n";
$activityType = (new ActivityType()) $activityType = (new ActivityType())
->setName(($t['name'])) ->setName(($t['name']));
->setCategory($this->getReference('activity_type_cat_'.$t['category']))
->setSocialIssuesVisible(1)
->setSocialActionsVisible(1);
$manager->persist($activityType); $manager->persist($activityType);
$reference = 'activity_type_'.$t['name']['fr']; $reference = 'activity_type_' . $t['name']['en'];
$this->addReference($reference, $activityType); $this->addReference($reference, $activityType);
static::$references[] = $reference; static::$references[] = $reference;
} }

View File

@@ -1,72 +0,0 @@
<?php
/*
* Chill is a software for social workers
*
* Copyright (C) 2014-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\DataFixtures\ORM;
use Doctrine\Bundle\FixturesBundle\Fixture;
use Doctrine\Common\DataFixtures\OrderedFixtureInterface;
use Doctrine\Persistence\ObjectManager;
use Chill\ActivityBundle\Entity\ActivityTypeCategory;
/**
* Fixtures for ActivityTypeCategory
*
* @author Champs-Libres Coop
*/
class LoadActivityTypeCategory extends Fixture implements OrderedFixtureInterface
{
public static $references = array();
public function getOrder()
{
return 16050;
}
public function load(ObjectManager $manager)
{
$categories = [
[
'name' => ['fr' => 'Échange avec usager', 'en' => 'Exchange with user'],
'ref' => 'exchange',
],
[
'name' => ['fr' => 'Réunion', 'en' => 'Meeting'],
'ref' => 'meeting',
],
];
foreach ($categories as $cat) {
print "Creating activity type category : " . $cat['ref'] . "\n";
$newCat = (new ActivityTypeCategory())
->setName(($cat['name']));
$manager->persist($newCat);
$reference = 'activity_type_cat_'.$cat['ref'];
$this->addReference($reference, $newCat);
static::$references[] = $reference;
}
$manager->flush();
}
}

View File

@@ -1,37 +1,25 @@
<?php <?php
/* /**
* Copyright (C) 2015 Julien Fastré <julien.fastre@champs-libres.coop> * Chill is a software for social workers
* *
* This program is free software: you can redistribute it and/or modify * For the full copyright and license information, please view
* it under the terms of the GNU Affero General Public License as published by * the LICENSE file that was distributed with this source code.
* 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\DataFixtures\ORM; namespace Chill\ActivityBundle\DataFixtures\ORM;
use Chill\ActivityBundle\Security\Authorization\ActivityStatsVoter;
use Chill\MainBundle\DataFixtures\ORM\LoadPermissionsGroup;
use Chill\MainBundle\DataFixtures\ORM\LoadScopes;
use Chill\MainBundle\Entity\RoleScope;
use Doctrine\Common\DataFixtures\AbstractFixture; use Doctrine\Common\DataFixtures\AbstractFixture;
use Doctrine\Common\DataFixtures\OrderedFixtureInterface; use Doctrine\Common\DataFixtures\OrderedFixtureInterface;
use Doctrine\Persistence\ObjectManager; use Doctrine\Persistence\ObjectManager;
use Chill\MainBundle\DataFixtures\ORM\LoadPermissionsGroup;
use Chill\MainBundle\Entity\RoleScope;
use Chill\MainBundle\DataFixtures\ORM\LoadScopes;
use Chill\ActivityBundle\Security\Authorization\ActivityStatsVoter;
/** /**
* Add a role CHILL_ACTIVITY_UPDATE & CHILL_ACTIVITY_CREATE for all groups except administrative, * Add a role CHILL_ACTIVITY_UPDATE & CHILL_ACTIVITY_CREATE for all groups except administrative,
* and a role CHILL_ACTIVITY_SEE for administrative * and a role CHILL_ACTIVITY_SEE for administrative.
*
* @author Julien Fastré <julien.fastre@champs-libres.coop>
*/ */
class LoadActivitytACL extends AbstractFixture implements OrderedFixtureInterface class LoadActivitytACL extends AbstractFixture implements OrderedFixtureInterface
{ {
@@ -40,12 +28,12 @@ class LoadActivitytACL extends AbstractFixture implements OrderedFixtureInterfac
return 16000; return 16000;
} }
public function load(ObjectManager $manager) public function load(ObjectManager $manager)
{ {
foreach (LoadPermissionsGroup::$refs as $permissionsGroupRef) { foreach (LoadPermissionsGroup::$refs as $permissionsGroupRef) {
$permissionsGroup = $this->getReference($permissionsGroupRef); $permissionsGroup = $this->getReference($permissionsGroupRef);
foreach (LoadScopes::$references as $scopeRef){
foreach (LoadScopes::$references as $scopeRef) {
$scope = $this->getReference($scopeRef); $scope = $this->getReference($scopeRef);
//create permission group //create permission group
switch ($permissionsGroup->getName()) { switch ($permissionsGroup->getName()) {
@@ -53,47 +41,49 @@ class LoadActivitytACL extends AbstractFixture implements OrderedFixtureInterfac
if ($scope->getName()['en'] === 'administrative') { if ($scope->getName()['en'] === 'administrative') {
break 2; // we do not want any power on administrative break 2; // we do not want any power on administrative
} }
break; break;
case 'administrative': case 'administrative':
case 'direction': case 'direction':
if (in_array($scope->getName()['en'], array('administrative', 'social'))) { if (in_array($scope->getName()['en'], ['administrative', 'social'])) {
break 2; // we do not want any power on social or administrative break 2; // we do not want any power on social or administrative
} }
break; break;
} }
printf("Adding CHILL_ACTIVITY_UPDATE & CHILL_ACTIVITY_CREATE & CHILL_ACTIVITY_DELETE, and stats and list permissions to %s " printf(
. "permission group, scope '%s' \n", 'Adding CHILL_ACTIVITY_UPDATE & CHILL_ACTIVITY_CREATE & CHILL_ACTIVITY_DELETE, and stats and list permissions to %s '
$permissionsGroup->getName(), $scope->getName()['en']); . "permission group, scope '%s' \n",
$permissionsGroup->getName(),
$scope->getName()['en']
);
$roleScopeUpdate = (new RoleScope()) $roleScopeUpdate = (new RoleScope())
->setRole('CHILL_ACTIVITY_UPDATE') ->setRole('CHILL_ACTIVITY_UPDATE')
->setScope($scope); ->setScope($scope);
$permissionsGroup->addRoleScope($roleScopeUpdate); $permissionsGroup->addRoleScope($roleScopeUpdate);
$roleScopeCreate = (new RoleScope()) $roleScopeCreate = (new RoleScope())
->setRole('CHILL_ACTIVITY_CREATE') ->setRole('CHILL_ACTIVITY_CREATE')
->setScope($scope); ->setScope($scope);
$permissionsGroup->addRoleScope($roleScopeCreate); $permissionsGroup->addRoleScope($roleScopeCreate);
$roleScopeDelete = (new RoleScope()) $roleScopeDelete = (new RoleScope())
->setRole('CHILL_ACTIVITY_DELETE') ->setRole('CHILL_ACTIVITY_DELETE')
->setScope($scope); ->setScope($scope);
$permissionsGroup->addRoleScope($roleScopeDelete); $permissionsGroup->addRoleScope($roleScopeDelete);
$roleScopeList = (new RoleScope()) $roleScopeList = (new RoleScope())
->setRole(ActivityStatsVoter::LISTS) ->setRole(ActivityStatsVoter::LISTS);
;
$permissionsGroup->addRoleScope($roleScopeList); $permissionsGroup->addRoleScope($roleScopeList);
$roleScopeStat = (new RoleScope()) $roleScopeStat = (new RoleScope())
->setRole(ActivityStatsVoter::STATS) ->setRole(ActivityStatsVoter::STATS);
;
$permissionsGroup->addRoleScope($roleScopeStat); $permissionsGroup->addRoleScope($roleScopeStat);
$manager->persist($roleScopeUpdate); $manager->persist($roleScopeUpdate);
$manager->persist($roleScopeCreate); $manager->persist($roleScopeCreate);
$manager->persist($roleScopeDelete); $manager->persist($roleScopeDelete);
} }
} }
$manager->flush(); $manager->flush();
} }
} }

View File

@@ -1,45 +1,28 @@
<?php <?php
/* /**
* Chill is a software for social workers * Chill is a software for social workers
* *
* Copyright (C) 2014-2015, Champs Libres Cooperative SCRLFS, * For the full copyright and license information, please view
* <http://www.champs-libres.coop>, <info@champs-libres.coop> * the LICENSE file that was distributed with this source code.
*
* 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\DependencyInjection; namespace Chill\ActivityBundle\DependencyInjection;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\Config\FileLocator;
use Symfony\Component\HttpKernel\DependencyInjection\Extension;
use Symfony\Component\DependencyInjection\Loader;
use Symfony\Component\DependencyInjection\Extension\PrependExtensionInterface;
use Chill\ActivityBundle\Security\Authorization\ActivityStatsVoter;
use Chill\ActivityBundle\Security\Authorization\ActivityVoter; use Chill\ActivityBundle\Security\Authorization\ActivityVoter;
use Symfony\Component\Config\FileLocator;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Extension\PrependExtensionInterface;
use Symfony\Component\DependencyInjection\Loader;
use Symfony\Component\HttpKernel\DependencyInjection\Extension;
/** /**
* This is the class that loads and manages your bundle configuration * This is the class that loads and manages your bundle configuration.
* *
* To learn more see {@link http://symfony.com/doc/current/cookbook/bundles/extension.html} * To learn more see {@link http://symfony.com/doc/current/cookbook/bundles/extension.html}
*/ */
class ChillActivityExtension extends Extension implements PrependExtensionInterface class ChillActivityExtension extends Extension implements PrependExtensionInterface
{ {
/**
* {@inheritdoc}
*/
public function load(array $configs, ContainerBuilder $container) public function load(array $configs, ContainerBuilder $container)
{ {
$configuration = new Configuration(); $configuration = new Configuration();
@@ -47,22 +30,33 @@ class ChillActivityExtension extends Extension implements PrependExtensionInterf
$container->setParameter('chill_activity.form.time_duration', $config['form']['time_duration']); $container->setParameter('chill_activity.form.time_duration', $config['form']['time_duration']);
$loader = new Loader\YamlFileLoader($container, new FileLocator(__DIR__.'/../config')); $loader = new Loader\YamlFileLoader($container, new FileLocator(__DIR__ . '/../config'));
$loader->load('services.yaml'); $loader->load('services.yaml');
$loader->load('services/export.yaml'); $loader->load('services/export.yaml');
$loader->load('services/repositories.yaml'); $loader->load('services/repositories.yaml');
$loader->load('services/fixtures.yaml'); $loader->load('services/fixtures.yaml');
$loader->load('services/menu.yaml');
$loader->load('services/controller.yaml'); $loader->load('services/controller.yaml');
$loader->load('services/form.yaml'); $loader->load('services/form.yaml');
$loader->load('services/templating.yaml'); $loader->load('services/templating.yaml');
$loader->load('services/accompanyingPeriodConsistency.yaml');
} }
public function prepend(ContainerBuilder $container) public function prepend(ContainerBuilder $container)
{ {
$this->prependRoutes($container); $this->prependRoutes($container);
$this->prependAuthorization($container); $this->prependAuthorization($container);
$this->prependCruds($container); }
public function prependAuthorization(ContainerBuilder $container)
{
$container->prependExtensionConfig('security', [
'role_hierarchy' => [
ActivityVoter::UPDATE => [ActivityVoter::SEE_DETAILS],
ActivityVoter::CREATE => [ActivityVoter::SEE_DETAILS],
ActivityVoter::DELETE => [ActivityVoter::SEE_DETAILS],
ActivityVoter::SEE_DETAILS => [ActivityVoter::SEE],
],
]);
} }
/* (non-PHPdoc) /* (non-PHPdoc)
@@ -71,95 +65,12 @@ class ChillActivityExtension extends Extension implements PrependExtensionInterf
public function prependRoutes(ContainerBuilder $container) public function prependRoutes(ContainerBuilder $container)
{ {
//add routes for custom bundle //add routes for custom bundle
$container->prependExtensionConfig('chill_main', array(
'routing' => array(
'resources' => array(
'@ChillActivityBundle/config/routes.yaml'
)
)
));
}
public function prependAuthorization(ContainerBuilder $container)
{
$container->prependExtensionConfig('security', array(
'role_hierarchy' => array(
ActivityVoter::UPDATE => array(ActivityVoter::SEE_DETAILS),
ActivityVoter::CREATE => array(ActivityVoter::SEE_DETAILS),
ActivityVoter::DELETE => array(ActivityVoter::SEE_DETAILS),
ActivityVoter::SEE_DETAILS => array(ActivityVoter::SEE)
)
));
}
protected function prependCruds(ContainerBuilder $container)
{
$container->prependExtensionConfig('chill_main', [ $container->prependExtensionConfig('chill_main', [
'cruds' => [ 'routing' => [
[ 'resources' => [
'class' => \Chill\ActivityBundle\Entity\ActivityType::class, '@ChillActivityBundle/config/routes.yaml',
'name' => 'activity_type',
'base_path' => '/admin/activity/type',
'form_class' => \Chill\ActivityBundle\Form\ActivityTypeType::class,
'controller' => \Chill\ActivityBundle\Controller\AdminActivityTypeController::class,
'actions' => [
'index' => [
'template' => '@ChillActivity/ActivityType/index.html.twig',
'role' => 'ROLE_ADMIN'
],
'new' => [
'role' => 'ROLE_ADMIN',
'template' => '@ChillActivity/ActivityType/new.html.twig',
],
'edit' => [
'role' => 'ROLE_ADMIN',
'template' => '@ChillActivity/ActivityType/edit.html.twig',
]
]
], ],
[ ],
'class' => \Chill\ActivityBundle\Entity\ActivityTypeCategory::class,
'name' => 'activity_type_category',
'base_path' => '/admin/activity/type_category',
'form_class' => \Chill\ActivityBundle\Form\ActivityTypeCategoryType::class,
'controller' => \Chill\ActivityBundle\Controller\AdminActivityTypeCategoryController::class,
'actions' => [
'index' => [
'template' => '@ChillActivity/ActivityTypeCategory/index.html.twig',
'role' => 'ROLE_ADMIN'
],
'new' => [
'role' => 'ROLE_ADMIN',
'template' => '@ChillActivity/ActivityTypeCategory/new.html.twig',
],
'edit' => [
'role' => 'ROLE_ADMIN',
'template' => '@ChillActivity/ActivityTypeCategory/edit.html.twig',
]
]
],
[
'class' => \Chill\ActivityBundle\Entity\ActivityPresence::class,
'name' => 'activity_presence',
'base_path' => '/admin/activity/presence',
'form_class' => \Chill\ActivityBundle\Form\ActivityPresenceType::class,
'controller' => \Chill\ActivityBundle\Controller\AdminActivityPresenceController::class,
'actions' => [
'index' => [
'template' => '@ChillActivity/ActivityPresence/index.html.twig',
'role' => 'ROLE_ADMIN'
],
'new' => [
'role' => 'ROLE_ADMIN',
'template' => '@ChillActivity/ActivityPresence/new.html.twig',
],
'edit' => [
'role' => 'ROLE_ADMIN',
'template' => '@ChillActivity/ActivityPresence/edit.html.twig',
]
]
],
]
]); ]);
} }
} }

View File

@@ -1,71 +1,73 @@
<?php <?php
/**
* Chill is a software for social workers
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/
namespace Chill\ActivityBundle\DependencyInjection; namespace Chill\ActivityBundle\DependencyInjection;
use Symfony\Component\Config\Definition\Builder\TreeBuilder; use Symfony\Component\Config\Definition\Builder\TreeBuilder;
use Symfony\Component\Config\Definition\ConfigurationInterface; use Symfony\Component\Config\Definition\ConfigurationInterface;
/** /**
* This is the class that validates and merges configuration from your app/config files * This is the class that validates and merges configuration from your app/config files.
* *
* To learn more see {@link http://symfony.com/doc/current/cookbook/bundles/extension.html#cookbook-bundles-extension-config-class} * To learn more see {@link http://symfony.com/doc/current/cookbook/bundles/extension.html#cookbook-bundles-extension-config-class}
*/ */
class Configuration implements ConfigurationInterface class Configuration implements ConfigurationInterface
{ {
/**
* {@inheritdoc}
*/
public function getConfigTreeBuilder() public function getConfigTreeBuilder()
{ {
$treeBuilder = new TreeBuilder('chill_activity'); $treeBuilder = new TreeBuilder('chill_activity');
$rootNode = $treeBuilder->getRootNode('chill_activity'); $rootNode = $treeBuilder->getRootNode('chill_activity');
$rootNode $rootNode
->children() ->children()
->arrayNode('form') ->arrayNode('form')
->canBeEnabled() ->canBeEnabled()
->children() ->children()
->arrayNode('time_duration') ->arrayNode('time_duration')
->isRequired() ->isRequired()
->requiresAtLeastOneElement() ->requiresAtLeastOneElement()
->defaultValue( ->defaultValue(
array( [
[ 'label' => '5 minutes', 'seconds' => 300], ['label' => '5 minutes', 'seconds' => 300],
[ 'label' => '10 minutes', 'seconds' => 600], ['label' => '10 minutes', 'seconds' => 600],
[ 'label' => '15 minutes', 'seconds' => 900], ['label' => '15 minutes', 'seconds' => 900],
[ 'label' => '20 minutes', 'seconds' => 1200], ['label' => '20 minutes', 'seconds' => 1200],
[ 'label' => '25 minutes', 'seconds' => 1500], ['label' => '25 minutes', 'seconds' => 1500],
[ 'label' => '30 minutes', 'seconds' => 1800], ['label' => '30 minutes', 'seconds' => 1800],
[ 'label' => '45 minutes', 'seconds' => 2700], ['label' => '45 minutes', 'seconds' => 2700],
[ 'label' => '1 hour', 'seconds' => 3600], ['label' => '1 hour', 'seconds' => 3600],
[ 'label' => '1 hour 15', 'seconds' => 4500], ['label' => '1 hour 15', 'seconds' => 4500],
[ 'label' => '1 hour 30', 'seconds' => 5400], ['label' => '1 hour 30', 'seconds' => 5400],
[ 'label' => '1 hour 45', 'seconds' => 6300], ['label' => '1 hour 45', 'seconds' => 6300],
[ 'label' => '2 hours', 'seconds' => 7200], ['label' => '2 hours', 'seconds' => 7200],
) ]
) )
->info('The intervals of time to show in activity form') ->info('The intervals of time to show in activity form')
->prototype('array')
->prototype('array') ->children()
->children() ->scalarNode('seconds')
->scalarNode('seconds') ->info('The number of seconds of this duration. Must be an integer.')
->info("The number of seconds of this duration. Must be an integer.") ->cannotBeEmpty()
->cannotBeEmpty() ->validate()
->validate() ->ifTrue(function ($data) {
->ifTrue(function($data) { return !is_int($data);
return !is_int($data); })->thenInvalid('The value %s is not a valid integer')
})->thenInvalid("The value %s is not a valid integer") ->end()
->end() ->end()
->end() ->scalarNode('label')
->scalarNode('label') ->cannotBeEmpty()
->cannotBeEmpty() ->info('The label to show into fields')
->info("The label to show into fields") ->end()
->end() ->end()
->end() ->end()
->end()
// ->validate() // ->validate()
// //
// ->ifTrue(function ($data) { // ->ifTrue(function ($data) {
// // test this is an array // // test this is an array
// if (!is_array($data)) { // if (!is_array($data)) {
@@ -84,11 +86,10 @@ class Configuration implements ConfigurationInterface
// }) // })
// ->thenInvalid("The data are invalid. The keys must be a string and the value integers") // ->thenInvalid("The data are invalid. The keys must be a string and the value integers")
// ->end() // ->end()
->end() ->end()
->end() ->end()
->end()
->end() ->end();
->end();
return $treeBuilder; return $treeBuilder;
} }

View File

@@ -1,557 +1,331 @@
<?php <?php
/* /**
* Chill is a software for social workers
* *
* Copyright (C) 2015, Champs Libres Cooperative SCRLFS, <http://www.champs-libres.coop> * For the full copyright and license information, please view
* * the LICENSE file that was distributed with this source code.
* 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\Entity; namespace Chill\ActivityBundle\Entity;
use Chill\DocStoreBundle\Entity\Document;
use Chill\DocStoreBundle\Entity\StoredObject;
use Chill\MainBundle\Entity\Embeddable\CommentEmbeddable;
use Chill\PersonBundle\AccompanyingPeriod\SocialIssueConsistency\AccompanyingPeriodLinkedWithSocialIssuesEntityInterface;
use Chill\PersonBundle\Entity\AccompanyingPeriod;
use Chill\PersonBundle\Entity\SocialWork\SocialAction;
use Chill\PersonBundle\Entity\SocialWork\SocialIssue;
use Chill\ThirdPartyBundle\Entity\ThirdParty;
use Doctrine\ORM\Mapping as ORM;
use Chill\MainBundle\Entity\Scope;
use Chill\MainBundle\Entity\User;
use Chill\MainBundle\Entity\Center; use Chill\MainBundle\Entity\Center;
use Chill\PersonBundle\Entity\Person; use Chill\MainBundle\Entity\Embeddable\CommentEmbeddable;
use Chill\MainBundle\Entity\HasCenterInterface; use Chill\MainBundle\Entity\HasCenterInterface;
use Chill\MainBundle\Entity\HasScopeInterface; use Chill\MainBundle\Entity\HasScopeInterface;
use Doctrine\Common\Collections\Collection; use Chill\MainBundle\Entity\Scope;
use Doctrine\Common\Collections\ArrayCollection; use Chill\MainBundle\Entity\User;
use Chill\MainBundle\Validator\Constraints\Entity\UserCircleConsistency; use Chill\MainBundle\Validator\Constraints\Entity\UserCircleConsistency;
use Symfony\Component\Serializer\Annotation\Groups; use Chill\PersonBundle\Entity\Person;
use Symfony\Component\Serializer\Annotation\DiscriminatorMap; use DateTime;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\Common\Collections\Collection;
use Doctrine\ORM\Mapping as ORM;
/** /**
* Class Activity * Class Activity.
* *
* @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
* @DiscriminatorMap(typeProperty="type", mapping={
* "activity"=Activity::class
* })
*/
/*
* TODO : revoir
* @UserCircleConsistency( * @UserCircleConsistency(
* "CHILL_ACTIVITY_SEE_DETAILS", * "CHILL_ACTIVITY_SEE_DETAILS",
* getUserFunction="getUser", * getUserFunction="getUser",
* path="scope") * path="scope")
*/ */
class Activity implements HasCenterInterface, HasScopeInterface
class Activity implements HasCenterInterface, HasScopeInterface, AccompanyingPeriodLinkedWithSocialIssuesEntityInterface
{ {
const SENTRECEIVED_SENT = 'sent';
const SENTRECEIVED_RECEIVED = 'received';
/** /**
* @ORM\Id * @var bool
* @ORM\Column(name="id", type="integer") * @ORM\Column(type="boolean")
* @ORM\GeneratedValue(strategy="AUTO")
* @Groups({"read"})
*/ */
private ?int $id = null; private $attendee;
/**
* @ORM\ManyToOne(targetEntity="Chill\MainBundle\Entity\User")
*/
private User $user;
/**
* @ORM\Column(type="datetime")
*/
private \DateTime $date;
/**
* @ORM\Column(type="time", nullable=true)
*/
private ?\DateTime $durationTime = null;
/**
* @ORM\Column(type="time", nullable=true)
*/
private ?\DateTime $travelTime = null;
/**
* @ORM\ManyToOne(targetEntity="Chill\ActivityBundle\Entity\ActivityPresence")
*/
private ?ActivityPresence $attendee = null;
/**
* @ORM\ManyToMany(targetEntity="Chill\ActivityBundle\Entity\ActivityReason")
*/
private Collection $reasons;
/**
* @ORM\ManyToMany(targetEntity="Chill\PersonBundle\Entity\SocialWork\SocialIssue")
* @ORM\JoinTable(name="chill_activity_activity_chill_person_socialissue")
* @Groups({"read"})
*/
private Collection $socialIssues;
/**
* @ORM\ManyToMany(targetEntity="Chill\PersonBundle\Entity\SocialWork\SocialAction")
* @ORM\JoinTable(name="chill_activity_activity_chill_person_socialaction")
* @Groups({"read"})
*/
private Collection $socialActions;
/**
* @ORM\ManyToOne(targetEntity="Chill\ActivityBundle\Entity\ActivityType")
*/
private ActivityType $type;
/**
* @ORM\ManyToOne(targetEntity="Chill\MainBundle\Entity\Scope")
*/
private ?Scope $scope = null;
/**
* @ORM\ManyToOne(targetEntity="Chill\PersonBundle\Entity\Person")
*/
private ?Person $person = null;
/**
* @ORM\ManyToOne(targetEntity="Chill\PersonBundle\Entity\AccompanyingPeriod")
* @Groups({"read"})
*/
private ?AccompanyingPeriod $accompanyingPeriod = null;
/** /**
* @ORM\Embedded(class="Chill\MainBundle\Entity\Embeddable\CommentEmbeddable", columnPrefix="comment_") * @ORM\Embedded(class="Chill\MainBundle\Entity\Embeddable\CommentEmbeddable", columnPrefix="comment_")
*/ */
private CommentEmbeddable $comment; private $comment;
/** /**
* @ORM\ManyToMany(targetEntity="Chill\PersonBundle\Entity\Person") * @var DateTime
* @Groups({"read"}) * @ORM\Column(type="datetime")
*/ */
private ?Collection $persons = null; private $date;
/** /**
* @ORM\ManyToMany(targetEntity="Chill\ThirdPartyBundle\Entity\ThirdParty") * @var DateTime
* @Groups({"read"}) * @ORM\Column(type="time")
*/ */
private ?Collection $thirdParties = null; private $durationTime;
/** /**
* @ORM\ManyToMany(targetEntity="Chill\DocStoreBundle\Entity\StoredObject") * @var int
*
* @ORM\Id
* @ORM\Column(name="id", type="integer")
* @ORM\GeneratedValue(strategy="AUTO")
*/ */
private Collection $documents; private $id;
/** /**
* @ORM\ManyToMany(targetEntity="Chill\MainBundle\Entity\User") * @var Person
* @Groups({"read"}) * @ORM\ManyToOne(targetEntity="Chill\PersonBundle\Entity\Person")
*/ */
private ?Collection $users = null; private $person;
/** /**
* @ORM\Column(type="boolean", options={"default"=false}) * @var ActivityReason
* @ORM\ManyToMany(targetEntity="Chill\ActivityBundle\Entity\ActivityReason")
*/ */
private bool $emergency = false; private $reasons;
/** /**
* @ORM\Column(type="string", options={"default"=""}) * @var Scope
* @ORM\ManyToOne(targetEntity="Chill\MainBundle\Entity\Scope")
*/ */
private string $sentReceived = ''; private $scope;
/**
* @var ActivityType
* @ORM\ManyToOne(targetEntity="Chill\ActivityBundle\Entity\ActivityType")
*/
private $type;
/**
* @var User
* @ORM\ManyToOne(targetEntity="Chill\MainBundle\Entity\User")
*/
private $user;
/**
* Activity constructor.
*/
public function __construct() public function __construct()
{ {
$this->reasons = new ArrayCollection(); $this->reasons = new ArrayCollection();
$this->comment = new CommentEmbeddable(); $this->comment = new CommentEmbeddable();
$this->persons = new ArrayCollection();
$this->thirdParties = new ArrayCollection();
$this->documents = new ArrayCollection();
$this->users = new ArrayCollection();
$this->socialIssues = new ArrayCollection();
$this->socialActions = new ArrayCollection();
} }
public function getId(): ?int /**
* Add a reason.
*
* @return Activity
*/
public function addReason(ActivityReason $reason)
{ {
return $this->id; $this->reasons[] = $reason;
}
public function setUser(User $user): self
{
$this->user = $user;
return $this; return $this;
} }
public function getUser(): User /**
* Get attendee.
*
* @return bool
*/
public function getAttendee()
{ {
return $this->user; return $this->attendee;
} }
public function setDate(\DateTime $date): self /**
* get the center
* center is extracted from person.
*
* @return Center
*/
public function getCenter()
{ {
$this->date = $date; return $this->person->getCenter();
return $this;
} }
public function getDate(): \DateTime /**
* @return \Chill\MainBundle\Entity\Embeddalbe\CommentEmbeddable
*/
public function getComment()
{
return $this->comment;
}
/**
* Get date.
*
* @return DateTime
*/
public function getDate()
{ {
return $this->date; return $this->date;
} }
public function setDurationTime(?\DateTime $durationTime): self /**
{ * Get durationTime.
$this->durationTime = $durationTime; *
* @return DateTime
return $this; */
} public function getDurationTime()
public function getDurationTime(): ?\DateTime
{ {
return $this->durationTime; return $this->durationTime;
} }
public function setTravelTime(\DateTime $travelTime): self /**
* Get id.
*
* @return int
*/
public function getId()
{ {
$this->travelTime = $travelTime; return $this->id;
return $this;
} }
public function getTravelTime(): ?\DateTime /**
* Get person.
*
* @return Person
*/
public function getPerson()
{ {
return $this->travelTime; return $this->person;
} }
public function setAttendee(ActivityPresence $attendee): self /**
* Get reasons.
*
* @return Collection
*/
public function getReasons()
{
return $this->reasons;
}
/**
* Get scope.
*
* @return Scope
*/
public function getScope()
{
return $this->scope;
}
/**
* Get type.
*
* @return ActivityType
*/
public function getType()
{
return $this->type;
}
/**
* Get user.
*
* @return User
*/
public function getUser()
{
return $this->user;
}
public function removeReason(ActivityReason $reason)
{
$this->reasons->removeElement($reason);
}
/**
* Set attendee.
*
* @param bool $attendee
*
* @return Activity
*/
public function setAttendee($attendee)
{ {
$this->attendee = $attendee; $this->attendee = $attendee;
return $this; return $this;
} }
public function getAttendee(): ?ActivityPresence /**
* @param \Chill\MainBundle\Entity\Embeddalbe\CommentEmbeddable $comment
*/
public function setComment($comment)
{ {
return $this->attendee; $this->comment = $comment;
} }
public function addReason(ActivityReason $reason): self /**
* Set date.
*
* @param DateTime $date
*
* @return Activity
*/
public function setDate($date)
{ {
$this->reasons->add($reason); $this->date = $date;
return $this; return $this;
} }
public function removeReason(ActivityReason $reason): void /**
* Set durationTime.
*
* @param DateTime $durationTime
*
* @return Activity
*/
public function setDurationTime($durationTime)
{ {
$this->reasons->removeElement($reason); $this->durationTime = $durationTime;
}
public function getReasons(): Collection
{
return $this->reasons;
}
public function setReasons(?ArrayCollection $reasons): self
{
$this->reasons = $reasons;
return $this; return $this;
} }
public function getSocialIssues(): Collection /**
{ * Set person.
return $this->socialIssues; *
} * @return Activity
*/
public function addSocialIssue(SocialIssue $socialIssue): self public function setPerson(Person $person)
{
if (!$this->socialIssues->contains($socialIssue)) {
$this->socialIssues[] = $socialIssue;
}
return $this;
}
public function removeSocialIssue(SocialIssue $socialIssue): self
{
$this->socialIssues->removeElement($socialIssue);
return $this;
}
public function getSocialActions(): Collection
{
return $this->socialActions;
}
public function addSocialAction(SocialAction $socialAction): self
{
if (!$this->socialActions->contains($socialAction)) {
$this->socialActions[] = $socialAction;
}
return $this;
}
public function removeSocialAction(SocialAction $socialAction): self
{
$this->socialActions->removeElement($socialAction);
return $this;
}
public function setType(ActivityType $type): self
{
$this->type = $type;
return $this;
}
public function getType(): ActivityType
{
return $this->type;
}
public function setScope(Scope $scope): self
{
$this->scope = $scope;
return $this;
}
public function getScope(): ?Scope
{
return $this->scope;
}
public function setPerson(?Person $person): self
{ {
$this->person = $person; $this->person = $person;
return $this; return $this;
} }
public function getPerson(): ?Person /**
* Set scope.
*
* @return Activity
*/
public function setScope(Scope $scope)
{ {
return $this->person; $this->scope = $scope;
}
public function getAccompanyingPeriod(): ?AccompanyingPeriod
{
return $this->accompanyingPeriod;
}
public function setAccompanyingPeriod(?AccompanyingPeriod $accompanyingPeriod): self
{
$this->accompanyingPeriod = $accompanyingPeriod;
return $this; return $this;
} }
/** /**
* get the center * Set type.
* center is extracted from person *
* @return Activity
*/ */
public function getCenter(): ?Center public function setType(ActivityType $type)
{ {
if ($this->person instanceof Person) { $this->type = $type;
return $this->person->getCenter();
}
return null;
}
public function getComment(): CommentEmbeddable
{
return $this->comment;
}
public function setComment(CommentEmbeddable $comment): self
{
$this->comment = $comment;
return $this; return $this;
} }
/** /**
* Add a person to the person list * Set user.
*
* @return Activity
*/ */
public function addPerson(?Person $person): self public function setUser(User $user)
{ {
if (null !== $person) { $this->user = $user;
$this->persons[] = $person;
}
return $this;
}
public function removePerson(Person $person): void
{
$this->persons->removeElement($person);
}
public function getPersons(): Collection
{
return $this->persons;
}
public function getPersonsAssociated(): array
{
if (null !== $this->accompanyingPeriod) {
$personsAssociated = [];
foreach ($this->accompanyingPeriod->getParticipations() as $participation) {
if ($this->persons->contains($participation->getPerson())) {
$personsAssociated[] = $participation->getPerson();
}
}
return $personsAssociated;
}
return [];
}
public function getPersonsNotAssociated(): array
{
if (null !== $this->accompanyingPeriod) {
$personsNotAssociated = [];
foreach ($this->persons as $person) {
if (!in_array($person, $this->getPersonsAssociated())) {
$personsNotAssociated[] = $person;
}
}
return $personsNotAssociated;
}
return [];
}
public function setPersons(?Collection $persons): self
{
$this->persons = $persons;
return $this;
}
public function addThirdParty(?ThirdParty $thirdParty): self
{
if (null !== $thirdParty) {
$this->thirdParties[] = $thirdParty;
}
return $this;
}
public function removeThirdParty(ThirdParty $thirdParty): void
{
$this->thirdParties->removeElement($thirdParty);
}
public function getThirdParties(): Collection
{
return $this->thirdParties;
}
public function setThirdParties(?Collection $thirdParties): self
{
$this->thirdParties = $thirdParties;
return $this;
}
public function addDocument(Document $document): self
{
$this->documents[] = $document;
return $this;
}
public function removeDocument(Document $document): void
{
$this->documents->removeElement($document);
}
public function getDocuments(): Collection
{
return $this->documents;
}
public function setDocuments(Collection $documents): self
{
$this->documents = $documents;
return $this;
}
public function addUser(?User $user): self
{
if (null !== $user) {
$this->users[] = $user;
}
return $this;
}
public function removeUser(User $user): void
{
$this->users->removeElement($user);
}
public function getUsers(): Collection
{
return $this->users;
}
public function setUsers(?Collection $users): self
{
$this->users = $users;
return $this;
}
public function isEmergency(): bool
{
return $this->getEmergency();
}
public function getEmergency(): bool
{
return $this->emergency;
}
public function setEmergency(bool $emergency): self
{
$this->emergency = $emergency;
return $this;
}
public function getSentReceived(): string
{
return $this->sentReceived;
}
public function setSentReceived(?string $sentReceived): self
{
$this->sentReceived = (string) $sentReceived;
return $this; return $this;
} }

View File

@@ -1,97 +0,0 @@
<?php
/*
*
* Copyright (C) 2015, Champs Libres Cooperative SCRLFS, <http://www.champs-libres.coop>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
namespace Chill\ActivityBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
/**
* Class ActivityPresence
*
* @package Chill\ActivityBundle\Entity
* @ORM\Entity()
* @ORM\Table(name="activitytpresence")
* @ORM\HasLifecycleCallbacks()
*/
class ActivityPresence
{
/**
* @ORM\Id
* @ORM\Column(name="id", type="integer")
* @ORM\GeneratedValue(strategy="AUTO")
*/
private ?int $id;
/**
* @ORM\Column(type="json")
*/
private array $name = [];
/**
* @ORM\Column(type="boolean")
*/
private bool $active = true;
public function getId(): int
{
return $this->id;
}
public function setName(array $name): self
{
$this->name = $name;
return $this;
}
public function getName(): array
{
return $this->name;
}
/**
* Get active
* return true if the category type is active.
*/
public function getActive(): bool
{
return $this->active;
}
/**
* Is active
* return true if the category type is active
*/
public function isActive(): bool
{
return $this->getActive();
}
/**
* Set active
* set to true if the category type is active
*/
public function setActive(bool $active): self
{
$this->active = $active;
return $this;
}
}

View File

@@ -1,40 +1,41 @@
<?php <?php
/* /**
* * Chill is a software for social workers
* Copyright (C) 2015, Champs Libres Cooperative SCRLFS, <http://www.champs-libres.coop> *
* * For the full copyright and license information, please view
* This program is free software: you can redistribute it and/or modify * the LICENSE file that was distributed with this source code.
* 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\Entity; namespace Chill\ActivityBundle\Entity;
use Doctrine\ORM\Mapping as ORM; use Doctrine\ORM\Mapping as ORM;
use Chill\ActivityBundle\Entity\ActivityReasonCategory;
/** /**
* Class ActivityReason * Class ActivityReason.
* *
* @package Chill\ActivityBundle\Entity * @ORM\Entity
* @ORM\Entity()
* @ORM\Table(name="activityreason") * @ORM\Table(name="activityreason")
* @ORM\HasLifecycleCallbacks() * @ORM\HasLifecycleCallbacks
*/ */
class ActivityReason class ActivityReason
{ {
/** /**
* @var integer * @var bool
* @ORM\Column(type="boolean")
*/
private $active = true;
/**
* @var ActivityReasonCategory
* @ORM\ManyToOne(
* targetEntity="Chill\ActivityBundle\Entity\ActivityReasonCategory",
* inversedBy="reasons")
*/
private $category;
/**
* @var int
* *
* @ORM\Id * @ORM\Id
* @ORM\Column(name="id", type="integer") * @ORM\Column(name="id", type="integer")
@@ -49,86 +50,17 @@ class ActivityReason
private $name; private $name;
/** /**
* @var ActivityReasonCategory * Get active.
* @ORM\ManyToOne(
* targetEntity="Chill\ActivityBundle\Entity\ActivityReasonCategory",
* inversedBy="reasons")
*/
private $category;
/**
* @var boolean
* @ORM\Column(type="boolean")
*/
private $active = true;
/**
* Get id
* *
* @return integer * @return bool
*/ */
public function getId() public function getActive()
{ {
return $this->id; return $this->active;
} }
/** /**
* Set name * Get category.
*
* @param array $name
* @return ActivityReason
*/
public function setName($name)
{
$this->name = $name;
return $this;
}
/**
* Get name
*
* @return array | string
*/
public function getName($locale = null)
{
if ($locale) {
if (isset($this->name[$locale])) {
return $this->name[$locale];
} else {
foreach ($this->name as $name) {
if (!empty($name)) {
return $name;
}
}
}
return '';
} else {
return $this->name;
}
}
/**
* Set category of the reason. If you set to the reason an inactive
* category, the reason will become inactive
*
* @param ActivityReasonCategory $category
* @return ActivityReason
*/
public function setCategory(ActivityReasonCategory $category)
{
if($this->category !== $category && ! $category->getActive()) {
$this->setActive(False);
}
$this->category = $category;
return $this;
}
/**
* Get category
* *
* @return ActivityReasonCategory * @return ActivityReasonCategory
*/ */
@@ -138,9 +70,46 @@ class ActivityReason
} }
/** /**
* Set active * Get id.
*
* @return int
*/
public function getId()
{
return $this->id;
}
/**
* Get name.
*
* @param mixed|null $locale
*
* @return array | string
*/
public function getName($locale = null)
{
if ($locale) {
if (isset($this->name[$locale])) {
return $this->name[$locale];
}
foreach ($this->name as $name) {
if (!empty($name)) {
return $name;
}
}
return '';
}
return $this->name;
}
/**
* Set active.
*
* @param bool $active
* *
* @param boolean $active
* @return ActivityReason * @return ActivityReason
*/ */
public function setActive($active) public function setActive($active)
@@ -151,13 +120,33 @@ class ActivityReason
} }
/** /**
* Get active * Set category of the reason. If you set to the reason an inactive
* category, the reason will become inactive.
* *
* @return boolean * @return ActivityReason
*/ */
public function getActive() public function setCategory(ActivityReasonCategory $category)
{ {
return $this->active; if ($this->category !== $category && !$category->getActive()) {
$this->setActive(false);
}
$this->category = $category;
return $this;
}
/**
* Set name.
*
* @param array $name
*
* @return ActivityReason
*/
public function setName($name)
{
$this->name = $name;
return $this;
} }
} }

View File

@@ -1,39 +1,34 @@
<?php <?php
/* /**
* Copyright (C) 2015, Champs Libres Cooperative SCRLFS, <http://www.champs-libres.coop> * Chill is a software for social workers
* *
* This program is free software: you can redistribute it and/or modify * For the full copyright and license information, please view
* it under the terms of the GNU Affero General Public License as * the LICENSE file that was distributed with this source code.
* 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\Entity; namespace Chill\ActivityBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
use Doctrine\Common\Collections\ArrayCollection; use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\ORM\Mapping as ORM;
/** /**
* Class ActivityReasonCategory * Class ActivityReasonCategory.
* *
* @package Chill\ActivityBundle\Entity * @ORM\Entity
* @ORM\Entity()
* @ORM\Table(name="activityreasoncategory") * @ORM\Table(name="activityreasoncategory")
* @ORM\HasLifecycleCallbacks() * @ORM\HasLifecycleCallbacks
*/ */
class ActivityReasonCategory class ActivityReasonCategory
{ {
/** /**
* @var integer * @var bool
* @ORM\Column(type="boolean")
*/
private $active = true;
/**
* @var int
* *
* @ORM\Id * @ORM\Id
* @ORM\Column(name="id", type="integer") * @ORM\Column(name="id", type="integer")
@@ -48,20 +43,15 @@ class ActivityReasonCategory
private $name; private $name;
/** /**
* @var boolean * Array of ActivityReason.
* @ORM\Column(type="boolean") *
*/
private $active = true;
/**
* Array of ActivityReason
* @var ArrayCollection * @var ArrayCollection
* @ORM\OneToMany( * @ORM\OneToMany(
* targetEntity="Chill\ActivityBundle\Entity\ActivityReason", * targetEntity="Chill\ActivityBundle\Entity\ActivityReason",
* mappedBy="category") * mappedBy="category")
*/ */
private $reasons; private $reasons;
/** /**
* ActivityReasonCategory constructor. * ActivityReasonCategory constructor.
*/ */
@@ -69,19 +59,29 @@ class ActivityReasonCategory
{ {
$this->reasons = new ArrayCollection(); $this->reasons = new ArrayCollection();
} }
/** /**
* @return string * @return string
*/ */
public function __toString() public function __toString()
{ {
return 'ActivityReasonCategory('.$this->getName('x').')'; return 'ActivityReasonCategory(' . $this->getName('x') . ')';
} }
/** /**
* Get id * Get active.
* *
* @return integer * @return bool
*/
public function getActive()
{
return $this->active;
}
/**
* Get id.
*
* @return int
*/ */
public function getId() public function getId()
{ {
@@ -89,20 +89,9 @@ class ActivityReasonCategory
} }
/** /**
* Set name * Get name.
* *
* @param array $name * @param mixed|null $locale
* @return ActivityReasonCategory
*/
public function setName($name)
{
$this->name = $name;
return $this;
}
/**
* Get name
* *
* @return array * @return array
*/ */
@@ -111,48 +100,53 @@ class ActivityReasonCategory
if ($locale) { if ($locale) {
if (isset($this->name[$locale])) { if (isset($this->name[$locale])) {
return $this->name[$locale]; return $this->name[$locale];
} else { }
foreach ($this->name as $name) {
if (!empty($name)) { foreach ($this->name as $name) {
return $name; if (!empty($name)) {
} return $name;
} }
} }
return ''; return '';
} else {
return $this->name;
} }
return $this->name;
} }
/** /**
* Declare a category as active (or not). When a category is set * Declare a category as active (or not). When a category is set
* as unactive, all the reason have this entity as category is also * as unactive, all the reason have this entity as category is also
* set as unactive * set as unactive.
*
* @param bool $active
* *
* @param boolean $active
* @return ActivityReasonCategory * @return ActivityReasonCategory
*/ */
public function setActive($active) public function setActive($active)
{ {
if($this->active !== $active && !$active) { if ($this->active !== $active && !$active) {
foreach ($this->reasons as $reason) { foreach ($this->reasons as $reason) {
$reason->setActive($active); $reason->setActive($active);
} }
} }
$this->active = $active; $this->active = $active;
return $this; return $this;
} }
/** /**
* Get active * Set name.
* *
* @return boolean * @param array $name
*
* @return ActivityReasonCategory
*/ */
public function getActive() public function setName($name)
{ {
return $this->active; $this->name = $name;
return $this;
} }
} }

View File

@@ -1,21 +1,10 @@
<?php <?php
/* /**
* Chill is a software for social workers
* *
* Copyright (C) 2015, Champs Libres Cooperative SCRLFS, <http://www.champs-libres.coop> * For the full copyright and license information, please view
* * the LICENSE file that was distributed with this source code.
* 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\Entity; namespace Chill\ActivityBundle\Entity;
@@ -23,800 +12,118 @@ namespace Chill\ActivityBundle\Entity;
use Doctrine\ORM\Mapping as ORM; use Doctrine\ORM\Mapping as ORM;
/** /**
* Class ActivityType * Class ActivityType.
* *
* @package Chill\ActivityBundle\Entity * @ORM\Entity
* @ORM\Entity()
* @ORM\Table(name="activitytype") * @ORM\Table(name="activitytype")
* @ORM\HasLifecycleCallbacks() * @ORM\HasLifecycleCallbacks
*/ */
class ActivityType class ActivityType
{ {
const FIELD_INVISIBLE = 0; /**
const FIELD_OPTIONAL = 1; * @var bool
const FIELD_REQUIRED = 2; * @ORM\Column(type="boolean")
*/
private $active = true;
/** /**
* @var int
*
* @ORM\Id * @ORM\Id
* @ORM\Column(name="id", type="integer") * @ORM\Column(name="id", type="integer")
* @ORM\GeneratedValue(strategy="AUTO") * @ORM\GeneratedValue(strategy="AUTO")
*/ */
private ?int $id; private $id;
/** /**
* @var array
* @ORM\Column(type="json_array") * @ORM\Column(type="json_array")
*/ */
private array $name = []; private $name;
/**
* @ORM\Column(type="boolean")
*/
private bool $active = true;
/**
* @ORM\ManyToOne(targetEntity="Chill\ActivityBundle\Entity\ActivityTypeCategory")
*/
private ?ActivityTypeCategory $category = null;
/**
* @ORM\Column(type="smallint", nullable=false, options={"default"=2})
*/
private int $personVisible = self::FIELD_REQUIRED;
/**
* @ORM\Column(type="string", nullable=false, options={"default"=""})
*/
private string $personLabel = '';
/**
* @ORM\Column(type="smallint", nullable=false, options={"default"=2})
*/
private int $userVisible = self::FIELD_REQUIRED;
/**
* @ORM\Column(type="string", nullable=false, options={"default"=""})
*/
private string $userLabel = '';
/**
* @ORM\Column(type="smallint", nullable=false, options={"default"=2})
*/
private int $dateVisible = self::FIELD_REQUIRED;
/**
* @ORM\Column(type="string", nullable=false, options={"default"=""})
*/
private string $dateLabel = '';
/**
* @ORM\Column(type="smallint", nullable=false, options={"default"=1})
*/
private int $placeVisible = self::FIELD_OPTIONAL;
/**
* @ORM\Column(type="string", nullable=false, options={"default"=""})
*/
private string $placeLabel = '';
/**
* @ORM\Column(type="smallint", nullable=false, options={"default"=1})
*/
private int $personsVisible = self::FIELD_OPTIONAL;
/**
* @ORM\Column(type="string", nullable=false, options={"default"=""})
*/
private string $personsLabel = '';
/**
* @ORM\Column(type="smallint", nullable=false, options={"default"=1})
*/
private int $thirdPartiesVisible = self::FIELD_INVISIBLE;
/**
* @ORM\Column(type="string", nullable=false, options={"default"=""})
*/
private string $thirdPartiesLabel = '';
/**
* @ORM\Column(type="smallint", nullable=false, options={"default"=1})
*/
private int $durationTimeVisible = self::FIELD_OPTIONAL;
/**
* @ORM\Column(type="string", nullable=false, options={"default"=""})
*/
private string $durationTimeLabel = '';
/**
* @ORM\Column(type="smallint", nullable=false, options={"default"=1})
*/
private int $travelTimeVisible = self::FIELD_OPTIONAL;
/**
* @ORM\Column(type="string", nullable=false, options={"default"=""})
*/
private string $travelTimeLabel = '';
/**
* @ORM\Column(type="smallint", nullable=false, options={"default"=1})
*/
private int $attendeeVisible = self::FIELD_OPTIONAL;
/**
* @ORM\Column(type="string", nullable=false, options={"default"=""})
*/
private string $attendeeLabel = '';
/**
* @ORM\Column(type="smallint", nullable=false, options={"default"=1})
*/
private int $reasonsVisible = self::FIELD_OPTIONAL;
/**
* @ORM\Column(type="string", nullable=false, options={"default"=""})
*/
private string $reasonsLabel = '';
/**
* @ORM\Column(type="smallint", nullable=false, options={"default"=1})
*/
private int $commentVisible = self::FIELD_OPTIONAL;
/**
* @ORM\Column(type="string", nullable=false, options={"default"=""})
*/
private string $commentLabel = '';
/**
* @ORM\Column(type="smallint", nullable=false, options={"default"=1})
*/
private int $sentReceivedVisible = self::FIELD_OPTIONAL;
/**
* @ORM\Column(type="string", nullable=false, options={"default"=""})
*/
private string $sentReceivedLabel = '';
/**
* @ORM\Column(type="smallint", nullable=false, options={"default"=1})
*/
private int $documentsVisible = self::FIELD_OPTIONAL;
/**
* @ORM\Column(type="string", nullable=false, options={"default"=""})
*/
private string $documentsLabel = '';
/**
* @ORM\Column(type="smallint", nullable=false, options={"default"=1})
*/
private int $usersVisible = self::FIELD_OPTIONAL;
/**
* @ORM\Column(type="string", nullable=false, options={"default"=""})
*/
private string $usersLabel = '';
/**
* @ORM\Column(type="smallint", nullable=false, options={"default"=1})
*/
private int $emergencyVisible = self::FIELD_INVISIBLE;
/**
* @ORM\Column(type="string", nullable=false, options={"default"=""})
*/
private string $emergencyLabel = '';
/**
* @ORM\Column(type="smallint", nullable=false, options={"default"=1})
*/
private int $accompanyingPeriodVisible = self::FIELD_INVISIBLE;
/**
* @ORM\Column(type="string", nullable=false, options={"default"=""})
*/
private string $accompanyingPeriodLabel = '';
/**
* @ORM\Column(type="smallint", nullable=false, options={"default"=1})
*/
private int $socialDataVisible = self::FIELD_INVISIBLE;
/**
* @ORM\Column(type="string", nullable=false, options={"default"=""})
*/
private string $socialDataLabel = '';
/**
* @ORM\Column(type="smallint", nullable=false, options={"default"=1})
*/
private int $socialIssuesVisible = self::FIELD_INVISIBLE;
/**
* @ORM\Column(type="string", nullable=false, options={"default"=""})
*/
private string $socialIssuesLabel = '';
/**
* @ORM\Column(type="smallint", nullable=false, options={"default"=1})
*/
private int $socialActionsVisible = self::FIELD_INVISIBLE;
/**
* @ORM\Column(type="string", nullable=false, options={"default"=""})
*/
private string $socialActionsLabel = '';
/**
* @ORM\Column(type="float", options={"default"="0.0"})
*/
private float $ordering = 0.0;
/**
* Get id
*/
public function getId(): int
{
return $this->id;
}
/**
* Set name
*/
public function setName(array $name): self
{
$this->name = $name;
return $this;
}
/**
* Get name
*/
public function getName(): array
{
return $this->name;
}
/** /**
* Get active * Get active
* return true if the type is active. * return true if the type is active.
*
* @return bool
*/ */
public function getActive(): bool public function getActive()
{ {
return $this->active; return $this->active;
} }
/** /**
* Is active * Get id.
* return true if the type is active *
* @return int
*/ */
public function isActive(): bool public function getId()
{
return $this->id;
}
/**
* Get name.
*
* @param mixed|null $locale
*
* @return array | string
*/
public function getName($locale = null)
{
if ($locale) {
if (isset($this->name[$locale])) {
return $this->name[$locale];
}
foreach ($this->name as $name) {
if (!empty($name)) {
return $name;
}
}
return '';
}
return $this->name;
}
/**
* Is active
* return true if the type is active.
*
* @return bool
*/
public function isActive()
{ {
return $this->getActive(); return $this->getActive();
} }
/** /**
* Set active * Set active
* set to true if the type is active * set to true if the type is active.
*
* @param bool $active
*
* @return ActivityType
*/ */
public function setActive(bool $active): self public function setActive($active)
{ {
$this->active = $active; $this->active = $active;
return $this; return $this;
} }
public function getCategory(): ?ActivityTypeCategory /**
{ * Set name.
return $this->category; *
} * @param array $name
*
public function setCategory(?ActivityTypeCategory $category): self * @return ActivityType
{ */
$this->category = $category; public function setName($name)
{
return $this; $this->name = $name;
}
public function getPersonVisible(): int
{
return $this->personVisible;
}
public function setPersonVisible(int $personVisible): self
{
$this->personVisible = $personVisible;
return $this;
}
public function getPersonLabel(): string
{
return $this->personLabel;
}
public function setPersonLabel(string $personLabel): self
{
$this->personLabel = $personLabel;
return $this;
}
public function getUserVisible(): int
{
return $this->userVisible;
}
public function setUserVisible(int $userVisible): self
{
$this->userVisible = $userVisible;
return $this;
}
public function getUserLabel(): string
{
return $this->userLabel;
}
public function setUserLabel(string $userLabel): self
{
$this->userLabel = $userLabel;
return $this;
}
public function getDateVisible(): int
{
return $this->dateVisible;
}
public function setDateVisible(int $dateVisible): self
{
$this->dateVisible = $dateVisible;
return $this;
}
public function getDateLabel(): string
{
return $this->dateLabel;
}
public function setDateLabel(string $dateLabel): self
{
$this->dateLabel = $dateLabel;
return $this;
}
public function getPlaceVisible(): int
{
return $this->placeVisible;
}
public function setPlaceVisible(int $placeVisible): self
{
$this->placeVisible = $placeVisible;
return $this;
}
public function getPlaceLabel(): string
{
return $this->placeLabel;
}
public function setPlaceLabel(string $placeLabel): self
{
$this->placeLabel = $placeLabel;
return $this;
}
public function getPersonsVisible(): int
{
return $this->personsVisible;
}
public function setPersonsVisible(int $personsVisible): self
{
$this->personsVisible = $personsVisible;
return $this;
}
public function getPersonsLabel(): string
{
return $this->personsLabel;
}
public function setPersonsLabel(string $personsLabel): self
{
$this->personsLabel = $personsLabel;
return $this;
}
public function getThirdPartiesVisible(): int
{
return $this->thirdPartiesVisible;
}
public function setThirdPartiesVisible(int $thirdPartiesVisible): self
{
$this->thirdPartiesVisible = $thirdPartiesVisible;
return $this;
}
public function getThirdPartiesLabel(): string
{
return $this->thirdPartiesLabel;
}
public function setThirdPartiesLabel(string $thirdPartiesLabel): self
{
$this->thirdPartiesLabel = $thirdPartiesLabel;
return $this;
}
public function getDurationTimeVisible(): int
{
return $this->durationTimeVisible;
}
public function setDurationTimeVisible(int $durationTimeVisible): self
{
$this->durationTimeVisible = $durationTimeVisible;
return $this;
}
public function getDurationTimeLabel(): string
{
return $this->durationTimeLabel;
}
public function setDurationTimeLabel(string $durationTimeLabel): self
{
$this->durationTimeLabel = $durationTimeLabel;
return $this;
}
public function getTravelTimeVisible(): int
{
return $this->travelTimeVisible;
}
public function setTravelTimeVisible(int $TravelTimeVisible): self
{
$this->travelTimeVisible = $TravelTimeVisible;
return $this;
}
public function getTravelTimeLabel(): string
{
return $this->travelTimeLabel;
}
public function setTravelTimeLabel(string $TravelTimeLabel): self
{
$this->travelTimeLabel = $TravelTimeLabel;
return $this;
}
public function getAttendeeVisible(): int
{
return $this->attendeeVisible;
}
public function setAttendeeVisible(int $attendeeVisible): self
{
$this->attendeeVisible = $attendeeVisible;
return $this;
}
public function getAttendeeLabel(): string
{
return $this->attendeeLabel;
}
public function setAttendeeLabel(string $attendeeLabel): self
{
$this->attendeeLabel = $attendeeLabel;
return $this;
}
public function getReasonsVisible(): int
{
return $this->reasonsVisible;
}
public function setReasonsVisible(int $reasonsVisible): self
{
$this->reasonsVisible = $reasonsVisible;
return $this;
}
public function getReasonsLabel(): string
{
return $this->reasonsLabel;
}
public function setReasonsLabel(string $reasonsLabel): self
{
$this->reasonsLabel = $reasonsLabel;
return $this;
}
public function getCommentVisible(): int
{
return $this->commentVisible;
}
public function setCommentVisible(int $commentVisible): self
{
$this->commentVisible = $commentVisible;
return $this;
}
public function getCommentLabel(): string
{
return $this->commentLabel;
}
public function setCommentLabel(string $commentLabel): self
{
$this->commentLabel = $commentLabel;
return $this;
}
public function getSentReceivedVisible(): int
{
return $this->sentReceivedVisible;
}
public function setSentReceivedVisible(int $sentReceivedVisible): self
{
$this->sentReceivedVisible = $sentReceivedVisible;
return $this;
}
public function getSentReceivedLabel(): string
{
return $this->sentReceivedLabel;
}
public function setSentReceivedLabel(string $sentReceivedLabel): self
{
$this->sentReceivedLabel = $sentReceivedLabel;
return $this;
}
public function getDocumentsVisible(): int
{
return $this->documentsVisible;
}
public function setDocumentsVisible(int $documentsVisible): self
{
$this->documentsVisible = $documentsVisible;
return $this;
}
public function getDocumentsLabel(): string
{
return $this->documentsLabel;
}
public function setDocumentsLabel(string $documentsLabel): self
{
$this->documentsLabel = $documentsLabel;
return $this;
}
public function getUsersVisible(): int
{
return $this->usersVisible;
}
public function setUsersVisible(int $usersVisible): self
{
$this->usersVisible = $usersVisible;
return $this;
}
public function getUsersLabel(): string
{
return $this->usersLabel;
}
public function setUsersLabel(string $usersLabel): self
{
$this->usersLabel = $usersLabel;
return $this;
}
public function getEmergencyVisible(): int
{
return $this->emergencyVisible;
}
public function setEmergencyVisible(int $emergencyVisible): self
{
$this->emergencyVisible = $emergencyVisible;
return $this;
}
public function getEmergencyLabel(): string
{
return $this->emergencyLabel;
}
public function setEmergencyLabel(string $emergencyLabel): self
{
$this->emergencyLabel = $emergencyLabel;
return $this;
}
public function getAccompanyingPeriodVisible(): int
{
return $this->accompanyingPeriodVisible;
}
public function setAccompanyingPeriodVisible(int $accompanyingPeriodVisible): self
{
$this->accompanyingPeriodVisible = $accompanyingPeriodVisible;
return $this;
}
public function getAccompanyingPeriodLabel(): string
{
return $this->accompanyingPeriodLabel;
}
public function setAccompanyingPeriodLabel(string $accompanyingPeriodLabel): self
{
$this->accompanyingPeriodLabel = $accompanyingPeriodLabel;
return $this;
}
public function getSocialDataVisible(): int
{
return $this->socialDataVisible;
}
public function setSocialDataVisible(int $socialDataVisible): self
{
$this->socialDataVisible = $socialDataVisible;
return $this;
}
public function getSocialDataLabel(): string
{
return $this->socialDataLabel;
}
public function setSocialDataLabel(string $socialDataLabel): self
{
$this->socialDataLabel = $socialDataLabel;
return $this;
}
public function isVisible(string $field): bool
{
$property = $field.'Visible';
if (!property_exists($this, $property)) {
throw new \InvalidArgumentException('Field "'.$field.'" not found');
}
return self::FIELD_INVISIBLE !== $this->$property;
}
public function isRequired(string $field): bool
{
$property = $field.'Visible';
if (!property_exists($this, $property)) {
throw new \InvalidArgumentException('Field "'.$field.'" not found');
}
return self::FIELD_REQUIRED === $this->$property;
}
public function getLabel(string $field): ?string
{
$property = $field.'Label';
if (!property_exists($this, $property)) {
throw new \InvalidArgumentException('Field "'.$field.'" not found');
}
return $this->$property;
}
public function getOrdering(): float
{
return $this->ordering;
}
public function setOrdering(float $ordering): self
{
$this->ordering = $ordering;
return $this;
}
public function getSocialIssuesVisible(): ?int
{
return $this->socialIssuesVisible;
}
public function setSocialIssuesVisible(int $socialIssuesVisible): self
{
$this->socialIssuesVisible = $socialIssuesVisible;
return $this;
}
public function getSocialIssuesLabel(): ?string
{
return $this->socialIssuesLabel;
}
public function setSocialIssuesLabel(string $socialIssuesLabel): self
{
$this->socialIssuesLabel = $socialIssuesLabel;
return $this;
}
public function getSocialActionsVisible(): ?int
{
return $this->socialActionsVisible;
}
public function setSocialActionsVisible(int $socialActionsVisible): self
{
$this->socialActionsVisible = $socialActionsVisible;
return $this;
}
public function getSocialActionsLabel(): ?string
{
return $this->socialActionsLabel;
}
public function setSocialActionsLabel(string $socialActionsLabel): self
{
$this->socialActionsLabel = $socialActionsLabel;
return $this; return $this;
} }

View File

@@ -1,123 +0,0 @@
<?php
/*
*
* Copyright (C) 2015, Champs Libres Cooperative SCRLFS, <http://www.champs-libres.coop>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
namespace Chill\ActivityBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
/**
* Class ActivityTypeCateogry
*
* @package Chill\ActivityBundle\Entity
* @ORM\Entity()
* @ORM\Table(name="activitytypecategory")
* @ORM\HasLifecycleCallbacks()
*/
class ActivityTypeCategory
{
/**
* @ORM\Id
* @ORM\Column(name="id", type="integer")
* @ORM\GeneratedValue(strategy="AUTO")
*/
private ?int $id;
/**
* @ORM\Column(type="json_array")
*/
private array $name = [];
/**
* @ORM\Column(type="boolean")
*/
private bool $active = true;
/**
* @ORM\Column(type="float", options={"default"="0.0"})
*/
private float $ordering = 0.0;
/**
* Get id
*/
public function getId(): int
{
return $this->id;
}
/**
* Set name
*/
public function setName(array $name): self
{
$this->name = $name;
return $this;
}
/**
* Get name
*/
public function getName(): array
{
return $this->name;
}
/**
* Get active
* return true if the category type is active.
*/
public function getActive(): bool
{
return $this->active;
}
/**
* Is active
* return true if the category type is active
*/
public function isActive(): bool
{
return $this->getActive();
}
/**
* Set active
* set to true if the category type is active
*/
public function setActive(bool $active): self
{
$this->active = $active;
return $this;
}
public function getOrdering(): float
{
return $this->ordering;
}
public function setOrdering(float $ordering): self
{
$this->ordering = $ordering;
return $this;
}
}

View File

@@ -1,107 +1,96 @@
<?php <?php
/* /**
* Copyright (C) 2016 Champs-Libres <info@champs-libres.coop> * Chill is a software for social workers
* *
* This program is free software: you can redistribute it and/or modify * For the full copyright and license information, please view
* it under the terms of the GNU Affero General Public License as published by * the LICENSE file that was distributed with this source code.
* 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\Export\Aggregator; namespace Chill\ActivityBundle\Export\Aggregator;
use Symfony\Component\Form\FormBuilderInterface;
use Doctrine\ORM\QueryBuilder;
use Chill\MainBundle\Export\AggregatorInterface;
use Symfony\Component\Security\Core\Role\Role;
use Chill\ActivityBundle\Security\Authorization\ActivityStatsVoter; use Chill\ActivityBundle\Security\Authorization\ActivityStatsVoter;
use Doctrine\ORM\EntityRepository; use Chill\MainBundle\Export\AggregatorInterface;
use Chill\MainBundle\Templating\TranslatableStringHelper;
use Doctrine\ORM\Query\Expr\Join;
use Chill\MainBundle\Export\ExportElementValidatedInterface; use Chill\MainBundle\Export\ExportElementValidatedInterface;
use Symfony\Component\Validator\Context\ExecutionContextInterface; use Chill\MainBundle\Templating\TranslatableStringHelper;
use Doctrine\ORM\EntityRepository;
use Doctrine\ORM\Query\Expr\Join;
use Doctrine\ORM\QueryBuilder;
use RuntimeException;
use Symfony\Component\Form\Extension\Core\Type\ChoiceType; use Symfony\Component\Form\Extension\Core\Type\ChoiceType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\Security\Core\Role\Role;
use Symfony\Component\Validator\Context\ExecutionContextInterface;
/** class ActivityReasonAggregator implements
* AggregatorInterface,
*
* @author Julien Fastré <julien.fastre@champs-libres.coop>
*/
class ActivityReasonAggregator implements AggregatorInterface,
ExportElementValidatedInterface ExportElementValidatedInterface
{ {
/** /**
*
* @var EntityRepository * @var EntityRepository
*/ */
protected $categoryRepository; protected $categoryRepository;
/** /**
*
* @var EntityRepository * @var EntityRepository
*/ */
protected $reasonRepository; protected $reasonRepository;
/** /**
*
* @var TranslatableStringHelper * @var TranslatableStringHelper
*/ */
protected $stringHelper; protected $stringHelper;
public function __construct( public function __construct(
EntityRepository $categoryRepository, EntityRepository $categoryRepository,
EntityRepository $reasonRepository, EntityRepository $reasonRepository,
TranslatableStringHelper $stringHelper TranslatableStringHelper $stringHelper
) { ) {
$this->categoryRepository = $categoryRepository; $this->categoryRepository = $categoryRepository;
$this->reasonRepository = $reasonRepository; $this->reasonRepository = $reasonRepository;
$this->stringHelper = $stringHelper; $this->stringHelper = $stringHelper;
}
public function addRole()
{
return new Role(ActivityStatsVoter::STATS);
} }
public function alterQuery(QueryBuilder $qb, $data) public function alterQuery(QueryBuilder $qb, $data)
{ {
// add select element // add select element
if ($data['level'] === 'reasons') { if ('reasons' === $data['level']) {
$elem = 'reasons.id'; $elem = 'reasons.id';
$alias = 'activity_reasons_id'; $alias = 'activity_reasons_id';
} elseif ($data['level'] === 'categories') { } elseif ('categories' === $data['level']) {
$elem = 'category.id'; $elem = 'category.id';
$alias = 'activity_categories_id'; $alias = 'activity_categories_id';
} else { } else {
throw new \RuntimeException('the data provided are not recognized'); throw new RuntimeException('the data provided are not recognized');
} }
$qb->addSelect($elem.' as '.$alias); $qb->addSelect($elem . ' as ' . $alias);
// make a jointure only if needed // make a jointure only if needed
$join = $qb->getDQLPart('join'); $join = $qb->getDQLPart('join');
if ( if (
(array_key_exists('activity', $join) (
&& array_key_exists('activity', $join)
!$this->checkJoinAlreadyDefined($join['activity'], 'reasons') && !$this->checkJoinAlreadyDefined($join['activity'], 'reasons')
) )
OR or (!array_key_exists('activity', $join))
(! array_key_exists('activity', $join))
) { ) {
$qb->add( $qb->add(
'join', 'join',
array('activity' => ['activity' => new Join(Join::INNER_JOIN, 'activity.reasons', 'reasons'),
new Join(Join::INNER_JOIN, 'activity.reasons', 'reasons') ],
), true
true); );
} }
// join category if necessary // join category if necessary
if ($alias === 'activity_categories_id') { if ('activity_categories_id' === $alias) {
// add join only if needed // add join only if needed
if (!$this->checkJoinAlreadyDefined($qb->getDQLPart('join')['activity'], 'category')) { if (!$this->checkJoinAlreadyDefined($qb->getDQLPart('join')['activity'], 'category')) {
$qb->join('reasons.category', 'category'); $qb->join('reasons.category', 'category');
@@ -118,12 +107,109 @@ class ActivityReasonAggregator implements AggregatorInterface,
} }
} }
public function applyOn()
{
return 'activity';
}
public function buildForm(FormBuilderInterface $builder)
{
$builder->add('level', ChoiceType::class, [
'choices' => [
'By reason' => 'reasons',
'By category of reason' => 'categories',
],
'multiple' => false,
'expanded' => true,
'label' => 'Reason\'s level',
]);
}
public function getLabels($key, array $values, $data)
{
// for performance reason, we load data from db only once
switch ($data['level']) {
case 'reasons':
$this->reasonRepository->findBy(['id' => $values]);
break;
case 'categories':
$this->categoryRepository->findBy(['id' => $values]);
break;
default:
throw new RuntimeException(sprintf(
"the level data '%s' is invalid",
$data['level']
));
}
return function ($value) use ($data) {
if ('_header' === $value) {
return 'reasons' === $data['level'] ?
'Group by reasons'
:
'Group by categories of reason';
}
switch ($data['level']) {
case 'reasons':
/* @var $r \Chill\ActivityBundle\Entity\ActivityReason */
$r = $this->reasonRepository->find($value);
return $this->stringHelper->localize($r->getCategory()->getName())
. ' > '
. $this->stringHelper->localize($r->getName());
break;
case 'categories':
$c = $this->categoryRepository->find($value);
return $this->stringHelper->localize($c->getName());
break;
// no need for a default : the default was already set above
}
};
}
public function getQueryKeys($data)
{
// add select element
if ('reasons' === $data['level']) {
return ['activity_reasons_id'];
}
if ('categories' === $data['level']) {
return ['activity_categories_id'];
}
throw new RuntimeException('the data provided are not recognised');
}
public function getTitle()
{
return 'Aggregate by activity reason';
}
public function validateForm($data, ExecutionContextInterface $context)
{
if (null === $data['level']) {
$context->buildViolation("The reasons's level should not be empty")
->addViolation();
}
}
/** /**
* Check if a join between Activity and another alias * Check if a join between Activity and another alias.
* *
* @param Join[] $joins * @param Join[] $joins
* @param string $alias the alias to search for * @param string $alias the alias to search for
* @return boolean *
* @return bool
*/ */
private function checkJoinAlreadyDefined(array $joins, $alias) private function checkJoinAlreadyDefined(array $joins, $alias)
{ {
@@ -135,99 +221,4 @@ class ActivityReasonAggregator implements AggregatorInterface,
return false; return false;
} }
public function applyOn()
{
return 'activity';
}
public function buildForm(FormBuilderInterface $builder)
{
$builder->add('level', ChoiceType::class, array(
'choices' => array(
'By reason' => 'reasons',
'By category of reason' => 'categories'
),
'multiple' => false,
'expanded' => true,
'label' => 'Reason\'s level'
));
}
public function validateForm($data, ExecutionContextInterface $context)
{
if ($data['level'] === null) {
$context->buildViolation("The reasons's level should not be empty")
->addViolation();
}
}
public function getTitle()
{
return "Aggregate by activity reason";
}
public function addRole()
{
return new Role(ActivityStatsVoter::STATS);
}
public function getLabels($key, array $values, $data)
{
// for performance reason, we load data from db only once
switch ($data['level']) {
case 'reasons':
$this->reasonRepository->findBy(array('id' => $values));
break;
case 'categories':
$this->categoryRepository->findBy(array('id' => $values));
break;
default:
throw new \RuntimeException(sprintf("the level data '%s' is invalid",
$data['level']));
}
return function($value) use ($data) {
if ($value === '_header') {
return $data['level'] === 'reasons' ?
'Group by reasons'
:
'Group by categories of reason'
;
}
switch ($data['level']) {
case 'reasons':
/* @var $r \Chill\ActivityBundle\Entity\ActivityReason */
$r = $this->reasonRepository->find($value);
return $this->stringHelper->localize($r->getCategory()->getName())
." > "
. $this->stringHelper->localize($r->getName());
;
break;
case 'categories':
$c = $this->categoryRepository->find($value);
return $this->stringHelper->localize($c->getName());
break;
// no need for a default : the default was already set above
}
};
}
public function getQueryKeys($data)
{
// add select element
if ($data['level'] === 'reasons') {
return array('activity_reasons_id');
} elseif ($data['level'] === 'categories') {
return array ('activity_categories_id');
} else {
throw new \RuntimeException('the data provided are not recognised');
}
}
} }

View File

@@ -1,89 +1,58 @@
<?php <?php
/* /**
* Copyright (C) 2016 Champs-Libres <info@champs-libres.coop> * Chill is a software for social workers
* *
* This program is free software: you can redistribute it and/or modify * For the full copyright and license information, please view
* it under the terms of the GNU Affero General Public License as published by * the LICENSE file that was distributed with this source code.
* 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\Export\Aggregator; namespace Chill\ActivityBundle\Export\Aggregator;
use Symfony\Component\Form\FormBuilderInterface;
use Doctrine\ORM\QueryBuilder;
use Chill\MainBundle\Export\AggregatorInterface;
use Symfony\Component\Security\Core\Role\Role;
use Chill\ActivityBundle\Security\Authorization\ActivityStatsVoter; use Chill\ActivityBundle\Security\Authorization\ActivityStatsVoter;
use Doctrine\ORM\EntityRepository; use Chill\MainBundle\Export\AggregatorInterface;
use Chill\MainBundle\Templating\TranslatableStringHelper; use Chill\MainBundle\Templating\TranslatableStringHelper;
use Doctrine\ORM\EntityRepository;
use Doctrine\ORM\Query\Expr\Join; use Doctrine\ORM\Query\Expr\Join;
use Doctrine\ORM\QueryBuilder;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\Security\Core\Role\Role;
/**
*
*
* @author Julien Fastré <julien.fastre@champs-libres.coop>
*/
class ActivityTypeAggregator implements AggregatorInterface class ActivityTypeAggregator implements AggregatorInterface
{ {
public const KEY = 'activity_type_aggregator';
/** /**
*
* @var EntityRepository
*/
protected $typeRepository;
/**
*
* @var TranslatableStringHelper * @var TranslatableStringHelper
*/ */
protected $stringHelper; protected $stringHelper;
const KEY = 'activity_type_aggregator'; /**
* @var EntityRepository
*/
protected $typeRepository;
public function __construct( public function __construct(
EntityRepository $typeRepository, EntityRepository $typeRepository,
TranslatableStringHelper $stringHelper TranslatableStringHelper $stringHelper
) { ) {
$this->typeRepository = $typeRepository; $this->typeRepository = $typeRepository;
$this->stringHelper = $stringHelper; $this->stringHelper = $stringHelper;
} }
public function addRole()
{
return new Role(ActivityStatsVoter::STATS);
}
public function alterQuery(QueryBuilder $qb, $data) public function alterQuery(QueryBuilder $qb, $data)
{ {
// add select element // add select element
$qb->addSelect(sprintf('IDENTITY(activity.type) AS %s', self::KEY)); $qb->addSelect(sprintf('IDENTITY(activity.type) AS %s', self::KEY));
// add the "group by" part // add the "group by" part
$groupBy = $qb->addGroupBy(self::KEY); $groupBy = $qb->addGroupBy(self::KEY);
} }
/**
* Check if a join between Activity and another alias
*
* @param Join[] $joins
* @param string $alias the alias to search for
* @return boolean
*/
private function checkJoinAlreadyDefined(array $joins, $alias)
{
foreach ($joins as $join) {
if ($join->getAlias() === $alias) {
return true;
}
}
return false;
}
public function applyOn() public function applyOn()
{ {
@@ -95,23 +64,13 @@ class ActivityTypeAggregator implements AggregatorInterface
// no form required for this aggregator // no form required for this aggregator
} }
public function getTitle()
{
return "Aggregate by activity type";
}
public function addRole()
{
return new Role(ActivityStatsVoter::STATS);
}
public function getLabels($key, array $values, $data) public function getLabels($key, array $values, $data)
{ {
// for performance reason, we load data from db only once // for performance reason, we load data from db only once
$this->typeRepository->findBy(array('id' => $values)); $this->typeRepository->findBy(['id' => $values]);
return function($value) use ($data) { return function ($value) {
if ($value === '_header') { if ('_header' === $value) {
return 'Activity type'; return 'Activity type';
} }
@@ -120,12 +79,34 @@ class ActivityTypeAggregator implements AggregatorInterface
return $this->stringHelper->localize($t->getName()); return $this->stringHelper->localize($t->getName());
}; };
} }
public function getQueryKeys($data) public function getQueryKeys($data)
{ {
return array(self::KEY); return [self::KEY];
} }
public function getTitle()
{
return 'Aggregate by activity type';
}
/**
* Check if a join between Activity and another alias.
*
* @param Join[] $joins
* @param string $alias the alias to search for
*
* @return bool
*/
private function checkJoinAlreadyDefined(array $joins, $alias)
{
foreach ($joins as $join) {
if ($join->getAlias() === $alias) {
return true;
}
}
return false;
}
} }

View File

@@ -1,51 +1,37 @@
<?php <?php
/*
* Copyright (C) 2019 Champs Libres Cooperative <info@champs-libres.coop>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
namespace Chill\ActivityBundle\Export\Aggregator;
use Symfony\Component\Form\FormBuilderInterface;
use Doctrine\ORM\QueryBuilder;
use Chill\MainBundle\Export\AggregatorInterface;
use Symfony\Component\Security\Core\Role\Role;
use Doctrine\ORM\Query\Expr\Join;
use Chill\ActivityBundle\Security\Authorization\ActivityStatsVoter;
use Doctrine\ORM\EntityManagerInterface;
use Chill\MainBundle\Entity\User;
/** /**
* * Chill is a software for social workers
* *
* @author Julien Fastré <julien.fastre@champs-libres.coop> * For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/ */
namespace Chill\ActivityBundle\Export\Aggregator;
use Chill\ActivityBundle\Security\Authorization\ActivityStatsVoter;
use Chill\MainBundle\Entity\User;
use Chill\MainBundle\Export\AggregatorInterface;
use Closure;
use Doctrine\ORM\EntityManagerInterface;
use Doctrine\ORM\QueryBuilder;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\Security\Core\Role\Role;
class ActivityUserAggregator implements AggregatorInterface class ActivityUserAggregator implements AggregatorInterface
{ {
public const KEY = 'activity_user_id';
/** /**
*
* @var EntityManagerInterface * @var EntityManagerInterface
*/ */
protected $em; protected $em;
const KEY = 'activity_user_id'; public function __construct(EntityManagerInterface $em)
function __construct(EntityManagerInterface $em)
{ {
$this->em = $em; $this->em = $em;
} }
public function addRole() public function addRole()
{ {
return new Role(ActivityStatsVoter::STATS); return new Role(ActivityStatsVoter::STATS);
@@ -53,9 +39,9 @@ class ActivityUserAggregator implements AggregatorInterface
public function alterQuery(QueryBuilder $qb, $data) public function alterQuery(QueryBuilder $qb, $data)
{ {
// add select element // add select element
$qb->addSelect(sprintf('IDENTITY(activity.user) AS %s', self::KEY)); $qb->addSelect(sprintf('IDENTITY(activity.user) AS %s', self::KEY));
// add the "group by" part // add the "group by" part
$qb->addGroupBy(self::KEY); $qb->addGroupBy(self::KEY);
} }
@@ -70,16 +56,17 @@ class ActivityUserAggregator implements AggregatorInterface
// nothing to add // nothing to add
} }
public function getLabels($key, $values, $data): \Closure public function getLabels($key, $values, $data): Closure
{ {
// preload users at once // preload users at once
$this->em->getRepository(User::class) $this->em->getRepository(User::class)
->findBy(['id' => $values]); ->findBy(['id' => $values]);
return function($value) { return function ($value) {
switch ($value) { switch ($value) {
case '_header': case '_header':
return 'activity user'; return 'activity user';
default: default:
return $this->em->getRepository(User::class)->find($value) return $this->em->getRepository(User::class)->find($value)
->getUsername(); ->getUsername();
@@ -89,11 +76,11 @@ class ActivityUserAggregator implements AggregatorInterface
public function getQueryKeys($data) public function getQueryKeys($data)
{ {
return [ self::KEY ]; return [self::KEY];
} }
public function getTitle(): string public function getTitle(): string
{ {
return "Aggregate by activity user"; return 'Aggregate by activity user';
} }
} }

View File

@@ -1,121 +1,65 @@
<?php <?php
/* /**
* Copyright (C) 2015 Champs-Libres <info@champs-libres.coop> * Chill is a software for social workers
* *
* This program is free software: you can redistribute it and/or modify * For the full copyright and license information, please view
* it under the terms of the GNU Affero General Public License as published by * the LICENSE file that was distributed with this source code.
* 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\Export\Export; namespace Chill\ActivityBundle\Export\Export;
use Chill\MainBundle\Export\ExportInterface;
use Doctrine\ORM\QueryBuilder;
use Symfony\Component\Security\Core\Role\Role;
use Doctrine\ORM\Query;
use Chill\ActivityBundle\Security\Authorization\ActivityStatsVoter; use Chill\ActivityBundle\Security\Authorization\ActivityStatsVoter;
use Chill\MainBundle\Export\ExportInterface;
use Doctrine\ORM\EntityManagerInterface; use Doctrine\ORM\EntityManagerInterface;
use Doctrine\ORM\Query;
use LogicException;
use Symfony\Component\Security\Core\Role\Role;
/**
*
*
* @author Julien Fastré <julien.fastre@champs-libres.coop>
*/
class CountActivity implements ExportInterface class CountActivity implements ExportInterface
{ {
/** /**
*
* @var EntityManagerInterface * @var EntityManagerInterface
*/ */
protected $entityManager; protected $entityManager;
public function __construct( public function __construct(
EntityManagerInterface $em EntityManagerInterface $em
) ) {
{
$this->entityManager = $em; $this->entityManager = $em;
} }
public function buildForm(\Symfony\Component\Form\FormBuilderInterface $builder) public function buildForm(\Symfony\Component\Form\FormBuilderInterface $builder)
{ {
}
public function getDescription()
{
return "Count activities by various parameters.";
}
public function getTitle()
{
return "Count activities";
}
public function getType()
{
return 'activity';
}
public function initiateQuery(array $requiredModifiers, array $acl, array $data = array())
{
$qb = $this->entityManager->createQueryBuilder();
$centers = array_map(function($el) { return $el['center']; }, $acl);
$qb->select('COUNT(activity.id) as export_count_activity')
->from('ChillActivityBundle:Activity', 'activity')
->join('activity.person', 'person')
;
$qb->where($qb->expr()->in('person.center', ':centers'))
->setParameter('centers', $centers)
;
return $qb;
}
public function supportsModifiers()
{
return array('person', 'activity');
}
public function requiredRole()
{
return new Role(ActivityStatsVoter::STATS);
} }
public function getAllowedFormattersTypes() public function getAllowedFormattersTypes()
{ {
return array(\Chill\MainBundle\Export\FormatterInterface::TYPE_TABULAR); return [\Chill\MainBundle\Export\FormatterInterface::TYPE_TABULAR];
}
public function getDescription()
{
return 'Count activities by various parameters.';
} }
public function getLabels($key, array $values, $data) public function getLabels($key, array $values, $data)
{ {
if ($key !== 'export_count_activity') { if ('export_count_activity' !== $key) {
throw new \LogicException("the key $key is not used by this export"); throw new LogicException("the key {$key} is not used by this export");
} }
return function($value) { return function ($value) {
return $value === '_header' ? return '_header' === $value ?
'Number of activities' 'Number of activities'
: :
$value $value;
;
}; };
} }
public function getQueryKeys($data) public function getQueryKeys($data)
{ {
return array('export_count_activity'); return ['export_count_activity'];
} }
public function getResult($qb, $data) public function getResult($qb, $data)
@@ -123,4 +67,40 @@ class CountActivity implements ExportInterface
return $qb->getQuery()->getResult(Query::HYDRATE_SCALAR); return $qb->getQuery()->getResult(Query::HYDRATE_SCALAR);
} }
public function getTitle()
{
return 'Count activities';
}
public function getType()
{
return 'activity';
}
public function initiateQuery(array $requiredModifiers, array $acl, array $data = [])
{
$qb = $this->entityManager->createQueryBuilder();
$centers = array_map(function ($el) {
return $el['center'];
}, $acl);
$qb->select('COUNT(activity.id) as export_count_activity')
->from('ChillActivityBundle:Activity', 'activity')
->join('activity.person', 'person');
$qb->where($qb->expr()->in('person.center', ':centers'))
->setParameter('centers', $centers);
return $qb;
}
public function requiredRole()
{
return new Role(ActivityStatsVoter::STATS);
}
public function supportsModifiers()
{
return ['person', 'activity'];
}
} }

View File

@@ -1,69 +1,42 @@
<?php <?php
/* /**
* Copyright (C) 2017 Champs-Libres <info@champs-libres.coop> * Chill is a software for social workers
* *
* This program is free software: you can redistribute it and/or modify * For the full copyright and license information, please view
* it under the terms of the GNU Affero General Public License as published by * the LICENSE file that was distributed with this source code.
* 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\Export\Export; namespace Chill\ActivityBundle\Export\Export;
use Chill\MainBundle\Export\ListInterface;
use Chill\ActivityBundle\Entity\ActivityReason; use Chill\ActivityBundle\Entity\ActivityReason;
use Chill\MainBundle\Entity\User;
use Chill\MainBundle\Entity\Scope;
use Chill\ActivityBundle\Entity\ActivityType;
use Doctrine\ORM\Query\Expr;
use Chill\MainBundle\Templating\TranslatableStringHelper;
use Symfony\Component\Security\Core\Role\Role;
use Chill\ActivityBundle\Security\Authorization\ActivityStatsVoter; use Chill\ActivityBundle\Security\Authorization\ActivityStatsVoter;
use Symfony\Component\Form\FormBuilderInterface; use Chill\MainBundle\Export\FormatterInterface;
use Chill\MainBundle\Export\ListInterface;
use Chill\MainBundle\Templating\TranslatableStringHelper;
use DateTime;
use Doctrine\ORM\EntityManagerInterface; use Doctrine\ORM\EntityManagerInterface;
use Doctrine\ORM\Query;
use Symfony\Component\Form\Extension\Core\Type\ChoiceType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\Security\Core\Role\Role;
use Symfony\Component\Translation\TranslatorInterface; use Symfony\Component\Translation\TranslatorInterface;
use Symfony\Component\Validator\Constraints\Callback; use Symfony\Component\Validator\Constraints\Callback;
use Doctrine\ORM\Query;
use Chill\MainBundle\Export\FormatterInterface;
use Symfony\Component\Form\Extension\Core\Type\ChoiceType;
use Symfony\Component\Validator\Context\ExecutionContextInterface; use Symfony\Component\Validator\Context\ExecutionContextInterface;
use function array_key_exists;
/** /**
* Create a list for all activities * Create a list for all activities.
*
* @author Julien Fastré <julien.fastre@champs-libres.coop>
*/ */
class ListActivity implements ListInterface class ListActivity implements ListInterface
{ {
/** /**
*
* @var EntityManagerInterface * @var EntityManagerInterface
*/ */
protected $entityManager; protected $entityManager;
/** protected $fields = [
*
* @var TranslatorInterface
*/
protected $translator;
/**
*
* @var TranslatableStringHelper
*/
protected $translatableStringHelper;
protected $fields = array(
'id', 'id',
'date', 'date',
'durationTime', 'durationTime',
@@ -74,115 +47,131 @@ class ListActivity implements ListInterface
'type_name', 'type_name',
'person_firstname', 'person_firstname',
'person_lastname', 'person_lastname',
'person_id' 'person_id',
); ];
/**
* @var TranslatableStringHelper
*/
protected $translatableStringHelper;
/**
* @var TranslatorInterface
*/
protected $translator;
public function __construct( public function __construct(
EntityManagerInterface $em, EntityManagerInterface $em,
TranslatorInterface $translator, TranslatorInterface $translator,
TranslatableStringHelper $translatableStringHelper TranslatableStringHelper $translatableStringHelper
) ) {
{
$this->entityManager = $em; $this->entityManager = $em;
$this->translator = $translator; $this->translator = $translator;
$this->translatableStringHelper = $translatableStringHelper; $this->translatableStringHelper = $translatableStringHelper;
} }
/**
* {@inheritDoc}
*
* @param FormBuilderInterface $builder
*/
public function buildForm(FormBuilderInterface $builder) public function buildForm(FormBuilderInterface $builder)
{ {
$builder->add('fields', ChoiceType::class, array( $builder->add('fields', ChoiceType::class, [
'multiple' => true, 'multiple' => true,
'expanded' => true, 'expanded' => true,
'choices' => array_combine($this->fields, $this->fields), 'choices' => array_combine($this->fields, $this->fields),
'label' => 'Fields to include in export', 'label' => 'Fields to include in export',
'constraints' => [new Callback(array( 'constraints' => [new Callback([
'callback' => function($selected, ExecutionContextInterface $context) { 'callback' => function ($selected, ExecutionContextInterface $context) {
if (count($selected) === 0) { if (count($selected) === 0) {
$context->buildViolation('You must select at least one element') $context->buildViolation('You must select at least one element')
->atPath('fields') ->atPath('fields')
->addViolation(); ->addViolation();
} }
} },
))] ])],
)); ]);
} }
/** /**
* {@inheritDoc}
*
* @return type * @return type
*/ */
public function getAllowedFormattersTypes() public function getAllowedFormattersTypes()
{ {
return array(FormatterInterface::TYPE_LIST); return [FormatterInterface::TYPE_LIST];
} }
public function getDescription() public function getDescription()
{ {
return "List activities"; return 'List activities';
} }
public function getLabels($key, array $values, $data) public function getLabels($key, array $values, $data)
{ {
switch ($key) switch ($key) {
{ case 'date':
case 'date' : return function ($value) {
return function($value) { if ('_header' === $value) {
if ($value === '_header') return 'date'; return 'date';
}
$date = \DateTime::createFromFormat('Y-m-d H:i:s', $value); $date = DateTime::createFromFormat('Y-m-d H:i:s', $value);
return $date->format('d-m-Y'); return $date->format('d-m-Y');
}; };
case 'attendee': case 'attendee':
return function($value) { return function ($value) {
if ($value === '_header') return 'attendee'; if ('_header' === $value) {
return 'attendee';
}
return $value ? 1 : 0; return $value ? 1 : 0;
}; };
case 'list_reasons' :
case 'list_reasons':
/* @var $activityReasonsRepository EntityRepository */ /* @var $activityReasonsRepository EntityRepository */
$activityRepository = $this->entityManager $activityRepository = $this->entityManager
->getRepository('ChillActivityBundle:Activity'); ->getRepository('ChillActivityBundle:Activity');
return function($value) use ($activityRepository) { return function ($value) use ($activityRepository) {
if ($value === '_header') return 'activity reasons'; if ('_header' === $value) {
return 'activity reasons';
}
$activity = $activityRepository $activity = $activityRepository
->find($value); ->find($value);
return implode(", ", array_map(function(ActivityReason $r) { return implode(', ', array_map(function (ActivityReason $r) {
return '"' .
return '"'.
$this->translatableStringHelper->localize($r->getCategory()->getName()) $this->translatableStringHelper->localize($r->getCategory()->getName())
.' > '. . ' > ' .
$this->translatableStringHelper->localize($r->getName()) $this->translatableStringHelper->localize($r->getName())
.'"'; . '"';
}, $activity->getReasons()->toArray())); }, $activity->getReasons()->toArray()));
}; };
case 'circle_name' :
return function($value) { case 'circle_name':
if ($value === '_header') return 'circle'; return function ($value) {
if ('_header' === $value) {
return 'circle';
}
return $this->translatableStringHelper return $this->translatableStringHelper
->localize(json_decode($value, true)); ->localize(json_decode($value, true));
}; };
case 'type_name' :
return function($value) { case 'type_name':
if ($value === '_header') return 'activity type'; return function ($value) {
if ('_header' === $value) {
return 'activity type';
}
return $this->translatableStringHelper return $this->translatableStringHelper
->localize(json_decode($value, true)); ->localize(json_decode($value, true));
}; };
default: default:
return function($value) use ($key) { return function ($value) use ($key) {
if ($value === '_header') return $key; if ('_header' === $value) {
return $key;
}
return $value; return $value;
}; };
@@ -209,68 +198,83 @@ class ListActivity implements ListInterface
return 'activity'; return 'activity';
} }
public function initiateQuery(array $requiredModifiers, array $acl, array $data = array()) public function initiateQuery(array $requiredModifiers, array $acl, array $data = [])
{ {
$centers = array_map(function($el) { return $el['center']; }, $acl); $centers = array_map(function ($el) {
return $el['center'];
}, $acl);
// throw an error if any fields are present // throw an error if any fields are present
if (!\array_key_exists('fields', $data)) { if (!array_key_exists('fields', $data)) {
throw new \Doctrine\DBAL\Exception\InvalidArgumentException("any fields " throw new \Doctrine\DBAL\Exception\InvalidArgumentException('any fields '
. "have been checked"); . 'have been checked');
} }
$qb = $this->entityManager->createQueryBuilder(); $qb = $this->entityManager->createQueryBuilder();
$qb $qb
->from('ChillActivityBundle:Activity', 'activity') ->from('ChillActivityBundle:Activity', 'activity')
->join('activity.person', 'person') ->join('activity.person', 'person')
->join('person.center', 'center') ->join('person.center', 'center')
->andWhere('center IN (:authorized_centers)') ->andWhere('center IN (:authorized_centers)')
->setParameter('authorized_centers', $centers); ->setParameter('authorized_centers', $centers);
;
foreach ($this->fields as $f) { foreach ($this->fields as $f) {
if (in_array($f, $data['fields'])) { if (in_array($f, $data['fields'])) {
switch ($f) { switch ($f) {
case 'id': case 'id':
$qb->addSelect('activity.id AS id'); $qb->addSelect('activity.id AS id');
break; break;
case 'person_firstname': case 'person_firstname':
$qb->addSelect('person.firstName AS person_firstname'); $qb->addSelect('person.firstName AS person_firstname');
break; break;
case 'person_lastname': case 'person_lastname':
$qb->addSelect('person.lastName AS person_lastname'); $qb->addSelect('person.lastName AS person_lastname');
break; break;
case 'person_id': case 'person_id':
$qb->addSelect('person.id AS person_id'); $qb->addSelect('person.id AS person_id');
break; break;
case 'user_username': case 'user_username':
$qb->join('activity.user', 'user'); $qb->join('activity.user', 'user');
$qb->addSelect('user.username AS user_username'); $qb->addSelect('user.username AS user_username');
break; break;
case 'circle_name': case 'circle_name':
$qb->join('activity.scope', 'circle'); $qb->join('activity.scope', 'circle');
$qb->addSelect('circle.name AS circle_name'); $qb->addSelect('circle.name AS circle_name');
break; break;
case 'type_name': case 'type_name':
$qb->join('activity.type', 'type'); $qb->join('activity.type', 'type');
$qb->addSelect('type.name AS type_name'); $qb->addSelect('type.name AS type_name');
break; break;
case 'list_reasons': case 'list_reasons':
// this is a trick... The reasons is filled with the // this is a trick... The reasons is filled with the
// activity id which will be used to load reasons // activity id which will be used to load reasons
$qb->addSelect('activity.id AS list_reasons'); $qb->addSelect('activity.id AS list_reasons');
break; break;
default: default:
$qb->addSelect(sprintf('activity.%s as %s', $f, $f)); $qb->addSelect(sprintf('activity.%s as %s', $f, $f));
break; break;
} }
} }
} }
return $qb; return $qb;
} }
@@ -281,7 +285,6 @@ class ListActivity implements ListInterface
public function supportsModifiers() public function supportsModifiers()
{ {
return array('activity', 'person'); return ['activity', 'person'];
} }
} }

View File

@@ -1,154 +1,93 @@
<?php <?php
/* /**
* Copyright (C) 2015 Champs-Libres <info@champs-libres.coop> * Chill is a software for social workers
* *
* This program is free software: you can redistribute it and/or modify * For the full copyright and license information, please view
* it under the terms of the GNU Affero General Public License as published by * the LICENSE file that was distributed with this source code.
* 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\Export\Export; namespace Chill\ActivityBundle\Export\Export;
use Chill\MainBundle\Export\ExportInterface;
use Doctrine\ORM\QueryBuilder;
use Symfony\Component\Security\Core\Role\Role;
use Doctrine\ORM\Query;
use Chill\ActivityBundle\Security\Authorization\ActivityStatsVoter; use Chill\ActivityBundle\Security\Authorization\ActivityStatsVoter;
use Chill\MainBundle\Export\ExportInterface;
use Doctrine\ORM\EntityManagerInterface; use Doctrine\ORM\EntityManagerInterface;
use Doctrine\ORM\Query;
use LogicException;
use Symfony\Component\Security\Core\Role\Role;
/** /**
* This export allow to compute stats on activity duration. * This export allow to compute stats on activity duration.
* *
* The desired stat must be given in constructor. * The desired stat must be given in constructor.
*
*
* @author Julien Fastré <julien.fastre@champs-libres.coop>
*/ */
class StatActivityDuration implements ExportInterface class StatActivityDuration implements ExportInterface
{ {
/** public const SUM = 'sum';
*
* @var EntityManagerInterface
*/
protected $entityManager;
const SUM = 'sum';
/** /**
* The action for this report. * The action for this report.
* *
* @var string * @var string
*/ */
protected $action; protected $action;
/** /**
* constructor * @var EntityManagerInterface
* */
* @param EntityManagerInterface $em protected $entityManager;
/**
* constructor.
*
* @param string $action the stat to perform * @param string $action the stat to perform
*/ */
public function __construct( public function __construct(
EntityManagerInterface $em, EntityManagerInterface $em,
$action = 'sum' $action = 'sum'
) ) {
{
$this->entityManager = $em; $this->entityManager = $em;
$this->action = $action; $this->action = $action;
} }
public function buildForm(\Symfony\Component\Form\FormBuilderInterface $builder) public function buildForm(\Symfony\Component\Form\FormBuilderInterface $builder)
{ {
}
public function getDescription()
{
if ($this->action === self::SUM) {
return "Sum activities duration by various parameters.";
}
}
public function getTitle()
{
if ($this->action === self::SUM) {
return "Sum activity duration";
}
}
public function getType()
{
return 'activity';
}
public function initiateQuery(array $requiredModifiers, array $acl, array $data = array())
{
$centers = array_map(function($el) { return $el['center']; }, $acl);
$qb = $this->entityManager->createQueryBuilder();
if ($this->action === self::SUM) {
$select = "SUM(activity.durationTime) AS export_stat_activity";
}
$qb->select($select)
->from('ChillActivityBundle:Activity', 'activity')
->join('activity.person', 'person')
->join('person.center', 'center')
->where($qb->expr()->in('center', ':centers'))
->setParameter(':centers', $centers)
;
return $qb;
}
public function supportsModifiers()
{
return array('person', 'activity');
}
public function requiredRole()
{
return new Role(ActivityStatsVoter::STATS);
} }
public function getAllowedFormattersTypes() public function getAllowedFormattersTypes()
{ {
return array(\Chill\MainBundle\Export\FormatterInterface::TYPE_TABULAR); return [\Chill\MainBundle\Export\FormatterInterface::TYPE_TABULAR];
}
public function getDescription()
{
if (self::SUM === $this->action) {
return 'Sum activities duration by various parameters.';
}
} }
public function getLabels($key, array $values, $data) public function getLabels($key, array $values, $data)
{ {
if ($key !== 'export_stat_activity') { if ('export_stat_activity' !== $key) {
throw new \LogicException("the key $key is not used by this export"); throw new LogicException("the key {$key} is not used by this export");
} }
switch ($this->action) { switch ($this->action) {
case self::SUM: case self::SUM:
$header = "Sum of activities duration"; $header = 'Sum of activities duration';
} }
return function($value) use ($header) { return function ($value) use ($header) {
return $value === '_header' ? return '_header' === $value ?
$header $header
: :
$value $value;
;
}; };
} }
public function getQueryKeys($data) public function getQueryKeys($data)
{ {
return array('export_stat_activity'); return ['export_stat_activity'];
} }
public function getResult($qb, $data) public function getResult($qb, $data)
@@ -156,4 +95,46 @@ class StatActivityDuration implements ExportInterface
return $qb->getQuery()->getResult(Query::HYDRATE_SCALAR); return $qb->getQuery()->getResult(Query::HYDRATE_SCALAR);
} }
public function getTitle()
{
if (self::SUM === $this->action) {
return 'Sum activity duration';
}
}
public function getType()
{
return 'activity';
}
public function initiateQuery(array $requiredModifiers, array $acl, array $data = [])
{
$centers = array_map(function ($el) {
return $el['center'];
}, $acl);
$qb = $this->entityManager->createQueryBuilder();
if (self::SUM === $this->action) {
$select = 'SUM(activity.durationTime) AS export_stat_activity';
}
$qb->select($select)
->from('ChillActivityBundle:Activity', 'activity')
->join('activity.person', 'person')
->join('person.center', 'center')
->where($qb->expr()->in('center', ':centers'))
->setParameter(':centers', $centers);
return $qb;
}
public function requiredRole()
{
return new Role(ActivityStatsVoter::STATS);
}
public function supportsModifiers()
{
return ['person', 'activity'];
}
} }

View File

@@ -1,52 +1,36 @@
<?php <?php
/* /**
* Copyright (C) 2017 Champs-Libres <info@champs-libres.coop> * Chill is a software for social workers
* *
* This program is free software: you can redistribute it and/or modify * For the full copyright and license information, please view
* it under the terms of the GNU Affero General Public License as published by * the LICENSE file that was distributed with this source code.
* 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\Export\Filter; namespace Chill\ActivityBundle\Export\Filter;
use Chill\MainBundle\Export\FilterInterface; use Chill\MainBundle\Export\FilterInterface;
use Symfony\Component\Form\FormEvent; use Chill\MainBundle\Form\Type\Export\FilterType;
use Symfony\Component\Form\FormEvents; use DateTime;
use Doctrine\ORM\Query\Expr;
use Symfony\Component\Form\Extension\Core\Type\DateType; use Symfony\Component\Form\Extension\Core\Type\DateType;
use Symfony\Component\Form\FormError; use Symfony\Component\Form\FormError;
use Chill\MainBundle\Form\Type\Export\FilterType; use Symfony\Component\Form\FormEvent;
use Doctrine\ORM\Query\Expr; use Symfony\Component\Form\FormEvents;
use Symfony\Component\Translation\TranslatorInterface; use Symfony\Component\Translation\TranslatorInterface;
/**
*
*
* @author Julien Fastré <julien.fastre@champs-libres.coop>
*/
class ActivityDateFilter implements FilterInterface class ActivityDateFilter implements FilterInterface
{ {
/** /**
*
* @var TranslatorInterface * @var TranslatorInterface
*/ */
protected $translator; protected $translator;
function __construct(TranslatorInterface $translator) public function __construct(TranslatorInterface $translator)
{ {
$this->translator = $translator; $this->translator = $translator;
} }
public function addRole() public function addRole()
{ {
return null; return null;
@@ -55,15 +39,18 @@ class ActivityDateFilter implements FilterInterface
public function alterQuery(\Doctrine\ORM\QueryBuilder $qb, $data) public function alterQuery(\Doctrine\ORM\QueryBuilder $qb, $data)
{ {
$where = $qb->getDQLPart('where'); $where = $qb->getDQLPart('where');
$clause = $qb->expr()->between('activity.date', ':date_from', $clause = $qb->expr()->between(
':date_to'); 'activity.date',
':date_from',
':date_to'
);
if ($where instanceof Expr\Andx) { if ($where instanceof Expr\Andx) {
$where->add($clause); $where->add($clause);
} else { } else {
$where = $qb->expr()->andX($clause); $where = $qb->expr()->andX($clause);
} }
$qb->add('where', $where); $qb->add('where', $where);
$qb->setParameter('date_from', $data['date_from']); $qb->setParameter('date_from', $data['date_from']);
$qb->setParameter('date_to', $data['date_to']); $qb->setParameter('date_to', $data['date_to']);
@@ -76,55 +63,58 @@ class ActivityDateFilter implements FilterInterface
public function buildForm(\Symfony\Component\Form\FormBuilderInterface $builder) public function buildForm(\Symfony\Component\Form\FormBuilderInterface $builder)
{ {
$builder->add('date_from', DateType::class, array( $builder->add('date_from', DateType::class, [
'label' => "Activities after this date", 'label' => 'Activities after this date',
'data' => new \DateTime(), 'data' => new DateTime(),
'attr' => array('class' => 'datepicker'), 'attr' => ['class' => 'datepicker'],
'widget'=> 'single_text', 'widget' => 'single_text',
'format' => 'dd-MM-yyyy', 'format' => 'dd-MM-yyyy',
)); ]);
$builder->add('date_to', DateType::class, array( $builder->add('date_to', DateType::class, [
'label' => "Activities before this date", 'label' => 'Activities before this date',
'data' => new \DateTime(), 'data' => new DateTime(),
'attr' => array('class' => 'datepicker'), 'attr' => ['class' => 'datepicker'],
'widget'=> 'single_text', 'widget' => 'single_text',
'format' => 'dd-MM-yyyy', 'format' => 'dd-MM-yyyy',
)); ]);
$builder->addEventListener(FormEvents::POST_SUBMIT, function(FormEvent $event) { $builder->addEventListener(FormEvents::POST_SUBMIT, function (FormEvent $event) {
/* @var $filterForm \Symfony\Component\Form\FormInterface */ /* @var $filterForm \Symfony\Component\Form\FormInterface */
$filterForm = $event->getForm()->getParent(); $filterForm = $event->getForm()->getParent();
$enabled = $filterForm->get(FilterType::ENABLED_FIELD)->getData(); $enabled = $filterForm->get(FilterType::ENABLED_FIELD)->getData();
if ($enabled === true) { if (true === $enabled) {
// if the filter is enabled, add some validation // if the filter is enabled, add some validation
$form = $event->getForm(); $form = $event->getForm();
$date_from = $form->get('date_from')->getData(); $date_from = $form->get('date_from')->getData();
$date_to = $form->get('date_to')->getData(); $date_to = $form->get('date_to')->getData();
// check that fields are not empty // check that fields are not empty
if ($date_from === null) { if (null === $date_from) {
$form->get('date_from')->addError(new FormError( $form->get('date_from')->addError(new FormError(
$this->translator->trans('This field ' $this->translator->trans('This field '
. 'should not be empty'))); . 'should not be empty')
));
} }
if ($date_to === null) {
if (null === $date_to) {
$form->get('date_to')->addError(new FormError( $form->get('date_to')->addError(new FormError(
$this->translator->trans('This field ' $this->translator->trans('This field '
. 'should not be empty'))); . 'should not be empty')
} ));
}
// check that date_from is before date_to // check that date_from is before date_to
if ( if (
($date_from !== null && $date_to !== null) (null !== $date_from && null !== $date_to)
&& && $date_from >= $date_to
$date_from >= $date_to
) { ) {
$form->get('date_to')->addError(new FormError( $form->get('date_to')->addError(new FormError(
$this->translator->trans('This date should be after ' $this->translator->trans('This date should be after '
. 'the date given in "Implied in an activity after ' . 'the date given in "Implied in an activity after '
. 'this date" field'))); . 'this date" field')
));
} }
} }
}); });
@@ -132,17 +122,16 @@ class ActivityDateFilter implements FilterInterface
public function describeAction($data, $format = 'string') public function describeAction($data, $format = 'string')
{ {
return array( return [
"Filtered by date of activity: only between %date_from% and %date_to%", 'Filtered by date of activity: only between %date_from% and %date_to%',
array( [
"%date_from%" => $data['date_from']->format('d-m-Y'), '%date_from%' => $data['date_from']->format('d-m-Y'),
'%date_to%' => $data['date_to']->format('d-m-Y') '%date_to%' => $data['date_to']->format('d-m-Y'),
)); ], ];
} }
public function getTitle() public function getTitle()
{ {
return "Filtered by date activity"; return 'Filtered by date activity';
} }
} }

View File

@@ -1,88 +1,76 @@
<?php <?php
/* /**
* Copyright (C) 2016 Champs-Libres <info@champs-libres.coop> * Chill is a software for social workers
* *
* This program is free software: you can redistribute it and/or modify * For the full copyright and license information, please view
* it under the terms of the GNU Affero General Public License as published by * the LICENSE file that was distributed with this source code.
* 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\Export\Filter; namespace Chill\ActivityBundle\Export\Filter;
use Chill\MainBundle\Export\FilterInterface;
use Doctrine\ORM\QueryBuilder;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Bridge\Doctrine\Form\Type\EntityType;
use Chill\ActivityBundle\Entity\ActivityReason; use Chill\ActivityBundle\Entity\ActivityReason;
use Chill\MainBundle\Templating\TranslatableStringHelper;
use Doctrine\ORM\Query\Expr;
use Symfony\Component\Security\Core\Role\Role;
use Chill\ActivityBundle\Security\Authorization\ActivityStatsVoter; use Chill\ActivityBundle\Security\Authorization\ActivityStatsVoter;
use Doctrine\ORM\EntityRepository;
use Doctrine\ORM\Query\Expr\Join;
use Symfony\Component\Validator\Context\ExecutionContextInterface;
use Chill\MainBundle\Export\ExportElementValidatedInterface; use Chill\MainBundle\Export\ExportElementValidatedInterface;
use Chill\MainBundle\Export\FilterInterface;
use Chill\MainBundle\Templating\TranslatableStringHelper;
use Doctrine\ORM\EntityRepository;
use Doctrine\ORM\Query\Expr;
use Doctrine\ORM\Query\Expr\Join;
use Doctrine\ORM\QueryBuilder;
use Symfony\Bridge\Doctrine\Form\Type\EntityType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\Security\Core\Role\Role;
use Symfony\Component\Validator\Context\ExecutionContextInterface;
/** class ActivityReasonFilter implements
* FilterInterface,
* ExportElementValidatedInterface
* @author Julien Fastré <julien.fastre@champs-libres.coop>
*/
class ActivityReasonFilter implements FilterInterface,
ExportElementValidatedInterface
{ {
/** /**
* * The repository for activity reasons.
* @var TranslatableStringHelper
*/
protected $translatableStringHelper;
/**
* The repository for activity reasons
* *
* @var EntityRepository * @var EntityRepository
*/ */
protected $reasonRepository; protected $reasonRepository;
/**
* @var TranslatableStringHelper
*/
protected $translatableStringHelper;
public function __construct( public function __construct(
TranslatableStringHelper $helper, TranslatableStringHelper $helper,
EntityRepository $reasonRepository EntityRepository $reasonRepository
) { ) {
$this->translatableStringHelper = $helper; $this->translatableStringHelper = $helper;
$this->reasonRepository = $reasonRepository; $this->reasonRepository = $reasonRepository;
} }
public function addRole()
{
return new Role(ActivityStatsVoter::STATS);
}
public function alterQuery(QueryBuilder $qb, $data) public function alterQuery(QueryBuilder $qb, $data)
{ {
$where = $qb->getDQLPart('where'); $where = $qb->getDQLPart('where');
$join = $qb->getDQLPart('join'); $join = $qb->getDQLPart('join');
$clause = $qb->expr()->in('reasons', ':selected_activity_reasons'); $clause = $qb->expr()->in('reasons', ':selected_activity_reasons');
//dump($join); //dump($join);
// add a join to reasons only if needed // add a join to reasons only if needed
if ( if (
(array_key_exists('activity', $join) (
&& array_key_exists('activity', $join)
!$this->checkJoinAlreadyDefined($join['activity'], 'reasons') && !$this->checkJoinAlreadyDefined($join['activity'], 'reasons')
) )
OR or (!array_key_exists('activity', $join))
(! array_key_exists('activity', $join))
) { ) {
$qb->add( $qb->add(
'join', 'join',
array('activity' => new Join(Join::INNER_JOIN, 'activity.reasons', 'reasons')), ['activity' => new Join(Join::INNER_JOIN, 'activity.reasons', 'reasons')],
true true
); );
} }
if ($where instanceof Expr\Andx) { if ($where instanceof Expr\Andx) {
@@ -90,27 +78,10 @@ class ActivityReasonFilter implements FilterInterface,
} else { } else {
$where = $qb->expr()->andX($clause); $where = $qb->expr()->andX($clause);
} }
$qb->add('where', $where); $qb->add('where', $where);
$qb->setParameter('selected_activity_reasons', $data['reasons']); $qb->setParameter('selected_activity_reasons', $data['reasons']);
} }
/**
* Check if a join between Activity and Reason is already defined
*
* @param Join[] $joins
* @return boolean
*/
private function checkJoinAlreadyDefined(array $joins, $alias)
{
foreach ($joins as $join) {
if ($join->getAlias() === $alias) {
return true;
}
}
return false;
}
public function applyOn() public function applyOn()
{ {
@@ -121,49 +92,63 @@ class ActivityReasonFilter implements FilterInterface,
{ {
//create a local copy of translatableStringHelper //create a local copy of translatableStringHelper
$helper = $this->translatableStringHelper; $helper = $this->translatableStringHelper;
$builder->add('reasons', EntityType::class, array( $builder->add('reasons', EntityType::class, [
'class' => 'ChillActivityBundle:ActivityReason', 'class' => 'ChillActivityBundle:ActivityReason',
'choice_label' => function (ActivityReason $reason) use ($helper) { 'choice_label' => function (ActivityReason $reason) use ($helper) {
return $helper->localize($reason->getName()); return $helper->localize($reason->getName());
}, },
'group_by' => function(ActivityReason $reason) use ($helper) { 'group_by' => function (ActivityReason $reason) use ($helper) {
return $helper->localize($reason->getCategory()->getName()); return $helper->localize($reason->getCategory()->getName());
}, },
'multiple' => true, 'multiple' => true,
'expanded' => false 'expanded' => false,
)); ]);
}
public function validateForm($data, ExecutionContextInterface $context)
{
if ($data['reasons'] === null || count($data['reasons']) === 0) {
$context->buildViolation("At least one reason must be choosen")
->addViolation();
}
} }
public function getTitle()
{
return 'Filter by reason';
}
public function addRole()
{
return new Role(ActivityStatsVoter::STATS);
}
public function describeAction($data, $format = 'string') public function describeAction($data, $format = 'string')
{ {
// collect all the reasons'name used in this filter in one array // collect all the reasons'name used in this filter in one array
$reasonsNames = array_map( $reasonsNames = array_map(
function(ActivityReason $r) { function (ActivityReason $r) {
return "\"".$this->translatableStringHelper->localize($r->getName())."\""; return '"' . $this->translatableStringHelper->localize($r->getName()) . '"';
}, },
$this->reasonRepository->findBy(array('id' => $data['reasons']->toArray())) $this->reasonRepository->findBy(['id' => $data['reasons']->toArray()])
); );
return array("Filtered by reasons: only %list%", return ['Filtered by reasons: only %list%',
["%list%" => implode(", ", $reasonsNames)]); ['%list%' => implode(', ', $reasonsNames)], ];
}
public function getTitle()
{
return 'Filter by reason';
}
public function validateForm($data, ExecutionContextInterface $context)
{
if (null === $data['reasons'] || count($data['reasons']) === 0) {
$context->buildViolation('At least one reason must be choosen')
->addViolation();
}
}
/**
* Check if a join between Activity and Reason is already defined.
*
* @param Join[] $joins
* @param mixed $alias
*
* @return bool
*/
private function checkJoinAlreadyDefined(array $joins, $alias)
{
foreach ($joins as $join) {
if ($join->getAlias() === $alias) {
return true;
}
}
return false;
} }
} }

View File

@@ -1,67 +1,57 @@
<?php <?php
/* /**
* Copyright (C) 2018 Champs-Libres <info@champs-libres.coop> * Chill is a software for social workers
* *
* This program is free software: you can redistribute it and/or modify * For the full copyright and license information, please view
* it under the terms of the GNU Affero General Public License as published by * the LICENSE file that was distributed with this source code.
* 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\Export\Filter; namespace Chill\ActivityBundle\Export\Filter;
use Chill\MainBundle\Export\FilterInterface;
use Doctrine\ORM\QueryBuilder;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Bridge\Doctrine\Form\Type\EntityType;
use Chill\MainBundle\Templating\TranslatableStringHelper;
use Doctrine\ORM\Query\Expr;
use Symfony\Component\Security\Core\Role\Role;
use Chill\ActivityBundle\Security\Authorization\ActivityStatsVoter;
use Doctrine\ORM\EntityRepository;
use Doctrine\ORM\Query\Expr\Join;
use Symfony\Component\Validator\Context\ExecutionContextInterface;
use Chill\MainBundle\Export\ExportElementValidatedInterface;
use Chill\ActivityBundle\Entity\ActivityType; use Chill\ActivityBundle\Entity\ActivityType;
use Chill\ActivityBundle\Security\Authorization\ActivityStatsVoter;
use Chill\MainBundle\Export\ExportElementValidatedInterface;
use Chill\MainBundle\Export\FilterInterface;
use Chill\MainBundle\Templating\TranslatableStringHelper;
use Doctrine\ORM\EntityRepository;
use Doctrine\ORM\Query\Expr;
use Doctrine\ORM\Query\Expr\Join;
use Doctrine\ORM\QueryBuilder;
use Symfony\Bridge\Doctrine\Form\Type\EntityType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\Security\Core\Role\Role;
use Symfony\Component\Validator\Context\ExecutionContextInterface;
/** class ActivityTypeFilter implements
* FilterInterface,
* ExportElementValidatedInterface
*/
class ActivityTypeFilter implements FilterInterface,
ExportElementValidatedInterface
{ {
/** /**
*
* @var TranslatableStringHelper * @var TranslatableStringHelper
*/ */
protected $translatableStringHelper; protected $translatableStringHelper;
/** /**
* The repository for activity reasons * The repository for activity reasons.
* *
* @var EntityRepository * @var EntityRepository
*/ */
protected $typeRepository; protected $typeRepository;
public function __construct( public function __construct(
TranslatableStringHelper $helper, TranslatableStringHelper $helper,
EntityRepository $typeRepository EntityRepository $typeRepository
) { ) {
$this->translatableStringHelper = $helper; $this->translatableStringHelper = $helper;
$this->typeRepository = $typeRepository; $this->typeRepository = $typeRepository;
} }
public function addRole()
{
return new Role(ActivityStatsVoter::STATS);
}
public function alterQuery(QueryBuilder $qb, $data) public function alterQuery(QueryBuilder $qb, $data)
{ {
$where = $qb->getDQLPart('where'); $where = $qb->getDQLPart('where');
@@ -72,27 +62,10 @@ class ActivityTypeFilter implements FilterInterface,
} else { } else {
$where = $qb->expr()->andX($clause); $where = $qb->expr()->andX($clause);
} }
$qb->add('where', $where); $qb->add('where', $where);
$qb->setParameter('selected_activity_types', $data['types']); $qb->setParameter('selected_activity_types', $data['types']);
} }
/**
* Check if a join between Activity and Reason is already defined
*
* @param Join[] $joins
* @return boolean
*/
private function checkJoinAlreadyDefined(array $joins, $alias)
{
foreach ($joins as $join) {
if ($join->getAlias() === $alias) {
return true;
}
}
return false;
}
public function applyOn() public function applyOn()
{ {
@@ -103,46 +76,60 @@ class ActivityTypeFilter implements FilterInterface,
{ {
//create a local copy of translatableStringHelper //create a local copy of translatableStringHelper
$helper = $this->translatableStringHelper; $helper = $this->translatableStringHelper;
$builder->add('types', EntityType::class, array( $builder->add('types', EntityType::class, [
'class' => ActivityType::class, 'class' => ActivityType::class,
'choice_label' => function (ActivityType $type) use ($helper) { 'choice_label' => function (ActivityType $type) use ($helper) {
return $helper->localize($type->getName()); return $helper->localize($type->getName());
}, },
'multiple' => true, 'multiple' => true,
'expanded' => false 'expanded' => false,
)); ]);
}
public function validateForm($data, ExecutionContextInterface $context)
{
if ($data['types'] === null || count($data['types']) === 0) {
$context->buildViolation("At least one type must be choosen")
->addViolation();
}
} }
public function getTitle()
{
return 'Filter by activity type';
}
public function addRole()
{
return new Role(ActivityStatsVoter::STATS);
}
public function describeAction($data, $format = 'string') public function describeAction($data, $format = 'string')
{ {
// collect all the reasons'name used in this filter in one array // collect all the reasons'name used in this filter in one array
$reasonsNames = array_map( $reasonsNames = array_map(
function(ActivityType $t) { function (ActivityType $t) {
return "\"".$this->translatableStringHelper->localize($t->getName())."\""; return '"' . $this->translatableStringHelper->localize($t->getName()) . '"';
}, },
$this->typeRepository->findBy(array('id' => $data['types']->toArray())) $this->typeRepository->findBy(['id' => $data['types']->toArray()])
); );
return array("Filtered by activity type: only %list%", return ['Filtered by activity type: only %list%',
["%list%" => implode(", ", $reasonsNames)]); ['%list%' => implode(', ', $reasonsNames)], ];
}
public function getTitle()
{
return 'Filter by activity type';
}
public function validateForm($data, ExecutionContextInterface $context)
{
if (null === $data['types'] || count($data['types']) === 0) {
$context->buildViolation('At least one type must be choosen')
->addViolation();
}
}
/**
* Check if a join between Activity and Reason is already defined.
*
* @param Join[] $joins
* @param mixed $alias
*
* @return bool
*/
private function checkJoinAlreadyDefined(array $joins, $alias)
{
foreach ($joins as $join) {
if ($join->getAlias() === $alias) {
return true;
}
}
return false;
} }
} }

View File

@@ -1,79 +1,60 @@
<?php <?php
/* /**
* Copyright (C) 2017 Champs-Libres <info@champs-libres.coop> * Chill is a software for social workers
* *
* This program is free software: you can redistribute it and/or modify * For the full copyright and license information, please view
* it under the terms of the GNU Affero General Public License as published by * the LICENSE file that was distributed with this source code.
* 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\Export\Filter; namespace Chill\ActivityBundle\Export\Filter;
use Chill\ActivityBundle\Entity\ActivityReason;
use Chill\MainBundle\Export\ExportElementValidatedInterface;
use Chill\MainBundle\Export\FilterInterface; use Chill\MainBundle\Export\FilterInterface;
use Symfony\Component\Form\FormEvent; use Chill\MainBundle\Form\Type\Export\FilterType;
use Symfony\Component\Form\FormEvents; use Chill\MainBundle\Templating\TranslatableStringHelper;
use Chill\PersonBundle\Export\Declarations;
use DateTime;
use Doctrine\ORM\EntityRepository;
use Doctrine\ORM\Query\Expr;
use Symfony\Bridge\Doctrine\Form\Type\EntityType;
use Symfony\Component\Form\Extension\Core\Type\DateType; use Symfony\Component\Form\Extension\Core\Type\DateType;
use Symfony\Component\Form\FormError; use Symfony\Component\Form\FormError;
use Chill\MainBundle\Form\Type\Export\FilterType; use Symfony\Component\Form\FormEvent;
use Doctrine\ORM\Query\Expr; use Symfony\Component\Form\FormEvents;
use Chill\MainBundle\Templating\TranslatableStringHelper;
use Symfony\Bridge\Doctrine\Form\Type\EntityType;
use Chill\ActivityBundle\Entity\ActivityReason;
use Doctrine\ORM\EntityRepository;
use Doctrine\ORM\EntityManager;
use Chill\PersonBundle\Export\Declarations;
use Symfony\Component\Translation\TranslatorInterface; use Symfony\Component\Translation\TranslatorInterface;
use Symfony\Component\Validator\Context\ExecutionContextInterface; use Symfony\Component\Validator\Context\ExecutionContextInterface;
use Chill\MainBundle\Export\ExportElementValidatedInterface;
/** class PersonHavingActivityBetweenDateFilter implements
* FilterInterface,
*
* @author Julien Fastré <julien.fastre@champs-libres.coop>
*/
class PersonHavingActivityBetweenDateFilter implements FilterInterface,
ExportElementValidatedInterface ExportElementValidatedInterface
{ {
/** /**
*
* @var TranslatableStringHelper
*/
protected $translatableStringHelper;
/**
*
* @var EntityRepository * @var EntityRepository
*/ */
protected $activityReasonRepository; protected $activityReasonRepository;
/** /**
* * @var TranslatableStringHelper
* @var TranslatorInterface */
protected $translatableStringHelper;
/**
* @var TranslatorInterface
*/ */
protected $translator; protected $translator;
public function __construct( public function __construct(
TranslatableStringHelper $translatableStringHelper, TranslatableStringHelper $translatableStringHelper,
EntityRepository $activityReasonRepository, EntityRepository $activityReasonRepository,
TranslatorInterface $translator TranslatorInterface $translator
) { ) {
$this->translatableStringHelper = $translatableStringHelper; $this->translatableStringHelper = $translatableStringHelper;
$this->activityReasonRepository = $activityReasonRepository; $this->activityReasonRepository = $activityReasonRepository;
$this->translator = $translator; $this->translator = $translator;
} }
public function addRole() public function addRole()
{ {
return null; return null;
@@ -83,24 +64,26 @@ class PersonHavingActivityBetweenDateFilter implements FilterInterface,
{ {
// create a query for activity // create a query for activity
$sqb = $qb->getEntityManager()->createQueryBuilder(); $sqb = $qb->getEntityManager()->createQueryBuilder();
$sqb->select("person_person_having_activity.id") $sqb->select('person_person_having_activity.id')
->from("ChillActivityBundle:Activity", "activity_person_having_activity") ->from('ChillActivityBundle:Activity', 'activity_person_having_activity')
->join("activity_person_having_activity.person", "person_person_having_activity") ->join('activity_person_having_activity.person', 'person_person_having_activity');
;
// add clause between date // add clause between date
$sqb->where("activity_person_having_activity.date BETWEEN " $sqb->where('activity_person_having_activity.date BETWEEN '
. ":person_having_activity_between_date_from" . ':person_having_activity_between_date_from'
. " AND " . ' AND '
. ":person_having_activity_between_date_to"); . ':person_having_activity_between_date_to');
// add clause activity reason // add clause activity reason
$sqb->join('activity_person_having_activity.reasons', $sqb->join(
'reasons_person_having_activity'); 'activity_person_having_activity.reasons',
'reasons_person_having_activity'
);
$sqb->andWhere( $sqb->andWhere(
$sqb->expr()->in( $sqb->expr()->in(
'reasons_person_having_activity', 'reasons_person_having_activity',
":person_having_activity_reasons") ':person_having_activity_reasons'
); )
);
$where = $qb->getDQLPart('where'); $where = $qb->getDQLPart('where');
$clause = $qb->expr()->in('person.id', $sqb->getDQL()); $clause = $qb->expr()->in('person.id', $sqb->getDQL());
@@ -109,12 +92,16 @@ class PersonHavingActivityBetweenDateFilter implements FilterInterface,
} else { } else {
$where = $qb->expr()->andX($clause); $where = $qb->expr()->andX($clause);
} }
$qb->add('where', $where); $qb->add('where', $where);
$qb->setParameter('person_having_activity_between_date_from', $qb->setParameter(
$data['date_from']); 'person_having_activity_between_date_from',
$qb->setParameter('person_having_activity_between_date_to', $data['date_from']
$data['date_to']); );
$qb->setParameter(
'person_having_activity_between_date_to',
$data['date_to']
);
$qb->setParameter('person_having_activity_reasons', $data['reasons']); $qb->setParameter('person_having_activity_reasons', $data['reasons']);
} }
@@ -125,104 +112,107 @@ class PersonHavingActivityBetweenDateFilter implements FilterInterface,
public function buildForm(\Symfony\Component\Form\FormBuilderInterface $builder) public function buildForm(\Symfony\Component\Form\FormBuilderInterface $builder)
{ {
$builder->add('date_from', DateType::class, array( $builder->add('date_from', DateType::class, [
'label' => "Implied in an activity after this date", 'label' => 'Implied in an activity after this date',
'data' => new \DateTime(), 'data' => new DateTime(),
'attr' => array('class' => 'datepicker'), 'attr' => ['class' => 'datepicker'],
'widget'=> 'single_text', 'widget' => 'single_text',
'format' => 'dd-MM-yyyy', 'format' => 'dd-MM-yyyy',
)); ]);
$builder->add('date_to', DateType::class, array( $builder->add('date_to', DateType::class, [
'label' => "Implied in an activity before this date", 'label' => 'Implied in an activity before this date',
'data' => new \DateTime(), 'data' => new DateTime(),
'attr' => array('class' => 'datepicker'), 'attr' => ['class' => 'datepicker'],
'widget'=> 'single_text', 'widget' => 'single_text',
'format' => 'dd-MM-yyyy', 'format' => 'dd-MM-yyyy',
)); ]);
$builder->add('reasons', EntityType::class, array( $builder->add('reasons', EntityType::class, [
'class' => 'ChillActivityBundle:ActivityReason', 'class' => 'ChillActivityBundle:ActivityReason',
'choice_label' => function (ActivityReason $reason) { 'choice_label' => function (ActivityReason $reason) {
return $this->translatableStringHelper return $this->translatableStringHelper
->localize($reason->getName()); ->localize($reason->getName());
}, },
'group_by' => function(ActivityReason $reason) { 'group_by' => function (ActivityReason $reason) {
return $this->translatableStringHelper return $this->translatableStringHelper
->localize($reason->getCategory()->getName()); ->localize($reason->getCategory()->getName());
}, },
'data' => $this->activityReasonRepository->findAll(), 'data' => $this->activityReasonRepository->findAll(),
'multiple' => true, 'multiple' => true,
'expanded' => false, 'expanded' => false,
'label' => "Activity reasons for those activities" 'label' => 'Activity reasons for those activities',
)); ]);
$builder->addEventListener(FormEvents::POST_SUBMIT, function(FormEvent $event) { $builder->addEventListener(FormEvents::POST_SUBMIT, function (FormEvent $event) {
/* @var $filterForm \Symfony\Component\Form\FormInterface */ /* @var $filterForm \Symfony\Component\Form\FormInterface */
$filterForm = $event->getForm()->getParent(); $filterForm = $event->getForm()->getParent();
$enabled = $filterForm->get(FilterType::ENABLED_FIELD)->getData(); $enabled = $filterForm->get(FilterType::ENABLED_FIELD)->getData();
if ($enabled === true) { if (true === $enabled) {
// if the filter is enabled, add some validation // if the filter is enabled, add some validation
$form = $event->getForm(); $form = $event->getForm();
$date_from = $form->get('date_from')->getData(); $date_from = $form->get('date_from')->getData();
$date_to = $form->get('date_to')->getData(); $date_to = $form->get('date_to')->getData();
// check that fields are not empty // check that fields are not empty
if ($date_from === null) { if (null === $date_from) {
$form->get('date_from')->addError(new FormError( $form->get('date_from')->addError(new FormError(
$this->translator->trans('This field ' $this->translator->trans('This field '
. 'should not be empty'))); . 'should not be empty')
));
} }
if ($date_to === null) {
if (null === $date_to) {
$form->get('date_to')->addError(new FormError( $form->get('date_to')->addError(new FormError(
$this->translator->trans('This field ' $this->translator->trans('This field '
. 'should not be empty'))); . 'should not be empty')
} ));
}
// check that date_from is before date_to // check that date_from is before date_to
if ( if (
($date_from !== null && $date_to !== null) (null !== $date_from && null !== $date_to)
&& && $date_from >= $date_to
$date_from >= $date_to
) { ) {
$form->get('date_to')->addError(new FormError( $form->get('date_to')->addError(new FormError(
$this->translator->trans('This date ' $this->translator->trans('This date '
. 'should be after the date given in "Implied in an ' . 'should be after the date given in "Implied in an '
. 'activity after this date" field'))); . 'activity after this date" field')
));
} }
} }
}); });
} }
public function validateForm($data, ExecutionContextInterface $context)
{
if ($data['reasons'] === null || count($data['reasons']) === 0) {
$context->buildViolation("At least one reason must be choosen")
->addViolation();
}
}
public function describeAction($data, $format = 'string') public function describeAction($data, $format = 'string')
{ {
return array( return [
"Filtered by person having an activity between %date_from% and " 'Filtered by person having an activity between %date_from% and '
. "%date_to% with reasons %reasons_name%", . '%date_to% with reasons %reasons_name%',
array( [
"%date_from%" => $data['date_from']->format('d-m-Y'), '%date_from%' => $data['date_from']->format('d-m-Y'),
'%date_to%' => $data['date_to']->format('d-m-Y'), '%date_to%' => $data['date_to']->format('d-m-Y'),
"%reasons_name%" => implode(", ", array_map( '%reasons_name%' => implode(', ', array_map(
function (ActivityReason $r) { function (ActivityReason $r) {
return '"'.$this->translatableStringHelper-> return '"' . $this->translatableStringHelper->
localize($r->getName()).'"'; localize($r->getName()) . '"';
}, },
$data['reasons'])) $data['reasons']
)); )),
], ];
} }
public function getTitle() public function getTitle()
{ {
return "Filtered by person having an activity in a period"; return 'Filtered by person having an activity in a period';
} }
public function validateForm($data, ExecutionContextInterface $context)
{
if (null === $data['reasons'] || count($data['reasons']) === 0) {
$context->buildViolation('At least one reason must be choosen')
->addViolation();
}
}
} }

View File

@@ -1,33 +0,0 @@
<?php
namespace Chill\ActivityBundle\Form;
use Chill\ActivityBundle\Entity\ActivityPresence;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;
use Symfony\Component\Form\Extension\Core\Type\ChoiceType;
use Chill\MainBundle\Form\Type\TranslatableStringFormType;
class ActivityPresenceType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options): void
{
$builder
->add('name', TranslatableStringFormType::class)
->add('active', ChoiceType::class, array(
'choices' => array(
'Yes' => true,
'No' => false
),
'expanded' => true
));
}
public function configureOptions(OptionsResolver $resolver): void
{
$resolver->setDefaults(array(
'data_class' => ActivityPresence::class
));
}
}

View File

@@ -1,25 +1,27 @@
<?php <?php
/**
* Chill is a software for social workers
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/
namespace Chill\ActivityBundle\Form; namespace Chill\ActivityBundle\Form;
use Chill\MainBundle\Form\Type\TranslatableStringFormType;
use Symfony\Component\Form\AbstractType; use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\Extension\Core\Type\CheckboxType;
use Symfony\Component\Form\FormBuilderInterface; use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver; use Symfony\Component\OptionsResolver\OptionsResolver;
use Symfony\Component\Form\Extension\Core\Type\CheckboxType;
use Chill\MainBundle\Form\Type\TranslatableStringFormType;
class ActivityReasonCategoryType extends AbstractType class ActivityReasonCategoryType extends AbstractType
{ {
/**
* @param FormBuilderInterface $builder
* @param array $options
*/
public function buildForm(FormBuilderInterface $builder, array $options) public function buildForm(FormBuilderInterface $builder, array $options)
{ {
$builder $builder
->add('name', TranslatableStringFormType::class) ->add('name', TranslatableStringFormType::class)
->add('active', CheckboxType::class, array('required' => false)) ->add('active', CheckboxType::class, ['required' => false]);
;
} }
/** /**
@@ -27,9 +29,9 @@ class ActivityReasonCategoryType extends AbstractType
*/ */
public function configureOptions(OptionsResolver $resolver) public function configureOptions(OptionsResolver $resolver)
{ {
$resolver->setDefaults(array( $resolver->setDefaults([
'data_class' => 'Chill\ActivityBundle\Entity\ActivityReasonCategory' 'data_class' => 'Chill\ActivityBundle\Entity\ActivityReasonCategory',
)); ]);
} }
/** /**

View File

@@ -1,37 +1,36 @@
<?php <?php
/**
* Chill is a software for social workers
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/
namespace Chill\ActivityBundle\Form; namespace Chill\ActivityBundle\Form;
use Chill\ActivityBundle\Form\Type\TranslatableActivityReasonCategory;
use Chill\MainBundle\Form\Type\TranslatableStringFormType;
use Symfony\Component\Form\AbstractType; use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\Extension\Core\Type\CheckboxType;
use Symfony\Component\Form\FormBuilderInterface; use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver; use Symfony\Component\OptionsResolver\OptionsResolver;
use Symfony\Component\Form\Extension\Core\Type\CheckboxType;
use Chill\MainBundle\Form\Type\TranslatableStringFormType;
use Chill\ActivityBundle\Form\Type\TranslatableActivityReasonCategory;
class ActivityReasonType extends AbstractType class ActivityReasonType extends AbstractType
{ {
/**
* @param FormBuilderInterface $builder
* @param array $options
*/
public function buildForm(FormBuilderInterface $builder, array $options) public function buildForm(FormBuilderInterface $builder, array $options)
{ {
$builder $builder
->add('name', TranslatableStringFormType::class) ->add('name', TranslatableStringFormType::class)
->add('active', CheckboxType::class, array('required' => false)) ->add('active', CheckboxType::class, ['required' => false])
->add('category', TranslatableActivityReasonCategory::class) ->add('category', TranslatableActivityReasonCategory::class);
;
} }
/**
* @param OptionsResolver $resolver
*/
public function configureOptions(OptionsResolver $resolver) public function configureOptions(OptionsResolver $resolver)
{ {
$resolver->setDefaults(array( $resolver->setDefaults([
'data_class' => 'Chill\ActivityBundle\Entity\ActivityReason' 'data_class' => 'Chill\ActivityBundle\Entity\ActivityReason',
)); ]);
} }
/** /**

View File

@@ -1,81 +1,81 @@
<?php <?php
/**
* Chill is a software for social workers
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/
namespace Chill\ActivityBundle\Form; namespace Chill\ActivityBundle\Form;
use Chill\ActivityBundle\Entity\Activity; use Chill\ActivityBundle\Form\Type\TranslatableActivityReason;
use Chill\ActivityBundle\Entity\ActivityPresence; use Chill\ActivityBundle\Form\Type\TranslatableActivityType;
use Chill\ActivityBundle\Entity\ActivityReason;
use Chill\DocStoreBundle\Form\StoredObjectType;
use Chill\MainBundle\Form\Type\ChillCollectionType;
use Chill\MainBundle\Form\Type\CommentType;
use Chill\PersonBundle\Entity\Person;
use Chill\PersonBundle\Entity\SocialWork\SocialIssue;
use Chill\PersonBundle\Entity\SocialWork\SocialAction;
use Chill\ThirdPartyBundle\Entity\ThirdParty;
use Doctrine\ORM\EntityRepository;
use Symfony\Bridge\Doctrine\Form\Type\EntityType;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\Extension\Core\Type\CheckboxType;
use Symfony\Component\Form\Extension\Core\Type\CollectionType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;
use Chill\MainBundle\Security\Authorization\AuthorizationHelper;
use Doctrine\Persistence\ObjectManager;
use Chill\MainBundle\Templating\TranslatableStringHelper;
use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface;
use Chill\MainBundle\Entity\User; use Chill\MainBundle\Entity\User;
use Chill\MainBundle\Form\Type\ChillDateType;
use Chill\MainBundle\Form\Type\CommentType;
use Chill\MainBundle\Form\Type\ScopePickerType;
use Chill\MainBundle\Form\Type\UserPickerType;
use Chill\MainBundle\Security\Authorization\AuthorizationHelper;
use Chill\MainBundle\Templating\TranslatableStringHelper;
use DateInterval;
use DateTime;
use DateTimeZone;
use Doctrine\Persistence\ObjectManager;
use RuntimeException;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\Extension\Core\DataTransformer\DateTimeToTimestampTransformer; use Symfony\Component\Form\Extension\Core\DataTransformer\DateTimeToTimestampTransformer;
use Symfony\Component\Form\Extension\Core\Type\ChoiceType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\Form\FormEvent; use Symfony\Component\Form\FormEvent;
use Symfony\Component\Form\FormEvents; use Symfony\Component\Form\FormEvents;
use Symfony\Component\Form\Extension\Core\Type\ChoiceType; use Symfony\Component\OptionsResolver\OptionsResolver;
use Chill\MainBundle\Form\Type\UserPickerType; use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface;
use Chill\MainBundle\Form\Type\ScopePickerType;
use Chill\MainBundle\Form\Type\ChillDateType;
use Symfony\Component\Form\Extension\Core\Type\HiddenType;
use Symfony\Component\Form\CallbackTransformer;
use Chill\PersonBundle\Form\DataTransformer\PersonToIdTransformer;
use Chill\PersonBundle\Templating\Entity\SocialIssueRender;
use Chill\PersonBundle\Templating\Entity\SocialActionRender;
class ActivityType extends AbstractType class ActivityType extends AbstractType
{ {
protected User $user; /**
* @var AuthorizationHelper
*/
protected $authorizationHelper;
protected AuthorizationHelper $authorizationHelper; /**
* @var ObjectManager
*/
protected $om;
protected ObjectManager $om; protected $timeChoices;
protected TranslatableStringHelper $translatableStringHelper; /**
* @var TranslatableStringHelper
*/
protected $translatableStringHelper;
protected SocialIssueRender $socialIssueRender; /**
* the user running this form.
*
* @var User
*/
protected $user;
protected SocialActionRender $socialActionRender; public function __construct(
protected array $timeChoices;
public function __construct (
TokenStorageInterface $tokenStorage, TokenStorageInterface $tokenStorage,
AuthorizationHelper $authorizationHelper, AuthorizationHelper $authorizationHelper,
ObjectManager $om, ObjectManager $om,
TranslatableStringHelper $translatableStringHelper, TranslatableStringHelper $translatableStringHelper,
array $timeChoices, array $timeChoices
SocialIssueRender $socialIssueRender,
SocialActionRender $socialActionRender
) { ) {
if (!$tokenStorage->getToken()->getUser() instanceof User) { if (!$tokenStorage->getToken()->getUser() instanceof User) {
throw new \RuntimeException("you should have a valid user"); throw new RuntimeException('you should have a valid user');
} }
$this->user = $tokenStorage->getToken()->getUser(); $this->user = $tokenStorage->getToken()->getUser();
$this->authorizationHelper = $authorizationHelper; $this->authorizationHelper = $authorizationHelper;
$this->om = $om; $this->om = $om;
$this->translatableStringHelper = $translatableStringHelper; $this->translatableStringHelper = $translatableStringHelper;
$this->timeChoices = $timeChoices; $this->timeChoices = $timeChoices;
$this->socialIssueRender = $socialIssueRender;
$this->socialActionRender = $socialActionRender;
} }
public function buildForm(FormBuilderInterface $builder, array $options): void public function buildForm(FormBuilderInterface $builder, array $options)
{ {
// handle times choices // handle times choices
$timeChoices = []; $timeChoices = [];
@@ -90,301 +90,104 @@ class ActivityType extends AbstractType
'placeholder' => 'Choose the duration', 'placeholder' => 'Choose the duration',
]; ];
/** @var \Chill\ActivityBundle\Entity\ActivityType $activityType */ $builder
$activityType = $options['activityType']; ->add('date', ChillDateType::class, [
'required' => true,
if (!$activityType->isActive()) { ])
throw new \InvalidArgumentException('Activity type must be active'); ->add('durationTime', ChoiceType::class, $durationTimeOptions)
} ->add('attendee', ChoiceType::class, [
// TODO revoir la gestion des center au niveau du form des activité.
if ($options['center']) {
$builder->add('scope', ScopePickerType::class, [
'center' => $options['center'],
'role' => $options['role']
]);
}
/** @var ? \Chill\PersonBundle\Entity\AccompanyingPeriod $accompanyingPeriod */
$accompanyingPeriod = NULL;
if ($options['accompanyingPeriod']) {
$accompanyingPeriod = $options['accompanyingPeriod'];
}
if ($activityType->isVisible('socialIssues') && $accompanyingPeriod) {
$builder->add('socialIssues', HiddenType::class);
$builder->get('socialIssues')
->addModelTransformer(new CallbackTransformer(
function (iterable $socialIssuesAsIterable): string {
$socialIssueIds = [];
foreach ($socialIssuesAsIterable as $value) {
$socialIssueIds[] = $value->getId();
}
return implode(',', $socialIssueIds);
},
function (?string $socialIssuesAsString): array {
if (null === $socialIssuesAsString) {
return [];
}
return array_map(
fn(string $id): ?SocialIssue => $this->om->getRepository(SocialIssue::class)->findOneBy(['id' => (int) $id]),
explode(',', $socialIssuesAsString)
);
}
))
;
}
if ($activityType->isVisible('socialActions') && $accompanyingPeriod) {
$builder->add('socialActions', HiddenType::class);
$builder->get('socialActions')
->addModelTransformer(new CallbackTransformer(
function (iterable $socialActionsAsIterable): string {
$socialActionIds = [];
foreach ($socialActionsAsIterable as $value) {
$socialActionIds[] = $value->getId();
}
return implode(',', $socialActionIds);
},
function (?string $socialActionsAsString): array {
if (null === $socialActionsAsString) {
return [];
}
return array_map(
fn(string $id): ?SocialAction => $this->om->getRepository(SocialAction::class)->findOneBy(['id' => (int) $id]),
explode(',', $socialActionsAsString)
);
}
))
;
}
if ($activityType->isVisible('date')) {
$builder->add('date', ChillDateType::class, [
'label' => $activityType->getLabel('date'),
'required' => $activityType->isRequired('date'),
]);
}
if ($activityType->isVisible('durationTime')) {
$durationTimeOptions['label'] = $activityType->getLabel('durationTime');
$durationTimeOptions['required'] = $activityType->isRequired('durationTime');
$builder->add('durationTime', ChoiceType::class, $durationTimeOptions);
}
if ($activityType->isVisible('travelTime')) {
$durationTimeOptions['label'] = $activityType->getLabel('travelTime');
$durationTimeOptions['required'] = $activityType->isRequired('travelTime');
$builder->add('travelTime', ChoiceType::class, $durationTimeOptions);
}
if ($activityType->isVisible('attendee')) {
$builder->add('attendee', EntityType::class, [
'label' => $activityType->getLabel('attendee'),
'required' => $activityType->isRequired('attendee'),
'expanded' => true, 'expanded' => true,
'class' => ActivityPresence::class, 'required' => false,
'choice_label' => function (ActivityPresence $activityPresence) {
return $this->translatableStringHelper->localize($activityPresence->getName());
},
'query_builder' => function (EntityRepository $er) {
return $er->createQueryBuilder('a')
->where('a.active = true');
},
]);
}
if ($activityType->isVisible('user') && $options['center']) {
$builder->add('user', UserPickerType::class, [
'label' => $activityType->getLabel('user'),
'required' => $activityType->isRequired('user'),
'center' => $options['center'],
'role' => $options['role']
]);
}
if ($activityType->isVisible('reasons')) {
$builder->add('reasons', EntityType::class, [
'label' => $activityType->getLabel('reasons'),
'required' => $activityType->isRequired('reasons'),
'class' => ActivityReason::class,
'multiple' => true,
'choice_label' => function (ActivityReason $activityReason) {
return $this->translatableStringHelper->localize($activityReason->getName());
},
'attr' => array('class' => 'select2 '),
'query_builder' => function (EntityRepository $er) {
return $er->createQueryBuilder('a')
->where('a.active = true');
},
]);
}
if ($activityType->isVisible('comment')) {
$builder->add('comment', CommentType::class, [
'label' => empty($activityType->getLabel('comment'))
? 'activity.comment' : $activityType->getLabel('comment'),
'required' => $activityType->isRequired('comment'),
]);
}
if ($activityType->isVisible('persons')) {
$builder->add('persons', HiddenType::class);
$builder->get('persons')
->addModelTransformer(new CallbackTransformer(
function (iterable $personsAsIterable): string {
$personIds = [];
foreach ($personsAsIterable as $value) {
$personIds[] = $value->getId();
}
return implode(',', $personIds);
},
function (?string $personsAsString): array {
return array_map(
fn(string $id): ?Person => $this->om->getRepository(Person::class)->findOneBy(['id' => (int) $id]),
explode(',', $personsAsString)
);
}
))
;
}
if ($activityType->isVisible('thirdParties')) {
$builder->add('thirdParties', HiddenType::class);
$builder->get('thirdParties')
->addModelTransformer(new CallbackTransformer(
function (iterable $thirdpartyAsIterable): string {
$thirdpartyIds = [];
foreach ($thirdpartyAsIterable as $value) {
$thirdpartyIds[] = $value->getId();
}
return implode(',', $thirdpartyIds);
},
function (?string $thirdpartyAsString): array {
return array_map(
fn(string $id): ?ThirdParty => $this->om->getRepository(ThirdParty::class)->findOneBy(['id' => (int) $id]),
explode(',', $thirdpartyAsString)
);
}
))
;
}
if ($activityType->isVisible('documents')) {
$builder->add('documents', ChillCollectionType::class, [
'entry_type' => StoredObjectType::class,
'label' => $activityType->getLabel('documents'),
'required' => $activityType->isRequired('documents'),
'allow_add' => true,
'button_add_label' => 'activity.Insert a document',
'button_remove_label' => 'activity.Remove a document'
]);
}
if ($activityType->isVisible('users')) {
$builder->add('users', HiddenType::class);
$builder->get('users')
->addModelTransformer(new CallbackTransformer(
function (iterable $usersAsIterable): string {
$userIds = [];
foreach ($usersAsIterable as $value) {
$userIds[] = $value->getId();
}
return implode(',', $userIds);
},
function (?string $usersAsString): array {
return array_map(
fn(string $id): ?User => $this->om->getRepository(User::class)->findOneBy(['id' => (int) $id]),
explode(',', $usersAsString)
);
}
))
;
}
if ($activityType->isVisible('emergency')) {
$builder->add('emergency', CheckboxType::class, [
'label' => $activityType->getLabel('emergency'),
'required' => $activityType->isRequired('emergency'),
]);
}
if ($activityType->isVisible('sentReceived')) {
$builder->add('sentReceived', ChoiceType::class, [
'label' => $activityType->getLabel('sentReceived'),
'required' => $activityType->isRequired('sentReceived'),
'choices' => [ 'choices' => [
'Sent' => Activity::SENTRECEIVED_SENT, 'present' => true,
'Received' => Activity::SENTRECEIVED_RECEIVED, 'not present' => false,
], ],
])
->add('user', UserPickerType::class, [
'center' => $options['center'],
'role' => $options['role'],
])
->add('scope', ScopePickerType::class, [
'center' => $options['center'],
'role' => $options['role'],
])
->add('reasons', TranslatableActivityReason::class, [
'multiple' => true,
'required' => false,
])
->add('type', TranslatableActivityType::class, [
'placeholder' => 'Choose a type',
'active_only' => true,
])
->add('comment', CommentType::class, [
'required' => false,
]); ]);
}
foreach (['durationTime', 'travelTime'] as $fieldName) { $builder->get('durationTime')
if (!$activityType->isVisible($fieldName)) { ->addModelTransformer($durationTimeTransformer);
continue;
}
$builder->get($fieldName) $builder->get('durationTime')
->addModelTransformer($durationTimeTransformer); ->addEventListener(
FormEvents::PRE_SET_DATA,
$builder->get($fieldName) function (FormEvent $formEvent) use (
->addEventListener(FormEvents::PRE_SET_DATA, function(FormEvent $formEvent) use (
$timeChoices, $timeChoices,
$builder, $builder,
$durationTimeTransformer, $durationTimeTransformer,
$durationTimeOptions, $durationTimeOptions
$fieldName
) { ) {
// set the timezone to GMT, and fix the difference between current and GMT // set the timezone to GMT, and fix the difference between current and GMT
// the datetimetransformer will then handle timezone as GMT // the datetimetransformer will then handle timezone as GMT
$timezoneUTC = new \DateTimeZone('GMT'); $timezoneUTC = new DateTimeZone('GMT');
/* @var $data \DateTime */ /* @var $data \DateTime */
$data = $formEvent->getData() === NULL ? $data = $formEvent->getData() === null ?
\DateTime::createFromFormat('U', 300) : DateTime::createFromFormat('U', 300) :
$formEvent->getData(); $formEvent->getData();
$seconds = $data->getTimezone()->getOffset($data); $seconds = $data->getTimezone()->getOffset($data);
$data->setTimeZone($timezoneUTC); $data->setTimeZone($timezoneUTC);
$data->add(new \DateInterval('PT'.$seconds.'S')); $data->add(new DateInterval('PT' . $seconds . 'S'));
// test if the timestamp is in the choices. // test if the timestamp is in the choices.
// If not, recreate the field with the new timestamp // If not, recreate the field with the new timestamp
if (!in_array($data->getTimestamp(), $timeChoices)) { if (!in_array($data->getTimestamp(), $timeChoices)) {
// the data are not in the possible values. add them // the data are not in the possible values. add them
$timeChoices[$data->format('H:i')] = $data->getTimestamp(); $timeChoices[$data->format('H:i')] = $data->getTimestamp();
$form = $builder->create($fieldName, ChoiceType::class, array_merge( $form = $builder->create(
$durationTimeOptions, [ 'durationTime',
'choices' => $timeChoices, ChoiceType::class,
'auto_initialize' => false array_merge(
] $durationTimeOptions,
)); [
'choices' => $timeChoices,
'auto_initialize' => false,
]
)
);
$form->addModelTransformer($durationTimeTransformer); $form->addModelTransformer($durationTimeTransformer);
$formEvent->getForm()->getParent()->add($form->getForm()); $formEvent->getForm()->getParent()->add($form->getForm());
} }
}); }
} );
} }
/**
* @param OptionsResolverInterface $resolver
public function configureOptions(OptionsResolver $resolver): void */
public function configureOptions(OptionsResolver $resolver)
{ {
$resolver->setDefaults([ $resolver->setDefaults([
'data_class' => Activity::class 'data_class' => 'Chill\ActivityBundle\Entity\Activity',
]); ]);
$resolver $resolver
->setRequired(['center', 'role', 'activityType', 'accompanyingPeriod']) ->setRequired(['center', 'role'])
->setAllowedTypes('center', ['null', 'Chill\MainBundle\Entity\Center']) ->setAllowedTypes('center', 'Chill\MainBundle\Entity\Center')
->setAllowedTypes('role', 'Symfony\Component\Security\Core\Role\Role') ->setAllowedTypes('role', 'Symfony\Component\Security\Core\Role\Role');
->setAllowedTypes('activityType', \Chill\ActivityBundle\Entity\ActivityType::class)
->setAllowedTypes('accompanyingPeriod', [\Chill\PersonBundle\Entity\AccompanyingPeriod::class, 'null'])
;
} }
public function getBlockPrefix(): string /**
* @return string
*/
public function getBlockPrefix()
{ {
return 'chill_activitybundle_activity'; return 'chill_activitybundle_activity';
} }

View File

@@ -1,39 +0,0 @@
<?php
namespace Chill\ActivityBundle\Form;
use Chill\ActivityBundle\Entity\ActivityTypeCategory;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\Extension\Core\Type\NumberType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;
use Symfony\Component\Form\Extension\Core\Type\ChoiceType;
use Chill\MainBundle\Form\Type\TranslatableStringFormType;
class ActivityTypeCategoryType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options): void
{
$builder
->add('name', TranslatableStringFormType::class)
->add('active', ChoiceType::class, array(
'choices' => array(
'Yes' => true,
'No' => false
),
'expanded' => true
))
->add('ordering', NumberType::class, [
'required' => true,
'scale' => 5
])
;
}
public function configureOptions(OptionsResolver $resolver): void
{
$resolver->setDefaults(array(
'data_class' => ActivityTypeCategory::class
));
}
}

View File

@@ -1,28 +1,22 @@
<?php <?php
/**
* Chill is a software for social workers
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/
namespace Chill\ActivityBundle\Form; namespace Chill\ActivityBundle\Form;
use Chill\ActivityBundle\Entity\ActivityTypeCategory; use Chill\MainBundle\Form\Type\TranslatableStringFormType;
use Chill\ActivityBundle\Form\Type\ActivityFieldPresence;
use Chill\MainBundle\Templating\TranslatableStringHelper;
use Symfony\Bridge\Doctrine\Form\Type\EntityType;
use Symfony\Component\Form\AbstractType; use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\Extension\Core\Type\NumberType; use Symfony\Component\Form\Extension\Core\Type\ChoiceType;
use Symfony\Component\Form\Extension\Core\Type\TextType;
use Symfony\Component\Form\FormBuilderInterface; use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver; use Symfony\Component\OptionsResolver\OptionsResolver;
use Symfony\Component\Form\Extension\Core\Type\ChoiceType;
use Chill\MainBundle\Form\Type\TranslatableStringFormType;
class ActivityTypeType extends AbstractType class ActivityTypeType extends AbstractType
{ {
private TranslatableStringHelper $translatableStringHelper;
public function __construct(TranslatableStringHelper $translatableStringHelper)
{
$this->translatableStringHelper = $translatableStringHelper;
}
public function buildForm(FormBuilderInterface $builder, array $options) public function buildForm(FormBuilderInterface $builder, array $options)
{ {
$builder $builder
@@ -30,42 +24,27 @@ class ActivityTypeType extends AbstractType
->add('active', ChoiceType::class, [ ->add('active', ChoiceType::class, [
'choices' => [ 'choices' => [
'Yes' => true, 'Yes' => true,
'No' => false 'No' => false,
], ],
'expanded' => true 'expanded' => true,
]) ]);
->add('category', EntityType::class, [
'class' => ActivityTypeCategory::class,
'choice_label' => function (ActivityTypeCategory $activityTypeCategory) {
return $this->translatableStringHelper->localize($activityTypeCategory->getName());
},
])
->add('ordering', NumberType::class, [
'required' => true,
'scale' => 5
])
;
$fields = [
'persons', 'user', 'date', 'place', 'persons',
'thirdParties', 'durationTime', 'travelTime', 'attendee',
'reasons', 'comment', 'sentReceived', 'documents',
'emergency', 'accompanyingPeriod', 'socialData', 'users'
];
foreach ($fields as $field) {
$builder
->add($field.'Visible', ActivityFieldPresence::class)
->add($field.'Label', TextType::class, [
'required' => false,
'empty_data' => '',
]);
}
} }
/**
* @param OptionsResolverInterface $resolver
*/
public function configureOptions(OptionsResolver $resolver) public function configureOptions(OptionsResolver $resolver)
{ {
$resolver->setDefaults(array( $resolver->setDefaults([
'data_class' => \Chill\ActivityBundle\Entity\ActivityType::class 'data_class' => 'Chill\ActivityBundle\Entity\ActivityType',
)); ]);
}
/**
* @return string
*/
public function getBlockPrefix()
{
return 'chill_activitybundle_activitytype';
} }
} }

View File

@@ -1,29 +0,0 @@
<?php
namespace Chill\ActivityBundle\Form\Type;
use Chill\ActivityBundle\Entity\ActivityType;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\Extension\Core\Type\ChoiceType;
use Symfony\Component\OptionsResolver\OptionsResolver;
class ActivityFieldPresence extends AbstractType
{
public function getParent()
{
return ChoiceType::class;
}
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults(
array(
'choices' => [
'Invisible' => ActivityType::FIELD_INVISIBLE,
'Optional' => ActivityType::FIELD_OPTIONAL,
'Required' => ActivityType::FIELD_REQUIRED,
],
)
);
}
}

View File

@@ -1,54 +1,37 @@
<?php <?php
/* /**
* Chill is a software for social workers * Chill is a software for social workers
* *
* Copyright (C) 2014-2020, Champs Libres Cooperative SCRLFS, * For the full copyright and license information, please view
* <http://www.champs-libres.coop>, <info@champs-libres.coop> * the LICENSE file that was distributed with this source code.
*
* 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\Form\Type; namespace Chill\ActivityBundle\Form\Type;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\OptionsResolver\OptionsResolver;
use Symfony\Bridge\Doctrine\Form\Type\EntityType;
use Chill\MainBundle\Templating\TranslatableStringHelper;
use Doctrine\ORM\EntityRepository;
use Chill\ActivityBundle\Entity\ActivityReason; use Chill\ActivityBundle\Entity\ActivityReason;
use Chill\ActivityBundle\Templating\Entity\ActivityReasonRender; use Chill\ActivityBundle\Templating\Entity\ActivityReasonRender;
use Chill\MainBundle\Templating\TranslatableStringHelper;
use Doctrine\ORM\EntityRepository;
use Symfony\Bridge\Doctrine\Form\Type\EntityType;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\OptionsResolver\OptionsResolver;
/** /**
* FormType to choose amongst activity reasons * FormType to choose amongst activity reasons.
*
*/ */
class TranslatableActivityReason extends AbstractType class TranslatableActivityReason extends AbstractType
{ {
/** /**
*
* @var TranslatableStringHelper
*/
protected $translatableStringHelper;
/**
*
* @var ActivityReasonRender * @var ActivityReasonRender
*/ */
protected $reasonRender; protected $reasonRender;
/**
* @var TranslatableStringHelper
*/
protected $translatableStringHelper;
public function __construct( public function __construct(
TranslatableStringHelper $translatableStringHelper, TranslatableStringHelper $translatableStringHelper,
ActivityReasonRender $reasonRender ActivityReasonRender $reasonRender
@@ -57,6 +40,30 @@ class TranslatableActivityReason extends AbstractType
$this->reasonRender = $reasonRender; $this->reasonRender = $reasonRender;
} }
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults(
[
'class' => 'ChillActivityBundle:ActivityReason',
'choice_label' => function (ActivityReason $choice) {
return $this->reasonRender->renderString($choice, []);
},
'group_by' => function (ActivityReason $choice): ?string {
if (null !== $category = $choice->getCategory()) {
return $this->translatableStringHelper->localize($category->getName());
}
return null;
},
'query_builder' => function (EntityRepository $er) {
return $er->createQueryBuilder('r')
->where('r.active = true');
},
'attr' => ['class' => ' select2 '],
]
);
}
public function getBlockPrefix() public function getBlockPrefix()
{ {
return 'translatable_activity_reason'; return 'translatable_activity_reason';
@@ -66,28 +73,4 @@ class TranslatableActivityReason extends AbstractType
{ {
return EntityType::class; return EntityType::class;
} }
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults(
array(
'class' => 'ChillActivityBundle:ActivityReason',
'choice_label' => function(ActivityReason $choice) {
return $this->reasonRender->renderString($choice, []);
},
'group_by' => function(ActivityReason $choice): ?string {
if (null !== $category = $choice->getCategory()) {
return $this->translatableStringHelper->localize($category->getName());
}
return null;
},
'query_builder' => function (EntityRepository $er) {
return $er->createQueryBuilder('r')
->where('r.active = true');
},
'attr' => [ 'class' => ' select2 ']
)
);
}
} }

View File

@@ -1,40 +1,23 @@
<?php <?php
/* /**
* Chill is a software for social workers * Chill is a software for social workers
* *
* Copyright (C) 2014-2015, Champs Libres Cooperative SCRLFS, * For the full copyright and license information, please view
* <http://www.champs-libres.coop>, <info@champs-libres.coop> * the LICENSE file that was distributed with this source code.
*
* 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\Form\Type; namespace Chill\ActivityBundle\Form\Type;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\OptionsResolver\OptionsResolver;
use Symfony\Component\HttpFoundation\RequestStack;
use Symfony\Bridge\Doctrine\Form\Type\EntityType;
use Doctrine\ORM\EntityRepository; use Doctrine\ORM\EntityRepository;
use Symfony\Bridge\Doctrine\Form\Type\EntityType;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\HttpFoundation\RequestStack;
use Symfony\Component\OptionsResolver\OptionsResolver;
/** /**
* Description of TranslatableActivityReasonCategory * Description of TranslatableActivityReasonCategory.
*
* @author Champs-Libres Coop
*/ */
class TranslatableActivityReasonCategory extends AbstractType class TranslatableActivityReasonCategory extends AbstractType
{ {
/** /**
@@ -47,6 +30,21 @@ class TranslatableActivityReasonCategory extends AbstractType
$this->requestStack = $requestStack; $this->requestStack = $requestStack;
} }
public function configureOptions(OptionsResolver $resolver)
{
$locale = $this->requestStack->getCurrentRequest()->getLocale();
$resolver->setDefaults(
[
'class' => 'ChillActivityBundle:ActivityReasonCategory',
'choice_label' => 'name[' . $locale . ']',
'query_builder' => function (EntityRepository $er) {
return $er->createQueryBuilder('c')
->where('c.active = true');
},
]
);
}
public function getBlockPrefix() public function getBlockPrefix()
{ {
return 'translatable_activity_reason_category'; return 'translatable_activity_reason_category';
@@ -56,19 +54,4 @@ class TranslatableActivityReasonCategory extends AbstractType
{ {
return EntityType::class; return EntityType::class;
} }
public function configureOptions(OptionsResolver $resolver)
{
$locale = $this->requestStack->getCurrentRequest()->getLocale();
$resolver->setDefaults(
array(
'class' => 'ChillActivityBundle:ActivityReasonCategory',
'choice_label' => 'name['.$locale.']',
'query_builder' => function (EntityRepository $er) {
return $er->createQueryBuilder('c')
->where('c.active = true');
}
)
);
}
} }

View File

@@ -1,60 +1,67 @@
<?php <?php
/* /**
* Chill is a software for social workers * Chill is a software for social workers
* *
* Copyright (C) 2014-2015, Champs Libres Cooperative SCRLFS, * For the full copyright and license information, please view
* <http://www.champs-libres.coop>, <info@champs-libres.coop> * the LICENSE file that was distributed with this source code.
*
* 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\Form\Type; namespace Chill\ActivityBundle\Form\Type;
use Symfony\Component\Form\AbstractType; use Chill\ActivityBundle\Entity\ActivityType;
use Symfony\Component\OptionsResolver\OptionsResolver;
use Symfony\Component\HttpFoundation\RequestStack;
use Symfony\Bridge\Doctrine\Form\Type\EntityType;
use Chill\MainBundle\Templating\TranslatableStringHelper; use Chill\MainBundle\Templating\TranslatableStringHelper;
use Doctrine\ORM\EntityRepository; use Doctrine\ORM\EntityRepository;
use Chill\ActivityBundle\Entity\ActivityType; use Symfony\Bridge\Doctrine\Form\Type\EntityType;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\OptionsResolver\OptionsResolver;
/** /**
* Description of TranslatableActivityType * Description of TranslatableActivityType.
*
* @author Champs-Libres Coop
*/ */
class TranslatableActivityType extends AbstractType class TranslatableActivityType extends AbstractType
{ {
protected $activityTypeRepository;
/** /**
*
* @var TranslatableStringHelper * @var TranslatableStringHelper
*/ */
protected $translatableStringHelper; protected $translatableStringHelper;
protected $activityTypeRepository;
public function __construct( public function __construct(
TranslatableStringHelper $helper, TranslatableStringHelper $helper,
EntityRepository $activityTypeRepository EntityRepository $activityTypeRepository
) ) {
{
$this->translatableStringHelper = $helper; $this->translatableStringHelper = $helper;
$this->activityTypeRepository = $activityTypeRepository; $this->activityTypeRepository = $activityTypeRepository;
} }
public function buildForm(\Symfony\Component\Form\FormBuilderInterface $builder, array $options)
{
/* @var $qb \Doctrine\ORM\QueryBuilder */
$qb = $options['query_builder'];
if (true === $options['active_only']) {
$qb->where($qb->expr()->eq('at.active', ':active'));
$qb->setParameter('active', true, \Doctrine\DBAL\Types\Type::BOOLEAN);
}
}
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults(
[
'class' => 'ChillActivityBundle:ActivityType',
'active_only' => true,
'query_builder' => $this->activityTypeRepository
->createQueryBuilder('at'),
'choice_label' => function (ActivityType $type) {
return $this->translatableStringHelper->localize($type->getName());
},
]
);
}
public function getBlockPrefix() public function getBlockPrefix()
{ {
return 'translatable_activity_type'; return 'translatable_activity_type';
@@ -64,30 +71,4 @@ class TranslatableActivityType extends AbstractType
{ {
return EntityType::class; return EntityType::class;
} }
public function buildForm(\Symfony\Component\Form\FormBuilderInterface $builder, array $options) {
/* @var $qb \Doctrine\ORM\QueryBuilder */
$qb = $options['query_builder'];
if ($options['active_only'] === true) {
$qb->where($qb->expr()->eq('at.active', ':active'));
$qb->setParameter('active', true, \Doctrine\DBAL\Types\Type::BOOLEAN);
}
}
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults(
array(
'class' => 'ChillActivityBundle:ActivityType',
'active_only' => true,
'query_builder' => $this->activityTypeRepository
->createQueryBuilder('at'),
'choice_label' => function (ActivityType $type) {
return $this->translatableStringHelper->localize($type->getName());
}
)
);
}
} }

View File

@@ -1,47 +0,0 @@
<?php
namespace Chill\ActivityBundle\Menu;
use Chill\MainBundle\Routing\LocalMenuBuilderInterface;
use Chill\MainBundle\Security\Authorization\AuthorizationHelper;
use Chill\PersonBundle\Entity\AccompanyingPeriod;
use Knp\Menu\MenuItem;
use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface;
use Symfony\Contracts\Translation\TranslatorInterface;
class AccompanyingCourseMenuBuilder implements LocalMenuBuilderInterface
{
protected TokenStorageInterface $tokenStorage;
protected AuthorizationHelper $authorizationHelper;
protected TranslatorInterface $translator;
public function __construct(
TokenStorageInterface $tokenStorage,
AuthorizationHelper $authorizationHelper,
TranslatorInterface $translator
) {
$this->translator = $translator;
$this->authorizationHelper = $authorizationHelper;
$this->tokenStorage = $tokenStorage;
}
public static function getMenuIds(): array
{
return ['accompanyingCourse'];
}
public function buildMenu($menuId, MenuItem $menu, array $parameters)
{
$period = $parameters['accompanyingCourse'];
if (AccompanyingPeriod::STEP_DRAFT !== $period->getStep()) {
$menu->addChild($this->translator->trans('Activity'), [
'route' => 'chill_activity_activity_list',
'routeParameters' => [
'accompanying_period_id' => $period->getId(),
]])
->setExtras(['order' => 40]);
}
}
}

View File

@@ -0,0 +1,84 @@
<?php
/**
* Chill is a software for social workers
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/
namespace Chill\ActivityBundle\Menu;
use Chill\ActivityBundle\Security\Authorization\ActivityVoter;
use Chill\MainBundle\Routing\LocalMenuBuilderInterface;
use Chill\MainBundle\Security\Authorization\AuthorizationHelper;
use Knp\Menu\MenuItem;
use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface;
use Symfony\Component\Security\Core\Role\Role;
use Symfony\Component\Translation\TranslatorInterface;
class MenuBuilder implements LocalMenuBuilderInterface
{
/**
* @var AuthorizationHelper
*/
protected $authorizationHelper;
/**
* @var TokenStorageInterface
*/
protected $tokenStorage;
/**
* @var TranslatorInterface
*/
protected $translator;
public function __construct(
TokenStorageInterface $tokenStorage,
TranslatorInterface $translator,
AuthorizationHelper $authorizationHelper
) {
$this->tokenStorage = $tokenStorage;
$this->translator = $translator;
$this->authorizationHelper = $authorizationHelper;
}
public function buildMenu($menuId, MenuItem $menu, array $parameters)
{
/* @var $person \Chill\PersonBundle\Entity\Person */
$person = $parameters['person'];
$user = $this->tokenStorage->getToken()->getUser();
$roleSee = new Role(ActivityVoter::SEE);
$roleAdd = new Role(ActivityVoter::CREATE);
if ($this->authorizationHelper->userHasAccess($user, $person, $roleSee)) {
$menu->addChild($this->translator->trans('Activity list'), [
'route' => 'chill_activity_activity_list',
'routeParameters' => [
'person_id' => $person->getId(),
],
])
->setExtras([
'order' => 201,
]);
}
if ($this->authorizationHelper->userHasAccess($user, $person, $roleAdd)) {
$menu->addChild($this->translator->trans('Add a new activity'), [
'route' => 'chill_activity_activity_new',
'routeParameters' => [
'person_id' => $person->getId(),
],
])
->setExtras([
'order' => 200,
]);
}
}
public static function getMenuIds(): array
{
return ['person'];
}
}

View File

@@ -1,68 +1,65 @@
<?php <?php
/*
* Copyright (C) 2018 Julien Fastré <julien.fastre@champs-libres.coop> /**
* Chill is a software for social workers
* *
* This program is free software: you can redistribute it and/or modify * For the full copyright and license information, please view
* it under the terms of the GNU Affero General Public License as published by * the LICENSE file that was distributed with this source code.
* 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\Menu;
namespace Chill\ActivityBundle\Menu;
use Chill\ActivityBundle\Security\Authorization\ActivityVoter;
use Chill\MainBundle\Routing\LocalMenuBuilderInterface; use Chill\MainBundle\Routing\LocalMenuBuilderInterface;
use Knp\Menu\MenuItem; use Knp\Menu\MenuItem;
use Symfony\Component\Security\Core\Authorization\AuthorizationCheckerInterface; use Symfony\Component\Security\Core\Authorization\AuthorizationCheckerInterface;
use Chill\ActivityBundle\Security\Authorization\ActivityVoter;
use Symfony\Component\Translation\TranslatorInterface; use Symfony\Component\Translation\TranslatorInterface;
/**
*
*
* @author Julien Fastré <julien.fastre@champs-libres.coop>
*/
class PersonMenuBuilder implements LocalMenuBuilderInterface class PersonMenuBuilder implements LocalMenuBuilderInterface
{ {
/** /**
*
* @var TranslatorInterface
*/
protected $translator;
/**
*
* @var AuthorizationCheckerInterface * @var AuthorizationCheckerInterface
*/ */
protected $authorizationChecker; protected $authorizationChecker;
/**
* @var TranslatorInterface
*/
protected $translator;
public function __construct( public function __construct(
AuthorizationCheckerInterface $authorizationChecker, AuthorizationCheckerInterface $authorizationChecker,
TranslatorInterface $translator) TranslatorInterface $translator
{ ) {
$this->translator = $translator; $this->translator = $translator;
$this->authorizationChecker = $authorizationChecker; $this->authorizationChecker = $authorizationChecker;
} }
public function buildMenu($menuId, MenuItem $menu, array $parameters) public function buildMenu($menuId, MenuItem $menu, array $parameters)
{ {
/* @var $person \Chill\PersonBundle\Entity\Person */ /* @var $person \Chill\PersonBundle\Entity\Person */
$person = $parameters['person']; $person = $parameters['person'];
if ($this->authorizationChecker->isGranted(ActivityVoter::SEE, $person)) { if ($this->authorizationChecker->isGranted(ActivityVoter::SEE, $person)) {
$menu->addChild( $menu->addChild(
$this->translator->trans('Activity list'), [ $this->translator->trans('Activity list'),
[
'route' => 'chill_activity_activity_list', 'route' => 'chill_activity_activity_list',
'routeParameters' => [ 'person_id' => $person->getId() ], 'routeParameters' => ['person_id' => $person->getId()],
]) ]
->setExtra('order', 201) )
; ->setExtra('order', 201);
}
if ($this->authorizationChecker->isGranted(ActivityVoter::CREATE, $person)) {
$menu->addChild(
$this->translator->trans('Add a new activity'),
[
'route' => 'chill_activity_activity_new',
'routeParameters' => ['person_id' => $person->getId()],
]
)
->setExtra('order', 200);
} }
} }

View File

@@ -1,24 +0,0 @@
<?php
namespace Chill\ActivityBundle\Notification;
use Chill\MainBundle\Entity\Notification;
use Chill\ActivityBundle\Entity\Activity;
final class ActivityNotificationRenderer
{
public function supports(Notification $notification, array $options = []): bool
{
return $notification->getRelatedEntityClass() == Activity::class;
}
public function getTemplate()
{
return '@ChillActivity/Activity/showInNotification.html.twig';
}
public function getTemplateData(Notification $notification)
{
return ['notification' => $notification];
}
}

View File

@@ -1,219 +0,0 @@
<?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\MainBundle\Security\Resolver\CenterResolverDispatcher;
use Chill\PersonBundle\Entity\AccompanyingPeriod;
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;
use Symfony\Component\Security\Core\Security;
final class ActivityACLAwareRepository implements ActivityACLAwareRepositoryInterface
{
private AuthorizationHelper $authorizationHelper;
private TokenStorageInterface $tokenStorage;
private ActivityRepository $repository;
private EntityManagerInterface $em;
private Security $security;
private CenterResolverDispatcher $centerResolverDispatcher;
public function __construct(
AuthorizationHelper $authorizationHelper,
CenterResolverDispatcher $centerResolverDispatcher,
TokenStorageInterface $tokenStorage,
ActivityRepository $repository,
EntityManagerInterface $em,
Security $security
) {
$this->authorizationHelper = $authorizationHelper;
$this->centerResolverDispatcher = $centerResolverDispatcher;
$this->tokenStorage = $tokenStorage;
$this->repository = $repository;
$this->em = $em;
$this->security = $security;
}
/**
* @param Person $person
* @param string $role
* @param int|null $start
* @param int|null $limit
* @param array $orderBy
* @return array|Activity[]
*/
public function findByPerson(Person $person, string $role, ?int $start = 0, ?int $limit = 1000, ?array $orderBy = []): array
{
$user = $this->security->getUser();
$center = $this->centerResolverDispatcher->resolveCenter($person);
if (0 === count($orderBy)) {
$orderBy = ['date' => 'DESC'];
}
$reachableScopes = $this->authorizationHelper
->getReachableCircles($user, $role, $center);
return $this->em->getRepository(Activity::class)
->findByPersonImplied($person, $reachableScopes, $orderBy, $limit, $start);
;
}
public function findByAccompanyingPeriod(AccompanyingPeriod $period, string $role, ?int $start = 0, ?int $limit = 1000, ?array $orderBy = []): array
{
$user = $this->security->getUser();
$center = $this->centerResolverDispatcher->resolveCenter($period);
if (0 === count($orderBy)) {
$orderBy = ['date' => 'DESC'];
}
$scopes = $this->authorizationHelper
->getReachableCircles($user, $role, $center);
return $this->em->getRepository(Activity::class)
->findByAccompanyingPeriod($period, $scopes, true, $limit, $start, $orderBy);
}
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

@@ -1,19 +0,0 @@
<?php
namespace Chill\ActivityBundle\Repository;
use Chill\PersonBundle\Entity\AccompanyingPeriod;
use Chill\PersonBundle\Entity\Person;
interface ActivityACLAwareRepositoryInterface
{
/**
* @return array|Activity[]
*/
public function findByPerson(Person $person, string $role, ?int $start = 0, ?int $limit = 1000, ?array $orderBy = []): array;
/**
* @return array|Activity[]
*/
public function findByAccompanyingPeriod(AccompanyingPeriod $period, string $role, ?int $start = 0, ?int $limit = 1000, ?array $orderBy = []): array;
}

View File

@@ -1,125 +0,0 @@
<?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\AccompanyingPeriod;
use Chill\PersonBundle\Entity\Person;
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);
}
/**
* @param $person
* @param array $scopes
* @param string[] $orderBy
* @param int $limit
* @param int $offset
* @return array|Activity[]
*/
public function findByPersonImplied(Person $person, array $scopes, ?array $orderBy = [ 'date' => 'DESC'], ?int $limit = 100, ?int $offset = 0): array
{
$qb = $this->createQueryBuilder('a');
$qb->select('a');
$qb
->where($qb->expr()->in('a.scope', ':scopes'))
->setParameter('scopes', $scopes)
->andWhere(
$qb->expr()->orX(
$qb->expr()->eq('a.person', ':person'),
':person MEMBER OF a.persons'
)
)
->setParameter('person', $person)
;
foreach ($orderBy as $k => $dir) {
$qb->addOrderBy('a.'.$k, $dir);
}
$qb->setMaxResults($limit)->setFirstResult($offset);
return $qb->getQuery()
->getResult();
}
/**
* @param AccompanyingPeriod $period
* @param array $scopes
* @param int|null $limit
* @param int|null $offset
* @param array|string[] $orderBy
* @return array|Activity[]
*/
public function findByAccompanyingPeriod(AccompanyingPeriod $period, array $scopes, ?bool $allowNullScope = false, ?int $limit = 100, ?int $offset = 0, array $orderBy = ['date' => 'desc']): array
{
$qb = $this->createQueryBuilder('a');
$qb->select('a');
if (!$allowNullScope) {
$qb
->where($qb->expr()->in('a.scope', ':scopes'))
->setParameter('scopes', $scopes)
;
} else {
$qb
->where(
$qb->expr()->orX(
$qb->expr()->in('a.scope', ':scopes'),
$qb->expr()->isNull('a.scope')
)
)
->setParameter('scopes', $scopes)
;
}
$qb
->andWhere(
$qb->expr()->eq('a.accompanyingPeriod', ':period')
)
->setParameter('period', $period)
;
foreach ($orderBy as $k => $dir) {
$qb->addOrderBy('a.'.$k, $dir);
}
$qb->setMaxResults($limit)->setFirstResult($offset);
return $qb->getQuery()
->getResult();
}
}

View File

@@ -0,0 +1,10 @@
@import '~ChillMainSass/custom/config/colors';
@import '~ChillMainSass/custom/mixins/entity';
.chill-entity.chill-entity__activity-reason {
@include entity($chill-pink, white);
}
.activity {
color: $chill-green;
}

View File

@@ -1,142 +0,0 @@
// Access to Bootstrap variables and mixins
@import '~ChillMainAssets/module/bootstrap/shared';
// activity creation first step: select type page
div.new-activity-select-type {
div.activity-row {
display: flex;
flex-direction: row;
flex-wrap: wrap;
justify-content: center;
gap: 12px;
div.bloc {
width: 200px;
align-self: flex-end;
height: 140px;
display: flex;
justify-content: center;
align-items: center;
}
}
}
// exceptions for flex-table in list-records
div.activity-list {
div.flex-table {
div.item-bloc {
div.item-row.main {
div.item-col {
&:first-child {
flex-basis: 15%;
}
ul.list-content {
li.social-issues, li.social-actions {
.badge-primary {
font-variant: small-caps;
font-weight: bold;
font-size: 88%;
margin-bottom: 0.2em;
}
}
li.social-issues .badge-primary {
background-color: $orange;
}
li.social-actions .badge-primary {
background-color: $green;
}
}
}
}
div.item-row.comment {
margin-left: 15%;
blockquote.chill-user-quote {
margin-top: 0.5em;
margin-bottom: 0.5em;
}
}
div.item-row.details {
margin-left: 15%;
// override flex-bloc to adapt in list
// TODO refund this
div.accompanyingCourse.flex-bloc.concerned-groups {
margin: 0;
width: 100%;
justify-content: space-around;
div.item-bloc {
box-shadow: unset;
padding: 0;
flex-basis: 25%;
div.item-row {
flex-direction: column;
div.item-col {
&:first-child {
width: unset;
}
&:last-child {
border-top: 0;
margin-top: 0;
padding-top: 0;
ul.list-content {
padding: 0;
}
}
}
}
}
}
}
ul.list-content {
list-style-type: none;
padding-left: 1em;
margin: 0 0;
li {
margin-bottom: 0.2em;
}
}
}
div.duration {
font-size: smaller;
padding-left: 1em;
margin-top: 1em;
}
}
}
// exceptions for flex-bloc in concerned-groups
div.flex-bloc.concerned-groups {
margin-top: 1em;
div.item-bloc {
flex-grow: 0; flex-shrink: 0; flex-basis: 25%; //4 blocs
ul.list-content {
list-style-type: none;
padding-left: 0;
li {
margin-bottom: 0.2em;
a {
color: $white;
cursor: pointer;
&:hover {
color: #ffffffab;
}
}
}
}
}
&.person div.item-bloc {
flex-basis: 33%; //3 blocs
}
}
/// CHILL ENTITY RENDER BOX
.chill-entity {
/// ACTIVITY-REASON
&.entity-activity-reason {
margin-right: 0.3em;
font-size: 120%;
}
}

View File

@@ -1 +0,0 @@
require('./chillactivity.scss');

View File

@@ -0,0 +1 @@
require('./activity/activity.scss');

View File

@@ -1,17 +0,0 @@
<template>
<concerned-groups></concerned-groups>
<social-issues-acc></social-issues-acc>
</template>
<script>
import ConcernedGroups from './components/ConcernedGroups.vue';
import SocialIssuesAcc from './components/SocialIssuesAcc.vue';
export default {
name: "App",
components: {
ConcernedGroups,
SocialIssuesAcc
}
}
</script>

View File

@@ -1,18 +0,0 @@
import { getSocialIssues } from 'ChillPersonAssets/vuejs/AccompanyingCourse/api.js';
/*
* Load socialActions by socialIssue (id)
*/
const getSocialActionByIssue = (id) => {
const url = `/api/1.0/person/social/social-action/by-social-issue/${id}.json`;
return fetch(url)
.then(response => {
if (response.ok) { return response.json(); }
throw Error('Error with request resource response');
});
};
export {
getSocialIssues,
getSocialActionByIssue
};

View File

@@ -1,185 +0,0 @@
<template>
<teleport to="#add-persons">
<div class="flex-bloc concerned-groups" :class="getContext">
<persons-bloc
v-for="bloc in contextPersonsBlocs"
v-bind:key="bloc.key"
v-bind:bloc="bloc"
v-bind:setPersonsInBloc="setPersonsInBloc">
</persons-bloc>
</div>
<div v-if="getContext === 'accompanyingCourse' && filterSuggestedPersons.length > 0">
<ul>
<li v-for="p in filterSuggestedPersons" @click="addNewPerson(p)">
{{ p.text }}
</li>
</ul>
</div>
<add-persons
buttonTitle="activity.add_persons"
modalTitle="activity.add_persons"
v-bind:key="addPersons.key"
v-bind:options="addPersons.options"
@addNewPersons="addNewPersons"
ref="addPersons">
</add-persons>
</teleport>
</template>
<script>
import { mapState, mapGetters } from 'vuex';
import AddPersons from 'ChillPersonAssets/vuejs/_components/AddPersons.vue';
import PersonsBloc from './ConcernedGroups/PersonsBloc.vue';
export default {
name: "ConcernedGroups",
components: {
AddPersons,
PersonsBloc
},
data() {
return {
personsBlocs: [
{ key: 'persons',
title: 'activity.bloc_persons',
persons: [],
included: false
},
{ key: 'personsAssociated',
title: 'activity.bloc_persons_associated',
persons: [],
included: false
},
{ key: 'personsNotAssociated',
title: 'activity.bloc_persons_not_associated',
persons: [],
included: false
},
{ key: 'thirdparty',
title: 'activity.bloc_thirdparty',
persons: [],
included: true
},
{ key: 'users',
title: 'activity.bloc_users',
persons: [],
included: true
},
],
addPersons: {
key: 'activity',
options: {
type: ['person', 'thirdparty', 'user'], // TODO add 'user'
priority: null,
uniq: false,
}
}
}
},
computed: {
...mapState({
persons: state => state.activity.persons,
thirdParties: state => state.activity.thirdParties,
users: state => state.activity.users,
accompanyingCourse: state => state.activity.accompanyingPeriod
}),
...mapGetters([
'filterSuggestedPersons'
]),
getContext() {
return (this.accompanyingCourse) ? "accompanyingCourse" : "person";
},
contextPersonsBlocs() {
return this.personsBlocs.filter(bloc => bloc.included !== false);
}
},
mounted() {
this.setPersonsInBloc();
},
methods: {
setPersonsInBloc() {
let groups;
if (this.accompanyingCourse) {
groups = this.splitPersonsInGroups();
}
this.personsBlocs.forEach(bloc => {
if (this.accompanyingCourse) {
switch (bloc.key) {
case 'personsAssociated':
bloc.persons = groups.personsAssociated;
bloc.included = true;
break;
case 'personsNotAssociated':
bloc.persons = groups.personsNotAssociated;
bloc.included = true;
break;
}
} else {
switch (bloc.key) {
case 'persons':
bloc.persons = this.persons;
bloc.included = true;
break;
}
}
switch (bloc.key) {
case 'thirdparty':
bloc.persons = this.thirdParties;
break;
case 'users':
bloc.persons = this.users;
break;
}
}, groups);
},
splitPersonsInGroups() {
let personsAssociated = [];
let personsNotAssociated = this.persons;
let participations = this.getCourseParticipations();
this.persons.forEach(person => {
participations.forEach(participation => {
if (person.id === participation.id) {
//console.log(person.id);
personsAssociated.push(person);
personsNotAssociated = personsNotAssociated.filter(p => p !== person);
}
});
});
return {
'personsAssociated': personsAssociated,
'personsNotAssociated': personsNotAssociated
};
},
getCourseParticipations() {
let participations = [];
this.accompanyingCourse.participations.forEach(participation => {
if (!participation.endDate) {
participations.push(participation.person);
}
});
return participations;
},
addNewPersons({ selected, modal }) {
console.log('@@@ CLICK button addNewPersons', selected);
selected.forEach(function(item) {
this.$store.dispatch('addPersonsInvolved', item);
}, this
);
this.$refs.addPersons.resetSearch(); // to cast child method
modal.showModal = false;
this.setPersonsInBloc();
},
addNewPerson(person) {
this.$store.dispatch('addPersonsInvolved', { result: person, type: 'person' });
this.setPersonsInBloc();
},
}
}
</script>
<style lang="scss" scoped>
</style>

View File

@@ -1,29 +0,0 @@
<template>
<li>
<span class="badge bg-primary" :title="person.text">
<span class="chill_denomination">
{{ textCutted }}
</span>
<a class="fa fa-fw fa-times"
@click.prevent="$emit('remove', person)">
</a>
</span>
</li>
</template>
<script>
export default {
name: "PersonBadge",
props: ['person'],
computed: {
textCutted() {
let more = (this.person.text.length > 15) ?'…' : '';
return this.person.text.slice(0,15) + more;
}
},
emits: ['remove'],
}
</script>
<style lang="css" scoped>
</style>

View File

@@ -1,41 +0,0 @@
<template>
<div class="item-bloc">
<div class="item-row">
<div class="item-col">
<h4>{{ $t(bloc.title) }}</h4>
</div>
<div class="item-col">
<ul class="list-content">
<person-badge
v-for="person in bloc.persons"
v-bind:key="person.id"
v-bind:person="person"
@remove="removePerson">
</person-badge>
</ul>
</div>
</div>
</div>
</template>
<script>
import PersonBadge from './PersonBadge.vue';
export default {
name:"PersonsBloc",
components: {
PersonBadge
},
props: ['bloc', 'setPersonsInBloc'],
methods: {
removePerson(item) {
console.log('@@ CLICK remove person: item', item);
this.$store.dispatch('removePersonInvolved', item);
this.setPersonsInBloc();
}
}
}
</script>
<style lang="scss">
</style>

View File

@@ -1,214 +0,0 @@
<template>
<teleport to="#social-issues-acc">
<div class="mb-3 row">
<div class="col-4">
<label class="col-form-label">{{ $t('activity.social_issues') }}</label>
</div>
<div class="col-8">
<check-social-issue
v-for="issue in socialIssuesList"
v-bind:key="issue.id"
v-bind:issue="issue"
v-bind:selection="socialIssuesSelected"
@updateSelected="updateIssuesSelected">
</check-social-issue>
<div class="my-3">
<VueMultiselect
name="otherIssues"
label="text"
track-by="id"
open-direction="bottom"
v-bind:close-on-select="true"
v-bind:preserve-search="false"
v-bind:reset-after="true"
v-bind:hide-selected="true"
v-bind:taggable="false"
v-bind:multiple="false"
v-bind:searchable="true"
v-bind:allow-empty="true"
v-bind:show-labels="false"
v-bind:loading="issueIsLoading"
v-bind:placeholder="$t('activity.choose_other_social_issue')"
v-bind:options="socialIssuesOther"
v-model="value"
@select="addIssueInList">
</VueMultiselect>
</div>
</div>
</div>
<div class="mb-3 row">
<div class="col-4">
<label class="col-form-label">{{ $t('activity.social_actions') }}</label>
</div>
<div class="col-8">
<div v-if="actionIsLoading === true">
<i class="chill-green fa fa-circle-o-notch fa-spin fa-lg"></i>
</div>
<check-social-action
v-if="socialIssuesSelected.length || socialActionsSelected.length"
v-for="action in socialActionsList"
v-bind:key="action.id"
v-bind:action="action"
v-bind:selection="socialActionsSelected"
@updateSelected="updateActionsSelected">
</check-social-action>
<span v-else class="inline-choice chill-no-data-statement mt-3">
{{ $t('activity.select_first_a_social_issue') }}
</span>
</div>
</div>
</teleport>
</template>
<script>
import { readonly } from 'vue';
import VueMultiselect from 'vue-multiselect';
import CheckSocialIssue from './SocialIssuesAcc/CheckSocialIssue.vue';
import CheckSocialAction from './SocialIssuesAcc/CheckSocialAction.vue';
import { getSocialIssues, getSocialActionByIssue } from '../api.js';
export default {
name: "SocialIssuesAcc",
components: {
CheckSocialIssue,
CheckSocialAction,
VueMultiselect
},
data() {
return {
issueIsLoading: false,
actionIsLoading: false
}
},
computed: {
socialIssuesList() {
return this.$store.state.activity.accompanyingPeriod.socialIssues;
},
socialIssuesSelected() {
return this.$store.state.activity.socialIssues;
},
socialIssuesOther() {
return this.$store.state.socialIssuesOther;
},
socialActionsList() {
return this.$store.state.socialActionsList;
},
socialActionsSelected() {
return this.$store.state.activity.socialActions;
}
},
mounted() {
/* Load others issues in multiselect
*/
this.issueIsLoading = true;
getSocialIssues().then(response => new Promise((resolve, reject) => {
this.$store.commit('updateIssuesOther', response.results);
/* Add in list the issues already associated (if not yet listed)
*/
this.socialIssuesSelected.forEach(issue => {
if (this.socialIssuesList.filter(i => i.id === issue.id).length !== 1) {
this.$store.commit('addIssueInList', issue);
}
}, this);
/* Remove from multiselect the issues that are not yet in checkbox list
*/
this.socialIssuesList.forEach(issue => {
this.$store.commit('removeIssueInOther', issue);
}, this);
/* Filter issues
*/
this.$store.commit('filterList', 'issues');
/* Add in list the actions already associated (if not yet listed)
*/
this.socialActionsSelected.forEach(action => {
this.$store.commit('addActionInList', action);
}, this);
/* Filter issues
*/
this.$store.commit('filterList', 'actions');
this.issueIsLoading = false;
resolve();
}));
},
methods: {
/* When choosing an issue in multiselect, add it in checkboxes (as selected),
remove it from multiselect, and add socialActions concerned
*/
addIssueInList(value) {
//console.log('addIssueInList', value);
this.$store.commit('addIssueInList', value);
this.$store.commit('removeIssueInOther', value);
this.$store.dispatch('addIssueSelected', value);
this.updateActionsList();
},
/* Update value for selected issues checkboxes
*/
updateIssuesSelected(issues) {
//console.log('updateIssuesSelected', issues);
this.$store.dispatch('updateIssuesSelected', issues);
this.updateActionsList();
},
/* Update value for selected actions checkboxes
*/
updateActionsSelected(actions) {
//console.log('updateActionsSelected', actions);
this.$store.dispatch('updateActionsSelected', actions);
},
/* Add socialActions concerned: after reset, loop on each issue selected
to get social actions concerned
*/
updateActionsList() {
//console.log('updateActionsList');
this.resetActionsList();
this.socialIssuesSelected.forEach(item => {
this.actionIsLoading = true;
getSocialActionByIssue(item.id)
.then(actions => new Promise((resolve, reject) => {
actions.results.forEach(action => {
this.$store.commit('addActionInList', action);
}, this);
this.$store.commit('filterList', 'actions');
this.actionIsLoading = false;
resolve();
}));
}, this);
},
/* Reset socialActions List: flush list and restore selected actions
*/
resetActionsList() {
this.$store.commit('resetActionsList');
this.socialActionsSelected.forEach(item => {
this.$store.commit('addActionInList', item);
}, this);
}
}
}
</script>
<style src="vue-multiselect/dist/vue-multiselect.css"></style>
<style lang="scss">
span.multiselect__single {
display: none !important;
}
</style>

View File

@@ -1,36 +0,0 @@
<template>
<span class="inline-choice">
<div class="form-check">
<input class="form-check-input"
type="checkbox"
v-model="selected"
name="action"
v-bind:id="action.id"
v-bind:value="action"
/>
<label class="form-check-label" v-bind:for="action.id">
{{ action.text }}
</label>
</div>
</span>
</template>
<script>
export default {
name: "CheckSocialAction",
props: [ 'action', 'selection' ],
emits: [ 'updateSelected' ],
computed: {
selected: {
set(value) {
this.$emit('updateSelected', value);
},
get() {
return this.selection;
}
}
}
}
</script>

View File

@@ -1,36 +0,0 @@
<template>
<span class="inline-choice">
<div class="form-check">
<input class="form-check-input"
type="checkbox"
v-model="selected"
name="issue"
v-bind:id="issue.id"
v-bind:value="issue"
/>
<label class="form-check-label" v-bind:for="issue.id">
{{ issue.text }}
</label>
</div>
</span>
</template>
<script>
export default {
name: "CheckSocialIssue",
props: [ 'issue', 'selection' ],
emits: [ 'updateSelected' ],
computed: {
selected: {
set(value) {
this.$emit('updateSelected', value);
},
get() {
return this.selection;
}
}
}
}
</script>

View File

@@ -1,27 +0,0 @@
import { personMessages } from 'ChillPersonAssets/vuejs/_js/i18n'
const appMessages = {
fr: {
activity: {
//
social_issues: "Problématiques sociales",
choose_other_social_issue: "Ajouter une autre problématique sociale...",
social_actions: "Actions d'accompagnement",
select_first_a_social_issue: "Sélectionnez d'abord une problématique sociale",
//
add_persons: "Ajouter des personnes concernées",
bloc_persons: "Usagers",
bloc_persons_associated: "Usagers du parcours",
bloc_persons_not_associated: "Tiers non-pro.",
bloc_thirdparty: "Tiers professionnels",
bloc_users: "T(M)S",
}
}
}
Object.assign(appMessages.fr, personMessages.fr);
export {
appMessages
};

View File

@@ -1,16 +0,0 @@
import { createApp } from 'vue';
import { _createI18n } from 'ChillMainAssets/vuejs/_js/i18n'
import { appMessages } from './i18n'
import store from './store'
import App from './App.vue';
const i18n = _createI18n(appMessages);
const app = createApp({
template: `<app></app>`,
})
.use(store)
.use(i18n)
.component('app', App)
.mount('#activity');

View File

@@ -1,180 +0,0 @@
import 'es6-promise/auto';
import { createStore } from 'vuex';
const debug = process.env.NODE_ENV !== 'production';
//console.log('window.activity', window.activity);
const addIdToValue = (string, id) => {
let array = string ? string.split(',') : [];
array.push(id.toString());
let str = array.join();
return str;
};
const removeIdFromValue = (string, id) => {
let array = string.split(',');
array = array.filter(el => el !== id.toString());
let str = array.join();
return str;
};
const store = createStore({
strict: debug,
state: {
activity: window.activity,
socialIssuesOther: [],
socialActionsList: [],
},
getters: {
filterSuggestedPersons(state) {
if (typeof(state.activity.accompanyingPeriod) === 'undefined') {
return [];
}
let existingPersonIds = state.activity.persons.map(p => p.id);
return state.activity.accompanyingPeriod.participations.filter(p => p.endDate === null)
.map(p => p.person)
.filter(p => !existingPersonIds.includes(p.id))
}
},
mutations: {
// SocialIssueAcc
addIssueInList(state, issue) {
//console.log('add issue list', issue.id);
state.activity.accompanyingPeriod.socialIssues.push(issue);
},
addIssueSelected(state, issue) {
//console.log('add issue selected', issue.id);
state.activity.socialIssues.push(issue);
},
updateIssuesSelected(state, issues) {
//console.log('update issues selected', issues);
state.activity.socialIssues = issues;
},
updateIssuesOther(state, payload) {
//console.log('update issues other');
state.socialIssuesOther = payload;
},
removeIssueInOther(state, issue) {
//console.log('remove issue other', issue.id);
state.socialIssuesOther = state.socialIssuesOther.filter(i => i.id !== issue.id);
},
resetActionsList(state) {
//console.log('reset list actions');
state.socialActionsList = [];
},
addActionInList(state, action) {
//console.log('add action list', action.id);
state.socialActionsList.push(action);
},
updateActionsSelected(state, actions) {
//console.log('update actions selected', actions);
state.activity.socialActions = actions;
},
filterList(state, list) {
const filterList = (list) => {
// remove duplicates entries
list = list.filter((value, index) => list.findIndex(array => array.id === value.id) === index);
// alpha sort
list.sort((a,b) => (a.text > b.text) ? 1 : ((b.text > a.text) ? -1 : 0));
return list;
};
if (list === 'issues') {
state.activity.accompanyingPeriod.socialIssues = filterList(state.activity.accompanyingPeriod.socialIssues);
}
if (list === 'actions') {
state.socialActionsList = filterList(state.socialActionsList);
}
},
// ConcernedGroups
addPersonsInvolved(state, payload) {
//console.log('### mutation addPersonsInvolved', payload.result.type);
switch (payload.result.type) {
case 'person':
state.activity.persons.push(payload.result);
break;
case 'thirdparty':
state.activity.thirdParties.push(payload.result);
break;
case 'user':
state.activity.users.push(payload.result);
break;
};
},
removePersonInvolved(state, payload) {
//console.log('### mutation removePersonInvolved', payload.type);
switch (payload.type) {
case 'person':
state.activity.persons = state.activity.persons.filter(person => person !== payload);
break;
case 'thirdparty':
state.activity.thirdParties = state.activity.thirdParties.filter(thirdparty => thirdparty !== payload);
break;
case 'user':
state.activity.users = state.activity.users.filter(user => user !== payload);
break;
};
}
},
actions: {
addIssueSelected({ commit }, issue) {
let aSocialIssues = document.getElementById("chill_activitybundle_activity_socialIssues");
aSocialIssues.value = addIdToValue(aSocialIssues.value, issue.id);
commit('addIssueSelected', issue);
},
updateIssuesSelected({ commit }, payload) {
let aSocialIssues = document.getElementById("chill_activitybundle_activity_socialIssues");
aSocialIssues.value = '';
payload.forEach(item => {
aSocialIssues.value = addIdToValue(aSocialIssues.value, item.id);
});
commit('updateIssuesSelected', payload);
},
updateActionsSelected({ commit }, payload) {
let aSocialActions = document.getElementById("chill_activitybundle_activity_socialActions");
aSocialActions.value = '';
payload.forEach(item => {
aSocialActions.value = addIdToValue(aSocialActions.value, item.id);
});
commit('updateActionsSelected', payload);
},
addPersonsInvolved({ commit }, payload) {
//console.log('### action addPersonsInvolved', payload.result.type);
switch (payload.result.type) {
case 'person':
let aPersons = document.getElementById("chill_activitybundle_activity_persons");
aPersons.value = addIdToValue(aPersons.value, payload.result.id);
break;
case 'thirdparty':
let aThirdParties = document.getElementById("chill_activitybundle_activity_thirdParties");
aThirdParties.value = addIdToValue(aThirdParties.value, payload.result.id);
break;
case 'user':
let aUsers = document.getElementById("chill_activitybundle_activity_users");
aUsers.value = addIdToValue(aUsers.value, payload.result.id);
break;
};
commit('addPersonsInvolved', payload);
},
removePersonInvolved({ commit }, payload) {
//console.log('### action removePersonInvolved', payload);
switch (payload.type) {
case 'person':
let aPersons = document.getElementById("chill_activitybundle_activity_persons");
aPersons.value = removeIdFromValue(aPersons.value, payload.id);
break;
case 'thirdparty':
let aThirdParties = document.getElementById("chill_activitybundle_activity_thirdParties");
aThirdParties.value = removeIdFromValue(aThirdParties.value, payload.id);
break;
case 'user':
let aUsers = document.getElementById("chill_activitybundle_activity_users");
aUsers.value = removeIdFromValue(aUsers.value, payload.id);
break;
};
commit('removePersonInvolved', payload);
}
}
});
export default store;

View File

@@ -1,13 +1,36 @@
<?php <?php
use Symfony\Component\HttpKernel\Kernel; /**
* Chill is a software for social workers
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/
use Symfony\Component\Config\Loader\LoaderInterface; use Symfony\Component\Config\Loader\LoaderInterface;
use Symfony\Component\HttpKernel\Kernel;
class AppKernel extends Kernel class AppKernel extends Kernel
{ {
/**
* @return string
*/
public function getCacheDir()
{
return sys_get_temp_dir() . '/ActivityBundle/cache';
}
/**
* @return string
*/
public function getLogDir()
{
return sys_get_temp_dir() . '/ActivityBundle/logs';
}
public function registerBundles() public function registerBundles()
{ {
return array( return [
new Symfony\Bundle\FrameworkBundle\FrameworkBundle(), new Symfony\Bundle\FrameworkBundle\FrameworkBundle(),
new Chill\CustomFieldsBundle\ChillCustomFieldsBundle(), new Chill\CustomFieldsBundle\ChillCustomFieldsBundle(),
new Symfony\Bundle\SecurityBundle\SecurityBundle(), new Symfony\Bundle\SecurityBundle\SecurityBundle(),
@@ -20,28 +43,12 @@ class AppKernel extends Kernel
new \Doctrine\Bundle\FixturesBundle\DoctrineFixturesBundle(), new \Doctrine\Bundle\FixturesBundle\DoctrineFixturesBundle(),
new Doctrine\Bundle\MigrationsBundle\DoctrineMigrationsBundle(), new Doctrine\Bundle\MigrationsBundle\DoctrineMigrationsBundle(),
new Symfony\Bundle\MonologBundle\MonologBundle(), new Symfony\Bundle\MonologBundle\MonologBundle(),
#add here all the required bundle (some bundle are not required) //add here all the required bundle (some bundle are not required)
); ];
} }
public function registerContainerConfiguration(LoaderInterface $loader) public function registerContainerConfiguration(LoaderInterface $loader)
{ {
$loader->load($this->getRootDir().'/config/config_'.$this->getEnvironment().'.yml'); $loader->load($this->getRootDir() . '/config/config_' . $this->getEnvironment() . '.yml');
}
/**
* @return string
*/
public function getCacheDir()
{
return sys_get_temp_dir().'/ActivityBundle/cache';
}
/**
* @return string
*/
public function getLogDir()
{
return sys_get_temp_dir().'/ActivityBundle/logs';
} }
} }

View File

@@ -1,11 +1,18 @@
<?php <?php
use Doctrine\Common\Annotations\AnnotationRegistry; /**
* Chill is a software for social workers
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/
use Composer\Autoload\ClassLoader; use Composer\Autoload\ClassLoader;
use Doctrine\Common\Annotations\AnnotationRegistry;
/** @var ClassLoader $loader */ /** @var ClassLoader $loader */
$loader = require __DIR__.'/../../../../../vendor/autoload.php'; $loader = require __DIR__ . '/../../../../../vendor/autoload.php';
AnnotationRegistry::registerLoader(array($loader, 'loadClass')); AnnotationRegistry::registerLoader([$loader, 'loadClass']);
return $loader; return $loader;

File diff suppressed because one or more lines are too long

View File

@@ -1,7 +1,14 @@
<?php <?php
use Symfony\Component\HttpFoundation\Request; /**
* Chill is a software for social workers
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/
use Symfony\Component\Debug\Debug; use Symfony\Component\Debug\Debug;
use Symfony\Component\HttpFoundation\Request;
// If you don't want to setup permissions the proper way, just uncomment the following PHP line // If you don't want to setup permissions the proper way, just uncomment the following PHP line
// read http://symfony.com/doc/current/book/installation.html#configuration-and-setup for more information // read http://symfony.com/doc/current/book/installation.html#configuration-and-setup for more information
@@ -9,18 +16,20 @@ use Symfony\Component\Debug\Debug;
// This check prevents access to debug front controllers that are deployed by accident to production servers. // This check prevents access to debug front controllers that are deployed by accident to production servers.
// Feel free to remove this, extend it, or make something more sophisticated. // Feel free to remove this, extend it, or make something more sophisticated.
if (isset($_SERVER['HTTP_CLIENT_IP']) if (
isset($_SERVER['HTTP_CLIENT_IP'])
|| isset($_SERVER['HTTP_X_FORWARDED_FOR']) || isset($_SERVER['HTTP_X_FORWARDED_FOR'])
|| !(in_array(@$_SERVER['REMOTE_ADDR'], array('127.0.0.1', 'fe80::1', '::1')) || php_sapi_name() === 'cli-server') || !(in_array(@$_SERVER['REMOTE_ADDR'], ['127.0.0.1', 'fe80::1', '::1']) || php_sapi_name() === 'cli-server')
) { ) {
header('HTTP/1.0 403 Forbidden'); header('HTTP/1.0 403 Forbidden');
exit('You are not allowed to access this file. Check '.basename(__FILE__).' for more information.');
exit('You are not allowed to access this file. Check ' . basename(__FILE__) . ' for more information.');
} }
$loader = require_once __DIR__.'/../app/bootstrap.php.cache'; $loader = require_once __DIR__ . '/../app/bootstrap.php.cache';
Debug::enable(); Debug::enable();
require_once __DIR__.'/../app/AppKernel.php'; require_once __DIR__ . '/../app/AppKernel.php';
$kernel = new AppKernel('dev', true); $kernel = new AppKernel('dev', true);
$kernel->loadClassCache(); $kernel->loadClassCache();

View File

@@ -1,103 +0,0 @@
{% macro href(pathname, key, value) %}
{% set parms = { (key): value } %}
{{ path(pathname, parms) }}
{% endmacro %}
{% if context == 'person' %}
{% set blocs = [
{ 'title': 'Others persons'|trans,
'items': entity.persons,
'path' : 'chill_person_view',
'key' : 'person_id'
},
{ 'title': 'Third parties'|trans,
'items': entity.thirdParties,
'path' : 'chill_3party_3party_show',
'key' : 'thirdparty_id'
},
{ 'title': 'Users concerned'|trans,
'items': entity.users,
'path' : 'admin_user_show',
'key' : 'id'
},
] %}
{% else %}
{% set blocs = [
{ 'title': 'Persons in accompanying course'|trans,
'items': entity.personsAssociated,
'path' : 'chill_person_view',
'key' : 'person_id'
},
{ 'title': 'Third persons'|trans,
'items': entity.personsNotAssociated,
'path' : 'chill_person_view',
'key' : 'person_id'
},
{ 'title': 'Third parties'|trans,
'items': entity.thirdParties,
'path' : 'chill_3party_3party_show',
'key' : 'thirdparty_id'
},
{ 'title': 'Users concerned'|trans,
'items': entity.users,
'path' : 'admin_user_show',
'key' : 'id'
},
] %}
{% endif %}
{% if (with_display == 'bloc') %}
<div class="{{ context }} flex-bloc concerned-groups">
{% for bloc in blocs %}
<div class="item-bloc">
<div class="item-row">
<div class="item-col">
<h4>{{ bloc.title }}</h4>
</div>
<div class="item-col">
<ul class="list-content">
{% for item in bloc.items %}
<li>
<a href="{{ _self.href(bloc.path, bloc.key, item.id) }}">
<span class="{% if (badge_person is defined and badge_person == true) %}badge-person{% else %}badge bg-primary{% endif %}">
{{ item|chill_entity_render_box({
'render': 'raw',
'addAltNames': false
}) }}
</span>
</a>
</li>
{% endfor %}
</ul>
</div>
</div>
</div>
{% endfor %}
</div>
{% endif %}
{% if (with_display == 'row') %}
<div class="concerned-groups">
{% for bloc in blocs %}
<div class="group">
{% if bloc.items|length > 0 %}
<h4>{{ bloc.title }}</h4>
<ul class="list-content">
{% for item in bloc.items %}
<li>
<a href="{{ _self.href(bloc.path, bloc.key, item.id) }}">
<span class="{% if (badge_person is defined and badge_person == true) %}badge-person{% else %}badge bg-primary{% endif %}">
{{ item|chill_entity_render_box({
'render': 'raw',
'addAltNames': false
}) }}
</span>
</a>
</li>
{% endfor %}
</ul>
{% endif %}
</div>
{% endfor %}
</div>
{% endif %}

View File

@@ -1,4 +1,4 @@
{% extends "@ChillPerson/Person/layout.html.twig" %} {% extends "@ChillPerson/layout.html.twig" %}
{% set activeRouteKey = 'chill_activity_activity_list' %} {% set activeRouteKey = 'chill_activity_activity_list' %}
{% set person = activity.person %} {% set person = activity.person %}
@@ -6,6 +6,7 @@
{% block title 'Remove activity'|trans %} {% block title 'Remove activity'|trans %}
{% block personcontent %} {% block personcontent %}
{{ include('@ChillMain/Util/confirmation_template.html.twig', {{ include('@ChillMain/Util/confirmation_template.html.twig',
{ {
'title' : 'Remove activity'|trans, 'title' : 'Remove activity'|trans,
@@ -14,4 +15,5 @@
'cancel_parameters' : { 'person_id' : activity.person.id, 'id' : activity.id }, 'cancel_parameters' : { 'person_id' : activity.person.id, 'id' : activity.id },
'form' : delete_form 'form' : delete_form
} ) }} } ) }}
{% endblock %} {% endblock %}

View File

@@ -1,16 +0,0 @@
{% extends "@ChillPerson/AccompanyingCourse/layout.html.twig" %}
{% set activeRouteKey = 'chill_activity_activity_list' %}
{% block title 'Remove activity'|trans %}
{% block content %}
{{ include('@ChillMain/Util/confirmation_template.html.twig',
{
'title' : 'Remove activity'|trans,
'confirm_question' : 'Are you sure you want to remove the activity about "%name%" ?'|trans({ '%name%' : accompanyingCourse.id } ),
'cancel_route' : 'chill_activity_activity_list',
'cancel_parameters' : { 'accompanying_course_id' : accompanyingCourse.id, 'id' : activity.id },
'form' : delete_form
} ) }}
{% endblock %}

View File

@@ -1,104 +1,59 @@
<h1>{{ "Update activity"|trans }}</h1> {#
<h2 class="chill-green mb-4">{{ entity.type.name|localize_translatable_string }}</h2> * Copyright (C) 2014, Champs Libres Cooperative SCRLFS, <http://www.champs-libres.coop>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
#}
{% extends "@ChillPerson/layout.html.twig" %}
{{ form_start(edit_form) }} {% set activeRouteKey = 'chill_activity_activity_list' %}
{{ form_errors(edit_form) }}
{%- if edit_form.emergency is defined -%} {% block title 'Update activity'|trans %}
{{ form_row(edit_form.emergency) }}
{% endif %}
{%- if edit_form.sentReceived is defined -%} {% block personcontent %}
{{ form_row(edit_form.sentReceived) }} <h1>{{ "Update activity"|trans }}</h1>
{% endif %}
{{ form_start(edit_form) }}
{%- if edit_form.user is defined -%}
{{ form_row(edit_form.user) }} {{ form_row(edit_form.user) }}
{% endif %}
{%- if edit_form.scope is defined -%}
{{ form_row(edit_form.scope) }} {{ form_row(edit_form.scope) }}
{% endif %}
{%- if edit_form.socialIssues is defined -%} <h2>{{ 'Activity data'|trans }}</h2>
{{ form_row(edit_form.socialIssues) }}
{% endif %}
{%- if edit_form.socialActions is defined -%}
{{ form_row(edit_form.socialActions) }}
{% endif %}
<div id="social-issues-acc"></div>
{%- if edit_form.reasons is defined -%}
{{ form_row(edit_form.reasons) }}
{% endif %}
<h2 class="chill-red">{{ 'Concerned groups'|trans }}</h2>
{%- if edit_form.persons is defined -%}
{{ form_widget(edit_form.persons) }}
{% endif %}
{%- if edit_form.thirdParties is defined -%}
{{ form_widget(edit_form.thirdParties) }}
{% endif %}
{%- if edit_form.users is defined -%}
{{ form_widget(edit_form.users) }}
{% endif %}
<div id="add-persons"></div>
<h2 class="chill-red">{{ 'Activity data'|trans }}</h2>
{%- if edit_form.date is defined -%}
{{ form_row(edit_form.date) }} {{ form_row(edit_form.date) }}
{% endif %}
{# TODO .. location #}
{%- if edit_form.durationTime is defined -%}
{{ form_row(edit_form.durationTime) }} {{ form_row(edit_form.durationTime) }}
{% endif %} {{ form_row(edit_form.type) }}
{%- if edit_form.travelTime is defined -%}
{{ form_row(edit_form.travelTime) }}
{% endif %}
{%- if edit_form.comment is defined -%}
{# TODO .. public and private #}
{{ form_row(edit_form.comment) }}
{% endif %}
{%- if edit_form.documents is defined -%}
{{ form_row(edit_form.documents) }}
{% endif %}
{%- if edit_form.attendee is defined -%}
{{ form_row(edit_form.attendee) }} {{ form_row(edit_form.attendee) }}
{% endif %} {{ form_row(edit_form.reasons) }}
{{ form_row(edit_form.comment) }}
{# TODO .. status #} {{ form_widget(edit_form) }}
<ul class="record_actions sticky-form-buttons">
<li class="cancel">
<a href="{{ path('chill_activity_activity_show', { 'id': entity.id, 'person_id': entity.person.id } ) }}" class="sc-button bt-cancel">
{{ 'Cancel'|trans }}
</a>
</li>
<li>
<button class="sc-button bt-update" type="submit">{{ 'Save activity'|trans }}</button>
</li>
</ul>
{{ form_end(edit_form) }}
{% set person_id = null %} {# {{ form(delete_form) }} #}
{% if entity.person %} {% endblock %}
{% set person_id = entity.person.id %}
{% endif %}
{% set accompanying_course_id = null %} {% block js %}
{% if accompanyingCourse %} <script type="text/javascript">
{% set accompanying_course_id = accompanyingCourse.id %} chill.displayAlertWhenLeavingModifiedForm('form[name="{{ edit_form.vars.form.vars.name }}"]', '{{ "You are going to leave a page with unsubmitted data. Are you sure you want to leave ?"|trans }}');
{% endif %} </script>
{% endblock %}
<ul class="record_actions sticky-form-buttons">
<li class="cancel">
<a href="{{ path('chill_activity_activity_show', { 'id': entity.id, 'person_id': person_id, 'accompanying_period_id': accompanying_course_id } ) }}" class="btn btn-cancel">
{{ 'Cancel'|trans }}
</a>
</li>
<li>
<button class="btn btn-update" type="submit">{{ 'Save'|trans }}</button>
</li>
</ul>
{{ form_end(edit_form) }}
{# {{ form(delete_form) }} #}

View File

@@ -1,33 +0,0 @@
{% extends "@ChillPerson/AccompanyingCourse/layout.html.twig" %}
{% set activeRouteKey = 'chill_activity_activity_list' %}
{% block title 'Update activity'|trans %}
{% block content %}
<div class="activity-edit">
<div id="activity"></div> {# <=== vue component #}
{% include 'ChillActivityBundle:Activity:edit.html.twig' %}
</div>
{% endblock %}
{% block js %}
{{ parent() }}
{{ encore_entry_link_tags('mod_async_upload') }}
<script type="text/javascript">
window.addEventListener('DOMContentLoaded', function (e) {
chill.displayAlertWhenLeavingModifiedForm('form[name="{{ edit_form.vars.form.vars.name }}"]',
'{{ "You are going to leave a page with unsubmitted data. Are you sure you want to leave ?"|trans }}');
});
window.activity = {{ activity_json|json_encode|raw }};
</script>
{{ encore_entry_script_tags('vue_activity') }}
{% endblock %}
{% block css %}
{{ parent() }}
{{ encore_entry_link_tags('mod_async_upload') }}
{{ encore_entry_link_tags('vue_activity') }}
{% endblock %}

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