Compare commits

..

6 Commits

Author SHA1 Message Date
148221cdc7 fix namespace of 'self' 2021-04-27 23:21:15 +02:00
58047faac6 force type for connection parameter 2021-04-27 23:20:49 +02:00
40dda65006 fix import namespacees 2021-04-27 23:20:25 +02:00
Pol Dellaiera
054a28ecf4 refactor: Update source code based on PHP conventions. 2021-04-26 17:18:38 +02:00
Pol Dellaiera
6b2eda0f94 chore: Add/update static files. 2021-04-26 15:44:37 +02:00
Pol Dellaiera
1359f1ba58 chore: Update composer.json 2021-04-26 14:02:26 +02:00
1021 changed files with 54180 additions and 95844 deletions

1
.gitignore vendored
View File

@@ -19,4 +19,3 @@ docs/build/
/phpunit.xml /phpunit.xml
.phpunit.result.cache .phpunit.result.cache
###< phpunit/phpunit ### ###< phpunit/phpunit ###

View File

@@ -11,15 +11,14 @@ before_script:
- PGPASSWORD=$POSTGRES_PASSWORD psql -U $POSTGRES_USER -h db -c "CREATE EXTENSION IF NOT EXISTS unaccent; CREATE EXTENSION IF NOT EXISTS pg_trgm;" - 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
- 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
@@ -31,12 +30,8 @@ variables:
POSTGRES_PASSWORD: postgres POSTGRES_PASSWORD: postgres
# fetch the chill-app using git submodules # fetch the chill-app using git submodules
GIT_SUBMODULE_STRATEGY: recursive GIT_SUBMODULE_STRATEGY: recursive
REDIS_HOST: redis
REDIS_PORT: 6379
REDIS_URL: redis://redis:6379
# Run our tests # Run our tests
test: test:
script: script:
- php -d memory_limit=3G bin/phpunit --colors=never - bin/phpunit --colors=never

25
.php_cs.dist Normal file
View File

@@ -0,0 +1,25 @@
<?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);
$config = require __DIR__ . '/vendor/drupol/php-conventions/config/php73/php_cs_fixer.config.php';
$config
->getFinder()
->ignoreDotFiles(false)
->name(['.php_cs.dist']);
$rules = $config->getRules();
$rules['header_comment']['header'] = trim(file_get_contents(__DIR__ . '/resource/header.txt'));
return $config->setRules($rules);

View File

@@ -1,9 +0,0 @@
# Chill framework
Documentation of the Chill software.
The online documentation can be found at http://docs.chill.social
See the [`docs`][1] directory for more.
[1]: docs/README.md

View File

@@ -1,69 +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",
"composer/package-versions-deprecated": "^1.10",
"doctrine/doctrine-bundle": "^2.1",
"doctrine/doctrine-migrations-bundle": "^3.0",
"doctrine/orm": "^2.7",
"drupol/php-conventions": "^5.0",
"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.6",
"phpoffice/phpspreadsheet": "^1.16",
"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/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",
@@ -84,10 +24,65 @@
"App\\": "tests/app/src/" "App\\": "tests/app/src/"
} }
}, },
"require": {
"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": "4.*",
"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,19 +1,26 @@
<?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.
*
* @see https://www.champs-libres.coop/
*/
declare(strict_types=1);
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 ExportElementValidatedInterface, FilterInterface
{ {
// add specific role for this filter // add specific role for this filter
public function addRole() public function addRole()
@@ -22,78 +29,16 @@ class BirthdateFilter implements FilterInterface, ExportElementValidatedInterfac
return null; return null;
} }
// we give information on which type of export this filter applies
public function applyOn()
{
return 'person';
}
public function getTitle()
{
return 'Filter by person\'s birthdate';
}
// we build a form to collect some parameters from the users
public function buildForm(\Symfony\Component\Form\FormBuilderInterface $builder)
{
$builder->add('date_from', DateType::class, array(
'label' => "Born after this date",
'data' => new \DateTime(),
'attr' => array('class' => 'datepicker'),
'widget'=> 'single_text',
'format' => 'dd-MM-yyyy',
));
$builder->add('date_to', DateType::class, array(
'label' => "Born before this date",
'data' => new \DateTime(),
'attr' => array('class' => 'datepicker'),
'widget'=> 'single_text',
'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 // here, we alter the query created by Export
public function alterQuery(\Doctrine\ORM\QueryBuilder $qb, $data) public function alterQuery(\Doctrine\ORM\QueryBuilder $qb, $data)
{ {
$where = $qb->getDQLPart('where'); $where = $qb->getDQLPart('where');
// we create the clause here // we create the clause here
$clause = $qb->expr()->between('person.birthdate', ':date_from', $clause = $qb->expr()->between(
':date_to'); 'person.birthdate',
':date_from',
':date_to'
);
// we have to take care **not to** remove previous clauses... // we have to take care **not to** remove previous clauses...
if ($where instanceof Expr\Andx) { if ($where instanceof Expr\Andx) {
@@ -108,16 +53,76 @@ class BirthdateFilter implements FilterInterface, ExportElementValidatedInterfac
$qb->setParameter('date_to', $data['date_to']); $qb->setParameter('date_to', $data['date_to']);
} }
// we give information on which type of export this filter applies
public function applyOn()
{
return 'person';
}
// we build a form to collect some parameters from the users
public function buildForm(\Symfony\Component\Form\FormBuilderInterface $builder)
{
$builder->add('date_from', DateType::class, [
'label' => 'Born after this date',
'data' => new DateTime(),
'attr' => ['class' => 'datepicker'],
'widget' => 'single_text',
'format' => 'dd-MM-yyyy',
]);
$builder->add('date_to', DateType::class, [
'label' => 'Born before this date',
'data' => new DateTime(),
'attr' => ['class' => 'datepicker'],
'widget' => 'single_text',
'format' => 'dd-MM-yyyy',
]);
}
// 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,62 +1,101 @@
<?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.
*
* @see https://www.champs-libres.coop/
*/
declare(strict_types=1);
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 buildForm(FormBuilderInterface $builder)
{
// this export does not add any form
}
public function getAllowedFormattersTypes()
{
return [FormatterInterface::TYPE_TABULAR];
}
public function getDescription()
{
return 'Count peoples by various parameters.';
}
public function getLabels($key, array $values, $data)
{
// 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 getQueryKeys($data)
{
// this array match the result keys in the query. We have only
// one column.
return ['export_result'];
}
public function getResult($qb, $data)
{
return $qb->getQuery()->getResult(Query::HYDRATE_SCALAR);
}
public function getTitle()
{
return 'Count peoples';
}
public function getType() public function getType()
{ {
return Declarations::PERSON_TYPE; return Declarations::PERSON_TYPE;
} }
public function getDescription() public function initiateQuery(array $requiredModifiers, array $acl, array $data = [])
{
return "Count peoples by various parameters.";
}
public function getTitle()
{
return "Count peoples";
}
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. // we gather all center the user choose.
$centers = array_map(function($el) { return $el['center']; }, $acl); $centers = array_map(static function ($el) {
return $el['center'];
}, $acl);
$qb = $this->entityManager->createQueryBuilder(); $qb = $this->entityManager->createQueryBuilder();
@@ -65,55 +104,18 @@ class CountPerson implements ExportInterface
->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);
;
return $qb; return $qb;
} }
public function getResult($qb, $data) public function requiredRole()
{ {
return $qb->getQuery()->getResult(Query::HYDRATE_SCALAR); return new Role(PersonVoter::STATS);
}
public function getQueryKeys($data)
{
// this array match the result keys in the query. We have only
// one column.
return array('export_result');
}
public function getLabels($key, array $values, $data)
{
// 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()
{
return array(FormatterInterface::TYPE_TABULAR);
}
public function buildForm(FormBuilderInterface $builder) {
// this export does not add any form
} }
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

@@ -1,747 +0,0 @@
.. Copyright (C) 2014 Champs Libres Cooperative SCRLFS
Permission is granted to copy, distribute and/or modify this document
under the terms of the GNU Free Documentation License, Version 1.3
or any later version published by the Free Software Foundation;
with no Invariant Sections, no Front-Cover Texts, and no Back-Cover Texts.
A copy of the license is included in the section entitled "GNU
Free Documentation License".
.. _api:
API
###
Chill provides a basic framework to build REST api.
Basic configuration
*******************
Configure a route
=================
Follow those steps to build a REST api:
1. Create your model;
2. Configure the API;
You can also:
* hook into the controller to customize some steps;
* add more route and steps
.. note::
Useful links:
* `How to use annotation to configure serialization <https://symfony.com/doc/current/serializer.html>`_
* `How to create your custom normalizer <https://symfony.com/doc/current/serializer/custom_normalizer.html>`_
Auto-loading the routes
=======================
Ensure that those lines are present in your file `app/config/routing.yml`:
.. code-block:: yaml
chill_cruds:
resource: 'chill_main_crud_route_loader:load'
type: service
Create your model
=================
Create your model on the usual way:
.. code-block:: php
namespace Chill\PersonBundle\Entity\AccompanyingPeriod;
use Chill\PersonBundle\Entity\AccompanyingPeriod\OriginRepository;
use Doctrine\ORM\Mapping as ORM;
/**
* @ORM\Entity(repositoryClass=OriginRepository::class)
* @ORM\Table(name="chill_person_accompanying_period_origin")
*/
class Origin
{
/**
* @ORM\Id
* @ORM\GeneratedValue
* @ORM\Column(type="integer")
*/
private $id;
/**
* @ORM\Column(type="json")
*/
private $label;
/**
* @ORM\Column(type="date_immutable", nullable=true)
*/
private $noActiveAfter;
// .. getters and setters
}
Configure api
=============
Configure the api using Yaml (see the full configuration: :ref:`api_full_configuration`):
.. code-block:: yaml
# config/packages/chill_main.yaml
chill_main:
apis:
accompanying_period_origin:
base_path: '/api/1.0/person/accompanying-period/origin'
class: 'Chill\PersonBundle\Entity\AccompanyingPeriod\Origin'
name: accompanying_period_origin
base_role: 'ROLE_USER'
actions:
_index:
methods:
GET: true
HEAD: true
_entity:
methods:
GET: true
HEAD: true
.. note::
If you are working on a shared bundle (aka "The chill bundles"), you should define your configuration inside the class :code:`ChillXXXXBundleExtension`, using the "prependConfig" feature:
.. code-block:: php
namespace Chill\PersonBundle\DependencyInjection;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Extension\PrependExtensionInterface;
use Symfony\Component\HttpFoundation\Request;
/**
* Class ChillPersonExtension
* Loads and manages your bundle configuration
*
* To learn more see {@link http://symfony.com/doc/current/cookbook/bundles/extension.html}
* @package Chill\PersonBundle\DependencyInjection
*/
class ChillPersonExtension extends Extension implements PrependExtensionInterface
{
public function prepend(ContainerBuilder $container)
{
$this->prependCruds($container);
}
/**
* @param ContainerBuilder $container
*/
protected function prependCruds(ContainerBuilder $container)
{
$container->prependExtensionConfig('chill_main', [
'apis' => [
[
'class' => \Chill\PersonBundle\Entity\AccompanyingPeriod\Origin::class,
'name' => 'accompanying_period_origin',
'base_path' => '/api/1.0/person/accompanying-period/origin',
'controller' => \Chill\PersonBundle\Controller\OpeningApiController::class,
'base_role' => 'ROLE_USER',
'actions' => [
'_index' => [
'methods' => [
Request::METHOD_GET => true,
Request::METHOD_HEAD => true
],
],
'_entity' => [
'methods' => [
Request::METHOD_GET => true,
Request::METHOD_HEAD => true
]
],
]
]
]
]);
}
}
The :code:`_index` and :code:`_entity` action
*********************************************
The :code:`_index` and :code:`_entity` action are default actions:
* they will call a specific method in the default controller;
* they will generate defined routes:
Index:
Name: :code:`chill_api_single_accompanying_period_origin__index`
Path: :code:`/api/1.0/person/accompanying-period/origin.{_format}`
Entity:
Name: :code:`chill_api_single_accompanying_period_origin__entity`
Path: :code:`/api/1.0/person/accompanying-period/origin/{id}.{_format}`
Role
****
By default, the key `base_role` is used to check ACL. Take care of creating the :code:`Voter` required to take that into account.
For index action, the role will be called with :code:`NULL` as :code:`$subject`. The retrieved entity will be the subject for single queries.
You can also define a role for each method. In this case, this role is used for the given method, and, if any, the base role is taken into account.
.. code-block:: yaml
# config/packages/chill_main.yaml
chill_main:
apis:
accompanying_period_origin:
base_path: '/api/1.0/person/bla/bla'
class: 'Chill\PersonBundle\Entity\Blah'
name: bla
actions:
_entity:
methods:
GET: true
HEAD: true
roles:
GET: MY_ROLE_SEE
HEAD: MY ROLE_SEE
Customize the controller
************************
You can customize the controller by hooking into the default actions. Take care of extending :code:`Chill\MainBundle\CRUD\Controller\ApiController`.
.. code-block:: php
namespace Chill\PersonBundle\Controller;
use Chill\MainBundle\CRUD\Controller\ApiController;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
class OpeningApiController extends ApiController
{
protected function customizeQuery(string $action, Request $request, $qb): void
{
$qb->where($qb->expr()->gt('e.noActiveAfter', ':now'))
->orWhere($qb->expr()->isNull('e.noActiveAfter'));
$qb->setParameter('now', new \DateTime('now'));
}
}
And set your controller in configuration:
.. code-block:: yaml
chill_main:
apis:
accompanying_period_origin:
base_path: '/api/1.0/person/accompanying-period/origin'
class: 'Chill\PersonBundle\Entity\AccompanyingPeriod\Origin'
name: accompanying_period_origin
# add a controller
controller: 'Chill\PersonBundle\Controller\OpeningApiController'
base_role: 'ROLE_USER'
actions:
_index:
methods:
GET: true
HEAD: true
_entity:
methods:
GET: true
HEAD: true
Create your own actions
***********************
You can add your own actions:
.. code-block:: yaml
chill_main:
apis:
-
class: Chill\PersonBundle\Entity\AccompanyingPeriod
name: accompanying_course
base_path: /api/1.0/person/accompanying-course
controller: Chill\PersonBundle\Controller\AccompanyingCourseApiController
actions:
# add a custom participation:
participation:
methods:
POST: true
DELETE: true
GET: false
HEAD: false
PUT: false
roles:
POST: CHILL_PERSON_ACCOMPANYING_PERIOD_SEE
DELETE: CHILL_PERSON_ACCOMPANYING_PERIOD_SEE
GET: null
HEAD: null
PUT: null
single-collection: single
The key :code:`single-collection` with value :code:`single` will add a :code:`/{id}/ + "action name"` (in this example, :code:`/{id}/participation`) into the path, after the base path. If the value is :code:`collection`, no id will be set, but the action name will be append to the path.
Then, create the corresponding action into your controller:
.. code-block:: php
namespace Chill\PersonBundle\Controller;
use Chill\MainBundle\CRUD\Controller\ApiController;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Chill\PersonBundle\Entity\AccompanyingPeriod;
use Symfony\Component\HttpFoundation\Exception\BadRequestException;
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
use Symfony\Component\Validator\Validator\ValidatorInterface;
use Chill\PersonBundle\Privacy\AccompanyingPeriodPrivacyEvent;
use Chill\PersonBundle\Entity\Person;
class AccompanyingCourseApiController extends ApiController
{
protected EventDispatcherInterface $eventDispatcher;
protected ValidatorInterface $validator;
public function __construct(EventDispatcherInterface $eventDispatcher, $validator)
{
$this->eventDispatcher = $eventDispatcher;
$this->validator = $validator;
}
public function participationApi($id, Request $request, $_format)
{
/** @var AccompanyingPeriod $accompanyingPeriod */
$accompanyingPeriod = $this->getEntity('participation', $id, $request);
$person = $this->getSerializer()
->deserialize($request->getContent(), Person::class, $_format, []);
if (NULL === $person) {
throw new BadRequestException('person id not found');
}
$this->onPostCheckACL('participation', $request, $accompanyingPeriod, $_format);
switch ($request->getMethod()) {
case Request::METHOD_POST:
$participation = $accompanyingPeriod->addPerson($person);
break;
case Request::METHOD_DELETE:
$participation = $accompanyingPeriod->removePerson($person);
break;
default:
throw new BadRequestException("This method is not supported");
}
$errors = $this->validator->validate($accompanyingPeriod);
if ($errors->count() > 0) {
// only format accepted
return $this->json($errors);
}
$this->getDoctrine()->getManager()->flush();
return $this->json($participation);
}
}
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
****************************
A specific model has been defined for returning collection:
.. code-block:: json
{
"count": 49,
"results": [
],
"pagination": {
"more": true,
"next": "/api/1.0/search.json&q=xxxx......&page=2",
"previous": null,
"first": 0,
"items_per_page": 1
}
}
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>`).
.. code-block:: php
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Chill\MainBundle\Pagination\PaginatorInterface;
class MyController extends AbstractController
{
protected function serializeCollection(PaginatorInterface $paginator, $entities): Response
{
$model = new Collection($entities, $paginator);
return $this->json($model, Response::HTTP_OK, [], $context);
}
}
.. _api_full_configuration:
Full configuration example
**************************
.. code-block:: yaml
apis:
-
class: Chill\PersonBundle\Entity\AccompanyingPeriod
name: accompanying_course
base_path: /api/1.0/person/accompanying-course
controller: Chill\PersonBundle\Controller\AccompanyingCourseApiController
actions:
_entity:
roles:
GET: CHILL_PERSON_ACCOMPANYING_PERIOD_SEE
HEAD: null
POST: null
DELETE: null
PUT: null
controller_action: null
path: null
single-collection: single
methods:
GET: true
HEAD: true
POST: false
DELETE: false
PUT: false
participation:
methods:
POST: true
DELETE: true
GET: false
HEAD: false
PUT: false
roles:
POST: CHILL_PERSON_ACCOMPANYING_PERIOD_SEE
DELETE: CHILL_PERSON_ACCOMPANYING_PERIOD_SEE
GET: null
HEAD: null
PUT: null
controller_action: null
# the requirements for the route. Will be set to `[ 'id' => '\d+' ]` if left empty.
requirements: []
path: null
single-collection: single
base_role: null

View File

@@ -16,7 +16,6 @@ As Chill rely on the `symfony <http://symfony.com>`_ framework, reading the fram
Instructions to create a new bundle <create-a-new-bundle.rst> Instructions to create a new bundle <create-a-new-bundle.rst>
CRUD (Create - Update - Delete) for one entity <crud.rst> CRUD (Create - Update - Delete) for one entity <crud.rst>
Helpers for building a REST API <api.rst>
Routing <routing.rst> Routing <routing.rst>
Menus <menus.rst> Menus <menus.rst>
Forms <forms.rst> Forms <forms.rst>

View File

@@ -7,8 +7,6 @@
Free Documentation License". Free Documentation License".
.. _pagination-ref:
Pagination Pagination
########## ##########
@@ -17,7 +15,7 @@ The Bundle :code:`Chill\MainBundle` provides a **Pagination** api which allow yo
A simple example A simple example
**************** ****************
In the controller, get the :code:`Chill\Main\Pagination\PaginatorFactory` from the `Container` and use this :code:`PaginatorFactory` to create a :code:`Paginator` instance. In the controller, get the :class:`Chill\Main\Pagination\PaginatorFactory` from the `Container` and use this :code:`PaginatorFactory` to create a :code:`Paginator` instance.
.. literalinclude:: pagination/example.php .. literalinclude:: pagination/example.php

View File

@@ -1,19 +1,28 @@
<?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.
*
* @see https://www.champs-libres.coop/
*/
declare(strict_types=1);
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 example 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
@@ -25,18 +34,18 @@ class ItemController extends Controller {
// 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->render(
'ChillMyBundle:Item:list.html.twig',
[
'items' => $items, 'items' => $items,
'paginator' => $paginator '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,33 +1,45 @@
<?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.
*
* @see https://www.champs-libres.coop/
*/
declare(strict_types=1);
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 \Chill\PersonBundle\Entity\Person $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 \Chill\MainBundle\Security\Authorization\AuthorizationHelper $authorizationHelper */
$authorizationHelper = $this->get('chill.main.security.' $authorizationHelper = $this->get('chill.main.security.'
. 'authorization.helper'); . 'authorization.helper');
@@ -46,10 +58,9 @@ class ConsultationController extends Controller
->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

@@ -1,31 +1,41 @@
<?php <?php
# Chill\MainBundle\DependencyInjection\Configuration.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);
// Chill\MainBundle\DependencyInjection\Configuration.php
namespace Chill\MainBundle\DependencyInjection; 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 ChillMainConfiguration implements ConfigurationInterface
{ {
use AddWidgetConfigurationTrait; use AddWidgetConfigurationTrait;
/** /**
*
* @var ContainerBuilder * @var ContainerBuilder
*/ */
private $containerBuilder; private $containerBuilder;
public function __construct(
public function __construct(array $widgetFactories = array(), array $widgetFactories,
ContainerBuilder $containerBuilder) ContainerBuilder $containerBuilder
{ ) {
// we register here widget factories (see below) // we register here widget factories (see below)
$this->setWidgetFactories($widgetFactories); $this->setWidgetFactories($widgetFactories);
// we will need the container builder later... // we will need the container builder later...
@@ -33,7 +43,7 @@
} }
/** /**
* {@inheritDoc} * {@inheritdoc}
*/ */
public function getConfigTreeBuilder() public function getConfigTreeBuilder()
{ {
@@ -44,7 +54,6 @@
->children() ->children()
// ... // ...
->arrayNode('widgets') ->arrayNode('widgets')
->canBeDisabled() ->canBeDisabled()
->children() ->children()
@@ -56,9 +65,6 @@
->end() // end of root ->end() // end of root
; ;
return $treeBuilder; return $treeBuilder;
} }
} }

View File

@@ -1,16 +1,23 @@
<?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.
*
* @see https://www.champs-libres.coop/
*/
declare(strict_types=1);
//Chill\MainBundle\DependencyInjection\ChillMainExtension.php
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,19 +25,23 @@ 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()
@@ -45,15 +56,11 @@ class ChillMainExtension extends Extension implements Widget\HasWidgetFactoriesE
$config = $this->processConfiguration($configuration, $configs); $config = $this->processConfiguration($configuration, $configs);
// add the key 'widget' without the key 'enable' // add the key 'widget' without the key 'enable'
$container->setParameter('chill_main.widgets', $container->setParameter(
array('homepage' => $config['widgets']['homepage'])); 'chill_main.widgets',
['homepage' => $config['widgets']['homepage']]
);
// ... // ...
} }
public function getConfiguration(array $config, ContainerBuilder $container)
{
return new Configuration($this->widgetFactories, $container);
}
} }

View File

@@ -1,17 +1,28 @@
<?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.
*
* @see https://www.champs-libres.coop/
*/
declare(strict_types=1);
// Chill/PersonBundle/Widget/PersonListWidgetFactory
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 ChillPersonAddAPersonListWidgetFactory extends AbstractWidgetFactory
{ {
/* /*
* append the option to the configuration * append the option to the configuration
@@ -29,27 +40,16 @@ class PersonListWidgetFactory extends AbstractWidgetFactory
$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';
} }
/* /*
@@ -65,5 +65,13 @@ class PersonListWidgetFactory extends AbstractWidgetFactory
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,56 +1,67 @@
<?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.
*
* @see https://www.champs-libres.coop/
*/
declare(strict_types=1);
// Chill/PersonBundle/Widget/PersonListWidget.php
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 ChillPersonAddAPersonWidget implements WidgetInterface
{ {
/** /**
* Repository for persons * the authorization helper.
*
* @var EntityRepository
*/
protected $personRepository;
/**
* The entity manager
*
* @var EntityManager
*/
protected $entityManager;
/**
* the authorization helper
* *
* @var AuthorizationHelper; * @var AuthorizationHelper;
*/ */
protected $authorizationHelper; protected $authorizationHelper;
/** /**
* The entity manager.
* *
* @var EntityManager
*/
protected $entityManager;
/**
* Repository for persons.
*
* @var EntityRepository
*/
protected $personRepository;
/**
* @var TokenStorage * @var TokenStorage
*/ */
protected $tokenStorage; protected $tokenStorage;
/** /**
*
* @var UserInterface * @var UserInterface
*/ */
protected $user; protected $user;
@@ -68,13 +79,11 @@ 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');
@@ -86,9 +95,8 @@ class PersonListWidget implements WidgetInterface
$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
@@ -101,7 +109,7 @@ class PersonListWidget implements WidgetInterface
(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
@@ -113,17 +121,15 @@ class PersonListWidget implements WidgetInterface
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,55 @@
<?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.
*
* @see https://www.champs-libres.coop/
*/
declare(strict_types=1);
// Chill/PersonBundle/DependencyInjection/ChillPersonExtension.php
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} * {@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

@@ -1,22 +1,8 @@
imports: imports:
- { resource: tests/app/vendor/drupol/php-conventions/config/php73/grumphp.yml } - { resource: vendor/drupol/php-conventions/config/php73/grumphp.yml }
parameters: parameters:
tasks.phpcsfixer.config: .php_cs.dist
tasks.license.name: AGPL-3.0 tasks.license.name: AGPL-3.0
tasks.license.holder: Champs-Libres tasks.license.holder: Champs-Libres
tasks.phpstan.configuration: phpstan.neon tasks.license.date_from: 2001
tasks.phpstan.ignore_patterns:
- /src\/Bundle\/(.*)\/migrations/
- /src\/Bundle\/(.*)\/Resources/
- /src\/Bundle\/(.*)\/Tests/
- /src\/Bundle\/(.*)\/Test/
- /src\/Bundle\/(.*)\/config/
- /src\/Bundle\/(.*)\/translations/
- /src\/Bundle\/(.*)\/DataFixtures/
- /^docs/
- /^tests/
skip_tasks:
- composer_require_checker
- phpcsfixer
- phpcs
- twigcs

File diff suppressed because it is too large Load Diff

View File

@@ -1,3 +0,0 @@
includes:
- phpstan-baseline.neon

View File

@@ -18,19 +18,11 @@
<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>
</testsuites> </testsuites>
<listeners> <listeners>

File diff suppressed because it is too large Load Diff

View File

@@ -1,16 +0,0 @@
<?xml version="1.0"?>
<psalm
errorLevel="7"
resolveFromConfigFile="true"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="https://getpsalm.org/schema/config"
xsi:schemaLocation="https://getpsalm.org/schema/config vendor/vimeo/psalm/config.xsd"
errorBaseline="psalm-baseline.xml"
>
<projectFiles>
<directory name="src" />
<ignoreFiles>
<directory name="tests/" />
</ignoreFiles>
</projectFiles>
</psalm>

6
resource/header.txt Normal file
View File

@@ -0,0 +1,6 @@
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/

View File

@@ -1,5 +1,16 @@
<?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.
*
* @see https://www.champs-libres.coop/
*/
declare(strict_types=1);
namespace Chill\ActivityBundle; namespace Chill\ActivityBundle;
use Symfony\Component\HttpKernel\Bundle\Bundle; use Symfony\Component\HttpKernel\Bundle\Bundle;

View File

@@ -1,57 +1,42 @@
<?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 * @see https://www.champs-libres.coop/
* 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/>.
*/ */
declare(strict_types=1);
namespace Chill\ActivityBundle\Controller; namespace Chill\ActivityBundle\Controller;
use Chill\ActivityBundle\Entity\Activity;
use Chill\ActivityBundle\Form\ActivityType;
use Chill\MainBundle\Security\Authorization\AuthorizationHelper; use Chill\MainBundle\Security\Authorization\AuthorizationHelper;
use Chill\PersonBundle\Privacy\PrivacyEvent; use Chill\PersonBundle\Privacy\PrivacyEvent;
use DateTime;
use Psr\Log\LoggerInterface; use Psr\Log\LoggerInterface;
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController; use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
use Symfony\Component\Form\Extension\Core\Type\SubmitType; use Symfony\Component\Form\Extension\Core\Type\SubmitType;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\Security\Core\Role\Role; use Symfony\Component\Security\Core\Role\Role;
use Chill\ActivityBundle\Entity\Activity;
use Chill\PersonBundle\Entity\Person;
use Chill\ActivityBundle\Form\ActivityType;
/**
* Class ActivityController
*
* @package Chill\ActivityBundle\Controller
*/
class ActivityController extends AbstractController class ActivityController extends AbstractController
{ {
/**
* @var AuthorizationHelper
*/
protected $authorizationHelper;
/** /**
* @var EventDispatcherInterface * @var EventDispatcherInterface
*/ */
protected $eventDispatcher; protected $eventDispatcher;
/**
* @var AuthorizationHelper
*/
protected $authorizationHelper;
/** /**
* @var LoggerInterface * @var LoggerInterface
*/ */
@@ -59,9 +44,6 @@ class ActivityController extends AbstractController
/** /**
* ActivityController constructor. * ActivityController constructor.
*
* @param EventDispatcherInterface $eventDispatcher
* @param AuthorizationHelper $authorizationHelper
*/ */
public function __construct( public function __construct(
EventDispatcherInterface $eventDispatcher, EventDispatcherInterface $eventDispatcher,
@@ -73,52 +55,17 @@ class ActivityController extends AbstractController
$this->logger = $logger; $this->logger = $logger;
} }
/**
* Lists all Activity entities.
*
*/
public function listAction($person_id, Request $request)
{
$em = $this->getDoctrine()->getManager();
$person = $em->getRepository('ChillPersonBundle:Person')->find($person_id);
if ($person === NULL) {
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(
array('person' => $person, 'scope' => $reachableScopes),
array('date' => 'DESC')
);
$event = new PrivacyEvent($person, array(
'element_class' => Activity::class,
'action' => 'list'
));
$this->eventDispatcher->dispatch(PrivacyEvent::PERSON_PRIVACY_EVENT, $event);
return $this->render('ChillActivityBundle:Activity:list.html.twig', array(
'activities' => $activities,
'person' => $person
));
}
/** /**
* Creates a new Activity entity. * Creates a new Activity entity.
* *
* @param mixed $person_id
*/ */
public function createAction($person_id, Request $request) public function createAction($person_id, Request $request)
{ {
$em = $this->getDoctrine()->getManager(); $em = $this->getDoctrine()->getManager();
$person = $em->getRepository('ChillPersonBundle:Person')->find($person_id); $person = $em->getRepository('ChillPersonBundle:Person')->find($person_id);
if ($person === NULL) { if (null === $person) {
throw $this->createNotFoundException('person not found'); throw $this->createNotFoundException('person not found');
} }
@@ -132,133 +79,115 @@ class ActivityController extends AbstractController
if ($form->isValid()) { if ($form->isValid()) {
$em = $this->getDoctrine()->getManager(); $em = $this->getDoctrine()->getManager();
$this->denyAccessUnlessGranted('CHILL_ACTIVITY_CREATE', $entity, $this->denyAccessUnlessGranted(
'creation of this activity not allowed'); 'CHILL_ACTIVITY_CREATE',
$entity,
'creation of this activity not allowed'
);
$em->persist($entity); $em->persist($entity);
$em->flush(); $em->flush();
$this->get('session') $this->get('session')
->getFlashBag() ->getFlashBag()
->add('success', ->add(
'success',
$this->get('translator') $this->get('translator')
->trans('Success : activity created!') ->trans('Success : activity created!')
); );
return $this->redirect( return $this->redirect(
$this->generateUrl('chill_activity_activity_show', $this->generateUrl(
array('id' => $entity->getId(), 'person_id' => $person_id))); 'chill_activity_activity_show',
['id' => $entity->getId(), 'person_id' => $person_id]
)
);
} }
$this->get('session') $this->get('session')
->getFlashBag()->add('danger', ->getFlashBag()->add(
'danger',
$this->get('translator') $this->get('translator')
->trans('The form is not valid. The activity has not been created !') ->trans('The form is not valid. The activity has not been created !')
); );
return $this->render('ChillActivityBundle:Activity:new.html.twig', array( return $this->render('ChillActivityBundle:Activity:new.html.twig', [
'entity' => $entity, 'entity' => $entity,
'form' => $form->createView(), 'form' => $form->createView(),
'person' => $person
));
}
/**
* 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)
{
$form = $this->createForm(ActivityType::class, $entity,
array(
'action' => $this->generateUrl('chill_activity_activity_create', [
'person_id' => $entity->getPerson()->getId(),
]),
'method' => 'POST',
'center' => $entity->getCenter(),
'role' => new Role('CHILL_ACTIVITY_CREATE')
)
);
return $form;
}
/**
* Displays a form to create a new Activity entity.
*
*/
public function newAction($person_id)
{
$em = $this->getDoctrine()->getManager();
$person = $em->getRepository('ChillPersonBundle:Person')->find($person_id);
if ($person === NULL){
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', array(
'person' => $person, 'person' => $person,
'entity' => $entity, ]);
'form' => $form->createView(),
));
} }
/** /**
* Finds and displays a Activity entity. * Deletes a Activity entity.
* *
* @param mixed $id
* @param mixed $person_id
*/ */
public function showAction($person_id, $id) public function deleteAction(Request $request, $id, $person_id)
{ {
$em = $this->getDoctrine()->getManager(); $em = $this->getDoctrine()->getManager();
$person = $em->getRepository('ChillPersonBundle:Person')->find($person_id);
if (!$person) { /** @var Activity $activity */
throw $this->createNotFoundException('person not found'); $activity = $em->getRepository('ChillActivityBundle:Activity')
} ->find($id);
$person = $activity->getPerson();
$this->denyAccessUnlessGranted('CHILL_PERSON_SEE', $person); if (!$activity) {
$entity = $em->getRepository('ChillActivityBundle:Activity')->find($id);
if (!$entity) {
throw $this->createNotFoundException('Unable to find Activity entity.'); throw $this->createNotFoundException('Unable to find Activity entity.');
} }
$this->denyAccessUnlessGranted('CHILL_ACTIVITY_SEE', $entity); $this->denyAccessUnlessGranted('CHILL_ACTIVITY_DELETE', $activity);
$deleteForm = $this->createDeleteForm($id, $person); $form = $this->createDeleteForm($id, $person);
$event = new PrivacyEvent($person, array( if ($request->getMethod() === Request::METHOD_DELETE) {
'element_class' => Activity::class, $form->handleRequest($request);
'element_id' => $entity->getId(),
'action' => 'show' if ($form->isValid()) {
$this->logger->notice('An activity has been removed', [
'by_user' => $this->getUser()->getUsername(),
'activity_id' => $activity->getId(),
'person_id' => $activity->getPerson()->getId(),
'comment' => $activity->getComment()->getComment(),
'scope_id' => $activity->getScope()->getId(),
'reasons_ids' => $activity->getReasons()
->map(static function ($ar) {
return $ar->getId();
})
->toArray(),
'type_id' => $activity->getType()->getId(),
'duration' => $activity->getDurationTime()->format('U'),
'date' => $activity->getDate()->format('Y-m-d'),
'attendee' => $activity->getAttendee(),
]);
$em->remove($activity);
$em->flush();
$this->addFlash('success', $this->get('translator')
->trans('The activity has been successfully removed.'));
return $this->redirect($this->generateUrl(
'chill_activity_activity_list',
[
'person_id' => $person_id,
]
)); ));
$this->eventDispatcher->dispatch(PrivacyEvent::PERSON_PRIVACY_EVENT, $event); }
}
return $this->render('ChillActivityBundle:Activity:show.html.twig', array( return $this->render('ChillActivityBundle:Activity:confirm_delete.html.twig', [
'person' => $person, 'activity' => $activity,
'entity' => $entity, 'delete_form' => $form->createView(),
'delete_form' => $deleteForm->createView(), ]);
));
} }
/** /**
* Displays a form to edit an existing Activity entity. * Displays a form to edit an existing Activity entity.
* *
* @param mixed $person_id
* @param mixed $id
*/ */
public function editAction($person_id, $id) public function editAction($person_id, $id)
{ {
@@ -282,46 +211,140 @@ class ActivityController extends AbstractController
$editForm = $this->createEditForm($entity); $editForm = $this->createEditForm($entity);
$deleteForm = $this->createDeleteForm($id, $person); $deleteForm = $this->createDeleteForm($id, $person);
$event = new PrivacyEvent($person, array( $event = new PrivacyEvent($person, [
'element_class' => Activity::class, 'element_class' => Activity::class,
'element_id' => $entity->getId(), 'element_id' => $entity->getId(),
'action' => 'edit' 'action' => 'edit',
)); ]);
$this->eventDispatcher->dispatch(PrivacyEvent::PERSON_PRIVACY_EVENT, $event); $this->eventDispatcher->dispatch(PrivacyEvent::PERSON_PRIVACY_EVENT, $event);
return $this->render('ChillActivityBundle:Activity:edit.html.twig', array( return $this->render('ChillActivityBundle:Activity:edit.html.twig', [
'entity' => $entity, 'entity' => $entity,
'edit_form' => $editForm->createView(), 'edit_form' => $editForm->createView(),
'delete_form' => $deleteForm->createView(), 'delete_form' => $deleteForm->createView(),
'person' => $person 'person' => $person,
)); ]);
} }
/** /**
* Creates a form to edit a Activity entity. * Lists all Activity entities.
* *
* @param Activity $entity The entity * @param mixed $person_id
*
* @return \Symfony\Component\Form\Form The form
*/ */
private function createEditForm(Activity $entity) public function listAction($person_id, Request $request)
{ {
$form = $this->createForm(ActivityType::class, $entity, array( $em = $this->getDoctrine()->getManager();
'action' => $this->generateUrl('chill_activity_activity_update', $person = $em->getRepository('ChillPersonBundle:Person')->find($person_id);
array(
'id' => $entity->getId(),
'person_id' => $entity->getPerson()->getId()
)),
'method' => 'PUT',
'center' => $entity->getCenter(),
'role' => new Role('CHILL_ACTIVITY_UPDATE')
));
return $form; 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. * Edits an existing Activity entity.
* *
* @param mixed $person_id
* @param mixed $id
*/ */
public function updateAction(Request $request, $person_id, $id) public function updateAction(Request $request, $person_id, $id)
{ {
@@ -340,11 +363,11 @@ class ActivityController extends AbstractController
$editForm = $this->createEditForm($entity); $editForm = $this->createEditForm($entity);
$editForm->handleRequest($request); $editForm->handleRequest($request);
$event = new PrivacyEvent($person, array( $event = new PrivacyEvent($person, [
'element_class' => Activity::class, 'element_class' => Activity::class,
'element_id' => $entity->getId(), 'element_id' => $entity->getId(),
'action' => 'update' 'action' => 'update',
)); ]);
$this->eventDispatcher->dispatch(PrivacyEvent::PERSON_PRIVACY_EVENT, $event); $this->eventDispatcher->dispatch(PrivacyEvent::PERSON_PRIVACY_EVENT, $event);
if ($editForm->isValid()) { if ($editForm->isValid()) {
@@ -352,95 +375,59 @@ class ActivityController extends AbstractController
$this->get('session') $this->get('session')
->getFlashBag() ->getFlashBag()
->add('success', ->add(
'success',
$this->get('translator') $this->get('translator')
->trans('Success : activity updated!') ->trans('Success : activity updated!')
); );
return $this->redirect($this->generateUrl('chill_activity_activity_show', array('id' => $id, 'person_id' => $person_id))); return $this->redirect($this->generateUrl('chill_activity_activity_show', ['id' => $id, 'person_id' => $person_id]));
} }
$this->get('session') $this->get('session')
->getFlashBag() ->getFlashBag()
->add('error', ->add(
'error',
$this->get('translator') $this->get('translator')
->trans('This form contains errors') ->trans('This form contains errors')
); );
return $this->render('ChillActivityBundle:Activity:edit.html.twig', array( return $this->render('ChillActivityBundle:Activity:edit.html.twig', [
'person' => $entity->getPerson(), 'person' => $entity->getPerson(),
'entity' => $entity, 'entity' => $entity,
'edit_form' => $editForm->createView(), 'edit_form' => $editForm->createView(),
'delete_form' => $deleteForm->createView(), 'delete_form' => $deleteForm->createView(),
)); ]);
} }
/** /**
* Deletes a Activity entity. * Creates a form to create a Activity entity.
* *
* @param Activity $entity The entity
*
* @return \Symfony\Component\Form\Form The form
*/ */
public function deleteAction(Request $request, $id, $person_id) private function createCreateForm(Activity $entity)
{ {
$em = $this->getDoctrine()->getManager(); return $this->createForm(
ActivityType::class,
/* @var $activity Activity */ $entity,
$activity = $em->getRepository('ChillActivityBundle:Activity') [
->find($id); 'action' => $this->generateUrl('chill_activity_activity_create', [
$person = $activity->getPerson(); 'person_id' => $entity->getPerson()->getId(),
]),
if (!$activity) { 'method' => 'POST',
throw $this->createNotFoundException('Unable to find Activity entity.'); 'center' => $entity->getCenter(),
} 'role' => new Role('CHILL_ACTIVITY_CREATE'),
]
$this->denyAccessUnlessGranted('CHILL_ACTIVITY_DELETE', $activity); );
$form = $this->createDeleteForm($id, $person);
if ($request->getMethod() === Request::METHOD_DELETE) {
$form->handleRequest($request);
if ($form->isValid()) {
$this->logger->notice("An activity has been removed", array(
'by_user' => $this->getUser()->getUsername(),
'activity_id' => $activity->getId(),
'person_id' => $activity->getPerson()->getId(),
'comment' => $activity->getComment()->getComment(),
'scope_id' => $activity->getScope()->getId(),
'reasons_ids' => $activity->getReasons()
->map(function ($ar) { return $ar->getId(); })
->toArray(),
'type_id' => $activity->getType()->getId(),
'duration' => $activity->getDurationTime()->format('U'),
'date' => $activity->getDate()->format('Y-m-d'),
'attendee' => $activity->getAttendee()
));
$em->remove($activity);
$em->flush();
$this->addFlash('success', $this->get('translator')
->trans("The activity has been successfully removed."));
return $this->redirect($this->generateUrl(
'chill_activity_activity_list', array(
'person_id' => $person_id
)));
}
}
return $this->render('ChillActivityBundle:Activity:confirm_delete.html.twig', array(
'activity' => $activity,
'delete_form' => $form->createView()
));
} }
/** /**
* 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 $id The entity id
* @param mixed $person
* *
* @return \Symfony\Component\Form\Form The form * @return \Symfony\Component\Form\Form The form
*/ */
@@ -449,10 +436,33 @@ class ActivityController extends AbstractController
return $this->createFormBuilder() return $this->createFormBuilder()
->setAction($this->generateUrl( ->setAction($this->generateUrl(
'chill_activity_activity_delete', 'chill_activity_activity_delete',
array('id' => $id, 'person_id' => $person->getId()))) ['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();
; }
/**
* 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)
{
return $this->createForm(ActivityType::class, $entity, [
'action' => $this->generateUrl(
'chill_activity_activity_update',
[
'id' => $entity->getId(),
'person_id' => $entity->getPerson()->getId(),
]
),
'method' => 'PUT',
'center' => $entity->getCenter(),
'role' => new Role('CHILL_ACTIVITY_UPDATE'),
]);
} }
} }

View File

@@ -1,38 +1,28 @@
<?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.
*
* @see https://www.champs-libres.coop/
*/
declare(strict_types=1);
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.
*
*/
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 +35,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 +61,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
*
* @return \Symfony\Component\Form\Form The form
*/ */
private function createEditForm(ActivityReasonCategory $entity) public function indexAction()
{ {
$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 +136,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,28 @@
<?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.
*
* @see https://www.champs-libres.coop/
*/
declare(strict_types=1);
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.
*
*/
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 +35,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 +61,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
*
* @return \Symfony\Component\Form\Form The form
*/ */
private function createEditForm(ActivityReason $entity) public function indexAction()
{ {
$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 +136,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

@@ -1,38 +1,28 @@
<?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.
*
* @see https://www.champs-libres.coop/
*/
declare(strict_types=1);
namespace Chill\ActivityBundle\Controller; namespace Chill\ActivityBundle\Controller;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\Form\Extension\Core\Type\SubmitType;
use Chill\ActivityBundle\Entity\ActivityType; use Chill\ActivityBundle\Entity\ActivityType;
use Chill\ActivityBundle\Form\ActivityTypeType; 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
*
* @package Chill\ActivityBundle\Controller
*/
class ActivityTypeController extends AbstractController class ActivityTypeController extends AbstractController
{ {
/**
* 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', array(
'entities' => $entities,
));
}
/** /**
* Creates a new ActivityType entity. * Creates a new ActivityType entity.
*
*/ */
public function createAction(Request $request) public function createAction(Request $request)
{ {
@@ -45,71 +35,19 @@ class ActivityTypeController extends AbstractController
$em->persist($entity); $em->persist($entity);
$em->flush(); $em->flush();
return $this->redirect($this->generateUrl('chill_activity_activitytype_show', array('id' => $entity->getId()))); return $this->redirect($this->generateUrl('chill_activity_activitytype_show', ['id' => $entity->getId()]));
} }
return $this->render('ChillActivityBundle:ActivityType:new.html.twig', array( return $this->render('ChillActivityBundle:ActivityType:new.html.twig', [
'entity' => $entity, 'entity' => $entity,
'form' => $form->createView(), 'form' => $form->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, array(
'action' => $this->generateUrl('chill_activity_activitytype_create'),
'method' => 'POST',
));
$form->add('submit', SubmitType::class, array('label' => 'Create'));
return $form;
}
/**
* 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', array(
'entity' => $entity,
'form' => $form->createView(),
));
}
/**
* Finds and displays a ActivityType entity.
*
*/
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', array(
'entity' => $entity,
));
} }
/** /**
* Displays a form to edit an existing ActivityType entity. * Displays a form to edit an existing ActivityType entity.
* *
* @param mixed $id
*/ */
public function editAction($id) public function editAction($id)
{ {
@@ -123,33 +61,64 @@ class ActivityTypeController extends AbstractController
$editForm = $this->createEditForm($entity); $editForm = $this->createEditForm($entity);
return $this->render('ChillActivityBundle:ActivityType:edit.html.twig', array( return $this->render('ChillActivityBundle:ActivityType:edit.html.twig', [
'entity' => $entity, 'entity' => $entity,
'edit_form' => $editForm->createView() 'edit_form' => $editForm->createView(),
)); ]);
} }
/** /**
* Creates a form to edit a ActivityType entity. * Lists all ActivityType entities.
*
* @param ActivityType $entity The entity
*
* @return \Symfony\Component\Form\Form The form
*/ */
private function createEditForm(ActivityType $entity) public function indexAction()
{ {
$form = $this->createForm(ActivityTypeType::class, $entity, array( $em = $this->getDoctrine()->getManager();
'action' => $this->generateUrl('chill_activity_activitytype_update', array('id' => $entity->getId())),
'method' => 'PUT',
));
$form->add('submit', SubmitType::class, array('label' => 'Update')); $entities = $em->getRepository('ChillActivityBundle:ActivityType')->findAll();
return $form; 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. * Edits an existing ActivityType entity.
* *
* @param mixed $id
*/ */
public function updateAction(Request $request, $id) public function updateAction(Request $request, $id)
{ {
@@ -167,12 +136,50 @@ class ActivityTypeController extends AbstractController
if ($editForm->isValid()) { if ($editForm->isValid()) {
$em->flush(); $em->flush();
return $this->redirect($this->generateUrl('chill_activity_activitytype_edit', array('id' => $id))); return $this->redirect($this->generateUrl('chill_activity_activitytype_edit', ['id' => $id]));
} }
return $this->render('ChillActivityBundle:ActivityType:edit.html.twig', array( return $this->render('ChillActivityBundle:ActivityType:edit.html.twig', [
'entity' => $entity, 'entity' => $entity,
'edit_form' => $editForm->createView(), '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,33 +1,22 @@
<?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, * @see https://www.champs-libres.coop/
* 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/>.
*/ */
declare(strict_types=1);
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
{ {

View File

@@ -1,44 +1,33 @@
<?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 * @see https://www.champs-libres.coop/
* 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/>.
*/ */
declare(strict_types=1);
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;
use function in_array;
/** /**
* Load reports into DB * Load reports into DB.
*
* @author Champs-Libres Coop
*/ */
class LoadActivity extends AbstractFixture implements OrderedFixtureInterface, ContainerAwareInterface class LoadActivity extends AbstractFixture implements ContainerAwareInterface, OrderedFixtureInterface
{ {
use \Symfony\Component\DependencyInjection\ContainerAwareTrait; use \Symfony\Component\DependencyInjection\ContainerAwareTrait;
@@ -57,54 +46,22 @@ 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 = mt_rand(0, 3);
for ($i = 0; $i < $activityNbr; ++$i) {
echo 'Creating an activity type for : ' . $person . "\n";
$activity = $this->newRandomActivity($person);
$manager->persist($activity);
} }
/**
* Return a random activityType
*
* @return \Chill\ActivityBundle\Entity\ActivityType
*/
private function getRandomActivityType()
{
$typeRef = LoadActivityType::$references[array_rand(LoadActivityType::$references)];
return $this->getReference($typeRef);
} }
$manager->flush();
/**
* Return a random activityReason
*
* @return \Chill\ActivityBundle\Entity\ActivityReason
*/
private function getRandomActivityReason(array $excludingIds)
{
$reasonRef = LoadActivityReason::$references[array_rand(LoadActivityReason::$references)];
if (in_array($this->getReference($reasonRef)->getId(), $excludingIds)) {
// we have a reason which should be excluded. Find another...
return $this->getRandomActivityReason($excludingIds);
}
return $this->getReference($reasonRef);
}
/**
* Return a random user
*
* @return \Chill\MainBundle\Entity\User
*/
private function getRandomUser()
{
$userRef = array_rand(LoadUsers::$refs);
return $this->getReference($userRef);
} }
public function newRandomActivity($person) public function newRandomActivity($person)
@@ -116,11 +73,11 @@ class LoadActivity extends AbstractFixture implements OrderedFixtureInterface, C
->setDurationTime($this->faker->dateTime(36000)) ->setDurationTime($this->faker->dateTime(36000))
->setType($this->getRandomActivityType()) ->setType($this->getRandomActivityType())
->setScope($this->getRandomScope()) ->setScope($this->getRandomScope())
->setAttendee($this->faker->boolean()) ->setAttendee($this->faker->boolean());
;
$usedId = array(); $usedId = [];
for ($i = 0; $i < rand(0, 4); $i++) {
for ($i = 0; mt_rand(0, 4) > $i; ++$i) {
$reason = $this->getRandomActivityReason($usedId); $reason = $this->getRandomActivityReason($usedId);
$usedId[] = $reason->getId(); $usedId[] = $reason->getId();
$activity->addReason($reason); $activity->addReason($reason);
@@ -129,20 +86,56 @@ class LoadActivity extends AbstractFixture implements OrderedFixtureInterface, C
return $activity; return $activity;
} }
public function load(ObjectManager $manager) /**
* Return a random activityReason.
*
* @return \Chill\ActivityBundle\Entity\ActivityReason
*/
private function getRandomActivityReason(array $excludingIds)
{ {
$persons = $this->container->get('doctrine.orm.entity_manager') $reasonRef = LoadActivityReason::$references[array_rand(LoadActivityReason::$references)];
->getRepository('ChillPersonBundle:Person')
->findAll();
foreach($persons as $person) { if (in_array($this->getReference($reasonRef)->getId(), $excludingIds, true)) {
$activityNbr = rand(0,3); // we have a reason which should be excluded. Find another...
for($i = 0; $i < $activityNbr; $i ++) { return $this->getRandomActivityReason($excludingIds);
print "Creating an activity type for : ".$person."\n"; }
$activity = $this->newRandomActivity($person);
$manager->persist($activity); return $this->getReference($reasonRef);
} }
}
$manager->flush(); /**
* 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
*/
private function getRandomUser()
{
$userRef = array_rand(LoadUsers::$refs);
return $this->getReference($userRef);
} }
} }

View File

@@ -1,71 +1,60 @@
<?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 * @see https://www.champs-libres.coop/
* 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/>.
*/ */
declare(strict_types=1);
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)

View File

@@ -1,35 +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 * @see https://www.champs-libres.coop/
* 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/>.
*/ */
declare(strict_types=1);
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
{ {
@@ -41,21 +31,20 @@ class LoadActivityReasonCategory extends AbstractFixture implements OrderedFixtu
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,59 +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 * @see https://www.champs-libres.coop/
* 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/>.
*/ */
declare(strict_types=1);
namespace Chill\ActivityBundle\DataFixtures\ORM; namespace Chill\ActivityBundle\DataFixtures\ORM;
use Chill\ActivityBundle\Entity\ActivityType;
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\ActivityType;
/** /**
* Description of LoadActivityType * Description of LoadActivityType.
*
* @author Champs-Libres Coop
*/ */
class LoadActivityType extends AbstractFixture 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 = [
[ 'name' => ['name' => ['fr' => 'Appel téléphonique', 'en' => 'Telephone call', 'nl' => 'Telefoon appel']],
['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', 'en' => 'Interview', 'nl' => 'Vraaggesprek']],
[ 'name' =>
['fr' => 'Inspection', 'en' => 'Inspection', 'nl' => 'Inspectie']]
]; ];
foreach ($types as $t) { foreach ($types as $t) {
print "Creating activity type : " . $t['name']['en'] . "\n"; echo 'Creating activity type : ' . $t['name']['en'] . "\n";
$activityType = (new ActivityType()) $activityType = (new ActivityType())
->setName(($t['name'])); ->setName(($t['name']));
$manager->persist($activityType); $manager->persist($activityType);

View File

@@ -1,22 +1,16 @@
<?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, * @see https://www.champs-libres.coop/
* 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/>.
*/ */
declare(strict_types=1);
namespace Chill\ActivityBundle\DataFixtures\ORM; namespace Chill\ActivityBundle\DataFixtures\ORM;
use Doctrine\Common\DataFixtures\AbstractFixture; use Doctrine\Common\DataFixtures\AbstractFixture;
@@ -27,12 +21,7 @@ use Chill\MainBundle\Entity\RoleScope;
use Chill\MainBundle\DataFixtures\ORM\LoadScopes; use Chill\MainBundle\DataFixtures\ORM\LoadScopes;
use Chill\ActivityBundle\Security\Authorization\ActivityStatsVoter; use Chill\ActivityBundle\Security\Authorization\ActivityStatsVoter;
/**
* Add a role CHILL_ACTIVITY_UPDATE & CHILL_ACTIVITY_CREATE for all groups except 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
{ {
public function getOrder() public function getOrder()
@@ -40,11 +29,11 @@ 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
@@ -53,18 +42,23 @@ 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'], true)) {
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(
'Adding CHILL_ACTIVITY_UPDATE & CHILL_ACTIVITY_CREATE & CHILL_ACTIVITY_DELETE, and stats and list permissions to %s '
. "permission group, scope '%s' \n", . "permission group, scope '%s' \n",
$permissionsGroup->getName(), $scope->getName()['en']); $permissionsGroup->getName(),
$scope->getName()['en']
);
$roleScopeUpdate = (new RoleScope()) $roleScopeUpdate = (new RoleScope())
->setRole('CHILL_ACTIVITY_UPDATE') ->setRole('CHILL_ACTIVITY_UPDATE')
->setScope($scope); ->setScope($scope);
@@ -78,22 +72,18 @@ class LoadActivitytACL extends AbstractFixture implements OrderedFixtureInterfac
->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,37 +1,27 @@
<?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 * @see https://www.champs-libres.coop/
* 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/>.
*/ */
declare(strict_types=1);
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}
*/ */
@@ -52,6 +42,7 @@ class ChillActivityExtension extends Extension implements PrependExtensionInterf
$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');
@@ -63,30 +54,30 @@ class ChillActivityExtension extends Extension implements PrependExtensionInterf
$this->prependAuthorization($container); $this->prependAuthorization($container);
} }
/* (non-PHPdoc) 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).
* @see \Symfony\Component\DependencyInjection\Extension\PrependExtensionInterface::prepend() * @see \Symfony\Component\DependencyInjection\Extension\PrependExtensionInterface::prepend()
*/ */
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( $container->prependExtensionConfig('chill_main', [
'routing' => array( 'routing' => [
'resources' => array( 'resources' => [
'@ChillActivityBundle/config/routes.yaml' '@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)
)
));
} }
} }

View File

@@ -1,12 +1,25 @@
<?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.
*
* @see https://www.champs-libres.coop/
*/
declare(strict_types=1);
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;
use function is_int;
/** /**
* 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}
*/ */
@@ -29,7 +42,7 @@ class Configuration implements ConfigurationInterface
->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],
@@ -42,27 +55,25 @@ class Configuration implements ConfigurationInterface
['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(static 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()
// //
@@ -86,7 +97,6 @@ class Configuration implements ConfigurationInterface
// ->end() // ->end()
->end() ->end()
->end() ->end()
->end() ->end()
->end(); ->end();

View File

@@ -1,46 +1,35 @@
<?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 * @see https://www.champs-libres.coop/
* 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/>.
*/ */
declare(strict_types=1);
namespace Chill\ActivityBundle\Entity; namespace Chill\ActivityBundle\Entity;
use Chill\MainBundle\Entity\Embeddable\CommentEmbeddable;
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\ActivityBundle\Entity\ActivityReason; use Chill\MainBundle\Entity\Embeddable\CommentEmbeddable;
use Chill\ActivityBundle\Entity\ActivityType;
use Chill\PersonBundle\Entity\Person;
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 Chill\PersonBundle\Entity\Person;
use DateTime;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\Common\Collections\Collection;
use Doctrine\ORM\Mapping as ORM;
/** /**
* Class Activity * @ORM\Entity
*
* @package Chill\ActivityBundle\Entity
* @ORM\Entity(repositoryClass="Chill\ActivityBundle\Repository\ActivityRepository")
* @ORM\Table(name="activity") * @ORM\Table(name="activity")
* @ORM\HasLifecycleCallbacks() * @ORM\HasLifecycleCallbacks
* @UserCircleConsistency( * @UserCircleConsistency(
* "CHILL_ACTIVITY_SEE_DETAILS", * "CHILL_ACTIVITY_SEE_DETAILS",
* getUserFunction="getUser", * getUserFunction="getUser",
@@ -49,7 +38,30 @@ use Chill\MainBundle\Validator\Constraints\Entity\UserCircleConsistency;
class Activity implements HasCenterInterface, HasScopeInterface class Activity implements HasCenterInterface, HasScopeInterface
{ {
/** /**
* @var integer * @var bool
* @ORM\Column(type="boolean")
*/
private $attendee;
/**
* @ORM\Embedded(class="Chill\MainBundle\Entity\Embeddable\CommentEmbeddable", columnPrefix="comment_")
*/
private $comment;
/**
* @var DateTime
* @ORM\Column(type="datetime")
*/
private $date;
/**
* @var DateTime
* @ORM\Column(type="time")
*/
private $durationTime;
/**
* @var int
* *
* @ORM\Id * @ORM\Id
* @ORM\Column(name="id", type="integer") * @ORM\Column(name="id", type="integer")
@@ -58,28 +70,10 @@ class Activity implements HasCenterInterface, HasScopeInterface
private $id; private $id;
/** /**
* @var User * @var Person
* @ORM\ManyToOne(targetEntity="Chill\MainBundle\Entity\User") * @ORM\ManyToOne(targetEntity="Chill\PersonBundle\Entity\Person")
*/ */
private $user; private $person;
/**
* @var \DateTime
* @ORM\Column(type="datetime")
*/
private $date;
/**
* @var \DateTime
* @ORM\Column(type="time")
*/
private $durationTime;
/**
* @var boolean
* @ORM\Column(type="boolean")
*/
private $attendee;
/** /**
* @var ActivityReason * @var ActivityReason
@@ -87,12 +81,6 @@ class Activity implements HasCenterInterface, HasScopeInterface
*/ */
private $reasons; private $reasons;
/**
* @var ActivityType
* @ORM\ManyToOne(targetEntity="Chill\ActivityBundle\Entity\ActivityType")
*/
private $type;
/** /**
* @var Scope * @var Scope
* @ORM\ManyToOne(targetEntity="Chill\MainBundle\Entity\Scope") * @ORM\ManyToOne(targetEntity="Chill\MainBundle\Entity\Scope")
@@ -100,15 +88,16 @@ class Activity implements HasCenterInterface, HasScopeInterface
private $scope; private $scope;
/** /**
* @var Person * @var ActivityType
* @ORM\ManyToOne(targetEntity="Chill\PersonBundle\Entity\Person") * @ORM\ManyToOne(targetEntity="Chill\ActivityBundle\Entity\ActivityType")
*/ */
private $person; private $type;
/** /**
* @ORM\Embedded(class="Chill\MainBundle\Entity\Embeddable\CommentEmbeddable", columnPrefix="comment_") * @var User
* @ORM\ManyToOne(targetEntity="Chill\MainBundle\Entity\User")
*/ */
private $comment; private $user;
/** /**
* Activity constructor. * Activity constructor.
@@ -120,111 +109,8 @@ class Activity implements HasCenterInterface, HasScopeInterface
} }
/** /**
* Get id * Add a reason.
* *
* @return integer
*/
public function getId()
{
return $this->id;
}
/**
* Set user
*
* @param User $user
* @return Activity
*/
public function setUser(User $user)
{
$this->user = $user;
return $this;
}
/**
* Get user
*
* @return User
*/
public function getUser()
{
return $this->user;
}
/**
* Set date
*
* @param \DateTime $date
* @return Activity
*/
public function setDate($date)
{
$this->date = $date;
return $this;
}
/**
* Get date
*
* @return \DateTime
*/
public function getDate()
{
return $this->date;
}
/**
* Set durationTime
*
* @param \DateTime $durationTime
* @return Activity
*/
public function setDurationTime($durationTime)
{
$this->durationTime = $durationTime;
return $this;
}
/**
* Get durationTime
*
* @return \DateTime
*/
public function getDurationTime()
{
return $this->durationTime;
}
/**
* Set attendee
*
* @param boolean $attendee
* @return Activity
*/
public function setAttendee($attendee)
{
$this->attendee = $attendee;
return $this;
}
/**
* Get attendee
*
* @return boolean
*/
public function getAttendee()
{
return $this->attendee;
}
/**
* Add a reason
*
* @param ActivityReason $reason
* @return Activity * @return Activity
*/ */
public function addReason(ActivityReason $reason) public function addReason(ActivityReason $reason)
@@ -235,95 +121,18 @@ class Activity implements HasCenterInterface, HasScopeInterface
} }
/** /**
* @param ActivityReason $reason * Get attendee.
*/
public function removeReason(ActivityReason $reason)
{
$this->reasons->removeElement($reason);
}
/**
* Get reasons
* *
* @return Collection * @return bool
*/ */
public function getReasons() public function getAttendee()
{ {
return $this->reasons; return $this->attendee;
}
/**
* Set type
*
* @param ActivityType $type
* @return Activity
*/
public function setType(ActivityType $type)
{
$this->type = $type;
return $this;
}
/**
* Get type
*
* @return ActivityType
*/
public function getType()
{
return $this->type;
}
/**
* Set scope
*
* @param Scope $scope
* @return Activity
*/
public function setScope(Scope $scope)
{
$this->scope = $scope;
return $this;
}
/**
* Get scope
*
* @return Scope
*/
public function getScope()
{
return $this->scope;
}
/**
* Set person
*
* @param Person $person
* @return Activity
*/
public function setPerson(Person $person)
{
$this->person = $person;
return $this;
}
/**
* Get person
*
* @return Person
*/
public function getPerson()
{
return $this->person;
} }
/** /**
* get the center * get the center
* center is extracted from person * center is extracted from person.
* *
* @return Center * @return Center
*/ */
@@ -340,6 +149,105 @@ class Activity implements HasCenterInterface, HasScopeInterface
return $this->comment; return $this->comment;
} }
/**
* Get date.
*
* @return DateTime
*/
public function getDate()
{
return $this->date;
}
/**
* Get durationTime.
*
* @return DateTime
*/
public function getDurationTime()
{
return $this->durationTime;
}
/**
* Get id.
*
* @return int
*/
public function getId()
{
return $this->id;
}
/**
* Get person.
*
* @return Person
*/
public function getPerson()
{
return $this->person;
}
/**
* 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;
return $this;
}
/** /**
* @param \Chill\MainBundle\Entity\Embeddalbe\CommentEmbeddable $comment * @param \Chill\MainBundle\Entity\Embeddalbe\CommentEmbeddable $comment
*/ */
@@ -347,5 +255,80 @@ class Activity implements HasCenterInterface, HasScopeInterface
{ {
$this->comment = $comment; $this->comment = $comment;
} }
/**
* Set date.
*
* @param DateTime $date
*
* @return Activity
*/
public function setDate($date)
{
$this->date = $date;
return $this;
} }
/**
* Set durationTime.
*
* @param DateTime $durationTime
*
* @return Activity
*/
public function setDurationTime($durationTime)
{
$this->durationTime = $durationTime;
return $this;
}
/**
* Set person.
*
* @return Activity
*/
public function setPerson(Person $person)
{
$this->person = $person;
return $this;
}
/**
* Set scope.
*
* @return Activity
*/
public function setScope(Scope $scope)
{
$this->scope = $scope;
return $this;
}
/**
* Set type.
*
* @return Activity
*/
public function setType(ActivityType $type)
{
$this->type = $type;
return $this;
}
/**
* Set user.
*
* @return Activity
*/
public function setUser(User $user)
{
$this->user = $user;
return $this;
}
}

View File

@@ -1,40 +1,43 @@
<?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 * @see https://www.champs-libres.coop/
* 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/>.
*/ */
declare(strict_types=1);
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 * @ORM\Entity
*
* @package Chill\ActivityBundle\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 +52,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 +72,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 +122,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,36 @@
<?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, * @see https://www.champs-libres.coop/
* 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/>.
*/ */
declare(strict_types=1);
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 * @ORM\Entity
*
* @package Chill\ActivityBundle\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,13 +45,8 @@ 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",
@@ -79,9 +71,19 @@ class ActivityReasonCategory
} }
/** /**
* 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 +91,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,25 +102,27 @@ 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) { foreach ($this->name as $name) {
if (!empty($name)) { if (!empty($name)) {
return $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)
@@ -146,13 +139,16 @@ class ActivityReasonCategory
} }
/** /**
* 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,39 +1,35 @@
<?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 * @see https://www.champs-libres.coop/
* 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/>.
*/ */
declare(strict_types=1);
namespace Chill\ActivityBundle\Entity; namespace Chill\ActivityBundle\Entity;
use Doctrine\ORM\Mapping as ORM; use Doctrine\ORM\Mapping as ORM;
/** /**
* Class ActivityType * @ORM\Entity
*
* @package Chill\ActivityBundle\Entity
* @ORM\Entity()
* @ORM\Table(name="activitytype") * @ORM\Table(name="activitytype")
* @ORM\HasLifecycleCallbacks() * @ORM\HasLifecycleCallbacks
*/ */
class ActivityType class ActivityType
{ {
/** /**
* @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,16 +44,20 @@ class ActivityType
private $name; private $name;
/** /**
* @var bool * Get active
* @ORM\Column(type="boolean") * return true if the type is active.
*
* @return bool
*/ */
private $active = true; public function getActive()
{
return $this->active;
}
/** /**
* Get id * Get id.
* *
* @return integer * @return int
*/ */
public function getId() public function getId()
{ {
@@ -65,20 +65,9 @@ class ActivityType
} }
/** /**
* Set name * Get name.
* *
* @param array $name * @param mixed|null $locale
* @return ActivityType
*/
public function setName($name)
{
$this->name = $name;
return $this;
}
/**
* Get name
* *
* @return array | string * @return array | string
*/ */
@@ -87,50 +76,57 @@ class ActivityType
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) { foreach ($this->name as $name) {
if (!empty($name)) { if (!empty($name)) {
return $name; return $name;
} }
} }
}
return ''; return '';
} else {
return $this->name;
}
} }
/** return $this->name;
* Get active
* return true if the type is active.
*
* @return boolean
*/
public function getActive() {
return $this->active;
} }
/** /**
* Is active * Is active
* return true if the type is active * return true if the type is active.
* *
* @return boolean * @return bool
*/ */
public function isActive() { 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
* *
* @param boolean $active
* @return ActivityType * @return ActivityType
*/ */
public function setActive($active) { public function setActive($active)
{
$this->active = $active; $this->active = $active;
return $this; return $this;
} }
} /**
* Set name.
*
* @param array $name
*
* @return ActivityType
*/
public function setName($name)
{
$this->name = $name;
return $this;
}
}

View File

@@ -1,58 +1,49 @@
<?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, * @see https://www.champs-libres.coop/
* 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/>.
*/ */
declare(strict_types=1);
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;
/** use function array_key_exists;
* use function count;
*
* @author Julien Fastré <julien.fastre@champs-libres.coop> class ActivityReasonAggregator implements
*/ AggregatorInterface,
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;
@@ -67,41 +58,46 @@ class ActivityReasonAggregator implements AggregatorInterface,
$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 || (!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 +114,107 @@ 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 \Chill\ActivityBundle\Entity\ActivityReason $r */
$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 +226,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,54 +1,40 @@
<?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, * @see https://www.champs-libres.coop/
* 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/>.
*/ */
declare(strict_types=1);
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,
@@ -58,6 +44,11 @@ class ActivityTypeAggregator implements AggregatorInterface
$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
@@ -67,24 +58,6 @@ class ActivityTypeAggregator implements AggregatorInterface
$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()
{ {
return 'activity'; return 'activity';
@@ -95,37 +68,49 @@ 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';
} }
/* @var $r \Chill\ActivityBundle\Entity\ActivityType */ /** @var \Chill\ActivityBundle\Entity\ActivityType $r */
$t = $this->typeRepository->find($value); $t = $this->typeRepository->find($value);
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,47 +1,37 @@
<?php <?php
/*
* Copyright (C) 2019 Champs Libres Cooperative <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, * @see https://www.champs-libres.coop/
* 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/>.
*/ */
declare(strict_types=1);
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 Doctrine\ORM\Query\Expr\Join;
use Chill\ActivityBundle\Security\Authorization\ActivityStatsVoter; use Chill\ActivityBundle\Security\Authorization\ActivityStatsVoter;
use Doctrine\ORM\EntityManagerInterface;
use Chill\MainBundle\Entity\User; 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;
/**
*
*
* @author Julien Fastré <julien.fastre@champs-libres.coop>
*/
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;
} }
@@ -70,7 +60,7 @@ 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)
@@ -80,6 +70,7 @@ class ActivityUserAggregator implements AggregatorInterface
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();
@@ -94,6 +85,6 @@ class ActivityUserAggregator implements AggregatorInterface
public function getTitle(): string public function getTitle(): string
{ {
return "Aggregate by activity user"; return 'Aggregate by activity user';
} }
} }

View File

@@ -1,121 +1,69 @@
<?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, * @see https://www.champs-libres.coop/
* 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/>.
*/ */
declare(strict_types=1);
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 static 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 +71,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(static 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,48 @@
<?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, * @see https://www.champs-libres.coop/
* 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/>.
*/ */
declare(strict_types=1);
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;
use function count;
use function in_array;
/** /**
* 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,91 +53,101 @@ 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} * {@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' => static 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} * {@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 static function ($value) {
if ($value === '_header') return 'date'; if ('_header' === $value) {
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 static 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 EntityRepository $activityReasonsRepository */
$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())
. ' > ' . . ' > ' .
@@ -168,21 +157,28 @@ class ListActivity implements ListInterface
}; };
case 'circle_name': case 'circle_name':
return function ($value) { return function ($value) {
if ($value === '_header') return 'circle'; if ('_header' === $value) {
return 'circle';
}
return $this->translatableStringHelper return $this->translatableStringHelper
->localize(json_decode($value, true)); ->localize(json_decode($value, true));
}; };
case 'type_name': case 'type_name':
return function ($value) { return function ($value) {
if ($value === '_header') return 'activity type'; 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 static function ($value) use ($key) {
if ($value === '_header') return $key; if ('_header' === $value) {
return $key;
}
return $value; return $value;
}; };
@@ -209,14 +205,16 @@ 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(static 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();
@@ -227,50 +225,56 @@ class ListActivity implements ListInterface
->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'], true)) {
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,48 +1,33 @@
<?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, * @see https://www.champs-libres.coop/
* 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/>.
*/ */
declare(strict_types=1);
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.
@@ -52,103 +37,61 @@ class StatActivityDuration implements ExportInterface
protected $action; protected $action;
/** /**
* constructor * @var EntityManagerInterface
*/
protected $entityManager;
/**
* constructor.
* *
* @param EntityManagerInterface $em
* @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 static 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 +99,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(static 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,40 @@
<?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, * @see https://www.champs-libres.coop/
* 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/>.
*/ */
declare(strict_types=1);
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,8 +43,11 @@ 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);
@@ -76,55 +67,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 \Symfony\Component\Form\FormInterface $filterForm */
$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 +126,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,59 +1,51 @@
<?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, * @see https://www.champs-libres.coop/
* 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/>.
*/ */
declare(strict_types=1);
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;
/** use function array_key_exists;
* use function count;
*
* @author Julien Fastré <julien.fastre@champs-libres.coop> class ActivityReasonFilter implements
*/ ExportElementValidatedInterface,
class ActivityReasonFilter implements FilterInterface, 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
@@ -62,6 +54,10 @@ class ActivityReasonFilter implements FilterInterface,
$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)
{ {
@@ -71,16 +67,15 @@ class ActivityReasonFilter implements FilterInterface,
//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 || (!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
); );
} }
@@ -95,11 +90,63 @@ class ActivityReasonFilter implements FilterInterface,
$qb->setParameter('selected_activity_reasons', $data['reasons']); $qb->setParameter('selected_activity_reasons', $data['reasons']);
} }
public function applyOn()
{
return 'activity';
}
public function buildForm(FormBuilderInterface $builder)
{
//create a local copy of translatableStringHelper
$helper = $this->translatableStringHelper;
$builder->add('reasons', EntityType::class, [
'class' => 'ChillActivityBundle:ActivityReason',
'choice_label' => static function (ActivityReason $reason) use ($helper) {
return $helper->localize($reason->getName());
},
'group_by' => static function (ActivityReason $reason) use ($helper) {
return $helper->localize($reason->getCategory()->getName());
},
'multiple' => true,
'expanded' => false,
]);
}
public function describeAction($data, $format = 'string')
{
// collect all the reasons'name used in this filter in one array
$reasonsNames = array_map(
function (ActivityReason $r) {
return '"' . $this->translatableStringHelper->localize($r->getName()) . '"';
},
$this->reasonRepository->findBy(['id' => $data['reasons']->toArray()])
);
return ['Filtered by reasons: only %list%',
['%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 * Check if a join between Activity and Reason is already defined.
* *
* @param Join[] $joins * @param Join[] $joins
* @return boolean * @param mixed $alias
*
* @return bool
*/ */
private function checkJoinAlreadyDefined(array $joins, $alias) private function checkJoinAlreadyDefined(array $joins, $alias)
{ {
@@ -111,59 +158,4 @@ class ActivityReasonFilter implements FilterInterface,
return false; return false;
} }
public function applyOn()
{
return 'activity';
}
public function buildForm(FormBuilderInterface $builder)
{
//create a local copy of translatableStringHelper
$helper = $this->translatableStringHelper;
$builder->add('reasons', EntityType::class, array(
'class' => 'ChillActivityBundle:ActivityReason',
'choice_label' => function (ActivityReason $reason) use ($helper) {
return $helper->localize($reason->getName());
},
'group_by' => function(ActivityReason $reason) use ($helper) {
return $helper->localize($reason->getCategory()->getName());
},
'multiple' => true,
'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')
{
// collect all the reasons'name used in this filter in one array
$reasonsNames = array_map(
function(ActivityReason $r) {
return "\"".$this->translatableStringHelper->localize($r->getName())."\"";
},
$this->reasonRepository->findBy(array('id' => $data['reasons']->toArray()))
);
return array("Filtered by reasons: only %list%",
["%list%" => implode(", ", $reasonsNames)]);
}
} }

View File

@@ -1,53 +1,45 @@
<?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, * @see https://www.champs-libres.coop/
* 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/>.
*/ */
declare(strict_types=1);
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;
/** use function count;
*
* class ActivityTypeFilter implements
*/ ExportElementValidatedInterface,
class ActivityTypeFilter implements FilterInterface, FilterInterface
ExportElementValidatedInterface
{ {
/** /**
*
* @var TranslatableStringHelper * @var TranslatableStringHelper
*/ */
protected $translatableStringHelper; protected $translatableStringHelper;
/** /**
* The repository for activity reasons * The repository for activity reasons.
* *
* @var EntityRepository * @var EntityRepository
*/ */
@@ -61,6 +53,10 @@ class ActivityTypeFilter implements FilterInterface,
$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)
{ {
@@ -77,11 +73,60 @@ class ActivityTypeFilter implements FilterInterface,
$qb->setParameter('selected_activity_types', $data['types']); $qb->setParameter('selected_activity_types', $data['types']);
} }
public function applyOn()
{
return 'activity';
}
public function buildForm(FormBuilderInterface $builder)
{
//create a local copy of translatableStringHelper
$helper = $this->translatableStringHelper;
$builder->add('types', EntityType::class, [
'class' => ActivityType::class,
'choice_label' => static function (ActivityType $type) use ($helper) {
return $helper->localize($type->getName());
},
'multiple' => true,
'expanded' => false,
]);
}
public function describeAction($data, $format = 'string')
{
// collect all the reasons'name used in this filter in one array
$reasonsNames = array_map(
function (ActivityType $t) {
return '"' . $this->translatableStringHelper->localize($t->getName()) . '"';
},
$this->typeRepository->findBy(['id' => $data['types']->toArray()])
);
return ['Filtered by activity type: only %list%',
['%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 * Check if a join between Activity and Reason is already defined.
* *
* @param Join[] $joins * @param Join[] $joins
* @return boolean * @param mixed $alias
*
* @return bool
*/ */
private function checkJoinAlreadyDefined(array $joins, $alias) private function checkJoinAlreadyDefined(array $joins, $alias)
{ {
@@ -93,56 +138,4 @@ class ActivityTypeFilter implements FilterInterface,
return false; return false;
} }
public function applyOn()
{
return 'activity';
}
public function buildForm(FormBuilderInterface $builder)
{
//create a local copy of translatableStringHelper
$helper = $this->translatableStringHelper;
$builder->add('types', EntityType::class, array(
'class' => ActivityType::class,
'choice_label' => function (ActivityType $type) use ($helper) {
return $helper->localize($type->getName());
},
'multiple' => true,
'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')
{
// collect all the reasons'name used in this filter in one array
$reasonsNames = array_map(
function(ActivityType $t) {
return "\"".$this->translatableStringHelper->localize($t->getName())."\"";
},
$this->typeRepository->findBy(array('id' => $data['types']->toArray()))
);
return array("Filtered by activity type: only %list%",
["%list%" => implode(", ", $reasonsNames)]);
}
} }

View File

@@ -1,64 +1,52 @@
<?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, * @see https://www.champs-libres.coop/
* 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/>.
*/ */
declare(strict_types=1);
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;
/** use function count;
*
* class PersonHavingActivityBetweenDateFilter implements
* @author Julien Fastré <julien.fastre@champs-libres.coop> ExportElementValidatedInterface,
*/ FilterInterface
class PersonHavingActivityBetweenDateFilter implements FilterInterface,
ExportElementValidatedInterface
{ {
/** /**
*
* @var TranslatableStringHelper
*/
protected $translatableStringHelper;
/**
*
* @var EntityRepository * @var EntityRepository
*/ */
protected $activityReasonRepository; protected $activityReasonRepository;
/** /**
* * @var TranslatableStringHelper
*/
protected $translatableStringHelper;
/**
* @var TranslatorInterface * @var TranslatorInterface
*/ */
protected $translator; protected $translator;
@@ -73,7 +61,6 @@ class PersonHavingActivityBetweenDateFilter implements FilterInterface,
$this->translator = $translator; $this->translator = $translator;
} }
public function addRole() public function addRole()
{ {
return null; return null;
@@ -83,22 +70,24 @@ 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');
@@ -111,10 +100,14 @@ class PersonHavingActivityBetweenDateFilter implements FilterInterface,
} }
$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,23 +118,23 @@ 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
@@ -154,75 +147,78 @@ class PersonHavingActivityBetweenDateFilter implements FilterInterface,
'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 \Symfony\Component\Form\FormInterface $filterForm */
$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,25 +1,31 @@
<?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.
*
* @see https://www.champs-libres.coop/
*/
declare(strict_types=1);
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 +33,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,40 @@
<?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.
*
* @see https://www.champs-libres.coop/
*/
declare(strict_types=1);
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,65 +1,78 @@
<?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.
*
* @see https://www.champs-libres.coop/
*/
declare(strict_types=1);
namespace Chill\ActivityBundle\Form; namespace Chill\ActivityBundle\Form;
use Chill\MainBundle\Form\Type\CommentType; use Chill\ActivityBundle\Form\Type\TranslatableActivityReason;
use Symfony\Component\Form\AbstractType; use Chill\ActivityBundle\Form\Type\TranslatableActivityType;
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\ActivityBundle\Form\Type\TranslatableActivityType; use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface;
use Chill\ActivityBundle\Form\Type\TranslatableActivityReason;
use Chill\MainBundle\Form\Type\UserPickerType; use function in_array;
use Chill\MainBundle\Form\Type\ScopePickerType;
use Chill\MainBundle\Form\Type\ChillDateType;
class ActivityType extends AbstractType class ActivityType extends AbstractType
{ {
/** /**
* the user running this form
*
* @var User
*/
protected $user;
/**
*
* @var AuthorizationHelper * @var AuthorizationHelper
*/ */
protected $authorizationHelper; protected $authorizationHelper;
/** /**
*
* @var ObjectManager * @var ObjectManager
*/ */
protected $om; protected $om;
protected $timeChoices;
/** /**
*
* @var TranslatableStringHelper * @var TranslatableStringHelper
*/ */
protected $translatableStringHelper; protected $translatableStringHelper;
protected $timeChoices; /**
* the user running this form.
*
* @var User
*/
protected $user;
public function __construct( public function __construct(
TokenStorageInterface $tokenStorage, TokenStorageInterface $tokenStorage,
AuthorizationHelper $authorizationHelper, ObjectManager $om, AuthorizationHelper $authorizationHelper,
ObjectManager $om,
TranslatableStringHelper $translatableStringHelper, TranslatableStringHelper $translatableStringHelper,
array $timeChoices array $timeChoices
) ) {
{
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;
@@ -68,87 +81,80 @@ class ActivityType extends AbstractType
$this->timeChoices = $timeChoices; $this->timeChoices = $timeChoices;
} }
/**
* @param FormBuilderInterface $builder
* @param array $options
*/
public function buildForm(FormBuilderInterface $builder, array $options) public function buildForm(FormBuilderInterface $builder, array $options)
{ {
// handle times choices // handle times choices
$timeChoices = array(); $timeChoices = [];
foreach ($this->timeChoices as $e) { foreach ($this->timeChoices as $e) {
$timeChoices[$e['label']] = $e['seconds']; $timeChoices[$e['label']] = $e['seconds'];
}; }
$durationTimeTransformer = new DateTimeToTimestampTransformer('GMT', 'GMT'); $durationTimeTransformer = new DateTimeToTimestampTransformer('GMT', 'GMT');
$durationTimeOptions = array( $durationTimeOptions = [
'choices' => $timeChoices, 'choices' => $timeChoices,
'placeholder' => 'Choose the duration', 'placeholder' => 'Choose the duration',
); ];
$builder $builder
->add('date', ChillDateType::class, array( ->add('date', ChillDateType::class, [
'required' => true 'required' => true,
)) ])
->add('durationTime', ChoiceType::class, $durationTimeOptions) ->add('durationTime', ChoiceType::class, $durationTimeOptions)
->add('attendee', ChoiceType::class, array( ->add('attendee', ChoiceType::class, [
'expanded' => true, 'expanded' => true,
'required' => false, 'required' => false,
'choices' => array( 'choices' => [
'present' => true, 'present' => true,
'not present' => false 'not present' => false,
) ],
)) ])
->add('user', UserPickerType::class, [ ->add('user', UserPickerType::class, [
'center' => $options['center'], 'center' => $options['center'],
'role' => $options['role'] 'role' => $options['role'],
]) ])
->add('scope', ScopePickerType::class, [ ->add('scope', ScopePickerType::class, [
'center' => $options['center'], 'center' => $options['center'],
'role' => $options['role'] 'role' => $options['role'],
]) ])
->add('reasons', TranslatableActivityReason::class, array( ->add('reasons', TranslatableActivityReason::class, [
'multiple' => true, 'multiple' => true,
'required' => false, 'required' => false,
)) ])
->add('type', TranslatableActivityType::class, array( ->add('type', TranslatableActivityType::class, [
'placeholder' => 'Choose a type', 'placeholder' => 'Choose a type',
'active_only' => true 'active_only' => true,
)) ])
->add('comment', CommentType::class, [ ->add('comment', CommentType::class, [
'required' => false, 'required' => false,
]) ]);
;
$builder->get('durationTime') $builder->get('durationTime')
->addModelTransformer($durationTimeTransformer); ->addModelTransformer($durationTimeTransformer);
$builder->get('durationTime') $builder->get('durationTime')
->addEventListener( ->addEventListener(
FormEvents::PRE_SET_DATA, FormEvents::PRE_SET_DATA,
function(FormEvent $formEvent) use ( static function (FormEvent $formEvent) use (
$timeChoices, $timeChoices,
$builder, $builder,
$durationTimeTransformer, $durationTimeTransformer,
$durationTimeOptions $durationTimeOptions
) ) {
{
// 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 DateTime $data */
$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, true)) {
// 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( $form = $builder->create(
@@ -156,15 +162,17 @@ class ActivityType extends AbstractType
ChoiceType::class, ChoiceType::class,
array_merge( array_merge(
$durationTimeOptions, $durationTimeOptions,
array( [
'choices' => $timeChoices, 'choices' => $timeChoices,
'auto_initialize' => false 'auto_initialize' => false,
]
) )
)); );
$form->addModelTransformer($durationTimeTransformer); $form->addModelTransformer($durationTimeTransformer);
$formEvent->getForm()->getParent()->add($form->getForm()); $formEvent->getForm()->getParent()->add($form->getForm());
} }
}); }
);
} }
/** /**
@@ -172,15 +180,14 @@ class ActivityType extends AbstractType
*/ */
public function configureOptions(OptionsResolver $resolver) public function configureOptions(OptionsResolver $resolver)
{ {
$resolver->setDefaults(array( $resolver->setDefaults([
'data_class' => 'Chill\ActivityBundle\Entity\Activity' 'data_class' => 'Chill\ActivityBundle\Entity\Activity',
)); ]);
$resolver $resolver
->setRequired(array('center', 'role')) ->setRequired(['center', 'role'])
->setAllowedTypes('center', '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');
;
} }
/** /**

View File

@@ -1,30 +1,37 @@
<?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.
*
* @see https://www.champs-libres.coop/
*/
declare(strict_types=1);
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\ChoiceType;
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
{ {
/**
* @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', ChoiceType::class, array( ->add('active', ChoiceType::class, [
'choices' => array( 'choices' => [
'Yes' => true, 'Yes' => true,
'No' => false 'No' => false,
), ],
'expanded' => true 'expanded' => true,
)); ]);
} }
/** /**
@@ -32,9 +39,9 @@ class ActivityTypeType extends AbstractType
*/ */
public function configureOptions(OptionsResolver $resolver) public function configureOptions(OptionsResolver $resolver)
{ {
$resolver->setDefaults(array( $resolver->setDefaults([
'data_class' => 'Chill\ActivityBundle\Entity\ActivityType' 'data_class' => 'Chill\ActivityBundle\Entity\ActivityType',
)); ]);
} }
/** /**

View File

@@ -1,54 +1,41 @@
<?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 * @see https://www.champs-libres.coop/
* 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/>.
*/ */
declare(strict_types=1);
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,20 +44,10 @@ class TranslatableActivityReason extends AbstractType
$this->reasonRender = $reasonRender; $this->reasonRender = $reasonRender;
} }
public function getBlockPrefix()
{
return 'translatable_activity_reason';
}
public function getParent()
{
return EntityType::class;
}
public function configureOptions(OptionsResolver $resolver) public function configureOptions(OptionsResolver $resolver)
{ {
$resolver->setDefaults( $resolver->setDefaults(
array( [
'class' => 'ChillActivityBundle:ActivityReason', 'class' => 'ChillActivityBundle:ActivityReason',
'choice_label' => function (ActivityReason $choice) { 'choice_label' => function (ActivityReason $choice) {
return $this->reasonRender->renderString($choice, []); return $this->reasonRender->renderString($choice, []);
@@ -82,12 +59,22 @@ class TranslatableActivityReason extends AbstractType
return null; return null;
}, },
'query_builder' => function (EntityRepository $er) { 'query_builder' => static function (EntityRepository $er) {
return $er->createQueryBuilder('r') return $er->createQueryBuilder('r')
->where('r.active = true'); ->where('r.active = true');
}, },
'attr' => [ 'class' => ' select2 '] 'attr' => ['class' => ' select2 '],
) ]
); );
} }
public function getBlockPrefix()
{
return 'translatable_activity_reason';
}
public function getParent()
{
return EntityType::class;
}
} }

View File

@@ -1,40 +1,27 @@
<?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 * @see https://www.champs-libres.coop/
* 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/>.
*/ */
declare(strict_types=1);
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 +34,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' => static 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 +58,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,71 @@
<?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 * @see https://www.champs-libres.coop/
* 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/>.
*/ */
declare(strict_types=1);
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 \Doctrine\ORM\QueryBuilder $qb */
$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 +75,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,42 +1,43 @@
<?php <?php
/*
*
*/
namespace Chill\ActivityBundle\Menu;
use Chill\MainBundle\Routing\LocalMenuBuilderInterface;
use Chill\MainBundle\Security\Authorization\AuthorizationHelper;
use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface;
use Symfony\Component\Translation\TranslatorInterface;
use Knp\Menu\MenuItem;
use Symfony\Component\Security\Core\Role\Role;
use Chill\ActivityBundle\Security\Authorization\ActivityVoter;
/** /**
* 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.
* *
* @author Julien Fastré <julien.fastre@champs-libres.coop> * @see https://www.champs-libres.coop/
*/ */
declare(strict_types=1);
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 class MenuBuilder implements LocalMenuBuilderInterface
{ {
/** /**
* * @var AuthorizationHelper
*/
protected $authorizationHelper;
/**
* @var TokenStorageInterface * @var TokenStorageInterface
*/ */
protected $tokenStorage; protected $tokenStorage;
/** /**
*
* @var TranslatorInterface * @var TranslatorInterface
*/ */
protected $translator; protected $translator;
/**
*
* @var AuthorizationHelper
*/
protected $authorizationHelper;
public function __construct( public function __construct(
TokenStorageInterface $tokenStorage, TokenStorageInterface $tokenStorage,
TranslatorInterface $translator, TranslatorInterface $translator,
@@ -47,10 +48,9 @@ class MenuBuilder implements LocalMenuBuilderInterface
$this->authorizationHelper = $authorizationHelper; $this->authorizationHelper = $authorizationHelper;
} }
public function buildMenu($menuId, MenuItem $menu, array $parameters) public function buildMenu($menuId, MenuItem $menu, array $parameters)
{ {
/* @var $person \Chill\PersonBundle\Entity\Person */ /** @var \Chill\PersonBundle\Entity\Person $person */
$person = $parameters['person']; $person = $parameters['person'];
$user = $this->tokenStorage->getToken()->getUser(); $user = $this->tokenStorage->getToken()->getUser();
$roleSee = new Role(ActivityVoter::SEE); $roleSee = new Role(ActivityVoter::SEE);
@@ -60,11 +60,11 @@ class MenuBuilder implements LocalMenuBuilderInterface
$menu->addChild($this->translator->trans('Activity list'), [ $menu->addChild($this->translator->trans('Activity list'), [
'route' => 'chill_activity_activity_list', 'route' => 'chill_activity_activity_list',
'routeParameters' => [ 'routeParameters' => [
'person_id' => $person->getId() 'person_id' => $person->getId(),
] ],
]) ])
->setExtras([ ->setExtras([
'order' => 201 'order' => 201,
]); ]);
} }
@@ -72,11 +72,11 @@ class MenuBuilder implements LocalMenuBuilderInterface
$menu->addChild($this->translator->trans('Add a new activity'), [ $menu->addChild($this->translator->trans('Add a new activity'), [
'route' => 'chill_activity_activity_new', 'route' => 'chill_activity_activity_new',
'routeParameters' => [ 'routeParameters' => [
'person_id' => $person->getId() 'person_id' => $person->getId(),
] ],
]) ])
->setExtras([ ->setExtras([
'order' => 200 'order' => 200,
]); ]);
} }
} }

View File

@@ -1,78 +1,69 @@
<?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, * @see https://www.champs-libres.coop/
* 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/>.
*/ */
declare(strict_types=1);
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 \Chill\PersonBundle\Entity\Person $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)) { if ($this->authorizationChecker->isGranted(ActivityVoter::CREATE, $person)) {
$menu->addChild( $menu->addChild(
$this->translator->trans('Add a new activity'), [ $this->translator->trans('Add a new activity'),
[
'route' => 'chill_activity_activity_new', 'route' => 'chill_activity_activity_new',
'routeParameters' => ['person_id' => $person->getId()], 'routeParameters' => ['person_id' => $person->getId()],
]) ]
->setExtra('order', 200) )
; ->setExtra('order', 200);
} }
} }

View File

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

View File

@@ -1,42 +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 Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository;
use Doctrine\Persistence\ManagerRegistry;
/**
* @method AccompanyingPeriodParticipation|null find($id, $lockMode = null, $lockVersion = null)
* @method AccompanyingPeriodParticipation|null findOneBy(array $criteria, array $orderBy = null)
* @method AccompanyingPeriodParticipation[] findAll()
* @method AccompanyingPeriodParticipation[] findBy(array $criteria, array $orderBy = null, $limit = null, $offset = null)
*/
class ActivityRepository extends ServiceEntityRepository
{
public function __construct(ManagerRegistry $registry)
{
parent::__construct($registry, Activity::class);
}
}

View File

@@ -1,34 +1,21 @@
<?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.
*
* @see https://www.champs-libres.coop/
*/
declare(strict_types=1);
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
{ {
public function registerBundles()
{
return array(
new Symfony\Bundle\FrameworkBundle\FrameworkBundle(),
new Chill\CustomFieldsBundle\ChillCustomFieldsBundle(),
new Symfony\Bundle\SecurityBundle\SecurityBundle(),
new Symfony\Bundle\TwigBundle\TwigBundle(),
new \Symfony\Bundle\AsseticBundle\AsseticBundle(),
new Doctrine\Bundle\DoctrineBundle\DoctrineBundle(),
new Chill\PersonBundle\ChillPersonBundle(),
new Chill\MainBundle\ChillMainBundle(),
new Chill\ActivityBundle\ChillActivityBundle(),
new \Doctrine\Bundle\FixturesBundle\DoctrineFixturesBundle(),
new Doctrine\Bundle\MigrationsBundle\DoctrineMigrationsBundle(),
new Symfony\Bundle\MonologBundle\MonologBundle(),
#add here all the required bundle (some bundle are not required)
);
}
public function registerContainerConfiguration(LoaderInterface $loader)
{
$loader->load($this->getRootDir().'/config/config_'.$this->getEnvironment().'.yml');
}
/** /**
* @return string * @return string
*/ */
@@ -44,4 +31,28 @@ class AppKernel extends Kernel
{ {
return sys_get_temp_dir() . '/ActivityBundle/logs'; return sys_get_temp_dir() . '/ActivityBundle/logs';
} }
public function registerBundles()
{
return [
new Symfony\Bundle\FrameworkBundle\FrameworkBundle(),
new Chill\CustomFieldsBundle\ChillCustomFieldsBundle(),
new Symfony\Bundle\SecurityBundle\SecurityBundle(),
new Symfony\Bundle\TwigBundle\TwigBundle(),
new \Symfony\Bundle\AsseticBundle\AsseticBundle(),
new Doctrine\Bundle\DoctrineBundle\DoctrineBundle(),
new Chill\PersonBundle\ChillPersonBundle(),
new Chill\MainBundle\ChillMainBundle(),
new Chill\ActivityBundle\ChillActivityBundle(),
new \Doctrine\Bundle\FixturesBundle\DoctrineFixturesBundle(),
new Doctrine\Bundle\MigrationsBundle\DoctrineMigrationsBundle(),
new Symfony\Bundle\MonologBundle\MonologBundle(),
//add here all the required bundle (some bundle are not required)
];
}
public function registerContainerConfiguration(LoaderInterface $loader)
{
$loader->load($this->getRootDir() . '/config/config_' . $this->getEnvironment() . '.yml');
}
} }

View File

@@ -1,11 +1,22 @@
<?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.
*
* @see https://www.champs-libres.coop/
*/
declare(strict_types=1);
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,18 @@
<?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.
*
* @see https://www.champs-libres.coop/
*/
declare(strict_types=1);
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,11 +20,13 @@ 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'], true) || \PHP_SAPI === '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.');
} }

View File

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

View File

@@ -1,41 +1,32 @@
<?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, * @see https://www.champs-libres.coop/
* 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/>.
*/ */
declare(strict_types=1);
namespace Chill\ActivityBundle\Security\Authorization; namespace Chill\ActivityBundle\Security\Authorization;
use Chill\MainBundle\Entity\Center;
use Chill\MainBundle\Security\Authorization\AbstractChillVoter; use Chill\MainBundle\Security\Authorization\AbstractChillVoter;
use Chill\MainBundle\Security\Authorization\AuthorizationHelper; use Chill\MainBundle\Security\Authorization\AuthorizationHelper;
use Chill\MainBundle\Security\ProvideRoleHierarchyInterface; use Chill\MainBundle\Security\ProvideRoleHierarchyInterface;
use Chill\MainBundle\Entity\Center;
/** use function in_array;
*
*
* @author Julien Fastré <julien.fastre@champs-libres.coop>
*/
class ActivityStatsVoter extends AbstractChillVoter implements ProvideRoleHierarchyInterface class ActivityStatsVoter extends AbstractChillVoter implements ProvideRoleHierarchyInterface
{ {
const STATS = 'CHILL_ACTIVITY_STATS'; public const LISTS = 'CHILL_ACTIVITY_LIST';
const LISTS = 'CHILL_ACTIVITY_LIST';
public const STATS = 'CHILL_ACTIVITY_STATS';
/** /**
*
* @var AuthorizationHelper * @var AuthorizationHelper
*/ */
protected $helper; protected $helper;
@@ -45,25 +36,24 @@ class ActivityStatsVoter extends AbstractChillVoter implements ProvideRoleHierar
$this->helper = $helper; $this->helper = $helper;
} }
private function getAttributes() public function getRoles()
{ {
return array(self::STATS, self::LISTS); return $this->getAttributes();
}
public function getRolesWithHierarchy()
{
return ['Activity' => $this->getRoles()];
}
public function getRolesWithoutScope()
{
return $this->getAttributes();
} }
protected function getSupportedClasses() protected function getSupportedClasses()
{ {
return array(Center::class); return [Center::class];
}
protected function supports($attribute, $subject)
{
if ($subject instanceof Center
&& \in_array($attribute, $this->getAttributes())) {
return true;
}
return false;
} }
protected function isGranted($attribute, $object, $user = null) protected function isGranted($attribute, $object, $user = null)
@@ -75,18 +65,20 @@ class ActivityStatsVoter extends AbstractChillVoter implements ProvideRoleHierar
return $this->helper->userHasAccess($user, $object, $attribute); return $this->helper->userHasAccess($user, $object, $attribute);
} }
public function getRoles() protected function supports($attribute, $subject)
{ {
return $this->getAttributes(); if (
$subject instanceof Center
&& in_array($attribute, $this->getAttributes(), true)
) {
return true;
} }
public function getRolesWithoutScope() return false;
{
return $this->getAttributes();
} }
public function getRolesWithHierarchy() private function getAttributes()
{ {
return [ 'Activity' => $this->getRoles() ]; return [self::STATS, self::LISTS];
} }
} }

View File

@@ -1,49 +1,42 @@
<?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, * @see https://www.champs-libres.coop/
* 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/>.
*/ */
declare(strict_types=1);
namespace Chill\ActivityBundle\Security\Authorization; namespace Chill\ActivityBundle\Security\Authorization;
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface; use Chill\ActivityBundle\Entity\Activity;
use Chill\MainBundle\Entity\User;
use Chill\MainBundle\Security\Authorization\AbstractChillVoter; use Chill\MainBundle\Security\Authorization\AbstractChillVoter;
use Chill\MainBundle\Security\Authorization\AuthorizationHelper; use Chill\MainBundle\Security\Authorization\AuthorizationHelper;
use Chill\MainBundle\Security\ProvideRoleHierarchyInterface; use Chill\MainBundle\Security\ProvideRoleHierarchyInterface;
use Chill\MainBundle\Entity\User;
use Chill\ActivityBundle\Entity\Activity;
use Chill\PersonBundle\Entity\Person; use Chill\PersonBundle\Entity\Person;
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
use Symfony\Component\Security\Core\Role\Role; use Symfony\Component\Security\Core\Role\Role;
/** use function in_array;
*
*
* @author Julien Fastré <julien.fastre@champs-libres.coop>
*/
class ActivityVoter extends AbstractChillVoter implements ProvideRoleHierarchyInterface class ActivityVoter extends AbstractChillVoter implements ProvideRoleHierarchyInterface
{ {
const CREATE = 'CHILL_ACTIVITY_CREATE'; public const CREATE = 'CHILL_ACTIVITY_CREATE';
const SEE = 'CHILL_ACTIVITY_SEE';
const SEE_DETAILS = 'CHILL_ACTIVITY_SEE_DETAILS'; public const DELETE = 'CHILL_ACTIVITY_DELETE';
const UPDATE = 'CHILL_ACTIVITY_UPDATE';
const DELETE = 'CHILL_ACTIVITY_DELETE'; public const SEE = 'CHILL_ACTIVITY_SEE';
public const SEE_DETAILS = 'CHILL_ACTIVITY_SEE_DETAILS';
public const UPDATE = 'CHILL_ACTIVITY_UPDATE';
/** /**
*
* @var AuthorizationHelper * @var AuthorizationHelper
*/ */
protected $helper; protected $helper;
@@ -53,18 +46,33 @@ class ActivityVoter extends AbstractChillVoter implements ProvideRoleHierarchyIn
$this->helper = $helper; $this->helper = $helper;
} }
public function getRoles()
{
return $this->getAttributes();
}
public function getRolesWithHierarchy()
{
return ['Activity' => $this->getRoles()];
}
public function getRolesWithoutScope()
{
return [];
}
protected function supports($attribute, $subject) protected function supports($attribute, $subject)
{ {
if ($subject instanceof Activity) { if ($subject instanceof Activity) {
return \in_array($attribute, $this->getAttributes()); return in_array($attribute, $this->getAttributes(), true);
} elseif ($subject instanceof Person) {
return $attribute === self::SEE
||
$attribute === self::CREATE;
} else {
return false;
} }
if ($subject instanceof Person) {
return self::SEE === $attribute
|| self::CREATE === $attribute;
}
return false;
} }
protected function voteOnAttribute($attribute, $subject, TokenInterface $token) protected function voteOnAttribute($attribute, $subject, TokenInterface $token)
@@ -76,7 +84,7 @@ class ActivityVoter extends AbstractChillVoter implements ProvideRoleHierarchyIn
if ($subject instanceof Person) { if ($subject instanceof Person) {
$centers = $this->helper->getReachableCenters($token->getUser(), new Role($attribute)); $centers = $this->helper->getReachableCenters($token->getUser(), new Role($attribute));
return \in_array($subject->getCenter(), $centers); return in_array($subject->getCenter(), $centers, true);
} }
/* @var $subject Activity */ /* @var $subject Activity */
@@ -86,24 +94,6 @@ class ActivityVoter extends AbstractChillVoter implements ProvideRoleHierarchyIn
private function getAttributes() private function getAttributes()
{ {
return [self::CREATE, self::SEE, self::UPDATE, self::DELETE, return [self::CREATE, self::SEE, self::UPDATE, self::DELETE,
self::SEE_DETAILS ]; self::SEE_DETAILS, ];
} }
public function getRoles()
{
return $this->getAttributes();
}
public function getRolesWithoutScope()
{
return array();
}
public function getRolesWithHierarchy()
{
return [ 'Activity' => $this->getRoles() ];
}
} }

View File

@@ -1,37 +1,28 @@
<?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 * @see https://www.champs-libres.coop/
* 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/>.
*/ */
declare(strict_types=1);
namespace Chill\ActivityBundle\Templating\Entity; namespace Chill\ActivityBundle\Templating\Entity;
use Chill\MainBundle\Templating\Entity\AbstractChillEntityRender;
use Chill\ActivityBundle\Entity\ActivityReason; use Chill\ActivityBundle\Entity\ActivityReason;
use Chill\MainBundle\Templating\Entity\AbstractChillEntityRender;
use Chill\MainBundle\Templating\TranslatableStringHelper; use Chill\MainBundle\Templating\TranslatableStringHelper;
/** /**
* Render activity reason * Render activity reason.
*
*/ */
class ActivityReasonRender extends AbstractChillEntityRender class ActivityReasonRender extends AbstractChillEntityRender
{ {
/** /**
*
* @var TranslatableStringHelper * @var TranslatableStringHelper
*/ */
protected $translatableStringHelper; protected $translatableStringHelper;
@@ -41,7 +32,6 @@ class ActivityReasonRender extends AbstractChillEntityRender
$this->translatableStringHelper = $translatableStringHelper; $this->translatableStringHelper = $translatableStringHelper;
} }
public function renderBox($entity, array $options): string public function renderBox($entity, array $options): string
{ {
return return
@@ -58,15 +48,11 @@ class ActivityReasonRender extends AbstractChillEntityRender
$entity->getName() $entity->getName()
) . ) .
'</span>' . '</span>' .
$this->getDefaultClosingBox() $this->getDefaultClosingBox();
;
} }
/** /**
*
* @param ActivityReason $entity * @param ActivityReason $entity
* @param array $options
* @return string
*/ */
public function renderString($entity, array $options): string public function renderString($entity, array $options): string
{ {
@@ -74,7 +60,8 @@ class ActivityReasonRender extends AbstractChillEntityRender
if (null !== $entity->getCategory()) { if (null !== $entity->getCategory()) {
$category = $this->translatableStringHelper->localize( $category = $this->translatableStringHelper->localize(
$entity->getCategory()->getName()). ' > '; $entity->getCategory()->getName()
) . ' > ';
} }
return $category . return $category .

View File

@@ -1,5 +1,16 @@
<?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.
*
* @see https://www.champs-libres.coop/
*/
declare(strict_types=1);
/* /*
* Copyright (C) 2015 Julien Fastré <julien.fastre@champs-libres.coop> * Copyright (C) 2015 Julien Fastré <julien.fastre@champs-libres.coop>
* *
@@ -24,26 +35,19 @@ use Chill\MainBundle\Entity\Scope;
use Chill\PersonBundle\Entity\Person; use Chill\PersonBundle\Entity\Person;
/** /**
* Prepare entities useful in tests * Prepare entities useful in tests.
*
*
* @author Julien Fastré <julien.fastre@champs-libres.coop>
*/ */
trait PrepareActivityTrait trait PrepareActivityTrait
{ {
/** /**
* Return an activity with a scope and a person inside * Return an activity with a scope and a person inside.
* *
* @param Scope $scope
* @param Person $person
* @return Activity * @return Activity
*/ */
public function prepareActivity(Scope $scope, Person $person) public function prepareActivity(Scope $scope, Person $person)
{ {
return (new Activity()) return (new Activity())
->setScope($scope) ->setScope($scope)
->setPerson($person) ->setPerson($person);
;
} }
} }

View File

@@ -1,16 +1,84 @@
<?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.
*
* @see https://www.champs-libres.coop/
*/
declare(strict_types=1);
namespace Chill\ActivityBundle\Tests\Controller; namespace Chill\ActivityBundle\Tests\Controller;
use RuntimeException;
use Symfony\Bundle\FrameworkBundle\Test\WebTestCase; use Symfony\Bundle\FrameworkBundle\Test\WebTestCase;
use Symfony\Component\Security\Core\Role\Role; use Symfony\Component\Security\Core\Role\Role;
use Symfony\Component\HttpFoundation\Response; use function count;
use function in_array;
class ActivityControllerTest extends WebTestCase /**
* @internal
* @coversNothing
*/
final class ActivityControllerTest extends WebTestCase
{ {
public function getSecuredPagesAuthenticated()
{
self::bootKernel();
$person = $this->getPersonFromFixtures();
$activities = $this->getActivitiesForPerson($person);
$user = $this->createFakeUser();
return [
[
$this->getAuthenticatedClient('center b_social'),
sprintf('fr/person/%d/activity/', $person->getId()),
],
[
$this->getAuthenticatedClient('center b_social'),
sprintf('fr/person/%d/activity/new', $person->getId()),
],
[
$this->getAuthenticatedClient('center b_social'),
sprintf('fr/person/%d/activity/%d/show', $person->getId(), $activities[0]->getId()),
],
[
$this->getAuthenticatedClient('center b_social'),
sprintf('fr/person/%d/activity/%d/edit', $person->getId(), $activities[0]->getId()),
],
[
$this->getAuthenticatedClient($user->getUsername()),
sprintf('fr/person/%d/activity/new', $person->getId()),
],
];
}
/**
* Provide a client unauthenticated and.
*/
public function getSecuredPagesUnauthenticated()
{
self::bootKernel();
$person = $this->getPersonFromFixtures();
$activities = $this->getActivitiesForPerson($person);
return [
[sprintf('fr/person/%d/activity/', $person->getId())],
[sprintf('fr/person/%d/activity/new', $person->getId())],
[sprintf('fr/person/%d/activity/%d/show', $person->getId(), $activities[0]->getId())],
[sprintf('fr/person/%d/activity/%d/edit', $person->getId(), $activities[0]->getId())],
];
}
/** /**
* @dataProvider getSecuredPagesUnauthenticated * @dataProvider getSecuredPagesUnauthenticated
*
* @param mixed $url
*/ */
public function testAccessIsDeniedForUnauthenticated($url) public function testAccessIsDeniedForUnauthenticated($url)
{ {
@@ -18,14 +86,16 @@ class ActivityControllerTest extends WebTestCase
$client->request('GET', $url); $client->request('GET', $url);
$this->assertEquals(302, $client->getResponse()->getStatusCode()); self::assertEquals(302, $client->getResponse()->getStatusCode());
$this->assertTrue($client->getResponse()->isRedirect('http://localhost/login'), self::assertTrue(
sprintf('the page "%s" does not redirect to http://localhost/login', $url)); $client->getResponse()->isRedirect('http://localhost/login'),
sprintf('the page "%s" does not redirect to http://localhost/login', $url)
);
} }
/** /**
*
* @dataProvider getSecuredPagesAuthenticated * @dataProvider getSecuredPagesAuthenticated
*
* @param type $client * @param type $client
* @param type $url * @param type $url
*/ */
@@ -33,66 +103,9 @@ class ActivityControllerTest extends WebTestCase
{ {
$client->request('GET', $url); $client->request('GET', $url);
$this->assertEquals(403, $client->getResponse()->getStatusCode()); self::assertEquals(403, $client->getResponse()->getStatusCode());
} }
public function getSecuredPagesAuthenticated()
{
static::bootKernel();
$person = $this->getPersonFromFixtures();
$activities = $this->getActivitiesForPerson($person);
$user = $this->createFakeUser();
return array(
array(
$this->getAuthenticatedClient('center b_social'),
sprintf('fr/person/%d/activity/', $person->getId())
),
array(
$this->getAuthenticatedClient('center b_social'),
sprintf('fr/person/%d/activity/new', $person->getId())
),
array(
$this->getAuthenticatedClient('center b_social'),
sprintf('fr/person/%d/activity/%d/show', $person->getId(), $activities[0]->getId())
),
array(
$this->getAuthenticatedClient('center b_social'),
sprintf('fr/person/%d/activity/%d/edit', $person->getId(), $activities[0]->getId())
),
array(
$this->getAuthenticatedClient($user->getUsername()),
sprintf('fr/person/%d/activity/new', $person->getId())
)
);
}
/**
* Provide a client unauthenticated and
*
*/
public function getSecuredPagesUnauthenticated()
{
static::bootKernel();
$person = $this->getPersonFromFixtures();
$activities = $this->getActivitiesForPerson($person);
return array(
[ sprintf('fr/person/%d/activity/', $person->getId()) ],
[ sprintf('fr/person/%d/activity/new', $person->getId()) ],
[ sprintf('fr/person/%d/activity/%d/show', $person->getId(), $activities[0]->getId()) ],
[ sprintf('fr/person/%d/activity/%d/edit', $person->getId(), $activities[0]->getId()) ],
);
}
public function testCompleteScenario() public function testCompleteScenario()
{ {
// Create a new client to browse the application // Create a new client to browse the application
@@ -100,212 +113,89 @@ class ActivityControllerTest extends WebTestCase
$person = $this->getPersonFromFixtures(); $person = $this->getPersonFromFixtures();
// Create a new entry in the database // Create a new entry in the database
$crawler = $client->request('GET', sprintf('en/person/%d/activity/', $crawler = $client->request('GET', sprintf(
$person->getId())); 'en/person/%d/activity/',
$this->assertEquals(200, $client->getResponse()->getStatusCode(), $person->getId()
"Unexpected HTTP status code for GET /activity/"); ));
self::assertEquals(
200,
$client->getResponse()->getStatusCode(),
'Unexpected HTTP status code for GET /activity/'
);
$crawler = $client->click($crawler->selectLink('Ajouter une nouvelle activité') $crawler = $client->click($crawler->selectLink('Ajouter une nouvelle activité')
->link()); ->link());
$reason1 = $this->getRandomActivityReason(); $reason1 = $this->getRandomActivityReason();
$reason2 = $this->getRandomActivityReason(array($reason1->getId())); $reason2 = $this->getRandomActivityReason([$reason1->getId()]);
// Fill in the form and submit it // Fill in the form and submit it
$form = $crawler->selectButton('Ajouter une nouvelle activité')->form(array( $form = $crawler->selectButton('Ajouter une nouvelle activité')->form([
'chill_activitybundle_activity'=> array( 'chill_activitybundle_activity' => [
'date' => '15-01-2015', 'date' => '15-01-2015',
'durationTime' => 600, 'durationTime' => 600,
// 'remark' => 'blabla', // 'remark' => 'blabla',
'scope' => $this->getRandomScope('center a_social', 'Center A')->getId(), 'scope' => $this->getRandomScope('center a_social', 'Center A')->getId(),
'type' => $this->getRandomActivityType()->getId() 'type' => $this->getRandomActivityType()->getId(),
) ],
)); ]);
$form['chill_activitybundle_activity[reasons]']->select(array ($reason1->getId(), $reason2->getId())); $form['chill_activitybundle_activity[reasons]']->select([$reason1->getId(), $reason2->getId()]);
$client->submit($form); $client->submit($form);
$this->assertTrue($client->getResponse()->isRedirect()); self::assertTrue($client->getResponse()->isRedirect());
$crawler = $client->followRedirect(); $crawler = $client->followRedirect();
// Check data in the show view // Check data in the show view
$this->assertGreaterThan(0, $crawler->filter('dd:contains("January 15, 2015")')->count(), self::assertGreaterThan(
'Missing element dd:contains("January 15, 2015")'); 0,
$crawler->filter('dd:contains("January 15, 2015")')->count(),
'Missing element dd:contains("January 15, 2015")'
);
// Edit the entity // Edit the entity
$crawler = $client->click($crawler->selectLink("Modifier l'activité")->link()); $crawler = $client->click($crawler->selectLink("Modifier l'activité")->link());
$form = $crawler->selectButton("Sauver l'activité")->form(array( $form = $crawler->selectButton("Sauver l'activité")->form([
'chill_activitybundle_activity' => array( 'chill_activitybundle_activity' => [
'date' => '25-01-2015', 'date' => '25-01-2015',
// 'remark' => 'Foo' // 'remark' => 'Foo'
) ],
)); ]);
$client->submit($form); $client->submit($form);
$this->assertTrue($client->getResponse()->isRedirect()); self::assertTrue($client->getResponse()->isRedirect());
$crawler = $client->followRedirect(); $crawler = $client->followRedirect();
// check that new data are present // check that new data are present
$this->assertGreaterThan(0, self::assertGreaterThan(
0,
$crawler->filter('dd:contains("January 25, 2015")')->count(), $crawler->filter('dd:contains("January 25, 2015")')->count(),
'Missing element dd:contains("January 25, 2015")'); 'Missing element dd:contains("January 25, 2015")'
$this->assertGreaterThan(0, );
self::assertGreaterThan(
0,
$crawler->filter('dd:contains("Foo")')->count(), $crawler->filter('dd:contains("Foo")')->count(),
'Missing element dd:contains("Foo")'); 'Missing element dd:contains("Foo")'
);
// delete the actvity // delete the actvity
$crawler = $client->click($crawler->selectLink("Supprimer")->link()); $crawler = $client->click($crawler->selectLink('Supprimer')->link());
$button = $crawler->selectButton('Supprimer'); $button = $crawler->selectButton('Supprimer');
$form = $button->form(); $form = $button->form();
$client->submit($form); $client->submit($form);
$this->assertTrue($client->getResponse()->isRedirect(sprintf('/en/person/%d/activity/', self::assertTrue($client->getResponse()->isRedirect(sprintf(
$person->getId()))); '/en/person/%d/activity/',
$person->getId()
)));
$crawler = $client->followRedirect(); $crawler = $client->followRedirect();
$this->assertNotContains('January 25, 2015', $crawler->text()); self::assertNotContains('January 25, 2015', $crawler->text());
}
/**
*
* @return \Symfony\Component\BrowserKit\Client
*/
private function getAuthenticatedClient($username = 'center a_social')
{
return static::createClient(array(), array(
'PHP_AUTH_USER' => $username,
'PHP_AUTH_PW' => 'password',
));
}
/**
*
* @return \Chill\PersonBundle\Entity\Person
*/
private function getPersonFromFixtures()
{
$em = static::$kernel->getContainer()
->get('doctrine.orm.entity_manager');
$person = $em->getRepository('ChillPersonBundle:Person')
->findOneBy(array(
'firstName' => 'Depardieu',
'lastName' => 'Gérard'
));
if ($person === NULL) {
throw new \RuntimeException("We need a person with firstname Gérard and"
. " lastname Depardieu. Did you add fixtures ?");
}
return $person;
}
private function getActivitiesForPerson(\Chill\PersonBundle\Entity\Person $person)
{
$em = static::$kernel->getContainer()
->get('doctrine.orm.entity_manager');
$activities = $em->getRepository('ChillActivityBundle:Activity')
->findBy(array('person' => $person));
if (count($activities) === 0) {
throw new \RuntimeException("We need activities associated with this "
. "person. Did you forget to add fixtures ?");
}
return $activities;
}
/**
*
* @param string $username
* @param string $centerName
* @return \Chill\MainBundle\Entity\Scope
*/
private function getRandomScope($username, $centerName)
{
$user = static::$kernel->getContainer()
->get('doctrine.orm.entity_manager')
->getRepository('ChillMainBundle:User')
->findOneByUsername($username);
if ($user === NULL) {
throw new \RuntimeException("The user with username $username "
. "does not exists in database. Did you add fixtures ?");
}
$center = static::$kernel->getContainer()
->get('doctrine.orm.entity_manager')
->getRepository('ChillMainBundle:Center')
->findOneByName($centerName);
// get scope reachable by both role UPDATE and DELETE
$reachableScopesUpdate = static::$kernel->getContainer()
->get('chill.main.security.authorization.helper')
->getReachableScopes($user, new Role('CHILL_ACTIVITY_UPDATE'),
$center);
$reachableScopesDelete = static::$kernel->getContainer()
->get('chill.main.security.authorization.helper')
->getReachableScopes($user, new Role('CHILL_ACTIVITY_DELETE'),
$center);
$reachableScopesId = array_intersect(
array_map(function ($s) { return $s->getId(); }, $reachableScopesDelete),
array_map(function ($s) { return $s->getId(); }, $reachableScopesUpdate)
);
if (count($reachableScopesId) === 0) {
throw new \RuntimeException("there are not scope reachable for "
. "both CHILL_ACTIVITY_UPDATE and CHILL_ACTIVITY_DELETE");
}
foreach($reachableScopesUpdate as $scope) {
if (in_array($scope->getId(), $reachableScopesId)) {
$reachableScopes[] = $scope;
}
}
return $reachableScopes[array_rand($reachableScopes)];
}
/**
*
* @param int[] $excludeIds An array of id to exclude
* @return \Chill\ActivityBundle\Entity\ActivityReason
*/
private function getRandomActivityReason(array $excludeIds = array())
{
$reasons = static::$kernel->getContainer()
->get('doctrine.orm.entity_manager')
->getRepository('ChillActivityBundle:ActivityReason')
->findAll();
$reason = $reasons[array_rand($reasons)];
if (in_array($reason->getId(), $excludeIds)) {
return $this->getRandomActivityReason($excludeIds);
}
return $reason;
}
/**
*
* @return \Chill\ActivityBundle\Entity\ActivityType
*/
private function getRandomActivityType()
{
$types = static::$kernel->getContainer()
->get('doctrine.orm.entity_manager')
->getRepository('ChillActivityBundle:ActivityType')
->findAll();
return $types[array_rand($types)];
} }
/** /**
@@ -316,7 +206,7 @@ class ActivityControllerTest extends WebTestCase
*/ */
private function createFakeUser() private function createFakeUser()
{ {
$container = static::$kernel->getContainer(); $container = self::$kernel->getContainer();
$em = $container->get('doctrine.orm.entity_manager'); $em = $container->get('doctrine.orm.entity_manager');
//get the social PermissionGroup, and remove CHILL_ACTIVITY_* //get the social PermissionGroup, and remove CHILL_ACTIVITY_*
@@ -334,7 +224,7 @@ class ActivityControllerTest extends WebTestCase
//create groupCenter //create groupCenter
$groupCenter = new \Chill\MainBundle\Entity\GroupCenter(); $groupCenter = new \Chill\MainBundle\Entity\GroupCenter();
$groupCenter->setCenter($em->getRepository('ChillMainBundle:Center') $groupCenter->setCenter($em->getRepository('ChillMainBundle:Center')
->findOneBy(array('name' => 'Center A'))) ->findOneBy(['name' => 'Center A']))
->setPermissionsGroup($withoutActivityPermissionGroup); ->setPermissionsGroup($withoutActivityPermissionGroup);
$em->persist($withoutActivityPermissionGroup); $em->persist($withoutActivityPermissionGroup);
$em->persist($groupCenter); $em->persist($groupCenter);
@@ -355,4 +245,146 @@ class ActivityControllerTest extends WebTestCase
return $user; return $user;
} }
private function getActivitiesForPerson(\Chill\PersonBundle\Entity\Person $person)
{
$em = self::$kernel->getContainer()
->get('doctrine.orm.entity_manager');
$activities = $em->getRepository('ChillActivityBundle:Activity')
->findBy(['person' => $person]);
if (count($activities) === 0) {
throw new RuntimeException('We need activities associated with this '
. 'person. Did you forget to add fixtures ?');
}
return $activities;
}
/**
* @param mixed $username
*
* @return \Symfony\Component\BrowserKit\Client
*/
private function getAuthenticatedClient($username = 'center a_social')
{
return self::createClient([], [
'PHP_AUTH_USER' => $username,
'PHP_AUTH_PW' => 'password',
]);
}
/**
* @return \Chill\PersonBundle\Entity\Person
*/
private function getPersonFromFixtures()
{
$em = self::$kernel->getContainer()
->get('doctrine.orm.entity_manager');
$person = $em->getRepository('ChillPersonBundle:Person')
->findOneBy([
'firstName' => 'Depardieu',
'lastName' => 'Gérard',
]);
if (null === $person) {
throw new RuntimeException('We need a person with firstname Gérard and'
. ' lastname Depardieu. Did you add fixtures ?');
}
return $person;
}
/**
* @param int[] $excludeIds An array of id to exclude
*
* @return \Chill\ActivityBundle\Entity\ActivityReason
*/
private function getRandomActivityReason(array $excludeIds = [])
{
$reasons = self::$kernel->getContainer()
->get('doctrine.orm.entity_manager')
->getRepository('ChillActivityBundle:ActivityReason')
->findAll();
$reason = $reasons[array_rand($reasons)];
if (in_array($reason->getId(), $excludeIds, true)) {
return $this->getRandomActivityReason($excludeIds);
}
return $reason;
}
/**
* @return \Chill\ActivityBundle\Entity\ActivityType
*/
private function getRandomActivityType()
{
$types = self::$kernel->getContainer()
->get('doctrine.orm.entity_manager')
->getRepository('ChillActivityBundle:ActivityType')
->findAll();
return $types[array_rand($types)];
}
/**
* @param string $username
* @param string $centerName
*
* @return \Chill\MainBundle\Entity\Scope
*/
private function getRandomScope($username, $centerName)
{
$user = self::$kernel->getContainer()
->get('doctrine.orm.entity_manager')
->getRepository('ChillMainBundle:User')
->findOneByUsername($username);
if (null === $user) {
throw new RuntimeException("The user with username {$username} "
. 'does not exists in database. Did you add fixtures ?');
}
$center = self::$kernel->getContainer()
->get('doctrine.orm.entity_manager')
->getRepository('ChillMainBundle:Center')
->findOneByName($centerName);
// get scope reachable by both role UPDATE and DELETE
$reachableScopesUpdate = self::$kernel->getContainer()
->get('chill.main.security.authorization.helper')
->getReachableScopes(
$user,
new Role('CHILL_ACTIVITY_UPDATE'),
$center
);
$reachableScopesDelete = self::$kernel->getContainer()
->get('chill.main.security.authorization.helper')
->getReachableScopes(
$user,
new Role('CHILL_ACTIVITY_DELETE'),
$center
);
$reachableScopesId = array_intersect(
array_map(static function ($s) { return $s->getId(); }, $reachableScopesDelete),
array_map(static function ($s) { return $s->getId(); }, $reachableScopesUpdate)
);
if (count($reachableScopesId) === 0) {
throw new RuntimeException('there are not scope reachable for '
. 'both CHILL_ACTIVITY_UPDATE and CHILL_ACTIVITY_DELETE');
}
foreach ($reachableScopesUpdate as $scope) {
if (in_array($scope->getId(), $reachableScopesId, true)) {
$reachableScopes[] = $scope;
}
}
return $reachableScopes[array_rand($reachableScopes)];
}
} }

View File

@@ -1,15 +1,31 @@
<?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.
*
* @see https://www.champs-libres.coop/
*/
declare(strict_types=1);
namespace Chill\ActivityBundle\Tests\Controller; namespace Chill\ActivityBundle\Tests\Controller;
use Symfony\Bundle\FrameworkBundle\Test\WebTestCase; use Symfony\Bundle\FrameworkBundle\Test\WebTestCase;
class ActivityReasonCategoryControllerTest extends WebTestCase /**
* @internal
* @coversNothing
*/
final class ActivityReasonCategoryControllerTest extends WebTestCase
{ {
public function testToWrite() public function testToWrite()
{ {
$this->markTestSkipped(); self::markTestSkipped();
} }
/* /*
public function testCompleteScenario() public function testCompleteScenario()
{ {

View File

@@ -1,15 +1,31 @@
<?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.
*
* @see https://www.champs-libres.coop/
*/
declare(strict_types=1);
namespace Chill\ActivityBundle\Tests\Controller; namespace Chill\ActivityBundle\Tests\Controller;
use Symfony\Bundle\FrameworkBundle\Test\WebTestCase; use Symfony\Bundle\FrameworkBundle\Test\WebTestCase;
class ActivityReasonControllerTest extends WebTestCase /**
* @internal
* @coversNothing
*/
final class ActivityReasonControllerTest extends WebTestCase
{ {
public function testToWrite() public function testToWrite()
{ {
$this->markTestSkipped(); self::markTestSkipped();
} }
/* /*
public function testCompleteScenario() public function testCompleteScenario()
{ {

View File

@@ -1,15 +1,31 @@
<?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.
*
* @see https://www.champs-libres.coop/
*/
declare(strict_types=1);
namespace Chill\ActivityBundle\Tests\Controller; namespace Chill\ActivityBundle\Tests\Controller;
use Symfony\Bundle\FrameworkBundle\Test\WebTestCase; use Symfony\Bundle\FrameworkBundle\Test\WebTestCase;
class ActivityTypeControllerTest extends WebTestCase /**
* @internal
* @coversNothing
*/
final class ActivityTypeControllerTest extends WebTestCase
{ {
public function testToWrite() public function testToWrite()
{ {
$this->markTestSkipped(); self::markTestSkipped();
} }
/* /*
public function testCompleteScenario() public function testCompleteScenario()
{ {

View File

@@ -1,49 +1,43 @@
<?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, * @see https://www.champs-libres.coop/
* 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/>.
*/ */
declare(strict_types=1);
namespace Chill\ActivityBundle\Tests\Aggregator; namespace Chill\ActivityBundle\Tests\Aggregator;
use Chill\MainBundle\Test\Export\AbstractAggregatorTest; use Chill\MainBundle\Test\Export\AbstractAggregatorTest;
/** /**
* Add tests for ActivityReasonAggregator * Add tests for ActivityReasonAggregator.
* *
* @author Julien Fastré <julien.fastre@champs-libres.coop> * @internal
* @coversNothing
*/ */
class ActivityReasonAggregatorTest extends AbstractAggregatorTest final class ActivityReasonAggregatorTest extends AbstractAggregatorTest
{ {
/** /**
*
* @var \Chill\ActivityBundle\Export\Aggregator\ActivityReasonAggregator * @var \Chill\ActivityBundle\Export\Aggregator\ActivityReasonAggregator
*/ */
private $aggregator; private $aggregator;
public function setUp() protected function setUp()
{ {
static::bootKernel(); self::bootKernel();
$container = static::$kernel->getContainer(); $container = self::$kernel->getContainer();
$this->aggregator = $container->get('chill.activity.export.reason_aggregator'); $this->aggregator = $container->get('chill.activity.export.reason_aggregator');
// add a fake request with a default locale (used in translatable string) // add a fake request with a default locale (used in translatable string)
$prophet = new \Prophecy\Prophet; $prophet = new \Prophecy\Prophet();
$request = $prophet->prophesize(); $request = $prophet->prophesize();
$request->willExtend(\Symfony\Component\HttpFoundation\Request::class); $request->willExtend(\Symfony\Component\HttpFoundation\Request::class);
$request->getLocale()->willReturn('fr'); $request->getLocale()->willReturn('fr');
@@ -59,22 +53,22 @@ class ActivityReasonAggregatorTest extends AbstractAggregatorTest
public function getFormData() public function getFormData()
{ {
return array( return [
array('level' => 'reasons'), ['level' => 'reasons'],
array('level' => 'categories') ['level' => 'categories'],
); ];
} }
public function getQueryBuilders() public function getQueryBuilders()
{ {
if (static::$kernel === null) { if (null === self::$kernel) {
static::bootKernel(); self::bootKernel();
} }
$em = static::$kernel->getContainer() $em = self::$kernel->getContainer()
->get('doctrine.orm.entity_manager'); ->get('doctrine.orm.entity_manager');
return array( return [
$em->createQueryBuilder() $em->createQueryBuilder()
->select('count(activity.id)') ->select('count(activity.id)')
->from('ChillActivityBundle:Activity', 'activity'), ->from('ChillActivityBundle:Activity', 'activity'),
@@ -86,8 +80,7 @@ class ActivityReasonAggregatorTest extends AbstractAggregatorTest
->select('count(activity.id)') ->select('count(activity.id)')
->from('ChillActivityBundle:Activity', 'activity') ->from('ChillActivityBundle:Activity', 'activity')
->join('activity.reasons', 'reasons') ->join('activity.reasons', 'reasons')
->join('reasons.category', 'category') ->join('reasons.category', 'category'),
); ];
} }
} }

View File

@@ -1,49 +1,43 @@
<?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, * @see https://www.champs-libres.coop/
* 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/>.
*/ */
declare(strict_types=1);
namespace Chill\ActivityBundle\Tests\Aggregator; namespace Chill\ActivityBundle\Tests\Aggregator;
use Chill\MainBundle\Test\Export\AbstractAggregatorTest; use Chill\MainBundle\Test\Export\AbstractAggregatorTest;
/** /**
* Add tests for ActivityTypeAggregator * Add tests for ActivityTypeAggregator.
* *
* @author Julien Fastré <julien.fastre@champs-libres.coop> * @internal
* @coversNothing
*/ */
class ActivityTypeAggregatorTest extends AbstractAggregatorTest final class ActivityTypeAggregatorTest extends AbstractAggregatorTest
{ {
/** /**
*
* @var \Chill\ActivityBundle\Export\Aggregator\ActivityReasonAggregator * @var \Chill\ActivityBundle\Export\Aggregator\ActivityReasonAggregator
*/ */
private $aggregator; private $aggregator;
public function setUp() protected function setUp()
{ {
static::bootKernel(); self::bootKernel();
$container = static::$kernel->getContainer(); $container = self::$kernel->getContainer();
$this->aggregator = $container->get('chill.activity.export.type_aggregator'); $this->aggregator = $container->get('chill.activity.export.type_aggregator');
// add a fake request with a default locale (used in translatable string) // add a fake request with a default locale (used in translatable string)
$prophet = new \Prophecy\Prophet; $prophet = new \Prophecy\Prophet();
$request = $prophet->prophesize(); $request = $prophet->prophesize();
$request->willExtend(\Symfony\Component\HttpFoundation\Request::class); $request->willExtend(\Symfony\Component\HttpFoundation\Request::class);
$request->getLocale()->willReturn('fr'); $request->getLocale()->willReturn('fr');
@@ -59,21 +53,21 @@ class ActivityTypeAggregatorTest extends AbstractAggregatorTest
public function getFormData() public function getFormData()
{ {
return array( return [
array() [],
); ];
} }
public function getQueryBuilders() public function getQueryBuilders()
{ {
if (static::$kernel === null) { if (null === self::$kernel) {
static::bootKernel(); self::bootKernel();
} }
$em = static::$kernel->getContainer() $em = self::$kernel->getContainer()
->get('doctrine.orm.entity_manager'); ->get('doctrine.orm.entity_manager');
return array( return [
$em->createQueryBuilder() $em->createQueryBuilder()
->select('count(activity.id)') ->select('count(activity.id)')
->from('ChillActivityBundle:Activity', 'activity'), ->from('ChillActivityBundle:Activity', 'activity'),
@@ -85,8 +79,7 @@ class ActivityTypeAggregatorTest extends AbstractAggregatorTest
->select('count(activity.id)') ->select('count(activity.id)')
->from('ChillActivityBundle:Activity', 'activity') ->from('ChillActivityBundle:Activity', 'activity')
->join('activity.reasons', 'reasons') ->join('activity.reasons', 'reasons')
->join('reasons.category', 'category') ->join('reasons.category', 'category'),
); ];
} }
} }

View File

@@ -1,48 +1,43 @@
<?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, * @see https://www.champs-libres.coop/
* 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/>.
*/ */
declare(strict_types=1);
namespace Chill\ActivityBundle\Tests\Aggregator; namespace Chill\ActivityBundle\Tests\Aggregator;
use Chill\MainBundle\Test\Export\AbstractAggregatorTest; use Chill\MainBundle\Test\Export\AbstractAggregatorTest;
/** /**
* Add tests for ActivityUsernAggregator * Add tests for ActivityUsernAggregator.
* *
* @internal
* @coversNothing
*/ */
class ActivityUserAggregatorTest extends AbstractAggregatorTest final class ActivityUserAggregatorTest extends AbstractAggregatorTest
{ {
/** /**
*
* @var \Chill\ActivityBundle\Export\Aggregator\ActivityUserAggregator * @var \Chill\ActivityBundle\Export\Aggregator\ActivityUserAggregator
*/ */
private $aggregator; private $aggregator;
public function setUp() protected function setUp()
{ {
static::bootKernel(); self::bootKernel();
$container = static::$kernel->getContainer(); $container = self::$kernel->getContainer();
$this->aggregator = $container->get('chill.activity.export.user_aggregator'); $this->aggregator = $container->get('chill.activity.export.user_aggregator');
// add a fake request with a default locale (used in translatable string) // add a fake request with a default locale (used in translatable string)
$prophet = new \Prophecy\Prophet; $prophet = new \Prophecy\Prophet();
$request = $prophet->prophesize(); $request = $prophet->prophesize();
$request->willExtend(\Symfony\Component\HttpFoundation\Request::class); $request->willExtend(\Symfony\Component\HttpFoundation\Request::class);
$request->getLocale()->willReturn('fr'); $request->getLocale()->willReturn('fr');
@@ -58,21 +53,21 @@ class ActivityUserAggregatorTest extends AbstractAggregatorTest
public function getFormData() public function getFormData()
{ {
return array( return [
array() [],
); ];
} }
public function getQueryBuilders() public function getQueryBuilders()
{ {
if (static::$kernel === null) { if (null === self::$kernel) {
static::bootKernel(); self::bootKernel();
} }
$em = static::$kernel->getContainer() $em = self::$kernel->getContainer()
->get('doctrine.orm.entity_manager'); ->get('doctrine.orm.entity_manager');
return array( return [
$em->createQueryBuilder() $em->createQueryBuilder()
->select('count(activity.id)') ->select('count(activity.id)')
->from('ChillActivityBundle:Activity', 'activity'), ->from('ChillActivityBundle:Activity', 'activity'),
@@ -84,8 +79,7 @@ class ActivityUserAggregatorTest extends AbstractAggregatorTest
->select('count(activity.id)') ->select('count(activity.id)')
->from('ChillActivityBundle:Activity', 'activity') ->from('ChillActivityBundle:Activity', 'activity')
->join('activity.reasons', 'reasons') ->join('activity.reasons', 'reasons')
->join('reasons.category', 'category') ->join('reasons.category', 'category'),
); ];
} }
} }

View File

@@ -1,27 +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.
*
* @see https://www.champs-libres.coop/
*/
declare(strict_types=1);
namespace Chill\ActivityBundle\Tests\Export\Export; namespace Chill\ActivityBundle\Tests\Export\Export;
use Chill\MainBundle\Test\Export\AbstractExportTest; use Chill\MainBundle\Test\Export\AbstractExportTest;
/** /**
* * @internal
* * @coversNothing
* @author Julien Fastré <julien.fastre@champs-libres.coop>
*/ */
class CountActivityTest extends AbstractExportTest final class CountActivityTest extends AbstractExportTest
{ {
/** /**
*
* @var * @var
*/ */
private $export; private $export;
public function setUp() protected function setUp()
{ {
static::bootKernel(); self::bootKernel();
/* @var $container \Symfony\Component\DependencyInjection\ContainerInterface */ /** @var \Symfony\Component\DependencyInjection\ContainerInterface $container */
$container = self::$kernel->getContainer(); $container = self::$kernel->getContainer();
$this->export = $container->get('chill.activity.export.count_activity'); $this->export = $container->get('chill.activity.export.count_activity');
@@ -34,17 +43,16 @@ class CountActivityTest extends AbstractExportTest
public function getFormData() public function getFormData()
{ {
return array( return [
array() [],
); ];
} }
public function getModifiersCombination() public function getModifiersCombination()
{ {
return array( return [
array('activity'), ['activity'],
array('activity', 'person') ['activity', 'person'],
); ];
} }
} }

View File

@@ -1,50 +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, * @see https://www.champs-libres.coop/
* 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/>.
*/ */
declare(strict_types=1);
namespace Chill\ActivityBundle\Tests\Export\Export; namespace Chill\ActivityBundle\Tests\Export\Export;
use Chill\MainBundle\Test\Export\AbstractExportTest; use Chill\MainBundle\Test\Export\AbstractExportTest;
/** /**
* * @internal
* * @coversNothing
* @author Julien Fastré <julien.fastre@champs-libres.coop>
*/ */
class ListActivityTest extends AbstractExportTest final class ListActivityTest extends AbstractExportTest
{ {
/** /**
*
* @var \Chill\ActivityBundle\Export\Export\ListActivity * @var \Chill\ActivityBundle\Export\Export\ListActivity
*/ */
private $export; private $export;
public function setUp() protected function setUp()
{ {
static::bootKernel(); self::bootKernel();
/* @var $container \Symfony\Component\DependencyInjection\ContainerInterface */ /** @var \Symfony\Component\DependencyInjection\ContainerInterface $container */
$container = self::$kernel->getContainer(); $container = self::$kernel->getContainer();
$this->export = $container->get('chill.activity.export.list_activity'); $this->export = $container->get('chill.activity.export.list_activity');
// add a fake request with a default locale (used in translatable string) // add a fake request with a default locale (used in translatable string)
$prophet = new \Prophecy\Prophet; $prophet = new \Prophecy\Prophet();
$request = $prophet->prophesize(); $request = $prophet->prophesize();
$request->willExtend(\Symfony\Component\HttpFoundation\Request::class); $request->willExtend(\Symfony\Component\HttpFoundation\Request::class);
$request->getLocale()->willReturn('fr'); $request->getLocale()->willReturn('fr');
@@ -53,12 +45,15 @@ class ListActivityTest extends AbstractExportTest
->push($request->reveal()); ->push($request->reveal());
} }
public function getExport()
{
return $this->export;
}
public function getFormData() public function getFormData()
{ {
return array( return [
array('fields' => array( ['fields' => [
'id', 'id',
'date', 'date',
'durationTime', 'durationTime',
@@ -68,26 +63,20 @@ class ListActivityTest extends AbstractExportTest
'type_name', 'type_name',
'person_firstname', 'person_firstname',
'person_lastname', 'person_lastname',
'person_id' 'person_id',
)), ]],
array('fields' => array( ['fields' => [
'id', 'id',
'list_reasons' 'list_reasons',
)), ]],
); ];
} }
public function getModifiersCombination() public function getModifiersCombination()
{ {
return array( return [
array('activity'), ['activity'],
array('activity', 'person') ['activity', 'person'],
); ];
} }
public function getExport()
{
return $this->export;
}
} }

View File

@@ -1,27 +1,38 @@
<?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.
*
* @see https://www.champs-libres.coop/
*/
declare(strict_types=1);
namespace Chill\ActivityBundle\Tests\Export\Export; namespace Chill\ActivityBundle\Tests\Export\Export;
use Chill\MainBundle\Test\Export\AbstractExportTest; use Chill\MainBundle\Test\Export\AbstractExportTest;
/** /**
* Test the "sum" part of StatActivityDuration * Test the "sum" part of StatActivityDuration.
* *
* @author Julien Fastré <julien.fastre@champs-libres.coop> * @internal
* @coversNothing
*/ */
class StatActivityDurationSumTest extends AbstractExportTest final class StatActivityDurationSumTest extends AbstractExportTest
{ {
/** /**
*
* @var \Chill\ActivityBundle\Export\Export\StatActivityDuration * @var \Chill\ActivityBundle\Export\Export\StatActivityDuration
*/ */
private $export; private $export;
public function setUp() protected function setUp()
{ {
static::bootKernel(); self::bootKernel();
/* @var $container \Symfony\Component\DependencyInjection\ContainerInterface */ /** @var \Symfony\Component\DependencyInjection\ContainerInterface $container */
$container = self::$kernel->getContainer(); $container = self::$kernel->getContainer();
$this->export = $container->get('chill.activity.export.sum_activity_duration'); $this->export = $container->get('chill.activity.export.sum_activity_duration');
@@ -34,17 +45,16 @@ class StatActivityDurationSumTest extends AbstractExportTest
public function getFormData() public function getFormData()
{ {
return array( return [
array() [],
); ];
} }
public function getModifiersCombination() public function getModifiersCombination()
{ {
return array( return [
array('activity'), ['activity'],
array('activity', 'person') ['activity', 'person'],
); ];
} }
} }

View File

@@ -1,50 +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, * @see https://www.champs-libres.coop/
* 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/>.
*/ */
declare(strict_types=1);
namespace Chill\ActivityBundle\Tests\Filter; namespace Chill\ActivityBundle\Tests\Filter;
use Chill\MainBundle\Test\Export\AbstractFilterTest; use Chill\MainBundle\Test\Export\AbstractFilterTest;
use Doctrine\Common\Collections\ArrayCollection; use Doctrine\Common\Collections\ArrayCollection;
/** /**
* * @internal
* * @coversNothing
* @author Julien Fastré <julien.fastre@champs-libres.coop>
*/ */
class ActivityReasonFilterTest extends AbstractFilterTest final class ActivityReasonFilterTest extends AbstractFilterTest
{ {
/** /**
*
* @var \Chill\PersonBundle\Export\Filter\GenderFilter * @var \Chill\PersonBundle\Export\Filter\GenderFilter
*/ */
private $filter; private $filter;
public function setUp() protected function setUp()
{ {
static::bootKernel(); self::bootKernel();
$container = static::$kernel->getContainer(); $container = self::$kernel->getContainer();
$this->filter = $container->get('chill.activity.export.reason_filter'); $this->filter = $container->get('chill.activity.export.reason_filter');
// add a fake request with a default locale (used in translatable string) // add a fake request with a default locale (used in translatable string)
$prophet = new \Prophecy\Prophet; $prophet = new \Prophecy\Prophet();
$request = $prophet->prophesize(); $request = $prophet->prophesize();
$request->willExtend(\Symfony\Component\HttpFoundation\Request::class); $request->willExtend(\Symfony\Component\HttpFoundation\Request::class);
$request->getLocale()->willReturn('fr'); $request->getLocale()->willReturn('fr');
@@ -53,7 +45,6 @@ class ActivityReasonFilterTest extends AbstractFilterTest
->push($request->reveal()); ->push($request->reveal());
} }
public function getFilter() public function getFilter()
{ {
return $this->filter; return $this->filter;
@@ -61,21 +52,20 @@ class ActivityReasonFilterTest extends AbstractFilterTest
public function getFormData() public function getFormData()
{ {
if (static::$kernel === null) { if (null === self::$kernel) {
static::bootKernel(); self::bootKernel();
} }
$em = static::$kernel->getContainer() $em = self::$kernel->getContainer()
->get('doctrine.orm.entity_manager') ->get('doctrine.orm.entity_manager');
;
$reasons = $em->createQuery("SELECT reason " $reasons = $em->createQuery('SELECT reason '
. "FROM ChillActivityBundle:ActivityReason reason") . 'FROM ChillActivityBundle:ActivityReason reason')
->getResult(); ->getResult();
// generate an array of 5 different combination of results // generate an array of 5 different combination of results
for ($i=0; $i < 5; $i++) { for ($i = 0; 5 > $i; ++$i) {
$r[] = array('reasons' => new ArrayCollection(array_splice($reasons, ($i + 1) * -1))); $r[] = ['reasons' => new ArrayCollection(array_splice($reasons, ($i + 1) * -1))];
} }
return $r; return $r;
@@ -83,14 +73,14 @@ class ActivityReasonFilterTest extends AbstractFilterTest
public function getQueryBuilders() public function getQueryBuilders()
{ {
if (static::$kernel === null) { if (null === self::$kernel) {
static::bootKernel(); self::bootKernel();
} }
$em = static::$kernel->getContainer() $em = self::$kernel->getContainer()
->get('doctrine.orm.entity_manager'); ->get('doctrine.orm.entity_manager');
return array( return [
$em->createQueryBuilder() $em->createQueryBuilder()
->select('count(activity.id)') ->select('count(activity.id)')
->from('ChillActivityBundle:Activity', 'activity'), ->from('ChillActivityBundle:Activity', 'activity'),
@@ -102,8 +92,7 @@ class ActivityReasonFilterTest extends AbstractFilterTest
->select('count(activity.id)') ->select('count(activity.id)')
->from('ChillActivityBundle:Activity', 'activity') ->from('ChillActivityBundle:Activity', 'activity')
->join('activity.reasons', 'reasons') ->join('activity.reasons', 'reasons')
->join('reasons.category', 'category') ->join('reasons.category', 'category'),
); ];
} }
} }

View File

@@ -1,48 +1,44 @@
<?php <?php
/*
* Copyright (C) 2017 Champs Libres Cooperative <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, * @see https://www.champs-libres.coop/
* 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/>.
*/ */
declare(strict_types=1);
namespace Chill\ActivityBundle\Tests\Filter; namespace Chill\ActivityBundle\Tests\Filter;
use Chill\MainBundle\Test\Export\AbstractFilterTest; use Chill\MainBundle\Test\Export\AbstractFilterTest;
use DateTime;
use function array_slice;
/** /**
* * @internal
* * @coversNothing
* @author Julien Fastré <julien.fastre@champs-libres.coop>
*/ */
class PersonHavingActivityBetweenDateFilterTest extends AbstractFilterTest final class PersonHavingActivityBetweenDateFilterTest extends AbstractFilterTest
{ {
/** /**
*
* @var \Chill\PersonBundle\Export\Filter\PersonHavingActivityBetweenDateFilter * @var \Chill\PersonBundle\Export\Filter\PersonHavingActivityBetweenDateFilter
*/ */
private $filter; private $filter;
public function setUp() protected function setUp()
{ {
static::bootKernel(); self::bootKernel();
$container = static::$kernel->getContainer(); $container = self::$kernel->getContainer();
$this->filter = $container->get('chill.activity.export.' $this->filter = $container->get('chill.activity.export.'
. 'person_having_an_activity_between_date_filter'); . 'person_having_an_activity_between_date_filter');
// add a fake request with a default locale (used in translatable string) // add a fake request with a default locale (used in translatable string)
$prophet = new \Prophecy\Prophet; $prophet = new \Prophecy\Prophet();
$request = $prophet->prophesize(); $request = $prophet->prophesize();
$request->willExtend(\Symfony\Component\HttpFoundation\Request::class); $request->willExtend(\Symfony\Component\HttpFoundation\Request::class);
$request->getLocale()->willReturn('fr'); $request->getLocale()->willReturn('fr');
@@ -58,49 +54,33 @@ class PersonHavingActivityBetweenDateFilterTest extends AbstractFilterTest
public function getFormData() public function getFormData()
{ {
$date_from = \DateTime::createFromFormat('Y-m-d', '2015-01-15'); $date_from = DateTime::createFromFormat('Y-m-d', '2015-01-15');
$date_to = new \DateTime(); // today $date_to = new DateTime(); // today
$reasons = $this->getActivityReasons(); $reasons = $this->getActivityReasons();
$data = [];
$data = array(); for ($i = 0; 4 > $i; ++$i) {
for ($i = 0; $i < 4; $i++) { $data[] = [
$data[] = array(
'date_from' => $date_from, 'date_from' => $date_from,
'date_to' => $date_to, 'date_to' => $date_to,
'reasons' => array_slice($reasons, 0, 1 + $i) 'reasons' => array_slice($reasons, 0, 1 + $i),
); ];
} }
return $data; return $data;
} }
/**
* Return all activity reasons
*
* @return \Chill\ActivityBundle\Entity\ActivityReason[]
*/
private function getActivityReasons()
{
if (static::$kernel === null) {
static::bootKernel();
}
return static::$kernel->getContainer()
->get('chill_activity.repository.reason')
->findAll();
}
public function getQueryBuilders() public function getQueryBuilders()
{ {
if (static::$kernel === null) { if (null === self::$kernel) {
static::bootKernel(); self::bootKernel();
} }
$em = static::$kernel->getContainer() $em = self::$kernel->getContainer()
->get('doctrine.orm.entity_manager'); ->get('doctrine.orm.entity_manager');
return array( return [
$em->createQueryBuilder() $em->createQueryBuilder()
->select('count(person.id)') ->select('count(person.id)')
->from('ChillPersonBundle:Person', 'person') ->from('ChillPersonBundle:Person', 'person')
@@ -112,6 +92,22 @@ class PersonHavingActivityBetweenDateFilterTest extends AbstractFilterTest
->join('activity.person', 'person') ->join('activity.person', 'person')
// add a fake where clause // add a fake where clause
->where('person.id > 0'), ->where('person.id > 0'),
); ];
}
/**
* Return all activity reasons.
*
* @return \Chill\ActivityBundle\Entity\ActivityReason[]
*/
private function getActivityReasons()
{
if (null === self::$kernel) {
self::bootKernel();
}
return self::$kernel->getContainer()
->get('chill_activity.repository.reason')
->findAll();
} }
} }

View File

@@ -1,77 +1,66 @@
<?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, * @see https://www.champs-libres.coop/
* 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/>.
*/ */
declare(strict_types=1);
namespace Chill\ActivityBundle\Tests\Form; namespace Chill\ActivityBundle\Tests\Form;
use Symfony\Bundle\FrameworkBundle\Test\KernelTestCase;
use Chill\ActivityBundle\Form\ActivityType;
use Chill\ActivityBundle\Entity\Activity; use Chill\ActivityBundle\Entity\Activity;
use Chill\ActivityBundle\Form\ActivityType;
use DateTime;
use Symfony\Bundle\FrameworkBundle\Test\KernelTestCase;
use Symfony\Component\Form\Extension\Core\Type\FormType;
use Symfony\Component\Security\Core\Authentication\Token\AbstractToken; use Symfony\Component\Security\Core\Authentication\Token\AbstractToken;
use Symfony\Component\Security\Core\Role\Role; use Symfony\Component\Security\Core\Role\Role;
use Symfony\Component\Form\Extension\Core\Type\FormType;
/** /**
* * @internal
* * @coversNothing
* @author Julien Fastré <julien.fastre@champs-libres.coop>
*/ */
class ActivityTypeTest extends KernelTestCase final class ActivityTypeTest extends KernelTestCase
{ {
/** /**
* * @var \Chill\MainBundle\Entity\Center
* @var \Symfony\Component\Form\FormBuilderInterface
*/ */
protected $formBuilder; protected $center;
/** /**
*
* @var \Symfony\Component\DependencyInjection\ContainerInterface * @var \Symfony\Component\DependencyInjection\ContainerInterface
*/ */
protected $container; protected $container;
/** /**
* * @var \Symfony\Component\Form\FormBuilderInterface
*/
protected $formBuilder;
/**
* @var \Symfony\Component\Security\Core\User\UserInterface * @var \Symfony\Component\Security\Core\User\UserInterface
*/ */
protected $user; protected $user;
/** protected function setUp()
*
* @var \Chill\MainBundle\Entity\Center
*/
protected $center;
public function setUp()
{ {
self::bootKernel(); self::bootKernel();
$this->container = self::$kernel->getContainer(); $this->container = self::$kernel->getContainer();
$prophet = new \Prophecy\Prophet; $prophet = new \Prophecy\Prophet();
$this->formBuilder = $this->container $this->formBuilder = $this->container
->get('form.factory') ->get('form.factory')
->createBuilder(FormType::class, null, array( ->createBuilder(FormType::class, null, [
'csrf_protection' => false, 'csrf_protection' => false,
'csrf_field_name' => '_token' 'csrf_field_name' => '_token',
)); ]);
$request = new \Symfony\Component\HttpFoundation\Request(); $request = new \Symfony\Component\HttpFoundation\Request();
$request->setLocale('fr'); $request->setLocale('fr');
@@ -82,124 +71,129 @@ class ActivityTypeTest extends KernelTestCase
$this->user = $this->container->get('doctrine.orm.entity_manager') $this->user = $this->container->get('doctrine.orm.entity_manager')
->getRepository('ChillMainBundle:User') ->getRepository('ChillMainBundle:User')
->findOneBy(array('username' => 'center a_social')); ->findOneBy(['username' => 'center a_social']);
$this->center = $this->container->get('doctrine.orm.entity_manager') $this->center = $this->container->get('doctrine.orm.entity_manager')
->getRepository('ChillMainBundle:Center') ->getRepository('ChillMainBundle:Center')
->findOneBy(array('name' => 'Center A')); ->findOneBy(['name' => 'Center A']);
$token = $prophet->prophesize(); $token = $prophet->prophesize();
$token->willExtend(AbstractToken::class); $token->willExtend(AbstractToken::class);
$token->getUser()->willReturn($this->user); $token->getUser()->willReturn($this->user);
$this->container->get('security.token_storage') $this->container->get('security.token_storage')
->setToken($token->reveal()); ->setToken($token->reveal());
} }
public function testForm() public function testForm()
{ {
$form = $this->formBuilder $form = $this->formBuilder
->add('activity', ActivityType::class, array( ->add('activity', ActivityType::class, [
'center' => $this->center, 'center' => $this->center,
'role' => new Role('CHILL_ACTIVITY_CREATE') 'role' => new Role('CHILL_ACTIVITY_CREATE'),
)) ])
->getForm(); ->getForm();
$form->submit(array()); $form->submit([]);
$this->assertTrue($form->isSynchronized());
$this->assertTrue($form->isValid());
$this->assertInstanceOf(Activity::class, $form->getData()['activity']);
self::assertTrue($form->isSynchronized());
self::assertTrue($form->isValid());
self::assertInstanceOf(Activity::class, $form->getData()['activity']);
} }
public function testFormSubmitting() public function testFormSubmitting()
{ {
$form = $this->formBuilder $form = $this->formBuilder
->add('activity', ActivityType::class, array( ->add('activity', ActivityType::class, [
'center' => $this->center, 'center' => $this->center,
'role' => new Role('CHILL_ACTIVITY_CREATE') 'role' => new Role('CHILL_ACTIVITY_CREATE'),
)) ])
->getForm(); ->getForm();
$form->submit(array( 'activity' => array( $form->submit(['activity' => [
'date' => '9-3-2015', 'date' => '9-3-2015',
'durationTime' => 300, 'durationTime' => 300,
// 'remark' => 'blabla', // 'remark' => 'blabla',
'attendee' => true 'attendee' => true,
))); ]]);
// var_dump($form->getErrors()->count()); var_dump($form->isValid()); // var_dump($form->getErrors()->count()); var_dump($form->isValid());
// foreach($form->getErrors() as $e) { fwrite(STDOUT, var_dump($e->getMessage())); } // foreach($form->getErrors() as $e) { fwrite(STDOUT, var_dump($e->getMessage())); }
// var_dump($form->getErrors()); // var_dump($form->getErrors());
$this->assertTrue($form->isSynchronized(), "Test the form is synchronized"); self::assertTrue($form->isSynchronized(), 'Test the form is synchronized');
$this->assertTrue($form->isValid(), "test the form is valid"); self::assertTrue($form->isValid(), 'test the form is valid');
$this->assertInstanceOf(Activity::class, $form->getData()['activity']); self::assertInstanceOf(Activity::class, $form->getData()['activity']);
// test the activity // test the activity
/* @var $activity Activity */ /** @var Activity $activity */
$activity = $form->getData()['activity']; $activity = $form->getData()['activity'];
$this->assertEquals('09-03-2015', $activity->getDate()->format('d-m-Y'), self::assertEquals(
"Test the date is correct"); '09-03-2015',
$this->assertEquals('00:05', $activity->getDurationTime()->format('H:i'), $activity->getDate()->format('d-m-Y'),
"Test the formatted hour is correct"); 'Test the date is correct'
$this->assertEquals(true, $activity->getAttendee()); );
self::assertEquals(
'00:05',
$activity->getDurationTime()->format('H:i'),
'Test the formatted hour is correct'
);
self::assertTrue($activity->getAttendee());
// $this->assertEquals('blabla', $activity->getRemark()); // $this->assertEquals('blabla', $activity->getRemark());
} }
/** /**
* Test that the form correctly build even with a durationTime which is not in * Test that the form correctly build even with a durationTime which is not in
* the listed in the possible durationTime * the listed in the possible durationTime.
*/ */
public function testFormWithActivityHavingDifferentTime() public function testFormWithActivityHavingDifferentTime()
{ {
$activity = new Activity(); $activity = new Activity();
$activity->setDurationTime(\DateTime::createFromFormat('U', 60)); $activity->setDurationTime(DateTime::createFromFormat('U', 60));
$builder = $this->container $builder = $this->container
->get('form.factory') ->get('form.factory')
->createBuilder(FormType::class, array('activity' => $activity), array( ->createBuilder(FormType::class, ['activity' => $activity], [
'csrf_protection' => false, 'csrf_protection' => false,
'csrf_field_name' => '_token' 'csrf_field_name' => '_token',
)); ]);
$form = $builder $form = $builder
->add('activity', ActivityType::class, array( ->add('activity', ActivityType::class, [
'center' => $this->center, 'center' => $this->center,
'role' => new Role('CHILL_ACTIVITY_CREATE') 'role' => new Role('CHILL_ACTIVITY_CREATE'),
)) ])
->getForm(); ->getForm();
$form->submit(['activity' => [
$form->submit(array( 'activity' => array(
'date' => '9-3-2015', 'date' => '9-3-2015',
'durationTime' => 60, 'durationTime' => 60,
// 'remark' => 'blabla', // 'remark' => 'blabla',
'attendee' => true 'attendee' => true,
))); ]]);
$this->assertTrue($form->isSynchronized()); self::assertTrue($form->isSynchronized());
$this->assertTrue($form->isValid()); self::assertTrue($form->isValid());
// test the activity // test the activity
/* @var $activity Activity */ /** @var Activity $activity */
$activity = $form->getData()['activity']; $activity = $form->getData()['activity'];
$this->assertEquals('00:01', $activity->getDurationTime()->format('H:i'), self::assertEquals(
"Test the formatted hour is correct"); '00:01',
$activity->getDurationTime()->format('H:i'),
'Test the formatted hour is correct'
);
// test the view : we want to be sure that the entry with 60 seconds exists // test the view : we want to be sure that the entry with 60 seconds exists
$view = $form->createView(); $view = $form->createView();
$this->assertTrue(isset($view['activity']['durationTime'])); self::assertTrue(isset($view['activity']['durationTime']));
// map all the values in an array // map all the values in an array
$values = array_map(function($choice) { return $choice->value; }, $values = array_map(
$view['activity']['durationTime']->vars['choices']); static function ($choice) { return $choice->value; },
$view['activity']['durationTime']->vars['choices']
$this->assertContains(60, $values); );
self::assertContains(60, $values);
} }
} }

View File

@@ -1,102 +1,51 @@
<?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, * @see https://www.champs-libres.coop/
* 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/>.
*/ */
declare(strict_types=1);
namespace Chill\ActivityBundle\Tests\Form\Type; namespace Chill\ActivityBundle\Tests\Form\Type;
use Symfony\Component\Form\Test\TypeTestCase;
use Chill\ActivityBundle\Form\Type\TranslatableActivityReason; use Chill\ActivityBundle\Form\Type\TranslatableActivityReason;
use Chill\MainBundle\Templating\TranslatableStringHelper; use Chill\MainBundle\Templating\TranslatableStringHelper;
use Symfony\Component\Form\PreloadedExtension; use Symfony\Component\Form\PreloadedExtension;
use Symfony\Component\Form\Test\TypeTestCase;
/** /**
* Test translatableActivityReason * Test translatableActivityReason.
* *
* @author Julien Fastré <julien.fastre@champs-libres.coop> * @internal
* @author Champs Libres <info@champs-libres.coop> * @coversNothing
*/ */
class TranslatableActivityReasonTest extends TypeTestCase final class TranslatableActivityReasonTest extends TypeTestCase
{ {
/** /**
*
* @var Prophecy\Prophet * @var Prophecy\Prophet
*/ */
private static $prophet; private static $prophet;
public function setUp() protected function setUp()
{ {
parent::setUp(); parent::setUp();
} }
protected function getExtensions()
{
$entityType = $this->getEntityType();
return array(new PreloadedExtension(array(
'entity' => $entityType
), array()));
}
public function testSimple() public function testSimple()
{ {
$translatableActivityReasonType = new TranslatableActivityReason( $translatableActivityReasonType = new TranslatableActivityReason(
$this->getTranslatableStringHelper() $this->getTranslatableStringHelper()
); );
$this->markTestSkipped("See issue 651"); self::markTestSkipped('See issue 651');
} }
/** /**
*
* @param string $locale
* @param string $fallbackLocale
* @return TranslatableStringHelper
*/
protected function getTranslatableStringHelper($locale = 'en',
$fallbackLocale = 'en')
{
$prophet = new \Prophecy\Prophet;
$requestStack = $prophet->prophesize();
$request = $prophet->prophesize();
$translator = $prophet->prophesize();
$request->willExtend('Symfony\Component\HttpFoundation\Request');
$request->getLocale()->willReturn($fallbackLocale);
$requestStack->willExtend('Symfony\Component\HttpFoundation\RequestStack');
$requestStack->getCurrentRequest()->will(function () use ($request) {
return $request;
});
$translator->willExtend('Symfony\Component\Translation\Translator');
$translator->getFallbackLocales()->willReturn($locale);
return new TranslatableStringHelper($requestStack->reveal(),
$translator->reveal());
}
/**
*
* @return \Symfony\Bridge\Doctrine\Form\Type\EntityType * @return \Symfony\Bridge\Doctrine\Form\Type\EntityType
*/ */
protected function getEntityType() protected function getEntityType()
@@ -107,4 +56,45 @@ class TranslatableActivityReasonTest extends TypeTestCase
return new \Symfony\Bridge\Doctrine\Form\Type\EntityType($managerRegistry->reveal()); return new \Symfony\Bridge\Doctrine\Form\Type\EntityType($managerRegistry->reveal());
} }
protected function getExtensions()
{
$entityType = $this->getEntityType();
return [new PreloadedExtension([
'entity' => $entityType,
], [])];
}
/**
* @param string $locale
* @param string $fallbackLocale
*
* @return TranslatableStringHelper
*/
protected function getTranslatableStringHelper(
$locale = 'en',
$fallbackLocale = 'en'
) {
$prophet = new \Prophecy\Prophet();
$requestStack = $prophet->prophesize();
$request = $prophet->prophesize();
$translator = $prophet->prophesize();
$request->willExtend('Symfony\Component\HttpFoundation\Request');
$request->getLocale()->willReturn($fallbackLocale);
$requestStack->willExtend('Symfony\Component\HttpFoundation\RequestStack');
$requestStack->getCurrentRequest()->will(static function () use ($request) {
return $request;
});
$translator->willExtend('Symfony\Component\Translation\Translator');
$translator->getFallbackLocales()->willReturn($locale);
return new TranslatableStringHelper(
$requestStack->reveal(),
$translator->reveal()
);
}
} }

View File

@@ -1,49 +1,39 @@
<?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, * @see https://www.champs-libres.coop/
* 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/>.
*/ */
declare(strict_types=1);
namespace Chill\ActivityBundle\Tests\Form\Type; namespace Chill\ActivityBundle\Tests\Form\Type;
use Symfony\Bundle\FrameworkBundle\Test\KernelTestCase;
use Chill\ActivityBundle\Form\Type\TranslatableActivityType; use Chill\ActivityBundle\Form\Type\TranslatableActivityType;
use Symfony\Bundle\FrameworkBundle\Test\KernelTestCase;
use Symfony\Component\Form\Extension\Core\Type\FormType; use Symfony\Component\Form\Extension\Core\Type\FormType;
/** /**
* * @internal
* * @coversNothing
* @author Julien Fastré <julien.fastre@champs-libres.coop>
*/ */
class TranslatableActivityTypeTest extends KernelTestCase final class TranslatableActivityTypeTest extends KernelTestCase
{ {
/** /**
*
* @var \Symfony\Component\Form\FormBuilderInterface * @var \Symfony\Component\Form\FormBuilderInterface
*/ */
protected $builder; protected $builder;
/** /**
*
* @var \Symfony\Component\DependencyInjection\ContainerInterface * @var \Symfony\Component\DependencyInjection\ContainerInterface
*/ */
protected $container; protected $container;
public function setUp() protected function setUp()
{ {
self::bootKernel(); self::bootKernel();
@@ -51,10 +41,10 @@ class TranslatableActivityTypeTest extends KernelTestCase
$this->builder = $this->container $this->builder = $this->container
->get('form.factory') ->get('form.factory')
->createBuilder(FormType::class, null, array( ->createBuilder(FormType::class, null, [
'csrf_protection' => false, 'csrf_protection' => false,
'csrf_field_name' => '_token' 'csrf_field_name' => '_token',
)); ]);
$request = new \Symfony\Component\HttpFoundation\Request(); $request = new \Symfony\Component\HttpFoundation\Request();
$request->setLocale('fr'); $request->setLocale('fr');
@@ -63,34 +53,23 @@ class TranslatableActivityTypeTest extends KernelTestCase
->push($request); ->push($request);
} }
/**
*
* @return \Chill\ActivityBundle\Entity\ActivityType
*/
protected function getRandomType($active = true)
{
$types = $this->container->get('doctrine.orm.entity_manager')
->getRepository('ChillActivityBundle:ActivityType')
->findBy(array('active' => $active));
return $types[array_rand($types)];
}
public function testForm() public function testForm()
{ {
$type = $this->getRandomType(); $type = $this->getRandomType();
$form = $this->builder->add('type', TranslatableActivityType::class) $form = $this->builder->add('type', TranslatableActivityType::class)
->getForm(); ->getForm();
$form->submit(array( $form->submit([
'type' => $type->getId() 'type' => $type->getId(),
)); ]);
$this->assertTrue($form->isSynchronized()); self::assertTrue($form->isSynchronized());
$this->assertInstanceOf(\Chill\ActivityBundle\Entity\ActivityType::class, self::assertInstanceOf(
\Chill\ActivityBundle\Entity\ActivityType::class,
$form->getData()['type'], $form->getData()['type'],
"The data is an instance of Chill\ActivityBundle\Entity\ActivityType"); 'The data is an instance of Chill\\ActivityBundle\\Entity\\ActivityType'
$this->assertEquals($type->getId(), $form->getData()['type']->getId()); );
self::assertEquals($type->getId(), $form->getData()['type']->getId());
// test the ordering of the types in the form // test the ordering of the types in the form
// since 2016-11-14 the types are not alphabetically ordered, skipping // since 2016-11-14 the types are not alphabetically ordered, skipping
@@ -108,9 +87,19 @@ class TranslatableActivityTypeTest extends KernelTestCase
$previous = $choice->label; $previous = $choice->label;
} }
}*/ }*/
} }
/**
* @param mixed $active
*
* @return \Chill\ActivityBundle\Entity\ActivityType
*/
protected function getRandomType($active = true)
{
$types = $this->container->get('doctrine.orm.entity_manager')
->getRepository('ChillActivityBundle:ActivityType')
->findBy(['active' => $active]);
return $types[array_rand($types)];
}
} }

View File

@@ -1,103 +1,59 @@
<?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, * @see https://www.champs-libres.coop/
* 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/>.
*/ */
declare(strict_types=1);
namespace Chill\ActivityBundle\Tests\Security\Authorization; namespace Chill\ActivityBundle\Tests\Security\Authorization;
use Symfony\Bundle\FrameworkBundle\Test\KernelTestCase; use Chill\ActivityBundle\Test\PrepareActivityTrait;
use Symfony\Component\Security\Core\Authorization\Voter\VoterInterface;
use Chill\MainBundle\Entity\Center; use Chill\MainBundle\Entity\Center;
use Chill\MainBundle\Entity\User;
use Chill\MainBundle\Entity\Scope; use Chill\MainBundle\Entity\Scope;
use Chill\MainBundle\Test\PrepareUserTrait; use Chill\MainBundle\Entity\User;
use Chill\MainBundle\Test\PrepareCenterTrait; use Chill\MainBundle\Test\PrepareCenterTrait;
use Chill\MainBundle\Test\PrepareScopeTrait; use Chill\MainBundle\Test\PrepareScopeTrait;
use Chill\MainBundle\Test\PrepareUserTrait;
use Chill\PersonBundle\Test\PreparePersonTrait; use Chill\PersonBundle\Test\PreparePersonTrait;
use Chill\ActivityBundle\Test\PrepareActivityTrait; use Symfony\Bundle\FrameworkBundle\Test\KernelTestCase;
use Symfony\Component\Security\Core\Authorization\Voter\VoterInterface;
/** /**
* * @internal
* * @coversNothing
* @author Julien Fastré <julien.fastre@champs-libres.coop>
*/ */
class ActivityVoterTest extends KernelTestCase final class ActivityVoterTest extends KernelTestCase
{ {
use PrepareUserTrait, PrepareCenterTrait, PrepareScopeTrait, use PrepareActivityTrait;
PreparePersonTrait, PrepareActivityTrait; use PrepareCenterTrait;
use PreparePersonTrait;
use PrepareScopeTrait;
use PrepareUserTrait;
/** /**
*
* @var \Chill\PersonBundle\Security\Authorization\PersonVoter
*/
protected $voter;
/**
*
* @var \Prophecy\Prophet * @var \Prophecy\Prophet
*/ */
protected $prophet; protected $prophet;
public function setUp() /**
* @var \Chill\PersonBundle\Security\Authorization\PersonVoter
*/
protected $voter;
protected function setUp()
{ {
static::bootKernel(); self::bootKernel();
$this->voter = static::$kernel->getContainer() $this->voter = self::$kernel->getContainer()
->get('chill.activity.security.authorization.activity_voter'); ->get('chill.activity.security.authorization.activity_voter');
$this->prophet = new \Prophecy\Prophet(); $this->prophet = new \Prophecy\Prophet();
} }
public function testNullUser()
{
$token = $this->prepareToken();
$center = $this->prepareCenter(1, 'center');
$person = $this->preparePerson($center);
$scope = $this->prepareScope(1, 'default');
$activity = $this->prepareActivity($scope, $person);
$this->assertEquals(
VoterInterface::ACCESS_DENIED,
$this->voter->vote($token, $activity, array('CHILL_ACTIVITY_SEE')),
"assert that a null user is not allowed to see"
);
}
/**
*
* @dataProvider dataProvider_testVoteAction
* @param type $expectedResult
* @param User $user
* @param Scope $scope
* @param Center $center
* @param string $attribute
* @param string $message
*/
public function testVoteAction($expectedResult, User $user, Scope $scope,
Center $center, $attribute, $message)
{
$token = $this->prepareToken($user);
$activity = $this->prepareActivity($scope, $this->preparePerson($center));
$this->assertEquals(
$expectedResult,
$this->voter->vote($token, $activity, array($attribute)),
$message
);
}
public function dataProvider_testVoteAction() public function dataProvider_testVoteAction()
{ {
$centerA = $this->prepareCenter(1, 'center A'); $centerA = $this->prepareCenter(1, 'center A');
@@ -106,66 +62,105 @@ class ActivityVoterTest extends KernelTestCase
$scopeB = $this->prepareScope(2, 'scope B'); $scopeB = $this->prepareScope(2, 'scope B');
$scopeC = $this->prepareScope(3, 'scope C'); $scopeC = $this->prepareScope(3, 'scope C');
$userA = $this->prepareUser(array( $userA = $this->prepareUser([
array( [
'center' => $centerA, 'center' => $centerA,
'permissionsGroup' => array( 'permissionsGroup' => [
['scope' => $scopeB, 'role' => 'CHILL_ACTIVITY_CREATE'], ['scope' => $scopeB, 'role' => 'CHILL_ACTIVITY_CREATE'],
['scope' => $scopeA, 'role' => 'CHILL_ACTIVITY_SEE'] ['scope' => $scopeA, 'role' => 'CHILL_ACTIVITY_SEE'],
) ],
), ],
array( [
'center' => $centerB, 'center' => $centerB,
'permissionsGroup' => array( 'permissionsGroup' => [
['scope' => $scopeA, 'role' => 'CHILL_ACTIVITY_CREATE'], ['scope' => $scopeA, 'role' => 'CHILL_ACTIVITY_CREATE'],
['scope' => $scopeC, 'role' => 'CHILL_ACTIVITY_CREATE'] ['scope' => $scopeC, 'role' => 'CHILL_ACTIVITY_CREATE'],
) ],
) ],
]);
)); return [
[
return array(
array(
VoterInterface::ACCESS_GRANTED, VoterInterface::ACCESS_GRANTED,
$userA, $userA,
$scopeB, $scopeB,
$centerA, $centerA,
'CHILL_ACTIVITY_CREATE', 'CHILL_ACTIVITY_CREATE',
'assert that a user granted with same rights' 'assert that a user granted with same rights',
), ],
array( [
VoterInterface::ACCESS_GRANTED, VoterInterface::ACCESS_GRANTED,
$userA, $userA,
$scopeB, $scopeB,
$centerA, $centerA,
'CHILL_ACTIVITY_SEE', 'CHILL_ACTIVITY_SEE',
'assert that a user granted with inheritance rights' 'assert that a user granted with inheritance rights',
), ],
array( [
VoterInterface::ACCESS_DENIED, VoterInterface::ACCESS_DENIED,
$userA, $userA,
$scopeC, $scopeC,
$centerA, $centerA,
'CHILL_ACTIVITY_SEE', 'CHILL_ACTIVITY_SEE',
'assert that a suer is denied if he is not granted right on this center' 'assert that a suer is denied if he is not granted right on this center',
],
];
}
) public function testNullUser()
{
$token = $this->prepareToken();
$center = $this->prepareCenter(1, 'center');
$person = $this->preparePerson($center);
$scope = $this->prepareScope(1, 'default');
$activity = $this->prepareActivity($scope, $person);
self::assertEquals(
VoterInterface::ACCESS_DENIED,
$this->voter->vote($token, $activity, ['CHILL_ACTIVITY_SEE']),
'assert that a null user is not allowed to see'
); );
} }
/** /**
* prepare a token interface with correct rights * @dataProvider dataProvider_testVoteAction
*
* @param type $expectedResult
* @param string $attribute
* @param string $message
*/
public function testVoteAction(
$expectedResult,
User $user,
Scope $scope,
Center $center,
$attribute,
$message
) {
$token = $this->prepareToken($user);
$activity = $this->prepareActivity($scope, $this->preparePerson($center));
self::assertEquals(
$expectedResult,
$this->voter->vote($token, $activity, [$attribute]),
$message
);
}
/**
* prepare a token interface with correct rights.
* *
* if $permissions = null, user will be null (no user associated with token * if $permissions = null, user will be null (no user associated with token
* *
* @return \Symfony\Component\Security\Core\Authentication\Token\TokenInterface * @return \Symfony\Component\Security\Core\Authentication\Token\TokenInterface
*/ */
protected function prepareToken(User $user = null) protected function prepareToken(?User $user = null)
{ {
$token = $this->prophet->prophesize(); $token = $this->prophet->prophesize();
$token $token
->willImplement('\Symfony\Component\Security\Core\Authentication\Token\TokenInterface'); ->willImplement('\Symfony\Component\Security\Core\Authentication\Token\TokenInterface');
if ($user === NULL) {
if (null === $user) {
$token->getUser()->willReturn(null); $token->getUser()->willReturn(null);
} else { } else {
$token->getUser()->willReturn($user); $token->getUser()->willReturn($user);

View File

@@ -1,36 +1,28 @@
<?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, * @see https://www.champs-libres.coop/
* 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/>.
*/ */
declare(strict_types=1);
namespace Chill\ActivityBundle\Tests\Timeline; namespace Chill\ActivityBundle\Tests\Timeline;
use Symfony\Bundle\FrameworkBundle\Test\WebTestCase; use Symfony\Bundle\FrameworkBundle\Test\WebTestCase;
/** /**
* * @internal
* * @coversNothing
* @author Julien Fastré <julien.fastre@champs-libres.coop>
*/ */
class TimelineProviderTest extends WebTestCase final class TimelineProviderTest extends WebTestCase
{ {
public function testAnActivityIsShownOnTimeline() public function testAnActivityIsShownOnTimeline()
{ {
$this->markTestSkipped("we have to write fixtures before writing this tests"); self::markTestSkipped('we have to write fixtures before writing this tests');
} }
} }

View File

@@ -1,182 +1,104 @@
<?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, * @see https://www.champs-libres.coop/
* 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/>.
*/ */
declare(strict_types=1);
namespace Chill\ActivityBundle\Timeline; namespace Chill\ActivityBundle\Timeline;
use Chill\MainBundle\Timeline\TimelineProviderInterface; use Chill\MainBundle\Entity\Scope;
use Chill\ActivityBundle\Repository\ActivityACLAwareRepository;
use Doctrine\ORM\EntityManager;
use Chill\MainBundle\Security\Authorization\AuthorizationHelper; use Chill\MainBundle\Security\Authorization\AuthorizationHelper;
use Chill\MainBundle\Timeline\TimelineProviderInterface;
use Chill\PersonBundle\Entity\Person;
use Doctrine\ORM\EntityManager;
use Doctrine\ORM\Mapping\ClassMetadata;
use LogicException;
use RuntimeException;
use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface; use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface;
use Symfony\Component\Security\Core\Role\Role; use Symfony\Component\Security\Core\Role\Role;
use Doctrine\ORM\Mapping\ClassMetadata;
use Chill\PersonBundle\Entity\Person; use function count;
use Chill\MainBundle\Entity\Scope;
use Chill\ActivityBundle\Entity\Activity;
use Chill\MainBundle\Timeline\TimelineSingleQuery;
/** /**
* Provide activity for inclusion in timeline * Provide activity for inclusion in timeline.
*
*/ */
class TimelineActivityProvider implements TimelineProviderInterface class TimelineActivityProvider implements TimelineProviderInterface
{ {
/** /**
*
* @var EntityManager * @var EntityManager
*/ */
protected $em; protected $em;
/** /**
*
* @var AuthorizationHelper * @var AuthorizationHelper
*/ */
protected $helper; protected $helper;
/** /**
*
* @var \Chill\MainBundle\Entity\User * @var \Chill\MainBundle\Entity\User
*/ */
protected $user; protected $user;
protected ActivityACLAwareRepository $aclAwareRepository;
private const SUPPORTED_CONTEXTS = [ 'center', 'person'];
/** /**
* TimelineActivityProvider constructor. * TimelineActivityProvider constructor.
*
* @param EntityManager $em
* @param AuthorizationHelper $helper
* @param TokenStorageInterface $storage
*/ */
public function __construct( public function __construct(
EntityManager $em, EntityManager $em,
AuthorizationHelper $helper, AuthorizationHelper $helper,
TokenStorageInterface $storage, TokenStorageInterface $storage
ActivityACLAwareRepository $aclAwareRepository ) {
)
{
$this->em = $em; $this->em = $em;
$this->helper = $helper; $this->helper = $helper;
$this->aclAwareRepository = $aclAwareRepository;
if (!$storage->getToken()->getUser() instanceof \Chill\MainBundle\Entity\User) if (!$storage->getToken()->getUser() instanceof \Chill\MainBundle\Entity\User) {
{ throw new RuntimeException('A user should be authenticated !');
throw new \RuntimeException('A user should be authenticated !');
} }
$this->user = $storage->getToken()->getUser(); $this->user = $storage->getToken()->getUser();
} }
/** /**
* * {@inheritdoc}
* {@inheritDoc}
*/ */
public function fetchQuery($context, array $args) public function fetchQuery($context, array $args)
{ {
if ('center' === $context) { $this->checkContext($context);
return TimelineSingleQuery::fromArray($this->aclAwareRepository
->queryTimelineIndexer($context, $args));
}
$metadataActivity = $this->em->getClassMetadata(Activity::class); $metadataActivity = $this->em->getClassMetadata('ChillActivityBundle:Activity');
$metadataPerson = $this->em->getClassMetadata('ChillPersonBundle:Person');
[$where, $parameters] = $this->getWhereClauseForPerson($args['person']); return [
return TimelineSingleQuery::fromArray([
'id' => $metadataActivity->getTableName() 'id' => $metadataActivity->getTableName()
. '.' . $metadataActivity->getColumnName('id'), . '.' . $metadataActivity->getColumnName('id'),
'type' => 'activity', 'type' => 'activity',
'date' => $metadataActivity->getTableName() 'date' => $metadataActivity->getTableName()
. '.' . $metadataActivity->getColumnName('date'), . '.' . $metadataActivity->getColumnName('date'),
'FROM' => $this->getFromClausePerson($args['person']), 'FROM' => $this->getFromClause($metadataActivity, $metadataPerson),
'WHERE' => $where, 'WHERE' => $this->getWhereClause(
'parameters' => $parameters $metadataActivity,
]); $metadataPerson,
} $args['person']
private function getWhereClauseForPerson(Person $person)
{
$parameters = [];
$metadataActivity = $this->em->getClassMetadata(Activity::class);
$associationMapping = $metadataActivity->getAssociationMapping('person');
$role = new Role('CHILL_ACTIVITY_SEE');
$reachableScopes = $this->helper->getReachableScopes($this->user,
$role, $person->getCenter());
$whereClause = sprintf(' {activity.person_id} = ? AND {activity.scope_id} IN ({scopes_ids}) ');
$scopes_ids = [];
// first parameter: activity.person_id
$parameters[] = $person->getId();
// loop on reachable scopes
foreach ($reachableScopes as $scope) {
if (\in_array($scope->getId(), $scopes_ids)) {
continue;
}
$scopes_ids[] = '?';
$parameters[] = $scope->getId();
}
return [
\strtr(
$whereClause,
[
'{activity.person_id}' => $associationMapping['joinColumns'][0]['name'],
'{activity.scope_id}' => $metadataActivity->getTableName().'.'.
$metadataActivity->getAssociationMapping('scope')['joinColumns'][0]['name'],
'{scopes_ids}' => \implode(", ", $scopes_ids)
,
]
), ),
$parameters
]; ];
} }
private function getFromClausePerson()
{
$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']
;
}
/** /**
* * {@inheritdoc}
* {@inheritDoc}
*/ */
public function getEntities(array $ids) public function getEntities(array $ids)
{ {
$activities = $this->em->getRepository(Activity::class) $activities = $this->em->getRepository('ChillActivityBundle:Activity')
->findBy(array('id' => $ids)); ->findBy(['id' => $ids]);
$result = [];
$result = array();
foreach ($activities as $activity) { foreach ($activities as $activity) {
$result[$activity->getId()] = $activity; $result[$activity->getId()] = $activity;
} }
@@ -185,8 +107,7 @@ class TimelineActivityProvider implements TimelineProviderInterface
} }
/** /**
* * {@inheritdoc}
* {@inheritDoc}
*/ */
public function getEntityTemplate($entity, $context, array $args) public function getEntityTemplate($entity, $context, array $args)
{ {
@@ -196,32 +117,100 @@ class TimelineActivityProvider implements TimelineProviderInterface
'template' => 'ChillActivityBundle:Timeline:activity_person_context.html.twig', 'template' => 'ChillActivityBundle:Timeline:activity_person_context.html.twig',
'template_data' => [ 'template_data' => [
'activity' => $entity, 'activity' => $entity,
'context' => $context 'person' => $args['person'],
] 'user' => $entity->getUser(),
],
]; ];
} }
/** /**
* * {@inheritdoc}
* {@inheritDoc}
*/ */
public function supportsType($type) public function supportsType($type)
{ {
return $type === 'activity'; return 'activity' === $type;
} }
/** /**
* check if the context is supported * check if the context is supported.
* *
* @param string $context * @param string $context
* @throws \LogicException if the context is not supported *
* @throws LogicException if the context is not supported
*/ */
private function checkContext($context) private function checkContext($context)
{ {
if (FALSE === \in_array($context, self::SUPPORTED_CONTEXTS)) { if ('person' !== $context) {
throw new \LogicException("The context '$context' is not " throw new LogicException("The context '{$context}' is not "
. "supported. Currently only 'person' is supported"); . "supported. Currently only 'person' is supported");
} }
} }
private function getFromClause(
ClassMetadata $metadataActivity,
ClassMetadata $metadataPerson
) {
$associationMapping = $metadataActivity->getAssociationMapping('person');
return $metadataActivity->getTableName() . ' JOIN '
. $metadataPerson->getTableName() . ' ON '
. $metadataPerson->getTableName() . '.' .
$associationMapping['joinColumns'][0]['referencedColumnName']
. ' = '
. $associationMapping['joinColumns'][0]['name'];
}
private function getWhereClause(
ClassMetadata $metadataActivity,
ClassMetadata $metadataPerson,
Person $person
) {
$role = new Role('CHILL_ACTIVITY_SEE');
$reachableCenters = $this->helper->getReachableCenters(
$this->user,
$role
);
$associationMapping = $metadataActivity->getAssociationMapping('person');
if (count($reachableCenters) === 0) {
return 'FALSE = TRUE';
}
// we start with activities having the person_id linked to person
// (currently only context "person" is supported)
$whereClause = sprintf(
'%s = %d',
$associationMapping['joinColumns'][0]['name'],
$person->getId()
);
// we add acl (reachable center and scopes)
$centerAndScopeLines = [];
foreach ($reachableCenters as $center) {
$reachablesScopesId = array_map(
static function (Scope $scope) {
return $scope->getId();
},
$this->helper->getReachableScopes(
$this->user,
$role,
$person->getCenter()
)
);
$centerAndScopeLines[] = sprintf(
'(%s = %d AND %s IN (%s))',
$metadataPerson->getTableName() . '.' .
$metadataPerson->getAssociationMapping('center')['joinColumns'][0]['name'],
$center->getId(),
$metadataActivity->getTableName() . '.' .
$metadataActivity->getAssociationMapping('scope')['joinColumns'][0]['name'],
implode(',', $reachablesScopesId)
);
}
$whereClause .= ' AND (' . implode(' OR ', $centerAndScopeLines) . ')';
return $whereClause;
}
} }

View File

@@ -22,14 +22,6 @@ services:
- '@doctrine.orm.entity_manager' - '@doctrine.orm.entity_manager'
- '@chill.main.security.authorization.helper' - '@chill.main.security.authorization.helper'
- '@security.token_storage' - '@security.token_storage'
- '@Chill\ActivityBundle\Repository\ActivityACLAwareRepository'
public: true public: true
tags: tags:
- { name: chill.timeline, context: 'person' } - { name: chill.timeline, context: 'person' }
- { name: chill.timeline, context: 'center' }
Chill\ActivityBundle\Menu\:
autowire: true
autoconfigure: true
resource: '../Menu/'
tags: ['chill.menu_builder']

View File

@@ -0,0 +1,8 @@
services:
Chill\ActivityBundle\Menu\MenuBuilder:
arguments:
$authorizationHelper: '@Chill\MainBundle\Security\Authorization\AuthorizationHelper'
$tokenStorage: '@Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface'
$translator: '@Symfony\Component\Translation\TranslatorInterface'
tags:
- { name: 'chill.menu_builder' }

View File

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

View File

@@ -1,42 +1,48 @@
<?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 * @see https://www.champs-libres.coop/
* 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/>.
*/ */
declare(strict_types=1);
namespace Chill\Migrations\Activity; namespace Chill\Migrations\Activity;
use Doctrine\Migrations\AbstractMigration;
use Doctrine\DBAL\Schema\Schema; use Doctrine\DBAL\Schema\Schema;
use Doctrine\Migrations\AbstractMigration;
/** /**
* Auto-generated Migration: Please modify to your needs! * Auto-generated Migration: Please modify to your needs!
*/ */
class Version20150701091248 extends AbstractMigration class Version20150701091248 extends AbstractMigration
{ {
/** public function down(Schema $schema): void
* @param Schema $schema {
*/ // this down() migration is auto-generated, please modify it to your needs
$this->abortIf($this->connection->getDatabasePlatform()->getName() !== 'postgresql', 'Migration can only be executed safely on \'postgresql\'.');
$this->addSql('ALTER TABLE Activity DROP CONSTRAINT FK_55026B0C59BB1592');
$this->addSql('ALTER TABLE ActivityReason DROP CONSTRAINT FK_654A2FCD12469DE2');
$this->addSql('ALTER TABLE Activity DROP CONSTRAINT FK_55026B0CC54C8C93');
$this->addSql('DROP SEQUENCE Activity_id_seq CASCADE');
$this->addSql('DROP SEQUENCE ActivityReason_id_seq CASCADE');
$this->addSql('DROP SEQUENCE ActivityReasonCategory_id_seq CASCADE');
$this->addSql('DROP SEQUENCE ActivityType_id_seq CASCADE');
$this->addSql('DROP TABLE Activity');
$this->addSql('DROP TABLE ActivityReason');
$this->addSql('DROP TABLE ActivityReasonCategory');
$this->addSql('DROP TABLE ActivityType');
}
public function up(Schema $schema): void public function up(Schema $schema): void
{ {
// this up() migration is auto-generated, please modify it to your needs // this up() migration is auto-generated, please modify it to your needs
$this->abortIf($this->connection->getDatabasePlatform()->getName() != 'postgresql', 'Migration can only be executed safely on \'postgresql\'.'); $this->abortIf($this->connection->getDatabasePlatform()->getName() !== 'postgresql', 'Migration can only be executed safely on \'postgresql\'.');
$this->addSql('CREATE SEQUENCE Activity_id_seq INCREMENT BY 1 MINVALUE 1 START 1'); $this->addSql('CREATE SEQUENCE Activity_id_seq INCREMENT BY 1 MINVALUE 1 START 1');
$this->addSql('CREATE SEQUENCE ActivityReason_id_seq INCREMENT BY 1 MINVALUE 1 START 1'); $this->addSql('CREATE SEQUENCE ActivityReason_id_seq INCREMENT BY 1 MINVALUE 1 START 1');
@@ -59,25 +65,4 @@ class Version20150701091248 extends AbstractMigration
$this->addSql('ALTER TABLE Activity ADD CONSTRAINT FK_55026B0C217BBB47 FOREIGN KEY (person_id) REFERENCES Person (id) NOT DEFERRABLE INITIALLY IMMEDIATE'); $this->addSql('ALTER TABLE Activity ADD CONSTRAINT FK_55026B0C217BBB47 FOREIGN KEY (person_id) REFERENCES Person (id) NOT DEFERRABLE INITIALLY IMMEDIATE');
$this->addSql('ALTER TABLE ActivityReason ADD CONSTRAINT FK_654A2FCD12469DE2 FOREIGN KEY (category_id) REFERENCES ActivityReasonCategory (id) NOT DEFERRABLE INITIALLY IMMEDIATE'); $this->addSql('ALTER TABLE ActivityReason ADD CONSTRAINT FK_654A2FCD12469DE2 FOREIGN KEY (category_id) REFERENCES ActivityReasonCategory (id) NOT DEFERRABLE INITIALLY IMMEDIATE');
} }
/**
* @param Schema $schema
*/
public function down(Schema $schema): void
{
// this down() migration is auto-generated, please modify it to your needs
$this->abortIf($this->connection->getDatabasePlatform()->getName() != 'postgresql', 'Migration can only be executed safely on \'postgresql\'.');
$this->addSql('ALTER TABLE Activity DROP CONSTRAINT FK_55026B0C59BB1592');
$this->addSql('ALTER TABLE ActivityReason DROP CONSTRAINT FK_654A2FCD12469DE2');
$this->addSql('ALTER TABLE Activity DROP CONSTRAINT FK_55026B0CC54C8C93');
$this->addSql('DROP SEQUENCE Activity_id_seq CASCADE');
$this->addSql('DROP SEQUENCE ActivityReason_id_seq CASCADE');
$this->addSql('DROP SEQUENCE ActivityReasonCategory_id_seq CASCADE');
$this->addSql('DROP SEQUENCE ActivityType_id_seq CASCADE');
$this->addSql('DROP TABLE Activity');
$this->addSql('DROP TABLE ActivityReason');
$this->addSql('DROP TABLE ActivityReasonCategory');
$this->addSql('DROP TABLE ActivityType');
}
} }

View File

@@ -1,58 +1,30 @@
<?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 * @see https://www.champs-libres.coop/
* 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/>.
*/ */
declare(strict_types=1);
namespace Chill\Migrations\Activity; namespace Chill\Migrations\Activity;
use Doctrine\Migrations\AbstractMigration;
use Doctrine\DBAL\Schema\Schema; use Doctrine\DBAL\Schema\Schema;
use Doctrine\Migrations\AbstractMigration;
/** /**
* Auto-generated Migration: Please modify to your needs! * Auto-generated Migration: Please modify to your needs!
*/ */
class Version20150702093317 extends AbstractMigration class Version20150702093317 extends AbstractMigration
{ {
/**
* @param Schema $schema
*/
public function up(Schema $schema): void
{
// this up() migration is auto-generated, please modify it to your needs
$this->abortIf($this->connection->getDatabasePlatform()->getName() != 'postgresql', 'Migration can only be executed safely on \'postgresql\'.');
$this->addSql('ALTER TABLE ActivityReasonCategory DROP COLUMN label;');
$this->addSql('ALTER TABLE ActivityReasonCategory ADD COLUMN name JSON;');
$this->addSql('ALTER TABLE ActivityReason DROP COLUMN label;');
$this->addSql('ALTER TABLE ActivityReason ADD COLUMN name JSON;');
$this->addSql('ALTER TABLE ActivityType DROP COLUMN name;');
$this->addSql('ALTER TABLE ActivityType ADD COLUMN name JSON;');
}
/**
* @param Schema $schema
*/
public function down(Schema $schema): void public function down(Schema $schema): void
{ {
// this down() migration is auto-generated, please modify it to your needs // this down() migration is auto-generated, please modify it to your needs
$this->abortIf($this->connection->getDatabasePlatform()->getName() != 'postgresql', 'Migration can only be executed safely on \'postgresql\'.'); $this->abortIf($this->connection->getDatabasePlatform()->getName() !== 'postgresql', 'Migration can only be executed safely on \'postgresql\'.');
$this->addSql('ALTER TABLE ActivityReasonCategory DROP COLUMN name;'); $this->addSql('ALTER TABLE ActivityReasonCategory DROP COLUMN name;');
$this->addSql('ALTER TABLE ActivityReasonCategory ADD COLUMN label VARCHAR(255) NOT NULL;'); $this->addSql('ALTER TABLE ActivityReasonCategory ADD COLUMN label VARCHAR(255) NOT NULL;');
@@ -61,4 +33,17 @@ class Version20150702093317 extends AbstractMigration
$this->addSql('ALTER TABLE ActivityType DROP COLUMN name;'); $this->addSql('ALTER TABLE ActivityType DROP COLUMN name;');
$this->addSql('ALTER TABLE ActivityType ADD COLUMN name VARCHAR(255) NOT NULL;'); $this->addSql('ALTER TABLE ActivityType ADD COLUMN name VARCHAR(255) NOT NULL;');
} }
public function up(Schema $schema): void
{
// this up() migration is auto-generated, please modify it to your needs
$this->abortIf($this->connection->getDatabasePlatform()->getName() !== 'postgresql', 'Migration can only be executed safely on \'postgresql\'.');
$this->addSql('ALTER TABLE ActivityReasonCategory DROP COLUMN label;');
$this->addSql('ALTER TABLE ActivityReasonCategory ADD COLUMN name JSON;');
$this->addSql('ALTER TABLE ActivityReason DROP COLUMN label;');
$this->addSql('ALTER TABLE ActivityReason ADD COLUMN name JSON;');
$this->addSql('ALTER TABLE ActivityType DROP COLUMN name;');
$this->addSql('ALTER TABLE ActivityType ADD COLUMN name JSON;');
}
} }

View File

@@ -1,57 +1,41 @@
<?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 * @see https://www.champs-libres.coop/
* 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/>.
*/ */
declare(strict_types=1);
namespace Chill\Migrations\Activity; namespace Chill\Migrations\Activity;
use Doctrine\Migrations\AbstractMigration;
use Doctrine\DBAL\Schema\Schema; use Doctrine\DBAL\Schema\Schema;
use Doctrine\Migrations\AbstractMigration;
/** /**
* Db Migration * Db Migration.
*
*/ */
class Version20150704091347 extends AbstractMigration class Version20150704091347 extends AbstractMigration
{ {
/**
* @param Schema $schema
*/
public function up(Schema $schema): void
{
// this up() migration is auto-generated, please modify it to your needs
$this->abortIf($this->connection->getDatabasePlatform()->getName() != 'postgresql', 'Migration can only be executed safely on \'postgresql\'.');
$this->addSql('ALTER TABLE Activity ALTER COLUMN remark DROP NOT NULL;');
$this->addSql('ALTER TABLE Activity ALTER COLUMN attendee DROP NOT NULL;');
}
/**
* @param Schema $schema
*/
public function down(Schema $schema): void public function down(Schema $schema): void
{ {
// this down() migration is auto-generated, please modify it to your needs // this down() migration is auto-generated, please modify it to your needs
$this->abortIf($this->connection->getDatabasePlatform()->getName() != 'postgresql', 'Migration can only be executed safely on \'postgresql\'.'); $this->abortIf($this->connection->getDatabasePlatform()->getName() !== 'postgresql', 'Migration can only be executed safely on \'postgresql\'.');
$this->addSql('ALTER TABLE Activity ALTER COLUMN remark SET NOT NULL;'); $this->addSql('ALTER TABLE Activity ALTER COLUMN remark SET NOT NULL;');
$this->addSql('ALTER TABLE Activity ALTER COLUMN attendee DROP NOT NULL;'); $this->addSql('ALTER TABLE Activity ALTER COLUMN attendee DROP NOT NULL;');
} }
public function up(Schema $schema): void
{
// this up() migration is auto-generated, please modify it to your needs
$this->abortIf($this->connection->getDatabasePlatform()->getName() !== 'postgresql', 'Migration can only be executed safely on \'postgresql\'.');
$this->addSql('ALTER TABLE Activity ALTER COLUMN remark DROP NOT NULL;');
$this->addSql('ALTER TABLE Activity ALTER COLUMN attendee DROP NOT NULL;');
}
} }

View File

@@ -1,9 +1,20 @@
<?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.
*
* @see https://www.champs-libres.coop/
*/
declare(strict_types=1);
namespace Chill\Migrations\Activity; namespace Chill\Migrations\Activity;
use Doctrine\Migrations\AbstractMigration;
use Doctrine\DBAL\Schema\Schema; use Doctrine\DBAL\Schema\Schema;
use Doctrine\Migrations\AbstractMigration;
/** /**
* Migrate schema to allow multiple or empty reasons on an activity. * Migrate schema to allow multiple or empty reasons on an activity.
@@ -13,17 +24,43 @@ use Doctrine\DBAL\Schema\Schema;
*/ */
class Version20160222103457 extends AbstractMigration class Version20160222103457 extends AbstractMigration
{ {
/** public function down(Schema $schema): void
* @param Schema $schema {
*/ $this->abortIf(
$this->connection->getDatabasePlatform()->getName() !== 'postgresql',
'Migration can only be executed safely on \'postgresql\'.'
);
$this->addSql('ALTER TABLE Activity ADD reason_id INT DEFAULT NULL');
$this->addSql('ALTER TABLE Activity ADD CONSTRAINT '
. 'fk_55026b0c59bb1592 FOREIGN KEY (reason_id) '
. 'REFERENCES activityreason (id) NOT DEFERRABLE INITIALLY IMMEDIATE');
$this->addSql('CREATE INDEX idx_55026b0c59bb1592 ON Activity (reason_id)');
// try to keep at least on activity reason...
$this->addSql(
'UPDATE activity
SET reason_id=rid
FROM (
SELECT activity_id AS aid, MIN(activityreason_id) AS rid
FROM activity_activityreason
GROUP BY activity_id ) AS sb
WHERE sb.aid = activity.id'
);
$this->addSql('DROP TABLE activity_activityreason');
}
public function up(Schema $schema): void public function up(Schema $schema): void
{ {
$this->abortIf(
$this->abortIf($this->connection->getDatabasePlatform()->getName() != 'postgresql', $this->connection->getDatabasePlatform()->getName() !== 'postgresql',
'Migration can only be executed safely on \'postgresql\'.'); 'Migration can only be executed safely on \'postgresql\'.'
);
// create the new table activity reason // create the new table activity reason
$this->addSql('CREATE TABLE activity_activityreason (' $this->addSql(
'CREATE TABLE activity_activityreason ('
. 'activity_id INT NOT NULL, ' . 'activity_id INT NOT NULL, '
. 'activityreason_id INT NOT NULL, ' . 'activityreason_id INT NOT NULL, '
. 'PRIMARY KEY(activity_id, activityreason_id))' . 'PRIMARY KEY(activity_id, activityreason_id))'
@@ -41,39 +78,9 @@ class Version20160222103457 extends AbstractMigration
$this->addSql('INSERT INTO activity_activityreason (activity_id, activityreason_id) ' $this->addSql('INSERT INTO activity_activityreason (activity_id, activityreason_id) '
. 'SELECT id, reason_id FROM activity WHERE reason_id IS NOT NULL'); . 'SELECT id, reason_id FROM activity WHERE reason_id IS NOT NULL');
// remove old column // remove old column
$this->addSql('ALTER TABLE activity DROP CONSTRAINT fk_55026b0c59bb1592'); $this->addSql('ALTER TABLE activity DROP CONSTRAINT fk_55026b0c59bb1592');
$this->addSql('DROP INDEX idx_55026b0c59bb1592'); $this->addSql('DROP INDEX idx_55026b0c59bb1592');
$this->addSql('ALTER TABLE activity DROP reason_id'); $this->addSql('ALTER TABLE activity DROP reason_id');
} }
/**
* @param Schema $schema
*/
public function down(Schema $schema): void
{
$this->abortIf($this->connection->getDatabasePlatform()->getName() != 'postgresql',
'Migration can only be executed safely on \'postgresql\'.');
$this->addSql('ALTER TABLE Activity ADD reason_id INT DEFAULT NULL');
$this->addSql('ALTER TABLE Activity ADD CONSTRAINT '
. 'fk_55026b0c59bb1592 FOREIGN KEY (reason_id) '
. 'REFERENCES activityreason (id) NOT DEFERRABLE INITIALLY IMMEDIATE');
$this->addSql('CREATE INDEX idx_55026b0c59bb1592 ON Activity (reason_id)');
// try to keep at least on activity reason...
$this->addSql('UPDATE activity
SET reason_id=rid
FROM (
SELECT activity_id AS aid, MIN(activityreason_id) AS rid
FROM activity_activityreason
GROUP BY activity_id ) AS sb
WHERE sb.aid = activity.id'
);
$this->addSql('DROP TABLE activity_activityreason');
}
} }

View File

@@ -1,29 +1,33 @@
<?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.
*
* @see https://www.champs-libres.coop/
*/
declare(strict_types=1);
namespace Chill\Migrations\Activity; namespace Chill\Migrations\Activity;
use Doctrine\Migrations\AbstractMigration;
use Doctrine\DBAL\Schema\Schema; use Doctrine\DBAL\Schema\Schema;
use Doctrine\DBAL\Types\Type; use Doctrine\Migrations\AbstractMigration;
/** /**
* Add an "active" column on activitytype table * Add an "active" column on activitytype table.
*/ */
class Version20161114085659 extends AbstractMigration class Version20161114085659 extends AbstractMigration
{ {
/**
* @param Schema $schema
*/
public function up(Schema $schema): void
{
$this->addSql('ALTER TABLE activitytype ADD active BOOLEAN NOT NULL DEFAULT \'t\'');
}
/**
* @param Schema $schema
*/
public function down(Schema $schema): void public function down(Schema $schema): void
{ {
$this->addSql('ALTER TABLE ActivityType DROP active'); $this->addSql('ALTER TABLE ActivityType DROP active');
} }
public function up(Schema $schema): void
{
$this->addSql('ALTER TABLE activitytype ADD active BOOLEAN NOT NULL DEFAULT \'t\'');
}
} }

View File

@@ -1,5 +1,14 @@
<?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.
*
* @see https://www.champs-libres.coop/
*/
declare(strict_types=1); declare(strict_types=1);
namespace Chill\Migrations\Activity; namespace Chill\Migrations\Activity;
@@ -12,6 +21,15 @@ use Doctrine\Migrations\AbstractMigration;
*/ */
final class Version20210304154629 extends AbstractMigration final class Version20210304154629 extends AbstractMigration
{ {
public function down(Schema $schema): void
{
// this down() migration is auto-generated, please modify it to your needs
$this->addSql('ALTER TABLE activity DROP comment_comment');
$this->addSql('ALTER TABLE activity DROP comment_userId');
$this->addSql('ALTER TABLE activity DROP comment_date');
}
public function getDescription(): string public function getDescription(): string
{ {
return ''; return '';
@@ -24,13 +42,4 @@ final class Version20210304154629 extends AbstractMigration
$this->addSql('ALTER TABLE activity ADD comment_userId INT DEFAULT NULL'); $this->addSql('ALTER TABLE activity ADD comment_userId INT DEFAULT NULL');
$this->addSql('ALTER TABLE activity ADD comment_date TIMESTAMP(0) WITHOUT TIME ZONE DEFAULT NULL'); $this->addSql('ALTER TABLE activity ADD comment_date TIMESTAMP(0) WITHOUT TIME ZONE DEFAULT NULL');
} }
public function down(Schema $schema) : void
{
// this down() migration is auto-generated, please modify it to your needs
$this->addSql('ALTER TABLE activity DROP comment_comment');
$this->addSql('ALTER TABLE activity DROP comment_userId');
$this->addSql('ALTER TABLE activity DROP comment_date');
}
} }

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