mirror of
				https://gitlab.com/Chill-Projet/chill-bundles.git
				synced 2025-11-04 11:18:25 +00:00 
			
		
		
		
	Compare commits
	
		
			7 Commits
		
	
	
		
			use-sympli
			...
			bootstrap-
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 695aa45b90 | |||
| 58b04783f2 | |||
| 88edb905a7 | |||
| b884eee626 | |||
| 167158db72 | |||
| 3c6b21be3b | |||
| e7772f0967 | 
							
								
								
									
										4
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										4
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							@@ -1,8 +1,7 @@
 | 
			
		||||
.composer/*
 | 
			
		||||
composer.phar
 | 
			
		||||
composer.lock
 | 
			
		||||
docs/build/
 | 
			
		||||
.php_cs.cache
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
###> symfony/framework-bundle ###
 | 
			
		||||
/.env.local
 | 
			
		||||
@@ -19,4 +18,3 @@ docs/build/
 | 
			
		||||
/phpunit.xml
 | 
			
		||||
.phpunit.result.cache
 | 
			
		||||
###< phpunit/phpunit ###
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -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;"
 | 
			
		||||
  # Install and run Composer
 | 
			
		||||
  - 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 -d memory_limit=2G tests/app/bin/console doctrine:fixtures:load -n
 | 
			
		||||
  - echo "before_script finished"
 | 
			
		||||
  - php tests/app/bin/console doctrine:fixtures:load -n
 | 
			
		||||
 | 
			
		||||
# 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.
 | 
			
		||||
services:
 | 
			
		||||
  - name: postgis/postgis:12-3.1-alpine
 | 
			
		||||
  - name: postgres:12
 | 
			
		||||
    alias: db
 | 
			
		||||
  - name: redis
 | 
			
		||||
    alias: redis
 | 
			
		||||
@@ -31,12 +30,8 @@ variables:
 | 
			
		||||
  POSTGRES_PASSWORD: postgres
 | 
			
		||||
  # fetch the chill-app using git submodules
 | 
			
		||||
  GIT_SUBMODULE_STRATEGY: recursive
 | 
			
		||||
  REDIS_HOST: redis
 | 
			
		||||
  REDIS_PORT: 6379
 | 
			
		||||
  REDIS_URL: redis://redis:6379
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
# Run our tests
 | 
			
		||||
test:
 | 
			
		||||
  script:
 | 
			
		||||
    - php -d memory_limit=3G bin/phpunit --colors=never
 | 
			
		||||
    - bin/phpunit --colors=never
 | 
			
		||||
 
 | 
			
		||||
@@ -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
 | 
			
		||||
							
								
								
									
										166
									
								
								composer.json
									
									
									
									
									
								
							
							
						
						
									
										166
									
								
								composer.json
									
									
									
									
									
								
							@@ -1,110 +1,86 @@
 | 
			
		||||
{
 | 
			
		||||
    "name": "chill-project/chill-bundles",
 | 
			
		||||
    "license": "AGPL-3.0-only",
 | 
			
		||||
    "type": "library",
 | 
			
		||||
    "description": "Most used bundles for chill-project",
 | 
			
		||||
    "keywords": ["chill", "social worker"],
 | 
			
		||||
    "authors": [
 | 
			
		||||
        {
 | 
			
		||||
            "name": "Champs-Libres",
 | 
			
		||||
            "email": "info@champs-libres.coop",
 | 
			
		||||
            "homepage": "http://www.champs-libres.coop"
 | 
			
		||||
        }
 | 
			
		||||
    ],
 | 
			
		||||
    "type": "library",
 | 
			
		||||
    "require": {
 | 
			
		||||
        "components/jquery": ">=1.7.1",
 | 
			
		||||
        "league/csv": "^9.6",
 | 
			
		||||
        "phpoffice/phpspreadsheet": "~1.2",
 | 
			
		||||
        "robloach/component-installer": "*"
 | 
			
		||||
    },
 | 
			
		||||
    "config": {
 | 
			
		||||
        "vendor-dir": "tests/app/vendor",
 | 
			
		||||
        "bin-dir": "bin"
 | 
			
		||||
    },
 | 
			
		||||
    "require-dev": {
 | 
			
		||||
        "doctrine/doctrine-fixtures-bundle": "^3.3",
 | 
			
		||||
        "fakerphp/faker": "^1.13",
 | 
			
		||||
        "nelmio/alice": "^3.8",
 | 
			
		||||
        "phpunit/phpunit": "^9.5",
 | 
			
		||||
        "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",
 | 
			
		||||
        "symplify/monorepo-builder": "^9.2"
 | 
			
		||||
    },
 | 
			
		||||
    "autoload": {
 | 
			
		||||
        "psr-4": {
 | 
			
		||||
            "Chill\\AMLI\\BudgetBundle\\": "src/Bundle/ChillBudgetBundle/",
 | 
			
		||||
            "Chill\\AMLI\\FamilyMembersBundle\\": "src/Bundle/ChillFamilyMembersBundle/",
 | 
			
		||||
            "Chill\\ActivityBundle\\": "src/Bundle/ChillActivityBundle/",
 | 
			
		||||
            "Chill\\CustomFieldsBundle\\": "src/Bundle/ChillCustomFieldsBundle/",
 | 
			
		||||
            "Chill\\DocStoreBundle\\": "src/Bundle/ChillDocStoreBundle/",
 | 
			
		||||
            "Chill\\EventBundle\\": "src/Bundle/ChillEventBundle/",
 | 
			
		||||
            "Chill\\MainBundle\\": "src/Bundle/ChillMainBundle/",
 | 
			
		||||
            "Chill\\PersonBundle\\": "src/Bundle/ChillPersonBundle/",
 | 
			
		||||
            "Chill\\ReportBundle\\": "src/Bundle/ChillReportBundle/",
 | 
			
		||||
            "Chill\\TaskBundle\\": "src/Bundle/ChillTaskBundle/",
 | 
			
		||||
            "Chill\\ThirdPartyBundle\\": "src/Bundle/ChillThirdPartyBundle/"
 | 
			
		||||
            "Chill\\ActivityBundle\\": "src/Bundle/ChillActivityBundle",
 | 
			
		||||
            "Chill\\BudgetBundle\\": "src/Bundle/ChillBudgetBundle",
 | 
			
		||||
            "Chill\\CustomFieldsBundle\\": "src/Bundle/ChillCustomFieldsBundle",
 | 
			
		||||
            "Chill\\DocStoreBundle\\": "src/Bundle/ChillDocStoreBundle",
 | 
			
		||||
            "Chill\\EventBundle\\": "src/Bundle/ChillEventBundle",
 | 
			
		||||
            "Chill\\FamilyMemberBundle\\": "src/Bundle/ChillFamilyMemberBundle",
 | 
			
		||||
            "Chill\\MainBundle\\": "src/Bundle/ChillMainBundle",
 | 
			
		||||
            "Chill\\PersonBundle\\": "src/Bundle/ChillPersonBundle",
 | 
			
		||||
            "Chill\\ReportBundle\\": "src/Bundle/ChillReportBundle",
 | 
			
		||||
            "Chill\\TaskBundle\\": "src/Bundle/ChillTaskBundle",
 | 
			
		||||
            "Chill\\ThirdPartyBundle\\": "src/Bundle/ChillThirdPartyBundle"
 | 
			
		||||
        }
 | 
			
		||||
    },
 | 
			
		||||
    "autoload-dev": {
 | 
			
		||||
        "classmap": [
 | 
			
		||||
            "src/Bundle/ChillActivityBundle/Resources/test/Fixtures/App/app/AppKernel.php",
 | 
			
		||||
            "src/Bundle/ChillCustomFieldsBundle/Resources/test/Fixtures/App/app/AppKernel.php",
 | 
			
		||||
            "src/Bundle/ChillMainBundle/Resources/test/Fixtures/App/app/AppKernel.php",
 | 
			
		||||
            "src/Bundle/ChillPersonBundle/Resources/test/Fixtures/App/app/AppKernel.php",
 | 
			
		||||
            "src/Bundle/ChillReportBundle/Resources/test/Fixtures/App/app/AppKernel.php"
 | 
			
		||||
        ]
 | 
			
		||||
        "psr-4": {
 | 
			
		||||
          "App\\": "tests/app/src/"
 | 
			
		||||
        }
 | 
			
		||||
    },
 | 
			
		||||
    "extra": {
 | 
			
		||||
        "component": {
 | 
			
		||||
            "scripts": [
 | 
			
		||||
                "select2.js"
 | 
			
		||||
            ],
 | 
			
		||||
            "files": [
 | 
			
		||||
                "select2.js",
 | 
			
		||||
                "select2_locale_*.js",
 | 
			
		||||
                "select2.css",
 | 
			
		||||
                "select2-bootstrap.css",
 | 
			
		||||
                "select2-spinner.gif",
 | 
			
		||||
                "select2.png",
 | 
			
		||||
                "select2x2.png"
 | 
			
		||||
            ]
 | 
			
		||||
        },
 | 
			
		||||
        "app-migrations-dir": [
 | 
			
		||||
            "Resources/test/Fixtures/App/app/DoctrineMigrations",
 | 
			
		||||
            "Resources/test/Fixtures/App/DoctrineMigrations"
 | 
			
		||||
        ],
 | 
			
		||||
        "symfony-app-dir": [
 | 
			
		||||
            "Tests/Fixtures/App/app",
 | 
			
		||||
            "Tests/Fixtures/App/",
 | 
			
		||||
            "Test/Fixtures/App/app/"
 | 
			
		||||
        ]
 | 
			
		||||
    "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.*",
 | 
			
		||||
        "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"
 | 
			
		||||
    },
 | 
			
		||||
    "conflict": {
 | 
			
		||||
        "symfony/symfony": "*"
 | 
			
		||||
    },
 | 
			
		||||
    "require-dev": {
 | 
			
		||||
        "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": {
 | 
			
		||||
        "merge": "vendor/bin/monorepo-builder merge --ansi",
 | 
			
		||||
        "propagate": "vendor/bin/monorepo-builder propagate --ansi",
 | 
			
		||||
        "validate-monorepo": "vendor/bin/monorepo-builder validate --ansi",
 | 
			
		||||
        "release": "vendor/bin/monorepo-builder release patch --ansi",
 | 
			
		||||
        "localize": "vendor/bin/monorepo-builder localize-composer-paths"
 | 
			
		||||
        "auto-scripts": {
 | 
			
		||||
            "cache:clear": "symfony-cmd",
 | 
			
		||||
            "assets:install %PUBLIC_DIR%": "symfony-cmd"
 | 
			
		||||
        }
 | 
			
		||||
    },
 | 
			
		||||
    "replace": {
 | 
			
		||||
        "chill-project/activity": "self.version",
 | 
			
		||||
        "chill-project/budget": "self.version",
 | 
			
		||||
        "chill-project/chill-doc-store": "self.version",
 | 
			
		||||
        "chill-project/custom-fields": "self.version",
 | 
			
		||||
        "chill-project/event": "self.version",
 | 
			
		||||
        "chill-project/family-members": "self.version",
 | 
			
		||||
        "chill-project/main": "self.version",
 | 
			
		||||
        "chill-project/person": "self.version",
 | 
			
		||||
        "chill-project/report": "self.version",
 | 
			
		||||
        "chill-project/task": "self.version",
 | 
			
		||||
        "chill-project/third-party": "self.version",
 | 
			
		||||
        "ivaynberg/select2": "self.version"
 | 
			
		||||
    },
 | 
			
		||||
    "minimum-stability": "dev",
 | 
			
		||||
    "prefer-stable": true
 | 
			
		||||
    "config": {
 | 
			
		||||
      "vendor-dir": "tests/app/vendor",
 | 
			
		||||
      "bin-dir": "bin"
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -10,19 +10,10 @@ Compilation into HTML
 | 
			
		||||
 | 
			
		||||
To compile this documentation :
 | 
			
		||||
 | 
			
		||||
1. Install [sphinx-doc](http://sphinx-doc.org)
 | 
			
		||||
    ``` bash
 | 
			
		||||
            $ virtualenv .venv # creation of the virtual env (only the first time)
 | 
			
		||||
            $ source .venv/bin/activate # activate the virtual env
 | 
			
		||||
    (.venv) $ pip install -r requirements.txt
 | 
			
		||||
    ```
 | 
			
		||||
1. Install [sphinx-doc](http://sphinx-doc.org) (eg. pip install sphinx &  pip install sphinx_rtd_theme)
 | 
			
		||||
2. Install submodules : $ git submodule update --init;
 | 
			
		||||
3. run `make html` from the root directory
 | 
			
		||||
4. The base file is located on build/html/index.html
 | 
			
		||||
    ``` bash
 | 
			
		||||
    $ cd build/html
 | 
			
		||||
    $ python -m http.server 8888 # will serve the site on the port 8888
 | 
			
		||||
    ```
 | 
			
		||||
 | 
			
		||||
Contribute
 | 
			
		||||
===========
 | 
			
		||||
 
 | 
			
		||||
@@ -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
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@@ -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>
 | 
			
		||||
    CRUD (Create - Update - Delete) for one entity <crud.rst>
 | 
			
		||||
    Helpers for building a REST API <api.rst>
 | 
			
		||||
    Routing <routing.rst>
 | 
			
		||||
    Menus <menus.rst>
 | 
			
		||||
    Forms <forms.rst>
 | 
			
		||||
@@ -30,7 +29,7 @@ As Chill rely on the `symfony <http://symfony.com>`_ framework, reading the fram
 | 
			
		||||
    Timelines <timelines.rst>
 | 
			
		||||
    Exports <exports.rst>
 | 
			
		||||
    Embeddable comments <embeddable-comments.rst>
 | 
			
		||||
    Run tests <run-tests.rst>
 | 
			
		||||
    Testing <make-test-working.rst>
 | 
			
		||||
    Useful snippets <useful-snippets.rst>
 | 
			
		||||
    manual/index.rst
 | 
			
		||||
    Assets <assets.rst>
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										231
									
								
								docs/source/development/make-test-working.rst
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										231
									
								
								docs/source/development/make-test-working.rst
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,231 @@
 | 
			
		||||
.. 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".
 | 
			
		||||
 | 
			
		||||
Make tests working
 | 
			
		||||
******************
 | 
			
		||||
 | 
			
		||||
Unit and functional tests are important to ensure that bundle may be deployed securely.
 | 
			
		||||
 | 
			
		||||
In reason of the Chill architecture, test should be runnable from the bundle's directory and works correctly: this will allow continuous integration tools to run tests automatically. 
 | 
			
		||||
 | 
			
		||||
.. note::
 | 
			
		||||
 | 
			
		||||
    Integration tools (i.e. `travis-ci <https://travis-ci.org>`_) works like this : 
 | 
			
		||||
 | 
			
		||||
    * they clone the bundle repository in a virtual machine, using git
 | 
			
		||||
    * they optionnaly run `composer` to download and install depedencies
 | 
			
		||||
    * they optionnaly run other command to prepare a database, insert fixtures, ...
 | 
			
		||||
    * they run test
 | 
			
		||||
 | 
			
		||||
On the developer's machine test should be runnable with two or three commands **runned from the bundle directory** : 
 | 
			
		||||
 | 
			
		||||
.. code-block:: bash
 | 
			
		||||
 | 
			
		||||
   $ composer install --dev
 | 
			
		||||
   $ // command to insert fixtures, ...
 | 
			
		||||
   $ phpunit
 | 
			
		||||
 | 
			
		||||
This chapter has been inspired by `this useful blog post <http://blog.kevingomez.fr/2013/01/09/functional-testing-standalone-symfony2-bundles/>`_.
 | 
			
		||||
 | 
			
		||||
Bootstrap phpunit for a standalone bundle
 | 
			
		||||
==========================================
 | 
			
		||||
 | 
			
		||||
Unit tests should run after achieving this step.
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
phpunit.xml
 | 
			
		||||
-----------
 | 
			
		||||
 | 
			
		||||
A `phpunit.xml.dist` file should be present at the bundle root.
 | 
			
		||||
 | 
			
		||||
.. code-block:: xml
 | 
			
		||||
 | 
			
		||||
   <?xml version="1.0" encoding="UTF-8"?>
 | 
			
		||||
 | 
			
		||||
   <phpunit bootstrap="./Tests/bootstrap.php" colors="true">
 | 
			
		||||
        <!-- the file "./Tests/boostrap.php" will be created on the next step -->
 | 
			
		||||
       <testsuites>
 | 
			
		||||
           <testsuite name="ChillMain test suite">
 | 
			
		||||
               <directory suffix="Test.php">./Tests</directory>
 | 
			
		||||
           </testsuite>
 | 
			
		||||
       </testsuites>
 | 
			
		||||
       <filter>
 | 
			
		||||
           <whitelist>
 | 
			
		||||
               <directory>./</directory>
 | 
			
		||||
               <exclude>
 | 
			
		||||
                   <directory>./Resources</directory>
 | 
			
		||||
                   <directory>./Tests</directory>
 | 
			
		||||
                   <directory>./vendor</directory>
 | 
			
		||||
               </exclude>
 | 
			
		||||
          </whitelist>
 | 
			
		||||
      </filter>
 | 
			
		||||
   </phpunit>
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
bootstrap.php
 | 
			
		||||
--------------
 | 
			
		||||
 | 
			
		||||
A file `boostrap.php`, located in the `Tests` directory, will allow phpunit to resolve class autoloading :
 | 
			
		||||
 | 
			
		||||
.. code-block:: php
 | 
			
		||||
 | 
			
		||||
   <?php
 | 
			
		||||
 | 
			
		||||
   if (!is_file($autoloadFile = __DIR__.'/../vendor/autoload.php')) {
 | 
			
		||||
       throw new \LogicException('Could not find autoload.php in vendor/. Did you run "composer install --dev"?');
 | 
			
		||||
   }
 | 
			
		||||
 | 
			
		||||
   require $autoloadFile;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
composer.json
 | 
			
		||||
-------------
 | 
			
		||||
 | 
			
		||||
The `composer.json` file **located at the bundle's root** should contains all depencies needed to run test (and to execute bundle functions).
 | 
			
		||||
 | 
			
		||||
Ensure that all dependencies are included in the `require` and `require-dev` sections.
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
Functional tests
 | 
			
		||||
================
 | 
			
		||||
 | 
			
		||||
If you want to access services, database, and run functional tests, you will have to bootstrap a symfony app, with the minimal configuration. Three files are required : 
 | 
			
		||||
 | 
			
		||||
* a `config_test.yml` file (eventually with a `config.yml`);
 | 
			
		||||
* a `routing.yml` file
 | 
			
		||||
* an `AppKernel.php` file
 | 
			
		||||
 | 
			
		||||
Adapt phpunit.xml
 | 
			
		||||
-----------------
 | 
			
		||||
 | 
			
		||||
You should add reference to the new application within `phpunit.xml.dist`. The directive `<php>` should be added like this, if your `AppKernel.php` file is located in `Tests/Fixtures/App` directory:
 | 
			
		||||
 | 
			
		||||
.. code-block:: xml
 | 
			
		||||
 | 
			
		||||
    <?xml version="1.0" encoding="UTF-8"?>
 | 
			
		||||
 | 
			
		||||
    <phpunit bootstrap="./Tests/bootstrap.php" colors="true">
 | 
			
		||||
        <testsuites>
 | 
			
		||||
            <testsuite name="ChillMain test suite">
 | 
			
		||||
                <directory suffix="Test.php">./Tests</directory>
 | 
			
		||||
            </testsuite>
 | 
			
		||||
        </testsuites>
 | 
			
		||||
        <filter>
 | 
			
		||||
            <whitelist>
 | 
			
		||||
                <directory>./</directory>
 | 
			
		||||
                <exclude>
 | 
			
		||||
                    <directory>./Resources</directory>
 | 
			
		||||
                    <directory>./Tests</directory>
 | 
			
		||||
                    <directory>./vendor</directory>
 | 
			
		||||
                </exclude>
 | 
			
		||||
            </whitelist>
 | 
			
		||||
        </filter>
 | 
			
		||||
        <!-- the lines we added --> 
 | 
			
		||||
       <php>
 | 
			
		||||
            <server name="KERNEL_DIR" value="./Tests/Fixtures/App/" />
 | 
			
		||||
        </php>
 | 
			
		||||
    </phpunit>
 | 
			
		||||
 | 
			
		||||
AppKernel.php
 | 
			
		||||
-------------
 | 
			
		||||
 | 
			
		||||
This file boostrap the app. It contains three functions. This is the file used in the ChillMain bundle :
 | 
			
		||||
 | 
			
		||||
.. code-block:: php
 | 
			
		||||
                                                                                                                                                                                                                 
 | 
			
		||||
    <?php
 | 
			
		||||
 | 
			
		||||
    use Symfony\Component\HttpKernel\Kernel;
 | 
			
		||||
    use Symfony\Component\Config\Loader\LoaderInterface;
 | 
			
		||||
 | 
			
		||||
    class AppKernel extends Kernel
 | 
			
		||||
    {
 | 
			
		||||
        public function registerBundles()
 | 
			
		||||
        {   
 | 
			
		||||
            return array(
 | 
			
		||||
                new Symfony\Bundle\FrameworkBundle\FrameworkBundle(),
 | 
			
		||||
                new Chill\MainBundle\ChillMainBundle(),
 | 
			
		||||
                new Symfony\Bundle\SecurityBundle\SecurityBundle(),
 | 
			
		||||
                new Symfony\Bundle\TwigBundle\TwigBundle(),
 | 
			
		||||
                new \Symfony\Bundle\AsseticBundle\AsseticBundle(),
 | 
			
		||||
                #add here all the required bundle (some bundle are not required)
 | 
			
		||||
            );
 | 
			
		||||
        }   
 | 
			
		||||
 | 
			
		||||
        public function registerContainerConfiguration(LoaderInterface $loader)
 | 
			
		||||
        {   
 | 
			
		||||
            $loader->load(__DIR__.'/config/config_'.$this->getEnvironment().'.yml');
 | 
			
		||||
        }   
 | 
			
		||||
 | 
			
		||||
        /** 
 | 
			
		||||
         * @return string
 | 
			
		||||
         */
 | 
			
		||||
        public function getCacheDir()
 | 
			
		||||
        {   
 | 
			
		||||
            return sys_get_temp_dir().'/ChillMainBundle/cache';
 | 
			
		||||
        }   
 | 
			
		||||
 | 
			
		||||
        /** 
 | 
			
		||||
         * @return string
 | 
			
		||||
         */
 | 
			
		||||
        public function getLogDir()
 | 
			
		||||
        {   
 | 
			
		||||
            return sys_get_temp_dir().'/ChillMainBundle/logs';
 | 
			
		||||
        }   
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
config_test.yml
 | 
			
		||||
---------------
 | 
			
		||||
 | 
			
		||||
There are only few parameters required for the config file. This is a basic version for ChillMain :
 | 
			
		||||
 | 
			
		||||
.. code-block:: yaml
 | 
			
		||||
 | 
			
		||||
    # config/config_test.yml
 | 
			
		||||
    imports:
 | 
			
		||||
        - { resource: config.yml } #here we import a config.yml file, this is not required
 | 
			
		||||
 | 
			
		||||
    framework:
 | 
			
		||||
        test: ~
 | 
			
		||||
        session:
 | 
			
		||||
            storage_id: session.storage.filesystem
 | 
			
		||||
 | 
			
		||||
.. code-block:: yaml
 | 
			
		||||
 | 
			
		||||
   # config/config.yml
 | 
			
		||||
   framework: 
 | 
			
		||||
    secret:          Not very secret
 | 
			
		||||
    router:          { resource: "%kernel.root_dir%/config/routing.yml" }
 | 
			
		||||
    form:            true
 | 
			
		||||
    csrf_protection: true
 | 
			
		||||
    session:         ~
 | 
			
		||||
    default_locale:  fr  
 | 
			
		||||
    translator:      { fallback: fr }
 | 
			
		||||
    profiler:        { only_exceptions: false }
 | 
			
		||||
    templating: #required for assetic. Remove if not needed
 | 
			
		||||
        engines: ['twig']
 | 
			
		||||
 | 
			
		||||
.. note:: 
 | 
			
		||||
 | 
			
		||||
    You must adapt config.yml file according to your required bundle. Some options will be missing, other may be removed...
 | 
			
		||||
 | 
			
		||||
.. note::
 | 
			
		||||
 | 
			
		||||
    If you would like to tests different environments, with differents configuration, you could create differents config_XXX.yml files.
 | 
			
		||||
 | 
			
		||||
routing.yml
 | 
			
		||||
------------
 | 
			
		||||
 | 
			
		||||
You should add there all routing information needed for your bundle. 
 | 
			
		||||
 | 
			
		||||
.. code-block: yaml
 | 
			
		||||
 | 
			
		||||
    chill_main_bundle:
 | 
			
		||||
      resource: "@CLChillMainBundle/Resources/config/routing.yml"
 | 
			
		||||
 | 
			
		||||
That's it. Tests should pass.
 | 
			
		||||
@@ -7,8 +7,6 @@
 | 
			
		||||
   Free Documentation License".
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
.. _pagination-ref:
 | 
			
		||||
 | 
			
		||||
Pagination
 | 
			
		||||
##########
 | 
			
		||||
 | 
			
		||||
@@ -17,7 +15,7 @@ The Bundle :code:`Chill\MainBundle` provides a **Pagination** api which allow yo
 | 
			
		||||
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
 | 
			
		||||
 
 | 
			
		||||
@@ -1,68 +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".
 | 
			
		||||
 | 
			
		||||
Run tests
 | 
			
		||||
*********
 | 
			
		||||
 | 
			
		||||
In reason of the Chill architecture, test should be runnable from the bundle's directory and works correctly: this will allow continuous integration tools to run tests automatically. 
 | 
			
		||||
 | 
			
		||||
From chill app
 | 
			
		||||
==============
 | 
			
		||||
 | 
			
		||||
This is the most convenient method for developer: run test for chill bundle from the main app.
 | 
			
		||||
 | 
			
		||||
.. code-block:: bash
 | 
			
		||||
 | 
			
		||||
   # run into a container
 | 
			
		||||
   docker-compose exec --user $(id -u) php bash
 | 
			
		||||
   # execute all tests suites
 | 
			
		||||
   bin/phpunit
 | 
			
		||||
   # .. or execute a single test
 | 
			
		||||
   bin/phpunit vendor/chill-project/chill-bundles/src/Bundle/ChillMainBundle/Tests/path/to/FileTest.php
 | 
			
		||||
 | 
			
		||||
You can also run tests in a single command:
 | 
			
		||||
 | 
			
		||||
.. code-block:: bash
 | 
			
		||||
 | 
			
		||||
   docker-compose exec --user $(id -u) php bin/phpunit
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
Tests from a bundle (chill-bundles)
 | 
			
		||||
-----------------------------------
 | 
			
		||||
 | 
			
		||||
Those tests needs the whole symfony app to execute Application Tests (which test html page).
 | 
			
		||||
 | 
			
		||||
For ease, the app is cloned using a :code:`git submodule`, which clone the main app into :code:`tests/app`, and tests are bootstrapped to this app. The dependencies are also installed into `tests/app/vendor` to ensure compliance with relative path from this symfony application.
 | 
			
		||||
 | 
			
		||||
You may boostrap the tests fro the chill bundle this way:
 | 
			
		||||
 | 
			
		||||
.. code-block:: bash
 | 
			
		||||
 | 
			
		||||
   # ensure to be located into the environement (provided by docker suits well)
 | 
			
		||||
   docker-compose exec --user $(id -u) php bash
 | 
			
		||||
   # go to chill subdirectory
 | 
			
		||||
   cd vendor/chill-project/chill-bundles
 | 
			
		||||
   # install submodule
 | 
			
		||||
   git submodule init
 | 
			
		||||
   git submodule update
 | 
			
		||||
   # install composer and dependencies
 | 
			
		||||
   curl -sS https://getcomposer.org/installer | php
 | 
			
		||||
   # run tests
 | 
			
		||||
   bin/phpunit
 | 
			
		||||
 | 
			
		||||
.. note::
 | 
			
		||||
 | 
			
		||||
   If you are on a fresh install, you will need to migrate database schema. 
 | 
			
		||||
 | 
			
		||||
   The path to console tool must be adapted to the app. To load migration and add fixtures, one can execute the following commands:
 | 
			
		||||
 | 
			
		||||
   .. code-block:: bash
 | 
			
		||||
      
 | 
			
		||||
      tests/app/bin/console doctrine:migrations:migrate
 | 
			
		||||
      tests/app/bin/console doctrine:fixtures:load
 | 
			
		||||
 | 
			
		||||
@@ -97,7 +97,7 @@ The has the following signature :
 | 
			
		||||
         * 
 | 
			
		||||
         * @param string $context
 | 
			
		||||
         * @param mixed[] $args the argument to the context.
 | 
			
		||||
         * @return TimelineSingleQuery
 | 
			
		||||
         * @return string[]
 | 
			
		||||
         * @throw  \LogicException if the context is not supported
 | 
			
		||||
         */
 | 
			
		||||
        public function fetchQuery($context, array $args);
 | 
			
		||||
@@ -163,16 +163,18 @@ The has the following signature :
 | 
			
		||||
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
 | 
			
		||||
* `type`: a string to indicate the type
 | 
			
		||||
* `date`: the name of the datetime column, used to order entities by date
 | 
			
		||||
* `FROM`: the FROM clause. May contains JOIN instructions
 | 
			
		||||
* `WHERE`: the WHERE clause;
 | 
			
		||||
* `parameters`: the parameters to pass to the query
 | 
			
		||||
* `FROM` (in capital) : the FROM clause. May contains JOIN instructions
 | 
			
		||||
 | 
			
		||||
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.
 | 
			
		||||
 | 
			
		||||
@@ -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
 | 
			
		||||
    );
 | 
			
		||||
 | 
			
		||||
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.
 | 
			
		||||
 | 
			
		||||
.. note::
 | 
			
		||||
@@ -206,12 +199,13 @@ Example of an implementation :
 | 
			
		||||
    namespace Chill\ReportBundle\Timeline;
 | 
			
		||||
 | 
			
		||||
    use Chill\MainBundle\Timeline\TimelineProviderInterface;
 | 
			
		||||
    use Chill\MainBundle\Timeline\TimelineSingleQuery;
 | 
			
		||||
    use Doctrine\ORM\EntityManager;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 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
 | 
			
		||||
    {
 | 
			
		||||
@@ -233,17 +227,16 @@ Example of an implementation :
 | 
			
		||||
                
 | 
			
		||||
                $metadata = $this->em->getClassMetadata('ChillReportBundle:Report');
 | 
			
		||||
                
 | 
			
		||||
                return TimelineSingleQuery::fromArray([
 | 
			
		||||
                return array(
 | 
			
		||||
                   'id' => $metadata->getColumnName('id'),
 | 
			
		||||
                   'type' => 'report',
 | 
			
		||||
                   'date' => $metadata->getColumnName('date'),
 | 
			
		||||
                   'FROM' => $metadata->getTableName(),
 | 
			
		||||
                   'WHERE' => sprintf('%s = ?',
 | 
			
		||||
                   'WHERE' => sprintf('%s = %d',
 | 
			
		||||
                         $metadata
 | 
			
		||||
                            ->getAssociationMapping('person')['joinColumns'][0]['name'])
 | 
			
		||||
                         )
 | 
			
		||||
                   'parameters' => [ $args['person']->getId() ]
 | 
			
		||||
                ]);
 | 
			
		||||
                            ->getAssociationMapping('person')['joinColumns'][0]['name'],
 | 
			
		||||
                         $args['person']->getId())
 | 
			
		||||
                );
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
        //....
 | 
			
		||||
 
 | 
			
		||||
@@ -82,7 +82,7 @@ Chill will be available at ``http://localhost:8001.`` Currently, there isn't any
 | 
			
		||||
 | 
			
		||||
.. 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:
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -1,45 +0,0 @@
 | 
			
		||||
<?php
 | 
			
		||||
 | 
			
		||||
declare(strict_types=1);
 | 
			
		||||
 | 
			
		||||
use Symfony\Component\DependencyInjection\Loader\Configurator\ContainerConfigurator;
 | 
			
		||||
use Symplify\ComposerJsonManipulator\ValueObject\ComposerJsonSection;
 | 
			
		||||
use Symplify\MonorepoBuilder\Release\ReleaseWorker\PushNextDevReleaseWorker;
 | 
			
		||||
use Symplify\MonorepoBuilder\Release\ReleaseWorker\PushTagReleaseWorker;
 | 
			
		||||
use Symplify\MonorepoBuilder\Release\ReleaseWorker\SetCurrentMutualDependenciesReleaseWorker;
 | 
			
		||||
use Symplify\MonorepoBuilder\Release\ReleaseWorker\SetNextMutualDependenciesReleaseWorker;
 | 
			
		||||
use Symplify\MonorepoBuilder\Release\ReleaseWorker\TagVersionReleaseWorker;
 | 
			
		||||
use Symplify\MonorepoBuilder\Release\ReleaseWorker\UpdateBranchAliasReleaseWorker;
 | 
			
		||||
use Symplify\MonorepoBuilder\Release\ReleaseWorker\UpdateReplaceReleaseWorker;
 | 
			
		||||
use Symplify\MonorepoBuilder\ValueObject\Option;
 | 
			
		||||
 | 
			
		||||
return static function (ContainerConfigurator $containerConfigurator): void {
 | 
			
		||||
    $parameters = $containerConfigurator->parameters();
 | 
			
		||||
 | 
			
		||||
    // where are the packages located?
 | 
			
		||||
    $parameters->set(Option::PACKAGE_DIRECTORIES, [
 | 
			
		||||
        // default value
 | 
			
		||||
        __DIR__ . '/src/Bundle',
 | 
			
		||||
    ]);
 | 
			
		||||
 | 
			
		||||
    // for "merge" command
 | 
			
		||||
    $parameters->set(
 | 
			
		||||
        Option::DATA_TO_APPEND,
 | 
			
		||||
        [
 | 
			
		||||
            ComposerJsonSection::REQUIRE_DEV => [
 | 
			
		||||
                'phpunit/phpunit' => '^9.5',
 | 
			
		||||
            ],
 | 
			
		||||
        ]
 | 
			
		||||
    );
 | 
			
		||||
 | 
			
		||||
    $services = $containerConfigurator->services();
 | 
			
		||||
 | 
			
		||||
    # release workers - in order to execute
 | 
			
		||||
    $services->set(UpdateReplaceReleaseWorker::class);
 | 
			
		||||
    $services->set(SetCurrentMutualDependenciesReleaseWorker::class);
 | 
			
		||||
    $services->set(TagVersionReleaseWorker::class);
 | 
			
		||||
    $services->set(PushTagReleaseWorker::class);
 | 
			
		||||
    $services->set(SetNextMutualDependenciesReleaseWorker::class);
 | 
			
		||||
    $services->set(UpdateBranchAliasReleaseWorker::class);
 | 
			
		||||
    $services->set(PushNextDevReleaseWorker::class);
 | 
			
		||||
};
 | 
			
		||||
@@ -18,20 +18,12 @@
 | 
			
		||||
       <testsuite name="MainBundle">
 | 
			
		||||
         <directory suffix="Test.php">src/Bundle/ChillMainBundle/Tests/</directory>
 | 
			
		||||
       </testsuite>
 | 
			
		||||
 | 
			
		||||
       <testsuite name="PersonBundle">
 | 
			
		||||
         <directory suffix="Test.php">src/Bundle/ChillPersonBundle/Tests/</directory>
 | 
			
		||||
         <!-- 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>
 | 
			
		||||
    </testsuites>
 | 
			
		||||
 | 
			
		||||
      </testsuites>
 | 
			
		||||
 | 
			
		||||
    <listeners>
 | 
			
		||||
        <listener class="Symfony\Bridge\PhpUnit\SymfonyTestsListener" />
 | 
			
		||||
 
 | 
			
		||||
@@ -52,6 +52,7 @@ class ChillActivityExtension extends Extension implements PrependExtensionInterf
 | 
			
		||||
        $loader->load('services/export.yaml');
 | 
			
		||||
        $loader->load('services/repositories.yaml');
 | 
			
		||||
        $loader->load('services/fixtures.yaml');
 | 
			
		||||
        $loader->load('services/menu.yaml');
 | 
			
		||||
        $loader->load('services/controller.yaml');
 | 
			
		||||
        $loader->load('services/form.yaml');
 | 
			
		||||
        $loader->load('services/templating.yaml');
 | 
			
		||||
 
 | 
			
		||||
@@ -38,7 +38,7 @@ use Chill\MainBundle\Validator\Constraints\Entity\UserCircleConsistency;
 | 
			
		||||
 * Class Activity
 | 
			
		||||
 *
 | 
			
		||||
 * @package Chill\ActivityBundle\Entity
 | 
			
		||||
 * @ORM\Entity(repositoryClass="Chill\ActivityBundle\Repository\ActivityRepository")
 | 
			
		||||
 * @ORM\Entity()
 | 
			
		||||
 * @ORM\Table(name="activity")
 | 
			
		||||
 * @ORM\HasLifecycleCallbacks()
 | 
			
		||||
 * @UserCircleConsistency(
 | 
			
		||||
 
 | 
			
		||||
@@ -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];
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
@@ -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);
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
}
 | 
			
		||||
@@ -1,11 +1,11 @@
 | 
			
		||||
{% import 'ChillActivityBundle:ActivityReason:macro.html.twig' as m %}
 | 
			
		||||
 | 
			
		||||
<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">
 | 
			
		||||
        <span class="statement">{{ '%user% has done an %activity_type%'|trans(
 | 
			
		||||
           {
 | 
			
		||||
             '%user%' : activity.user,
 | 
			
		||||
             '%user%' : user,
 | 
			
		||||
             '%activity_type%': activity.type.name|localize_translatable_string,
 | 
			
		||||
             '%date%' : activity.date|format_date('long') }
 | 
			
		||||
        ) }}</span>
 | 
			
		||||
@@ -29,13 +29,13 @@
 | 
			
		||||
 | 
			
		||||
    <ul class="record_actions">
 | 
			
		||||
        <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 }}
 | 
			
		||||
            </a>
 | 
			
		||||
        </li>
 | 
			
		||||
        {% if is_granted('CHILL_ACTIVITY_UPDATE', activity) %}
 | 
			
		||||
        <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 }}
 | 
			
		||||
            </a>
 | 
			
		||||
        </li>
 | 
			
		||||
 
 | 
			
		||||
@@ -21,7 +21,6 @@
 | 
			
		||||
namespace Chill\ActivityBundle\Timeline;
 | 
			
		||||
 | 
			
		||||
use Chill\MainBundle\Timeline\TimelineProviderInterface;
 | 
			
		||||
use Chill\ActivityBundle\Repository\ActivityACLAwareRepository;
 | 
			
		||||
use Doctrine\ORM\EntityManager;
 | 
			
		||||
use Chill\MainBundle\Security\Authorization\AuthorizationHelper;
 | 
			
		||||
use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface;
 | 
			
		||||
@@ -29,13 +28,13 @@ use Symfony\Component\Security\Core\Role\Role;
 | 
			
		||||
use Doctrine\ORM\Mapping\ClassMetadata;
 | 
			
		||||
use Chill\PersonBundle\Entity\Person;
 | 
			
		||||
use Chill\MainBundle\Entity\Scope;
 | 
			
		||||
use Chill\ActivityBundle\Entity\Activity;
 | 
			
		||||
use Chill\MainBundle\Timeline\TimelineSingleQuery;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Provide activity for inclusion in timeline
 | 
			
		||||
 *
 | 
			
		||||
*/
 | 
			
		||||
 * @author Julien Fastré <julien.fastre@champs-libres.coop>
 | 
			
		||||
 * @author Champs Libres <info@champs-libres.coop>
 | 
			
		||||
 */
 | 
			
		||||
class TimelineActivityProvider implements TimelineProviderInterface
 | 
			
		||||
{
 | 
			
		||||
    
 | 
			
		||||
@@ -56,10 +55,6 @@ class TimelineActivityProvider implements TimelineProviderInterface
 | 
			
		||||
     * @var \Chill\MainBundle\Entity\User 
 | 
			
		||||
     */
 | 
			
		||||
    protected $user;
 | 
			
		||||
 | 
			
		||||
    protected ActivityACLAwareRepository $aclAwareRepository;
 | 
			
		||||
 | 
			
		||||
    private const SUPPORTED_CONTEXTS = [ 'center', 'person'];
 | 
			
		||||
    
 | 
			
		||||
    /**
 | 
			
		||||
     * TimelineActivityProvider constructor.
 | 
			
		||||
@@ -71,13 +66,11 @@ class TimelineActivityProvider implements TimelineProviderInterface
 | 
			
		||||
    public function __construct(
 | 
			
		||||
        EntityManager $em,
 | 
			
		||||
        AuthorizationHelper $helper,
 | 
			
		||||
        TokenStorageInterface $storage,
 | 
			
		||||
        ActivityACLAwareRepository $aclAwareRepository
 | 
			
		||||
        TokenStorageInterface $storage
 | 
			
		||||
    )
 | 
			
		||||
    {
 | 
			
		||||
        $this->em = $em;
 | 
			
		||||
        $this->helper = $helper;
 | 
			
		||||
        $this->aclAwareRepository = $aclAwareRepository;
 | 
			
		||||
        
 | 
			
		||||
        if (!$storage->getToken()->getUser() instanceof \Chill\MainBundle\Entity\User)
 | 
			
		||||
        {
 | 
			
		||||
@@ -93,69 +86,67 @@ class TimelineActivityProvider implements TimelineProviderInterface
 | 
			
		||||
     */
 | 
			
		||||
    public function fetchQuery($context, array $args)
 | 
			
		||||
    {
 | 
			
		||||
        if ('center' === $context) {
 | 
			
		||||
            return TimelineSingleQuery::fromArray($this->aclAwareRepository
 | 
			
		||||
                ->queryTimelineIndexer($context, $args));
 | 
			
		||||
        }
 | 
			
		||||
        $this->checkContext($context);
 | 
			
		||||
        
 | 
			
		||||
        $metadataActivity = $this->em->getClassMetadata(Activity::class);
 | 
			
		||||
 | 
			
		||||
        [$where, $parameters] =  $this->getWhereClauseForPerson($args['person']);
 | 
			
		||||
        $metadataActivity = $this->em->getClassMetadata('ChillActivityBundle:Activity');
 | 
			
		||||
        $metadataPerson = $this->em->getClassMetadata('ChillPersonBundle:Person');
 | 
			
		||||
        
 | 
			
		||||
        return TimelineSingleQuery::fromArray([
 | 
			
		||||
        return array(
 | 
			
		||||
           'id' => $metadataActivity->getTableName()
 | 
			
		||||
                .'.'.$metadataActivity->getColumnName('id'),
 | 
			
		||||
           'type' => 'activity',
 | 
			
		||||
           'date' => $metadataActivity->getTableName()
 | 
			
		||||
                .'.'.$metadataActivity->getColumnName('date'),
 | 
			
		||||
           'FROM' => $this->getFromClausePerson($args['person']),
 | 
			
		||||
           'WHERE' => $where,
 | 
			
		||||
           'parameters' => $parameters
 | 
			
		||||
       ]);
 | 
			
		||||
           'FROM' => $this->getFromClause($metadataActivity, $metadataPerson),
 | 
			
		||||
           'WHERE' => $this->getWhereClause($metadataActivity, $metadataPerson,
 | 
			
		||||
                   $args['person'])
 | 
			
		||||
        );
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    private function getWhereClauseForPerson(Person $person)
 | 
			
		||||
    private function getWhereClause(ClassMetadata $metadataActivity, 
 | 
			
		||||
            ClassMetadata $metadataPerson, 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();
 | 
			
		||||
        $reachableCenters = $this->helper->getReachableCenters($this->user, 
 | 
			
		||||
                $role);
 | 
			
		||||
        $associationMapping = $metadataActivity->getAssociationMapping('person');
 | 
			
		||||
        
 | 
			
		||||
        if (count($reachableCenters) === 0) {
 | 
			
		||||
            return 'FALSE = TRUE';
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return [
 | 
			
		||||
            \strtr(
 | 
			
		||||
                $whereClause,
 | 
			
		||||
                [
 | 
			
		||||
                    '{activity.person_id}' => $associationMapping['joinColumns'][0]['name'],
 | 
			
		||||
                    '{activity.scope_id}' => $metadataActivity->getTableName().'.'.
 | 
			
		||||
        
 | 
			
		||||
        // 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 = array();
 | 
			
		||||
        foreach ($reachableCenters as $center) {
 | 
			
		||||
            $reachablesScopesId = array_map(
 | 
			
		||||
                    function(Scope $scope) { return $scope->getId(); },
 | 
			
		||||
                    $this->helper->getReachableScopes($this->user, $role, 
 | 
			
		||||
                        $person->getCenter())
 | 
			
		||||
                );
 | 
			
		||||
                    
 | 
			
		||||
            $centerAndScopeLines[] = sprintf('(%s = %d AND %s IN (%s))',
 | 
			
		||||
                    $metadataPerson->getTableName().'.'.
 | 
			
		||||
                        $metadataPerson->getAssociationMapping('center')['joinColumns'][0]['name'],
 | 
			
		||||
                    $center->getId(),
 | 
			
		||||
                    $metadataActivity->getTableName().'.'.
 | 
			
		||||
                        $metadataActivity->getAssociationMapping('scope')['joinColumns'][0]['name'],
 | 
			
		||||
                    '{scopes_ids}' => \implode(", ", $scopes_ids)
 | 
			
		||||
,
 | 
			
		||||
                ]
 | 
			
		||||
            ),
 | 
			
		||||
            $parameters
 | 
			
		||||
        ];
 | 
			
		||||
                    implode(',', $reachablesScopesId));
 | 
			
		||||
            
 | 
			
		||||
        }
 | 
			
		||||
        $whereClause .= ' AND ('.implode(' OR ', $centerAndScopeLines).')';
 | 
			
		||||
        
 | 
			
		||||
        return $whereClause;
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    private function getFromClausePerson()
 | 
			
		||||
    private function getFromClause(ClassMetadata $metadataActivity,
 | 
			
		||||
            ClassMetadata $metadataPerson)
 | 
			
		||||
    {
 | 
			
		||||
        $metadataActivity = $this->em->getClassMetadata(Activity::class);
 | 
			
		||||
        $metadataPerson = $this->em->getClassMetadata(Person::class);
 | 
			
		||||
        $associationMapping = $metadataActivity->getAssociationMapping('person');
 | 
			
		||||
        
 | 
			
		||||
        return $metadataActivity->getTableName().' JOIN '
 | 
			
		||||
@@ -166,14 +157,14 @@ class TimelineActivityProvider implements TimelineProviderInterface
 | 
			
		||||
            .$associationMapping['joinColumns'][0]['name']
 | 
			
		||||
            ;
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 
 | 
			
		||||
     * {@inheritDoc}
 | 
			
		||||
     */
 | 
			
		||||
    public function getEntities(array $ids)
 | 
			
		||||
    {
 | 
			
		||||
        $activities = $this->em->getRepository(Activity::class)
 | 
			
		||||
        $activities = $this->em->getRepository('ChillActivityBundle:Activity')
 | 
			
		||||
              ->findBy(array('id' => $ids));
 | 
			
		||||
        
 | 
			
		||||
        $result = array();
 | 
			
		||||
@@ -192,13 +183,14 @@ class TimelineActivityProvider implements TimelineProviderInterface
 | 
			
		||||
    {
 | 
			
		||||
        $this->checkContext($context);
 | 
			
		||||
        
 | 
			
		||||
        return [
 | 
			
		||||
        return array(
 | 
			
		||||
           'template' => 'ChillActivityBundle:Timeline:activity_person_context.html.twig',
 | 
			
		||||
           'template_data' => [
 | 
			
		||||
           'template_data' => array(
 | 
			
		||||
              'activity' => $entity,
 | 
			
		||||
              'context' => $context
 | 
			
		||||
            ]
 | 
			
		||||
        ];
 | 
			
		||||
              'person' => $args['person'],
 | 
			
		||||
              'user' => $entity->getUser()
 | 
			
		||||
           )
 | 
			
		||||
        );
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
@@ -218,7 +210,7 @@ class TimelineActivityProvider implements TimelineProviderInterface
 | 
			
		||||
     */
 | 
			
		||||
    private function checkContext($context)
 | 
			
		||||
    {
 | 
			
		||||
        if (FALSE === \in_array($context, self::SUPPORTED_CONTEXTS)) {
 | 
			
		||||
        if ($context !== 'person') {
 | 
			
		||||
            throw new \LogicException("The context '$context' is not "
 | 
			
		||||
                  . "supported. Currently only 'person' is supported");
 | 
			
		||||
        }
 | 
			
		||||
 
 | 
			
		||||
@@ -3,17 +3,13 @@
 | 
			
		||||
    "description": "This bundle extend chill for recording the different activities of the user",
 | 
			
		||||
    "type": "symfony-bundle",
 | 
			
		||||
    "license": "AGPL-3.0",
 | 
			
		||||
    "keywords": ["chill", "social work"],
 | 
			
		||||
    "homepage": "https://github.com/Chill-project/Activity",
 | 
			
		||||
    "keywords" : ["chill", "social work"],
 | 
			
		||||
    "homepage" : "https://github.com/Chill-project/Activity",
 | 
			
		||||
    "autoload": {
 | 
			
		||||
        "psr-4": {
 | 
			
		||||
            "Chill\\ActivityBundle\\": ""
 | 
			
		||||
        }
 | 
			
		||||
        "psr-4": { "Chill\\ActivityBundle\\": "" }
 | 
			
		||||
    },
 | 
			
		||||
    "autoload-dev": {
 | 
			
		||||
        "classmap": [
 | 
			
		||||
            "Resources/test/Fixtures/App/app/AppKernel.php"
 | 
			
		||||
        ]
 | 
			
		||||
        "classmap": [ "Resources/test/Fixtures/App/app/AppKernel.php" ]
 | 
			
		||||
    },
 | 
			
		||||
    "authors": [
 | 
			
		||||
        {
 | 
			
		||||
@@ -21,6 +17,10 @@
 | 
			
		||||
            "email": "info@champs-libres.coop"
 | 
			
		||||
        }
 | 
			
		||||
    ],
 | 
			
		||||
    "require": {
 | 
			
		||||
    },
 | 
			
		||||
    "require-dev": {
 | 
			
		||||
    },
 | 
			
		||||
    "scripts": {
 | 
			
		||||
        "post-install-cmd": [
 | 
			
		||||
            "ComposerBundleMigration\\Composer\\Migrations::synchronizeMigrations",
 | 
			
		||||
 
 | 
			
		||||
@@ -22,14 +22,6 @@ services:
 | 
			
		||||
            - '@doctrine.orm.entity_manager'
 | 
			
		||||
            - '@chill.main.security.authorization.helper'
 | 
			
		||||
            - '@security.token_storage'
 | 
			
		||||
            - '@Chill\ActivityBundle\Repository\ActivityACLAwareRepository'
 | 
			
		||||
        public: true
 | 
			
		||||
        tags:
 | 
			
		||||
            - { name: chill.timeline, context: 'person' }
 | 
			
		||||
            - { name: chill.timeline, context: 'center' }
 | 
			
		||||
 | 
			
		||||
    Chill\ActivityBundle\Menu\:
 | 
			
		||||
        autowire: true
 | 
			
		||||
        autoconfigure: true
 | 
			
		||||
        resource: '../Menu/'
 | 
			
		||||
        tags: ['chill.menu_builder']
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										8
									
								
								src/Bundle/ChillActivityBundle/config/services/menu.yaml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										8
									
								
								src/Bundle/ChillActivityBundle/config/services/menu.yaml
									
									
									
									
									
										Normal 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' }
 | 
			
		||||
@@ -1,32 +1,18 @@
 | 
			
		||||
---
 | 
			
		||||
services:
 | 
			
		||||
    chill_activity.repository.activity_type:
 | 
			
		||||
        class: Doctrine\ORM\EntityRepository
 | 
			
		||||
        factory: ['@doctrine.orm.entity_manager', getRepository]
 | 
			
		||||
        arguments:
 | 
			
		||||
            - 'Chill\ActivityBundle\Entity\ActivityType'
 | 
			
		||||
 | 
			
		||||
            
 | 
			
		||||
    chill_activity.repository.reason:
 | 
			
		||||
        class: Doctrine\ORM\EntityRepository
 | 
			
		||||
        factory: ['@doctrine.orm.entity_manager', getRepository]
 | 
			
		||||
        arguments:
 | 
			
		||||
            - 'Chill\ActivityBundle\Entity\ActivityReason'
 | 
			
		||||
 | 
			
		||||
            
 | 
			
		||||
    chill_activity.repository.reason_category:
 | 
			
		||||
        class: Doctrine\ORM\EntityRepository
 | 
			
		||||
        factory: ['@doctrine.orm.entity_manager', getRepository]
 | 
			
		||||
        arguments:
 | 
			
		||||
            - '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'
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -3,12 +3,13 @@
 | 
			
		||||
    "description": "This bundle extend chill for recording element of a budget for peoples",
 | 
			
		||||
    "type": "symfony-bundle",
 | 
			
		||||
    "license": "AGPL-3.0",
 | 
			
		||||
    "keywords": ["chill", "social work"],
 | 
			
		||||
    "homepage": "https://framagit.org/Chill-project/BudgetBundle",
 | 
			
		||||
    "keywords" : ["chill", "social work"],
 | 
			
		||||
    "homepage" : "https://framagit.org/Chill-project/BudgetBundle",
 | 
			
		||||
    "autoload": {
 | 
			
		||||
        "psr-4": {
 | 
			
		||||
            "Chill\\AMLI\\BudgetBundle\\": ""
 | 
			
		||||
        }
 | 
			
		||||
        "psr-4": { "Chill\\AMLI\\BudgetBundle\\": "" }
 | 
			
		||||
    },
 | 
			
		||||
    "autoload-dev": {
 | 
			
		||||
        "classmap": [ "Resources/test/Fixtures/App/app/AppKernel.php" ]
 | 
			
		||||
    },
 | 
			
		||||
    "authors": [
 | 
			
		||||
        {
 | 
			
		||||
@@ -16,8 +17,13 @@
 | 
			
		||||
            "email": "info@champs-libres.coop"
 | 
			
		||||
        }
 | 
			
		||||
    ],
 | 
			
		||||
    "require": {
 | 
			
		||||
    },
 | 
			
		||||
    "require-dev": {
 | 
			
		||||
    },
 | 
			
		||||
    "extra": {
 | 
			
		||||
        "app-migrations-dir": "Resources/test/Fixtures/App/app/DoctrineMigrations"
 | 
			
		||||
        "app-migrations-dir": "Resources/test/Fixtures/App/app/DoctrineMigrations",
 | 
			
		||||
        "symfony-app-dir": "Test/Fixtures/App/app/"
 | 
			
		||||
    },
 | 
			
		||||
    "minimum-stability": "dev",
 | 
			
		||||
    "prefer-stable": true
 | 
			
		||||
 
 | 
			
		||||
@@ -3,25 +3,25 @@
 | 
			
		||||
    "license": "AGPL-3.0",
 | 
			
		||||
    "type": "symfony-bundle",
 | 
			
		||||
    "description": "This bundle allow to add custom fields on entities.",
 | 
			
		||||
    "keywords": ["chill", "social work"],
 | 
			
		||||
    "homepage": "https://github.com/Chill-project/CustomFields",
 | 
			
		||||
    "keywords" : ["chill", "social work"],
 | 
			
		||||
    "homepage" : "https://github.com/Chill-project/CustomFields",
 | 
			
		||||
    "autoload": {
 | 
			
		||||
        "psr-4": {
 | 
			
		||||
            "Chill\\CustomFieldsBundle\\": ""
 | 
			
		||||
        }
 | 
			
		||||
        "psr-4": { "Chill\\CustomFieldsBundle\\": "" }
 | 
			
		||||
    },
 | 
			
		||||
    "autoload-dev": {
 | 
			
		||||
        "classmap": [
 | 
			
		||||
            "Resources/test/Fixtures/App/app/AppKernel.php"
 | 
			
		||||
        ]
 | 
			
		||||
        "classmap": [ "Resources/test/Fixtures/App/app/AppKernel.php" ]
 | 
			
		||||
    },
 | 
			
		||||
    "authors": [
 | 
			
		||||
    "authors" : [
 | 
			
		||||
        {
 | 
			
		||||
            "name": "Champs-Libres",
 | 
			
		||||
            "email": "info@champs-libres.coop",
 | 
			
		||||
            "homepage": "http://www.champs-libres.coop"
 | 
			
		||||
        }
 | 
			
		||||
    ],
 | 
			
		||||
    "require": {
 | 
			
		||||
    },
 | 
			
		||||
    "require-dev": {
 | 
			
		||||
    },
 | 
			
		||||
    "minimum-stability": "dev",
 | 
			
		||||
    "prefer-stable": true,
 | 
			
		||||
    "scripts": {
 | 
			
		||||
 
 | 
			
		||||
@@ -3,9 +3,9 @@
 | 
			
		||||
    "description": "A Chill bundle to store documents",
 | 
			
		||||
    "type": "symfony-bundle",
 | 
			
		||||
    "autoload": {
 | 
			
		||||
        "psr-4": {
 | 
			
		||||
            "Chill\\DocStoreBundle\\": ""
 | 
			
		||||
        }
 | 
			
		||||
      "psr-4": { "Chill\\DocStoreBundle\\" : "" }
 | 
			
		||||
    },
 | 
			
		||||
    "require": {
 | 
			
		||||
    },
 | 
			
		||||
    "license": "AGPL-3.0"
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -23,7 +23,6 @@ namespace Chill\EventBundle\Timeline;
 | 
			
		||||
use Chill\EventBundle\Entity\Event;
 | 
			
		||||
use Chill\MainBundle\Entity\Scope;
 | 
			
		||||
use Chill\MainBundle\Timeline\TimelineProviderInterface;
 | 
			
		||||
use Chill\MainBundle\Timeline\TimelineSingleQuery;
 | 
			
		||||
use Doctrine\ORM\EntityManager;
 | 
			
		||||
use Chill\MainBundle\Security\Authorization\AuthorizationHelper;
 | 
			
		||||
use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface;
 | 
			
		||||
@@ -89,14 +88,13 @@ class TimelineEventProvider implements TimelineProviderInterface
 | 
			
		||||
        $metadataParticipation = $this->em->getClassMetadata('ChillEventBundle:Participation');
 | 
			
		||||
        $metadataPerson = $this->em->getClassMetadata('ChillPersonBundle:Person');
 | 
			
		||||
        
 | 
			
		||||
        $query = TimelineSingleQuery::fromArray([
 | 
			
		||||
        $query = array(
 | 
			
		||||
            'id' => $metadataEvent->getTableName().'.'.$metadataEvent->getColumnName('id'),
 | 
			
		||||
            'type' => 'event',
 | 
			
		||||
            'date' => $metadataEvent->getTableName().'.'.$metadataEvent->getColumnName('date'),
 | 
			
		||||
            'FROM' => $this->getFromClause($metadataEvent, $metadataParticipation, $metadataPerson),
 | 
			
		||||
            'WHERE' => $this->getWhereClause($metadataEvent, $metadataParticipation, $metadataPerson, $args['person']),
 | 
			
		||||
            'parameters' => []
 | 
			
		||||
        ]);
 | 
			
		||||
            'WHERE' => $this->getWhereClause($metadataEvent, $metadataParticipation, $metadataPerson, $args['person'])
 | 
			
		||||
        );
 | 
			
		||||
        
 | 
			
		||||
        return $query;
 | 
			
		||||
    }
 | 
			
		||||
@@ -240,4 +238,4 @@ class TimelineEventProvider implements TimelineProviderInterface
 | 
			
		||||
        );
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
}
 | 
			
		||||
}
 | 
			
		||||
@@ -3,18 +3,16 @@
 | 
			
		||||
    "description": "This bundle extend chill software. This bundle allow to define event and participation to those events.",
 | 
			
		||||
    "type": "symfony-bundle",
 | 
			
		||||
    "license": "AGPL-3.0-only",
 | 
			
		||||
    "keywords": ["chill", "social work"],
 | 
			
		||||
    "homepage": "https://git.framasoft.org/Chill-project/Chill-Group",
 | 
			
		||||
    "keywords" : ["chill", "social work"],
 | 
			
		||||
    "homepage" : "https://git.framasoft.org/Chill-project/Chill-Group",
 | 
			
		||||
    "autoload": {
 | 
			
		||||
        "psr-4": {
 | 
			
		||||
            "Chill\\EventBundle\\": ""
 | 
			
		||||
        }
 | 
			
		||||
        "psr-4": { "Chill\\EventBundle\\": "" }
 | 
			
		||||
    },
 | 
			
		||||
    "support": {
 | 
			
		||||
        "issues": "https://git.framasoft.org/Chill-project/Chill-Event/issues",
 | 
			
		||||
        "source": "https://git.framasoft.org/Chill-project/Chill-Event",
 | 
			
		||||
        "docs": "http://docs.chill.social",
 | 
			
		||||
        "email": "dev@listes.chill.social"
 | 
			
		||||
        "docs" :  "http://docs.chill.social",
 | 
			
		||||
        "email":  "dev@listes.chill.social"
 | 
			
		||||
    },
 | 
			
		||||
    "authors": [
 | 
			
		||||
        {
 | 
			
		||||
@@ -22,7 +20,11 @@
 | 
			
		||||
            "email": "info@champs-libres.coop"
 | 
			
		||||
        }
 | 
			
		||||
    ],
 | 
			
		||||
    "suggest": {
 | 
			
		||||
    "require": {
 | 
			
		||||
    },
 | 
			
		||||
    "require-dev": {
 | 
			
		||||
    },
 | 
			
		||||
    "suggest" : {
 | 
			
		||||
        "chill-project/group": "dev-master@dev"
 | 
			
		||||
    },
 | 
			
		||||
    "scripts": {
 | 
			
		||||
 
 | 
			
		||||
@@ -3,12 +3,13 @@
 | 
			
		||||
    "description": "This bundle extend chill for recording family members into a file",
 | 
			
		||||
    "type": "symfony-bundle",
 | 
			
		||||
    "license": "AGPL-3.0-or-later",
 | 
			
		||||
    "keywords": ["chill", "social work"],
 | 
			
		||||
    "homepage": "https://framagit.org/Chill-project/Chill-FamilyMembers",
 | 
			
		||||
    "keywords" : ["chill", "social work"],
 | 
			
		||||
    "homepage" : "https://framagit.org/Chill-project/Chill-FamilyMembers",
 | 
			
		||||
    "autoload": {
 | 
			
		||||
        "psr-4": {
 | 
			
		||||
            "Chill\\AMLI\\FamilyMembersBundle\\": ""
 | 
			
		||||
        }
 | 
			
		||||
        "psr-4": { "Chill\\AMLI\\FamilyMembersBundle\\": "" }
 | 
			
		||||
    },
 | 
			
		||||
    "autoload-dev": {
 | 
			
		||||
        "classmap": [ "Resources/test/Fixtures/App/app/AppKernel.php" ]
 | 
			
		||||
    },
 | 
			
		||||
    "authors": [
 | 
			
		||||
        {
 | 
			
		||||
@@ -16,8 +17,13 @@
 | 
			
		||||
            "email": "info@champs-libres.coop"
 | 
			
		||||
        }
 | 
			
		||||
    ],
 | 
			
		||||
    "require": {
 | 
			
		||||
    },
 | 
			
		||||
    "require-dev": {
 | 
			
		||||
    },
 | 
			
		||||
    "extra": {
 | 
			
		||||
        "app-migrations-dir": "Resources/test/Fixtures/App/app/DoctrineMigrations"
 | 
			
		||||
        "app-migrations-dir": "Resources/test/Fixtures/App/app/DoctrineMigrations",
 | 
			
		||||
        "symfony-app-dir": "Test/Fixtures/App/app/"
 | 
			
		||||
    },
 | 
			
		||||
    "minimum-stability": "dev",
 | 
			
		||||
    "prefer-stable": true
 | 
			
		||||
 
 | 
			
		||||
@@ -1,77 +0,0 @@
 | 
			
		||||
<?php
 | 
			
		||||
/*
 | 
			
		||||
 * Copyright (C) 2018 Champs Libres Cooperative <info@champs-libres.coop>
 | 
			
		||||
 *
 | 
			
		||||
 * This program is free software: you can redistribute it and/or modify
 | 
			
		||||
 * it under the terms of the GNU Affero General Public License as published by
 | 
			
		||||
 * the Free Software Foundation, either version 3 of the License, or
 | 
			
		||||
 * (at your option) any later version.
 | 
			
		||||
 *
 | 
			
		||||
 * This program is distributed in the hope that it will be useful,
 | 
			
		||||
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
			
		||||
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
			
		||||
 * GNU Affero General Public License for more details.
 | 
			
		||||
 *
 | 
			
		||||
 * You should have received a copy of the GNU Affero General Public License
 | 
			
		||||
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 | 
			
		||||
 */
 | 
			
		||||
namespace Chill\MainBundle\CRUD\CompilerPass;
 | 
			
		||||
 | 
			
		||||
use Symfony\Component\DependencyInjection\ContainerBuilder;
 | 
			
		||||
use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
 | 
			
		||||
use Symfony\Component\DependencyInjection\Reference;
 | 
			
		||||
use Chill\MainBundle\Routing\MenuComposer;
 | 
			
		||||
use Symfony\Component\DependencyInjection\Definition;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 
 | 
			
		||||
 *
 | 
			
		||||
 */
 | 
			
		||||
class CRUDControllerCompilerPass implements CompilerPassInterface
 | 
			
		||||
{
 | 
			
		||||
    public function process(ContainerBuilder $container)
 | 
			
		||||
    {
 | 
			
		||||
        $crudConfig = $container->getParameter('chill_main_crud_route_loader_config');
 | 
			
		||||
        $apiConfig = $container->getParameter('chill_main_api_route_loader_config');
 | 
			
		||||
 | 
			
		||||
        foreach ($crudConfig as $crudEntry) {
 | 
			
		||||
            $this->configureCrudController($container, $crudEntry, 'crud');
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        foreach ($apiConfig as $crudEntry) {
 | 
			
		||||
            $this->configureCrudController($container, $crudEntry, 'api');
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Add a controller for each definition, and add a methodCall to inject crud configuration to controller
 | 
			
		||||
     */
 | 
			
		||||
    private function configureCrudController(ContainerBuilder $container, array $crudEntry, string $apiOrCrud): void
 | 
			
		||||
    {
 | 
			
		||||
        $controllerClass = $crudEntry['controller'];
 | 
			
		||||
 | 
			
		||||
        $controllerServiceName = 'cs'.$apiOrCrud.'_'.$crudEntry['name'].'_controller';
 | 
			
		||||
 | 
			
		||||
        if ($container->hasDefinition($controllerClass)) {
 | 
			
		||||
            $controller = $container->getDefinition($controllerClass);
 | 
			
		||||
            $container->removeDefinition($controllerClass);
 | 
			
		||||
            $alreadyDefined = true;
 | 
			
		||||
        } else {
 | 
			
		||||
            $controller = new Definition($controllerClass);
 | 
			
		||||
            $alreadyDefined = false;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        $controller->addTag('controller.service_arguments');
 | 
			
		||||
        if (FALSE === $alreadyDefined) {
 | 
			
		||||
            $controller->setAutoconfigured(true);
 | 
			
		||||
            $controller->setPublic(true);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        $param = 'chill_main_'.$apiOrCrud.'_config_'.$crudEntry['name'];
 | 
			
		||||
        $container->setParameter($param, $crudEntry);
 | 
			
		||||
        $controller->addMethodCall('setCrudConfig', ['%'.$param.'%']);
 | 
			
		||||
 | 
			
		||||
        $container->setDefinition($controllerServiceName, $controller);
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
}
 | 
			
		||||
@@ -1,251 +0,0 @@
 | 
			
		||||
<?php
 | 
			
		||||
 | 
			
		||||
namespace Chill\MainBundle\CRUD\Controller;
 | 
			
		||||
 | 
			
		||||
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
 | 
			
		||||
use Symfony\Component\HttpFoundation\Request;
 | 
			
		||||
use Symfony\Component\HttpFoundation\Response;
 | 
			
		||||
use Symfony\Component\Validator\Validator\ValidatorInterface;
 | 
			
		||||
use Chill\MainBundle\Pagination\PaginatorFactory;
 | 
			
		||||
use Chill\MainBundle\Pagination\PaginatorInterface;
 | 
			
		||||
 | 
			
		||||
class AbstractCRUDController extends AbstractController
 | 
			
		||||
{
 | 
			
		||||
    /**
 | 
			
		||||
     * The crud configuration 
 | 
			
		||||
     *
 | 
			
		||||
     * This configuration si defined by `chill_main['crud']` or `chill_main['apis']`
 | 
			
		||||
     *
 | 
			
		||||
     * @var array
 | 
			
		||||
     */
 | 
			
		||||
    protected array $crudConfig = [];
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * get the instance of the entity with the given id
 | 
			
		||||
     * 
 | 
			
		||||
     * @param string $id
 | 
			
		||||
     * @return object
 | 
			
		||||
     * @throw Symfony\Component\HttpKernel\Exception\NotFoundHttpException if the object is not found
 | 
			
		||||
     */
 | 
			
		||||
    protected function getEntity($action, $id, Request $request): object
 | 
			
		||||
    {
 | 
			
		||||
        $e = $this->getDoctrine()
 | 
			
		||||
            ->getRepository($this->getEntityClass())
 | 
			
		||||
            ->find($id);
 | 
			
		||||
 | 
			
		||||
        if (NULL === $e) {
 | 
			
		||||
            throw $this->createNotFoundException(sprintf("The object %s for id %s is not found", $this->getEntityClass(), $id));
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return $e;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Create an entity.
 | 
			
		||||
     * 
 | 
			
		||||
     * @param string $action
 | 
			
		||||
     * @param Request $request
 | 
			
		||||
     * @return object
 | 
			
		||||
     */
 | 
			
		||||
    protected function createEntity(string $action, Request $request): object
 | 
			
		||||
    {
 | 
			
		||||
        $type = $this->getEntityClass();
 | 
			
		||||
        
 | 
			
		||||
        return new $type;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Count the number of entities
 | 
			
		||||
     *
 | 
			
		||||
     * By default, count all entities. You can customize the query by 
 | 
			
		||||
     * using the method `customizeQuery`.
 | 
			
		||||
     * 
 | 
			
		||||
     * @param string $action
 | 
			
		||||
     * @param Request $request
 | 
			
		||||
     * @return int
 | 
			
		||||
     */
 | 
			
		||||
    protected function countEntities(string $action, Request $request, $_format): int
 | 
			
		||||
    {
 | 
			
		||||
        return $this->buildQueryEntities($action, $request)
 | 
			
		||||
            ->select('COUNT(e)')
 | 
			
		||||
            ->getQuery()
 | 
			
		||||
            ->getSingleScalarResult()
 | 
			
		||||
            ;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Query the entity.
 | 
			
		||||
     * 
 | 
			
		||||
     * By default, get all entities. You can customize the query by using the
 | 
			
		||||
     * method `customizeQuery`.
 | 
			
		||||
     * 
 | 
			
		||||
     * The method `orderEntity` is called internally to order entities.
 | 
			
		||||
     * 
 | 
			
		||||
     * It returns, by default, a query builder.
 | 
			
		||||
     * 
 | 
			
		||||
     */
 | 
			
		||||
    protected function queryEntities(string $action, Request $request, string $_format, PaginatorInterface $paginator)
 | 
			
		||||
    {
 | 
			
		||||
        $query = $this->buildQueryEntities($action, $request)
 | 
			
		||||
            ->setFirstResult($paginator->getCurrentPage()->getFirstItemNumber())
 | 
			
		||||
            ->setMaxResults($paginator->getItemsPerPage());
 | 
			
		||||
        
 | 
			
		||||
        // allow to order queries and return the new query
 | 
			
		||||
        return $this->orderQuery($action, $query, $request, $paginator, $_format);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Add ordering fields in the query build by self::queryEntities
 | 
			
		||||
     * 
 | 
			
		||||
     */
 | 
			
		||||
    protected function orderQuery(string $action, $query, Request $request, PaginatorInterface $paginator, $_format)
 | 
			
		||||
    {
 | 
			
		||||
        return $query;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Build the base query for listing all entities.
 | 
			
		||||
     *
 | 
			
		||||
     * This method is used internally by `countEntities` `queryEntities`
 | 
			
		||||
     * 
 | 
			
		||||
     * This base query does not contains any `WHERE` or `SELECT` clauses. You
 | 
			
		||||
     * can add some by using the method `customizeQuery`.
 | 
			
		||||
     *
 | 
			
		||||
     * The alias for the entity is "e".
 | 
			
		||||
     * 
 | 
			
		||||
     * @param string $action
 | 
			
		||||
     * @param Request $request
 | 
			
		||||
     * @return QueryBuilder
 | 
			
		||||
     */
 | 
			
		||||
    protected function buildQueryEntities(string $action, Request $request)
 | 
			
		||||
    {
 | 
			
		||||
        $qb = $this->getDoctrine()->getManager()
 | 
			
		||||
            ->createQueryBuilder()
 | 
			
		||||
            ->select('e')
 | 
			
		||||
            ->from($this->getEntityClass(), 'e')
 | 
			
		||||
            ;
 | 
			
		||||
 | 
			
		||||
        $this->customizeQuery($action, $request, $qb);
 | 
			
		||||
 | 
			
		||||
        return $qb;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    protected function customizeQuery(string $action, Request $request, $query): void {}
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Get the result of the query
 | 
			
		||||
     */
 | 
			
		||||
    protected function getQueryResult(string $action, Request $request, string $_format, int $totalItems, PaginatorInterface $paginator, $query) 
 | 
			
		||||
    {
 | 
			
		||||
        return $query->getQuery()->getResult();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    protected function onPreIndex(string $action, Request $request, string $_format): ?Response
 | 
			
		||||
    { 
 | 
			
		||||
        return null; 
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    /**
 | 
			
		||||
     * method used by indexAction
 | 
			
		||||
     */
 | 
			
		||||
    protected function onPreIndexBuildQuery(string $action, Request $request, string $_format, int $totalItems, PaginatorInterface $paginator): ?Response
 | 
			
		||||
    { 
 | 
			
		||||
        return null;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * method used by indexAction
 | 
			
		||||
     */
 | 
			
		||||
    protected function onPostIndexBuildQuery(string $action, Request $request, string $_format, int $totalItems, PaginatorInterface $paginator, $query): ?Response
 | 
			
		||||
    {
 | 
			
		||||
        return null;
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    /**
 | 
			
		||||
     * method used by indexAction
 | 
			
		||||
     */
 | 
			
		||||
    protected function onPostIndexFetchQuery(string $action, Request $request, string $_format, int $totalItems, PaginatorInterface $paginator, $entities): ?Response
 | 
			
		||||
    {
 | 
			
		||||
        return null;
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Get the complete FQDN of the class
 | 
			
		||||
     * 
 | 
			
		||||
     * @return string the complete fqdn of the class
 | 
			
		||||
     */
 | 
			
		||||
    protected function getEntityClass(): string
 | 
			
		||||
    {
 | 
			
		||||
        return $this->crudConfig['class'];
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    /**
 | 
			
		||||
     * called on post fetch entity 
 | 
			
		||||
     */
 | 
			
		||||
    protected function onPostFetchEntity(string $action, Request $request, $entity, $_format): ?Response
 | 
			
		||||
    {
 | 
			
		||||
        return null;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Called on post check ACL
 | 
			
		||||
     */
 | 
			
		||||
    protected function onPostCheckACL(string $action, Request $request, string $_format, $entity): ?Response
 | 
			
		||||
    {
 | 
			
		||||
        return null;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * check the acl. Called by every action.
 | 
			
		||||
     * 
 | 
			
		||||
     * By default, check the role given by `getRoleFor` for the value given in 
 | 
			
		||||
     * $entity.
 | 
			
		||||
     * 
 | 
			
		||||
     * Throw an \Symfony\Component\Security\Core\Exception\AccessDeniedHttpException
 | 
			
		||||
     * if not accessible.
 | 
			
		||||
     * 
 | 
			
		||||
     * @throws \Symfony\Component\Security\Core\Exception\AccessDeniedHttpException
 | 
			
		||||
     */
 | 
			
		||||
    protected function checkACL(string $action, Request $request, string $_format, $entity = null)
 | 
			
		||||
    {
 | 
			
		||||
        $this->denyAccessUnlessGranted($this->getRoleFor($action, $request, $entity, $_format), $entity);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 
 | 
			
		||||
     * @return string the crud name
 | 
			
		||||
     */
 | 
			
		||||
    protected function getCrudName(): string
 | 
			
		||||
    {
 | 
			
		||||
        return $this->crudConfig['name'];
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    protected function getActionConfig(string $action)
 | 
			
		||||
    {
 | 
			
		||||
        return $this->crudConfig['actions'][$action];
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    /**
 | 
			
		||||
     * Set the crud configuration
 | 
			
		||||
     *
 | 
			
		||||
     * Used by the container to inject configuration for this crud.
 | 
			
		||||
     */
 | 
			
		||||
    public function setCrudConfig(array $config): void
 | 
			
		||||
    {
 | 
			
		||||
        $this->crudConfig = $config;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * @return PaginatorFactory
 | 
			
		||||
     */
 | 
			
		||||
    protected function getPaginatorFactory(): PaginatorFactory
 | 
			
		||||
    {
 | 
			
		||||
        return $this->container->get('chill_main.paginator_factory');
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    protected function getValidator(): ValidatorInterface
 | 
			
		||||
    {
 | 
			
		||||
        return $this->get('validator');
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -1,517 +0,0 @@
 | 
			
		||||
<?php
 | 
			
		||||
 | 
			
		||||
namespace Chill\MainBundle\CRUD\Controller;
 | 
			
		||||
 | 
			
		||||
use Symfony\Component\HttpFoundation\Request;
 | 
			
		||||
use Symfony\Component\HttpFoundation\Response;
 | 
			
		||||
use Symfony\Component\Routing\Annotation\Route;
 | 
			
		||||
use Symfony\Component\Serializer\SerializerInterface;
 | 
			
		||||
use Chill\MainBundle\Serializer\Model\Collection;
 | 
			
		||||
use Chill\MainBundle\Pagination\PaginatorInterface;
 | 
			
		||||
use Symfony\Component\Serializer\Normalizer\AbstractNormalizer;
 | 
			
		||||
use Symfony\Component\Validator\ConstraintViolationListInterface;
 | 
			
		||||
use Symfony\Component\Serializer\Exception\NotEncodableValueException;
 | 
			
		||||
use Symfony\Component\HttpFoundation\Exception\BadRequestException;
 | 
			
		||||
 | 
			
		||||
class ApiController extends AbstractCRUDController
 | 
			
		||||
{
 | 
			
		||||
    /**
 | 
			
		||||
     * The view action.
 | 
			
		||||
     * 
 | 
			
		||||
     * Some steps may be overriden during this process of rendering:
 | 
			
		||||
     * 
 | 
			
		||||
     * This method:
 | 
			
		||||
     * 
 | 
			
		||||
     * 1.  fetch the entity, using `getEntity`
 | 
			
		||||
     * 2.  launch `onPostFetchEntity`. If postfetch is an instance of Response,
 | 
			
		||||
     *     this response is returned.
 | 
			
		||||
     * 2.  throw an HttpNotFoundException if entity is null
 | 
			
		||||
     * 3.  check ACL using `checkACL` ;
 | 
			
		||||
     * 4.  launch `onPostCheckACL`. If the result is an instance of Response, 
 | 
			
		||||
     *     this response is returned ;
 | 
			
		||||
     * 5.  Serialize the entity and return the result. The serialization context is given by `getSerializationContext`
 | 
			
		||||
     * 
 | 
			
		||||
     */
 | 
			
		||||
    protected function entityGet(string $action, Request $request, $id, $_format = 'html'): Response
 | 
			
		||||
    {
 | 
			
		||||
        $entity = $this->getEntity($action, $id, $request, $_format);
 | 
			
		||||
        
 | 
			
		||||
        $postFetch = $this->onPostFetchEntity($action, $request, $entity, $_format);
 | 
			
		||||
        
 | 
			
		||||
        if ($postFetch instanceof Response) {
 | 
			
		||||
            return $postFetch;
 | 
			
		||||
        }
 | 
			
		||||
        
 | 
			
		||||
        $response = $this->checkACL($action, $request, $_format, $entity);
 | 
			
		||||
        if ($response instanceof Response) {
 | 
			
		||||
            return $response;
 | 
			
		||||
        }
 | 
			
		||||
        
 | 
			
		||||
        $response = $this->onPostCheckACL($action, $request, $_format, $entity);
 | 
			
		||||
        if ($response instanceof Response) {
 | 
			
		||||
            return $response;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        $response = $this->onBeforeSerialize($action, $request, $_format, $entity);
 | 
			
		||||
        if ($response instanceof Response) {
 | 
			
		||||
            return $response;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if ($_format === 'json') {
 | 
			
		||||
            $context = $this->getContextForSerialization($action, $request, $_format, $entity);
 | 
			
		||||
 | 
			
		||||
            return $this->json($entity, Response::HTTP_OK, [], $context);
 | 
			
		||||
        } else {
 | 
			
		||||
            throw new \Symfony\Component\HttpFoundation\Exception\BadRequestException("This format is not implemented");
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function onBeforeSerialize(string $action, Request $request, $_format, $entity): ?Response
 | 
			
		||||
    {
 | 
			
		||||
        return null;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Base method for handling api action
 | 
			
		||||
     *
 | 
			
		||||
     * @return void
 | 
			
		||||
     */
 | 
			
		||||
    public function entityApi(Request $request, $id, $_format): Response
 | 
			
		||||
    {
 | 
			
		||||
        switch ($request->getMethod()) {
 | 
			
		||||
            case Request::METHOD_GET:
 | 
			
		||||
            case Request::METHOD_HEAD:
 | 
			
		||||
                return $this->entityGet('_entity', $request, $id, $_format);
 | 
			
		||||
            case Request::METHOD_PUT:
 | 
			
		||||
            case Request::METHOD_PATCH:
 | 
			
		||||
                return $this->entityPut('_entity', $request, $id, $_format);
 | 
			
		||||
            case Request::METHOD_POST:
 | 
			
		||||
                return $this->entityPostAction('_entity', $request, $id, $_format);
 | 
			
		||||
            default:
 | 
			
		||||
                throw new \Symfony\Component\HttpFoundation\Exception\BadRequestException("This method is not implemented");
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    public function entityPost(Request $request, $_format): Response
 | 
			
		||||
    {
 | 
			
		||||
        switch($request->getMethod()) {
 | 
			
		||||
            case Request::METHOD_POST:
 | 
			
		||||
                return $this->entityPostAction('_entity', $request, $_format);
 | 
			
		||||
            default:
 | 
			
		||||
                throw new \Symfony\Component\HttpFoundation\Exception\BadRequestException("This method is not implemented");
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    protected function entityPostAction($action, Request $request, string $_format): Response
 | 
			
		||||
    {
 | 
			
		||||
        $entity = $this->createEntity($action, $request);
 | 
			
		||||
 | 
			
		||||
        try {
 | 
			
		||||
            $entity = $this->deserialize($action, $request, $_format, $entity);
 | 
			
		||||
        } catch (NotEncodableValueException $e) {
 | 
			
		||||
            throw new BadRequestException("invalid json", 400, $e);
 | 
			
		||||
        }
 | 
			
		||||
        
 | 
			
		||||
        $errors = $this->validate($action, $request, $_format, $entity);
 | 
			
		||||
        
 | 
			
		||||
        $response = $this->onAfterValidation($action, $request, $_format, $entity, $errors);
 | 
			
		||||
        if ($response instanceof Response) {
 | 
			
		||||
            return $response;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if ($errors->count() > 0) {
 | 
			
		||||
            $response = $this->json($errors);
 | 
			
		||||
            $response->setStatusCode(Response::HTTP_UNPROCESSABLE_ENTITY);
 | 
			
		||||
 | 
			
		||||
            return $response;
 | 
			
		||||
        }
 | 
			
		||||
        
 | 
			
		||||
        $response = $this->checkACL($action, $request, $_format, $entity);
 | 
			
		||||
        if ($response instanceof Response) {
 | 
			
		||||
            return $response;
 | 
			
		||||
        }
 | 
			
		||||
        
 | 
			
		||||
        $response = $this->onPostCheckACL($action, $request, $_format, $entity);
 | 
			
		||||
        if ($response instanceof Response) {
 | 
			
		||||
            return $response;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        $this->getDoctrine()->getManager()->persist($entity);
 | 
			
		||||
        $this->getDoctrine()->getManager()->flush();
 | 
			
		||||
 | 
			
		||||
        $response = $this->onAfterFlush($action, $request, $_format, $entity, $errors);
 | 
			
		||||
        if ($response instanceof Response) {
 | 
			
		||||
            return $response;
 | 
			
		||||
        }
 | 
			
		||||
        $response = $this->onBeforeSerialize($action, $request, $_format, $entity);
 | 
			
		||||
        if ($response instanceof Response) {
 | 
			
		||||
            return $response;
 | 
			
		||||
        }
 | 
			
		||||
        
 | 
			
		||||
        return $this->json(
 | 
			
		||||
            $entity,
 | 
			
		||||
            Response::HTTP_OK,
 | 
			
		||||
            [], 
 | 
			
		||||
            $this->getContextForSerializationPostAlter($action, $request, $_format, $entity)
 | 
			
		||||
        );
 | 
			
		||||
    }
 | 
			
		||||
    public function entityPut($action, Request $request, $id, string $_format): Response
 | 
			
		||||
    {
 | 
			
		||||
        $entity = $this->getEntity($action, $id, $request, $_format);
 | 
			
		||||
        
 | 
			
		||||
        $postFetch = $this->onPostFetchEntity($action, $request, $entity, $_format);
 | 
			
		||||
        if ($postFetch instanceof Response) {
 | 
			
		||||
            return $postFetch;
 | 
			
		||||
        }
 | 
			
		||||
        
 | 
			
		||||
        if (NULL === $entity) {
 | 
			
		||||
            throw $this->createNotFoundException(sprintf("The %s with id %s "
 | 
			
		||||
                . "is not found", $this->getCrudName(), $id));
 | 
			
		||||
        }
 | 
			
		||||
        
 | 
			
		||||
        $response = $this->checkACL($action, $request, $_format, $entity);
 | 
			
		||||
        if ($response instanceof Response) {
 | 
			
		||||
            return $response;
 | 
			
		||||
        }
 | 
			
		||||
        
 | 
			
		||||
        $response = $this->onPostCheckACL($action, $request, $_format, $entity);
 | 
			
		||||
        if ($response instanceof Response) {
 | 
			
		||||
            return $response;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        $response = $this->onBeforeSerialize($action, $request, $_format, $entity);
 | 
			
		||||
        if ($response instanceof Response) {
 | 
			
		||||
            return $response;
 | 
			
		||||
        }
 | 
			
		||||
        
 | 
			
		||||
        try {
 | 
			
		||||
            $entity = $this->deserialize($action, $request, $_format, $entity);
 | 
			
		||||
        } catch (NotEncodableValueException $e) {
 | 
			
		||||
            throw new BadRequestException("invalid json", 400, $e);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        $errors = $this->validate($action, $request, $_format, $entity);
 | 
			
		||||
 | 
			
		||||
        $response = $this->onAfterValidation($action, $request, $_format, $entity, $errors);
 | 
			
		||||
        if ($response instanceof Response) {
 | 
			
		||||
            return $response;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if ($errors->count() > 0) {
 | 
			
		||||
            $response = $this->json($errors);
 | 
			
		||||
            $response->setStatusCode(Response::HTTP_UNPROCESSABLE_ENTITY);
 | 
			
		||||
 | 
			
		||||
            return $response;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        $this->getDoctrine()->getManager()->flush();
 | 
			
		||||
 | 
			
		||||
        $response = $this->onAfterFlush($action, $request, $_format, $entity, $errors);
 | 
			
		||||
        if ($response instanceof Response) {
 | 
			
		||||
            return $response;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return $this->json(
 | 
			
		||||
            $entity,
 | 
			
		||||
            Response::HTTP_OK,
 | 
			
		||||
            [], 
 | 
			
		||||
            $this->getContextForSerializationPostAlter($action, $request, $_format, $entity)
 | 
			
		||||
        );
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    protected function onAfterValidation(string $action, Request $request, string $_format, $entity, ConstraintViolationListInterface $errors, array $more = []): ?Response
 | 
			
		||||
    {
 | 
			
		||||
        return null;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    protected function onAfterFlush(string $action, Request $request, string $_format, $entity, ConstraintViolationListInterface $errors, array $more = []): ?Response
 | 
			
		||||
    {
 | 
			
		||||
        return null;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    protected function getValidationGroups(string $action, Request $request, string $_format, $entity): ?array
 | 
			
		||||
    {
 | 
			
		||||
        return null;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    protected function validate(string $action, Request $request, string $_format, $entity, array $more = []): ConstraintViolationListInterface
 | 
			
		||||
    {
 | 
			
		||||
        $validationGroups = $this->getValidationGroups($action, $request, $_format, $entity);
 | 
			
		||||
        
 | 
			
		||||
        return $this->getValidator()->validate($entity, null, $validationGroups);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Deserialize the content of the request into the class associated with the curd
 | 
			
		||||
     */
 | 
			
		||||
    protected function deserialize(string $action, Request $request, string $_format, $entity = null): object
 | 
			
		||||
    {
 | 
			
		||||
        $default = [];
 | 
			
		||||
 | 
			
		||||
        if (NULL !== $entity) {
 | 
			
		||||
            $default[AbstractNormalizer::OBJECT_TO_POPULATE] = $entity;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        $context = \array_merge(
 | 
			
		||||
            $default,
 | 
			
		||||
            $this->getContextForSerialization($action, $request, $_format, $entity)
 | 
			
		||||
        );
 | 
			
		||||
 | 
			
		||||
        return $this->getSerializer()->deserialize($request->getContent(), $this->getEntityClass(), $_format, $context);
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Base action for indexing entities
 | 
			
		||||
     */
 | 
			
		||||
    public function indexApi(Request $request, string $_format)
 | 
			
		||||
    {
 | 
			
		||||
        switch ($request->getMethod()) {
 | 
			
		||||
            case Request::METHOD_GET:
 | 
			
		||||
            case REQUEST::METHOD_HEAD:
 | 
			
		||||
                return $this->indexApiAction('_index', $request, $_format);
 | 
			
		||||
            default:
 | 
			
		||||
                throw $this->createNotFoundException("This method is not supported");
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Build an index page.
 | 
			
		||||
     * 
 | 
			
		||||
     * Some steps may be overriden during this process of rendering.
 | 
			
		||||
     * 
 | 
			
		||||
     * This method:
 | 
			
		||||
     * 
 | 
			
		||||
     * 1.  Launch `onPreIndex`
 | 
			
		||||
     * x.  check acl. If it does return a response instance, return it
 | 
			
		||||
     * x.  launch `onPostCheckACL`. If it does return a response instance, return it
 | 
			
		||||
     * 1.  count the items, using `countEntities`
 | 
			
		||||
     * 2.  build a paginator element from the the number of entities ;
 | 
			
		||||
     * 3.  Launch `onPreIndexQuery`. If it does return a response instance, return it
 | 
			
		||||
     * 3.  build a query, using `queryEntities`
 | 
			
		||||
     * x.  fetch the results, using `getQueryResult`
 | 
			
		||||
     * x.  Launch `onPostIndexFetchQuery`. If it does return a response instance, return it
 | 
			
		||||
     * 4.  Serialize the entities in a Collection, using `SerializeCollection`
 | 
			
		||||
     * 
 | 
			
		||||
     * @param string $action
 | 
			
		||||
     * @param Request $request
 | 
			
		||||
     * @return type
 | 
			
		||||
     */
 | 
			
		||||
    protected function indexApiAction($action, Request $request, $_format)
 | 
			
		||||
    {
 | 
			
		||||
        $this->onPreIndex($action, $request, $_format);
 | 
			
		||||
        
 | 
			
		||||
        $response = $this->checkACL($action, $request, $_format);
 | 
			
		||||
        if ($response instanceof Response) {
 | 
			
		||||
            return $response;
 | 
			
		||||
        }
 | 
			
		||||
        
 | 
			
		||||
        if (!isset($entity)) {
 | 
			
		||||
            $entity = '';
 | 
			
		||||
        }
 | 
			
		||||
        
 | 
			
		||||
        $response = $this->onPostCheckACL($action, $request, $_format, $entity);
 | 
			
		||||
        if ($response instanceof Response) {
 | 
			
		||||
            return $response;
 | 
			
		||||
        }
 | 
			
		||||
        
 | 
			
		||||
        $totalItems = $this->countEntities($action, $request, $_format);
 | 
			
		||||
        $paginator = $this->getPaginatorFactory()->create($totalItems);
 | 
			
		||||
        
 | 
			
		||||
        $response = $this->onPreIndexBuildQuery($action, $request, $_format, $totalItems, 
 | 
			
		||||
            $paginator);
 | 
			
		||||
        
 | 
			
		||||
        if ($response instanceof Response) {
 | 
			
		||||
            return $response;
 | 
			
		||||
        }
 | 
			
		||||
        
 | 
			
		||||
        $query = $this->queryEntities($action, $request, $_format, $paginator);
 | 
			
		||||
        
 | 
			
		||||
        $response = $this->onPostIndexBuildQuery($action, $request, $_format, $totalItems, 
 | 
			
		||||
            $paginator, $query);
 | 
			
		||||
        
 | 
			
		||||
        if ($response instanceof Response) {
 | 
			
		||||
            return $response;
 | 
			
		||||
        }
 | 
			
		||||
        
 | 
			
		||||
        $entities = $this->getQueryResult($action, $request, $_format, $totalItems, $paginator, $query);
 | 
			
		||||
        
 | 
			
		||||
        $response = $this->onPostIndexFetchQuery($action, $request, $_format, $totalItems, 
 | 
			
		||||
            $paginator, $entities);
 | 
			
		||||
        
 | 
			
		||||
        if ($response instanceof Response) {
 | 
			
		||||
            return $response;
 | 
			
		||||
        }
 | 
			
		||||
        
 | 
			
		||||
        return $this->serializeCollection($action, $request, $_format, $paginator, $entities);    
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Add or remove an associated entity, using `add` and `remove` methods.
 | 
			
		||||
     *
 | 
			
		||||
     * This method:
 | 
			
		||||
     *
 | 
			
		||||
     * 1. Fetch the base entity (throw 404 if not found)
 | 
			
		||||
     * 2. checkACL, 
 | 
			
		||||
     * 3. run onPostCheckACL, return response if any,
 | 
			
		||||
     * 4. deserialize posted data into the entity given by $postedDataType, with the context in $postedDataContext
 | 
			
		||||
     * 5. run 'add+$property' for POST method, or 'remove+$property' for DELETE method
 | 
			
		||||
     * 6. validate the base entity (not the deserialized one). Groups are fetched from getValidationGroups, validation is perform by `validate`
 | 
			
		||||
     * 7. run onAfterValidation
 | 
			
		||||
     * 8. if errors, return a 422 response with errors
 | 
			
		||||
     * 9. flush the data 
 | 
			
		||||
     * 10. run onAfterFlush
 | 
			
		||||
     * 11. return a 202 response for DELETE with empty body, or HTTP 200 for post with serialized posted entity
 | 
			
		||||
     *
 | 
			
		||||
     * @param string action
 | 
			
		||||
     * @param mixed id
 | 
			
		||||
     * @param Request $request
 | 
			
		||||
     * @param string $_format
 | 
			
		||||
     * @param string $property the name of the property. This will be used to make a `add+$property` and `remove+$property` method
 | 
			
		||||
     * @param string $postedDataType the type of the posted data (the content)
 | 
			
		||||
     * @param string $postedDataContext a context to deserialize posted data (the content)
 | 
			
		||||
     * @throw BadRequestException if unable to deserialize the posted data
 | 
			
		||||
     * @throw BadRequestException if the method is not POST or DELETE
 | 
			
		||||
     *
 | 
			
		||||
     */ 
 | 
			
		||||
    protected function addRemoveSomething(string $action, $id, Request $request, string $_format, string $property, string $postedDataType, $postedDataContext = []): Response
 | 
			
		||||
    {
 | 
			
		||||
        $entity = $this->getEntity($action, $id, $request);
 | 
			
		||||
 | 
			
		||||
        $postFetch = $this->onPostFetchEntity($action, $request, $entity, $_format);
 | 
			
		||||
        if ($postFetch instanceof Response) {
 | 
			
		||||
            return $postFetch;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        $response = $this->checkACL($action, $request, $_format, $entity);
 | 
			
		||||
        if ($response instanceof Response) {
 | 
			
		||||
            return $response;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        $response = $this->onPostCheckACL($action, $request, $_format, $entity);
 | 
			
		||||
        if ($response instanceof Response) {
 | 
			
		||||
            return $response;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        $response = $this->onBeforeSerialize($action, $request, $_format, $entity);
 | 
			
		||||
        if ($response instanceof Response) {
 | 
			
		||||
            return $response;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        try {
 | 
			
		||||
            $postedData = $this->getSerializer()->deserialize($request->getContent(), $postedDataType, $_format, $postedDataContext);
 | 
			
		||||
        } catch (\Symfony\Component\Serializer\Exception\UnexpectedValueException $e) {
 | 
			
		||||
            throw new BadRequestException(sprintf("Unable to deserialize posted ".
 | 
			
		||||
                "data: %s", $e->getMessage()), 0, $e);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        switch ($request->getMethod()) {
 | 
			
		||||
            case Request::METHOD_DELETE:
 | 
			
		||||
                // oups... how to use property accessor to remove element ?
 | 
			
		||||
                $entity->{'remove'.\ucfirst($property)}($postedData);
 | 
			
		||||
                break;
 | 
			
		||||
            case Request::METHOD_POST:
 | 
			
		||||
                $entity->{'add'.\ucfirst($property)}($postedData);
 | 
			
		||||
                break;
 | 
			
		||||
            default:
 | 
			
		||||
                throw new BadRequestException("this method is not supported");
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        $errors = $this->validate($action, $request, $_format, $entity, [$postedData]);
 | 
			
		||||
 | 
			
		||||
        $response = $this->onAfterValidation($action, $request, $_format, $entity, $errors, [$postedData]);
 | 
			
		||||
        if ($response instanceof Response) {
 | 
			
		||||
            return $response;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if ($errors->count() > 0) {
 | 
			
		||||
            // only format accepted
 | 
			
		||||
            return $this->json($errors, 422);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        $this->getDoctrine()->getManager()->flush();
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
        $response = $this->onAfterFlush($action, $request, $_format, $entity, $errors, [$postedData]);
 | 
			
		||||
        if ($response instanceof Response) {
 | 
			
		||||
            return $response;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        switch ($request->getMethod()) {
 | 
			
		||||
            case Request::METHOD_DELETE:
 | 
			
		||||
                return $this->json('', Response::HTTP_OK);
 | 
			
		||||
            case Request::METHOD_POST:
 | 
			
		||||
                return $this->json(
 | 
			
		||||
                    $postedData,
 | 
			
		||||
                    Response::HTTP_OK,
 | 
			
		||||
                    [], 
 | 
			
		||||
                    $this->getContextForSerializationPostAlter($action, $request, $_format, $entity, [$postedData])
 | 
			
		||||
                );
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    /**
 | 
			
		||||
     * Serialize collections
 | 
			
		||||
     *
 | 
			
		||||
     */
 | 
			
		||||
    protected function serializeCollection(string $action, Request $request, string $_format, PaginatorInterface $paginator, $entities): Response
 | 
			
		||||
    {
 | 
			
		||||
        $model = new Collection($entities, $paginator);
 | 
			
		||||
 | 
			
		||||
        $context = $this->getContextForSerialization($action, $request, $_format, $entities);
 | 
			
		||||
 | 
			
		||||
        return $this->json($model, Response::HTTP_OK, [], $context);
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
 | 
			
		||||
    protected function getContextForSerialization(string $action, Request $request, string $_format, $entity): array
 | 
			
		||||
    {
 | 
			
		||||
        switch ($request->getMethod()) {
 | 
			
		||||
            case Request::METHOD_GET:
 | 
			
		||||
                return [ 'groups' => [ 'read' ]];
 | 
			
		||||
            case Request::METHOD_PUT:
 | 
			
		||||
            case Request::METHOD_PATCH:
 | 
			
		||||
            case Request::METHOD_POST:
 | 
			
		||||
                return [ 'groups' => [ 'write' ]];
 | 
			
		||||
            default:
 | 
			
		||||
                throw new \LogicException("get context for serialization is not implemented for this method");
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Get the context for serialization post alter query (in case of 
 | 
			
		||||
     * PATCH, PUT, or POST method)
 | 
			
		||||
     *
 | 
			
		||||
     * This is called **after** the entity was altered.
 | 
			
		||||
     */
 | 
			
		||||
    protected function getContextForSerializationPostAlter(string $action, Request $request, string $_format, $entity, array $more = []): array
 | 
			
		||||
    {
 | 
			
		||||
        return [ 'groups' => [ 'read' ]];
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * get the role given from the config.
 | 
			
		||||
     */
 | 
			
		||||
    protected function getRoleFor(string $action, Request $request, $entity, $_format): string
 | 
			
		||||
    {
 | 
			
		||||
        $actionConfig = $this->getActionConfig($action);
 | 
			
		||||
 | 
			
		||||
        if (NULL !== $actionConfig['roles'][$request->getMethod()]) {
 | 
			
		||||
            return $actionConfig['roles'][$request->getMethod()];
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if ($this->crudConfig['base_role']) {
 | 
			
		||||
            return $this->crudConfig['base_role'];
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        throw new \RuntimeException(sprintf("the config does not have any role for the ".
 | 
			
		||||
            "method %s nor a global role for the whole action. Add those to your ".
 | 
			
		||||
            "configuration or override the required method", $request->getMethod()));
 | 
			
		||||
        
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    protected function getSerializer(): SerializerInterface
 | 
			
		||||
    {
 | 
			
		||||
        return $this->get('serializer');
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							@@ -23,9 +23,6 @@ namespace Chill\MainBundle\CRUD\Routing;
 | 
			
		||||
use Symfony\Component\Config\Loader\Loader;
 | 
			
		||||
use Symfony\Component\Routing\Route;
 | 
			
		||||
use Symfony\Component\Routing\RouteCollection;
 | 
			
		||||
use Symfony\Component\HttpFoundation\Request;
 | 
			
		||||
use Chill\MainBundle\CRUD\Controller\ApiController;
 | 
			
		||||
use Chill\MainBundle\CRUD\Controller\CRUDController;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Class CRUDRoutesLoader
 | 
			
		||||
@@ -35,34 +32,24 @@ use Chill\MainBundle\CRUD\Controller\CRUDController;
 | 
			
		||||
 */
 | 
			
		||||
class CRUDRoutesLoader extends Loader
 | 
			
		||||
{
 | 
			
		||||
    protected array $crudConfig = [];
 | 
			
		||||
 | 
			
		||||
    protected array $apiCrudConfig = [];
 | 
			
		||||
    /**
 | 
			
		||||
     * @var array
 | 
			
		||||
     */
 | 
			
		||||
    protected $config = [];
 | 
			
		||||
    
 | 
			
		||||
    /**
 | 
			
		||||
     * @var bool
 | 
			
		||||
     */
 | 
			
		||||
    private $isLoaded = false;
 | 
			
		||||
 | 
			
		||||
    private const ALL_SINGLE_METHODS = [
 | 
			
		||||
        Request::METHOD_GET,
 | 
			
		||||
        Request::METHOD_POST,
 | 
			
		||||
        Request::METHOD_PUT,
 | 
			
		||||
        Request::METHOD_DELETE
 | 
			
		||||
    ];
 | 
			
		||||
 | 
			
		||||
    private const ALL_INDEX_METHODS = [ Request::METHOD_GET, Request::METHOD_HEAD ];
 | 
			
		||||
    
 | 
			
		||||
    /**
 | 
			
		||||
     * CRUDRoutesLoader constructor.
 | 
			
		||||
     *
 | 
			
		||||
     * @param $crudConfig the config from cruds
 | 
			
		||||
     * @param $apicrudConfig the config from api_crud
 | 
			
		||||
     * @param $config
 | 
			
		||||
     */
 | 
			
		||||
    public function __construct(array $crudConfig, array $apiConfig)
 | 
			
		||||
    public function __construct($config)
 | 
			
		||||
    {
 | 
			
		||||
        $this->crudConfig = $crudConfig;
 | 
			
		||||
        $this->apiConfig = $apiConfig;
 | 
			
		||||
        $this->config = $config;
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    /**
 | 
			
		||||
@@ -76,153 +63,53 @@ class CRUDRoutesLoader extends Loader
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    /**
 | 
			
		||||
     * Load routes for CRUD and CRUD Api
 | 
			
		||||
     * @return RouteCollection
 | 
			
		||||
     */
 | 
			
		||||
    public function load($resource, $type = null): RouteCollection
 | 
			
		||||
    public function load($resource, $type = null)
 | 
			
		||||
    {
 | 
			
		||||
    
 | 
			
		||||
        if (true === $this->isLoaded) {
 | 
			
		||||
            throw new \RuntimeException('Do not add the "CRUD" loader twice');
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        
 | 
			
		||||
        $collection = new RouteCollection();
 | 
			
		||||
        
 | 
			
		||||
        foreach ($this->crudConfig as $crudConfig) {
 | 
			
		||||
            $collection->addCollection($this->loadCrudConfig($crudConfig));
 | 
			
		||||
        foreach ($this->config as $config) {
 | 
			
		||||
            $collection->addCollection($this->loadConfig($config));
 | 
			
		||||
        }
 | 
			
		||||
        foreach ($this->apiConfig as $crudConfig) {
 | 
			
		||||
            $collection->addCollection($this->loadApi($crudConfig));
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        
 | 
			
		||||
        return $collection;
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    /**
 | 
			
		||||
     * Load routes for CRUD (without api)
 | 
			
		||||
     *
 | 
			
		||||
     * @param $crudConfig
 | 
			
		||||
     * @param $config
 | 
			
		||||
     * @return RouteCollection
 | 
			
		||||
     */
 | 
			
		||||
    protected function loadCrudConfig($crudConfig): RouteCollection
 | 
			
		||||
    protected function loadConfig($config): RouteCollection
 | 
			
		||||
    {
 | 
			
		||||
        $collection = new RouteCollection();
 | 
			
		||||
        $controller ='cscrud_'.$crudConfig['name'].'_controller';
 | 
			
		||||
 | 
			
		||||
        foreach ($crudConfig['actions'] as $name => $action) {
 | 
			
		||||
            // defaults (controller name)
 | 
			
		||||
        foreach ($config['actions'] as $name => $action) {
 | 
			
		||||
            $defaults = [
 | 
			
		||||
                '_controller' => $controller.':'.($action['controller_action'] ?? $name)
 | 
			
		||||
                '_controller' => 'cscrud_'.$config['name'].'_controller'.':'.($action['controller_action'] ?? $name)
 | 
			
		||||
            ];
 | 
			
		||||
            
 | 
			
		||||
            if ($name === 'index') {
 | 
			
		||||
                $path = "{_locale}".$crudConfig['base_path'];
 | 
			
		||||
                $path = "{_locale}".$config['base_path'];
 | 
			
		||||
                $route = new Route($path, $defaults);
 | 
			
		||||
            } elseif ($name === 'new') {
 | 
			
		||||
                $path = "{_locale}".$crudConfig['base_path'].'/'.$name;
 | 
			
		||||
                $path = "{_locale}".$config['base_path'].'/'.$name;
 | 
			
		||||
                $route = new Route($path, $defaults);
 | 
			
		||||
            } else {
 | 
			
		||||
                $path = "{_locale}".$crudConfig['base_path'].($action['path'] ?? '/{id}/'.$name);
 | 
			
		||||
                $path = "{_locale}".$config['base_path'].($action['path'] ?? '/{id}/'.$name);
 | 
			
		||||
                $requirements = $action['requirements'] ?? [
 | 
			
		||||
                    '{id}' => '\d+'
 | 
			
		||||
                ];
 | 
			
		||||
                $route = new Route($path, $defaults, $requirements);
 | 
			
		||||
            }
 | 
			
		||||
            
 | 
			
		||||
            $collection->add('chill_crud_'.$crudConfig['name'].'_'.$name, $route);
 | 
			
		||||
            $collection->add('chill_crud_'.$config['name'].'_'.$name, $route);
 | 
			
		||||
        }
 | 
			
		||||
        
 | 
			
		||||
        return $collection;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Load routes for api single
 | 
			
		||||
     *
 | 
			
		||||
     * @param $crudConfig
 | 
			
		||||
     * @return RouteCollection
 | 
			
		||||
     */
 | 
			
		||||
    protected function loadApi(array $crudConfig): RouteCollection
 | 
			
		||||
    {
 | 
			
		||||
        $collection = new RouteCollection();
 | 
			
		||||
        $controller ='csapi_'.$crudConfig['name'].'_controller';
 | 
			
		||||
 | 
			
		||||
        foreach ($crudConfig['actions'] as $name => $action) {
 | 
			
		||||
            // filter only on single actions
 | 
			
		||||
            $singleCollection = $action['single-collection'] ?? $name === '_entity' ? 'single' : NULL;
 | 
			
		||||
            if ('collection' === $singleCollection) {
 | 
			
		||||
//                continue;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            // compute default action
 | 
			
		||||
            switch ($name) {
 | 
			
		||||
                case '_entity':
 | 
			
		||||
                    $controllerAction = 'entityApi';
 | 
			
		||||
                    break;
 | 
			
		||||
                case '_index':
 | 
			
		||||
                    $controllerAction = 'indexApi';
 | 
			
		||||
                    break;
 | 
			
		||||
                default:
 | 
			
		||||
                    $controllerAction = $name.'Api';
 | 
			
		||||
                    break;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            $defaults = [
 | 
			
		||||
                '_controller' => $controller.':'.($action['controller_action'] ?? $controllerAction)
 | 
			
		||||
            ];
 | 
			
		||||
 | 
			
		||||
            // path are rewritten
 | 
			
		||||
            // if name === 'default', we rewrite it to nothing :-)
 | 
			
		||||
            $localName = \in_array($name, [ '_entity', '_index' ]) ? '' : '/'.$name;
 | 
			
		||||
            if ('collection' === $action['single-collection'] || '_index' === $name) {
 | 
			
		||||
                $localPath = $action['path'] ?? $localName.'.{_format}';
 | 
			
		||||
            } else {
 | 
			
		||||
                $localPath = $action['path'] ?? '/{id}'.$localName.'.{_format}';
 | 
			
		||||
            }
 | 
			
		||||
            $path = $crudConfig['base_path'].$localPath;
 | 
			
		||||
 | 
			
		||||
            $requirements = $action['requirements'] ?? [ '{id}' => '\d+' ];
 | 
			
		||||
 | 
			
		||||
            $methods = \array_keys(\array_filter($action['methods'], function($value, $key) { return $value; },
 | 
			
		||||
                ARRAY_FILTER_USE_BOTH));
 | 
			
		||||
 | 
			
		||||
            if (count($methods) === 0) {
 | 
			
		||||
                throw new \RuntimeException("The api configuration named \"{$crudConfig['name']}\", action \"{$name}\", ".
 | 
			
		||||
                    "does not have any allowed methods. You should remove this action from the config ".
 | 
			
		||||
                    "or allow, at least, one method"); 
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            if ('_entity' === $name && \in_array(Request::METHOD_POST, $methods)) {
 | 
			
		||||
                unset($methods[\array_search(Request::METHOD_POST, $methods)]);
 | 
			
		||||
                $entityPostRoute = $this->createEntityPostRoute($name, $crudConfig, $action, 
 | 
			
		||||
                    $controller);
 | 
			
		||||
                $collection->add("chill_api_single_{$crudConfig['name']}_{$name}_create", 
 | 
			
		||||
                    $entityPostRoute);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            if (count($methods) === 0) {
 | 
			
		||||
                // the only method was POST,
 | 
			
		||||
                // continue to next
 | 
			
		||||
                continue;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            $route = new Route($path, $defaults, $requirements);
 | 
			
		||||
            $route->setMethods($methods);
 | 
			
		||||
            
 | 
			
		||||
            $collection->add('chill_api_single_'.$crudConfig['name'].'_'.$name, $route);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return $collection;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private function createEntityPostRoute(string $name, $crudConfig, array $action, $controller): Route
 | 
			
		||||
    {
 | 
			
		||||
        $localPath = $action['path'].'.{_format}';
 | 
			
		||||
        $defaults = [
 | 
			
		||||
            '_controller' => $controller.':'.($action['controller_action'] ?? 'entityPost')
 | 
			
		||||
        ];
 | 
			
		||||
        $path = $crudConfig['base_path'].$localPath;
 | 
			
		||||
        $requirements = $action['requirements'] ?? [];
 | 
			
		||||
        $route = new Route($path, $defaults, $requirements);
 | 
			
		||||
        $route->setMethods([ Request::METHOD_POST ]);
 | 
			
		||||
 | 
			
		||||
        return $route;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -14,7 +14,6 @@ use Chill\MainBundle\DependencyInjection\CompilerPass\NotificationCounterCompile
 | 
			
		||||
use Chill\MainBundle\DependencyInjection\CompilerPass\MenuCompilerPass;
 | 
			
		||||
use Chill\MainBundle\DependencyInjection\CompilerPass\ACLFlagsCompilerPass;
 | 
			
		||||
use Chill\MainBundle\DependencyInjection\CompilerPass\GroupingCenterCompilerPass;
 | 
			
		||||
use Chill\MainBundle\CRUD\CompilerPass\CRUDControllerCompilerPass;
 | 
			
		||||
use Chill\MainBundle\Templating\Entity\CompilerPass as RenderEntityCompilerPass;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@@ -34,6 +33,5 @@ class ChillMainBundle extends Bundle
 | 
			
		||||
        $container->addCompilerPass(new ACLFlagsCompilerPass());
 | 
			
		||||
        $container->addCompilerPass(new GroupingCenterCompilerPass());
 | 
			
		||||
        $container->addCompilerPass(new RenderEntityCompilerPass());
 | 
			
		||||
        $container->addCompilerPass(new CRUDControllerCompilerPass());
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -1,27 +0,0 @@
 | 
			
		||||
<?php
 | 
			
		||||
 | 
			
		||||
namespace Chill\MainBundle\Controller;
 | 
			
		||||
 | 
			
		||||
use Chill\MainBundle\CRUD\Controller\ApiController;
 | 
			
		||||
use Symfony\Component\HttpFoundation\Request;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Class AddressReferenceAPIController
 | 
			
		||||
 *
 | 
			
		||||
 * @package Chill\MainBundle\Controller
 | 
			
		||||
 * @author Champs Libres
 | 
			
		||||
 */
 | 
			
		||||
class AddressReferenceAPIController extends ApiController
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
    protected function customizeQuery(string $action, Request $request, $qb): void
 | 
			
		||||
    {
 | 
			
		||||
        if ($request->query->has('postal_code')) {
 | 
			
		||||
 | 
			
		||||
            $qb->where('e.postcode = :postal_code')
 | 
			
		||||
               ->setParameter('postal_code', $request->query->get('postal_code'));
 | 
			
		||||
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
@@ -1,27 +0,0 @@
 | 
			
		||||
<?php
 | 
			
		||||
 | 
			
		||||
namespace Chill\MainBundle\Controller;
 | 
			
		||||
 | 
			
		||||
use Chill\MainBundle\CRUD\Controller\ApiController;
 | 
			
		||||
use Symfony\Component\HttpFoundation\Request;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Class PostalCodeAPIController
 | 
			
		||||
 *
 | 
			
		||||
 * @package Chill\MainBundle\Controller
 | 
			
		||||
 * @author Champs Libres
 | 
			
		||||
 */
 | 
			
		||||
class PostalCodeAPIController extends ApiController
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
    protected function customizeQuery(string $action, Request $request, $qb): void
 | 
			
		||||
    {
 | 
			
		||||
        if ($request->query->has('country')) {
 | 
			
		||||
 | 
			
		||||
            $qb->where('e.country = :country')
 | 
			
		||||
               ->setParameter('country', $request->query->get('country'));
 | 
			
		||||
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
@@ -22,7 +22,6 @@
 | 
			
		||||
 | 
			
		||||
namespace Chill\MainBundle\Controller;
 | 
			
		||||
 | 
			
		||||
use Chill\MainBundle\Serializer\Model\Collection;
 | 
			
		||||
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
 | 
			
		||||
use Symfony\Component\HttpFoundation\Request;
 | 
			
		||||
use Chill\MainBundle\Search\UnknowSearchDomainException;
 | 
			
		||||
@@ -35,7 +34,6 @@ use Symfony\Component\HttpFoundation\JsonResponse;
 | 
			
		||||
use Chill\MainBundle\Search\SearchProvider;
 | 
			
		||||
use Symfony\Contracts\Translation\TranslatorInterface;
 | 
			
		||||
use Chill\MainBundle\Pagination\PaginatorFactory;
 | 
			
		||||
use Chill\MainBundle\Search\SearchApi;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Class SearchController
 | 
			
		||||
@@ -44,24 +42,32 @@ use Chill\MainBundle\Search\SearchApi;
 | 
			
		||||
 */
 | 
			
		||||
class SearchController extends AbstractController
 | 
			
		||||
{
 | 
			
		||||
    protected SearchProvider $searchProvider;
 | 
			
		||||
    /**
 | 
			
		||||
     *
 | 
			
		||||
     * @var SearchProvider
 | 
			
		||||
     */
 | 
			
		||||
    protected $searchProvider;
 | 
			
		||||
    
 | 
			
		||||
    protected TranslatorInterface $translator;
 | 
			
		||||
    /**
 | 
			
		||||
     *
 | 
			
		||||
     * @var TranslatorInterface
 | 
			
		||||
     */
 | 
			
		||||
    protected $translator;
 | 
			
		||||
    
 | 
			
		||||
    protected PaginatorFactory $paginatorFactory;
 | 
			
		||||
 | 
			
		||||
    protected SearchApi $searchApi;
 | 
			
		||||
    /**
 | 
			
		||||
     *
 | 
			
		||||
     * @var PaginatorFactory
 | 
			
		||||
     */
 | 
			
		||||
    protected $paginatorFactory;
 | 
			
		||||
    
 | 
			
		||||
    function __construct(
 | 
			
		||||
        SearchProvider $searchProvider, 
 | 
			
		||||
        TranslatorInterface $translator,
 | 
			
		||||
        PaginatorFactory $paginatorFactory,
 | 
			
		||||
        SearchApi $searchApi
 | 
			
		||||
        PaginatorFactory $paginatorFactory
 | 
			
		||||
    ) {
 | 
			
		||||
        $this->searchProvider = $searchProvider;
 | 
			
		||||
        $this->translator = $translator;
 | 
			
		||||
        $this->paginatorFactory = $paginatorFactory;
 | 
			
		||||
        $this->searchApi = $searchApi;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    
 | 
			
		||||
@@ -146,19 +152,6 @@ class SearchController extends AbstractController
 | 
			
		||||
              array('results' => $results, 'pattern' => $pattern)
 | 
			
		||||
              );
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function searchApi(Request $request, $_format): JsonResponse
 | 
			
		||||
    {
 | 
			
		||||
        //TODO this is an incomplete implementation
 | 
			
		||||
        $query = $request->query->get('q', '');
 | 
			
		||||
 | 
			
		||||
        $results = $this->searchApi->getResults($query, 0, 150);
 | 
			
		||||
        $paginator = $this->paginatorFactory->create(count($results));
 | 
			
		||||
 | 
			
		||||
        $collection = new Collection($results, $paginator);
 | 
			
		||||
 | 
			
		||||
        return $this->json($collection);
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    public function advancedSearchListAction(Request $request)
 | 
			
		||||
    {
 | 
			
		||||
 
 | 
			
		||||
@@ -1,91 +0,0 @@
 | 
			
		||||
<?php
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * Copyright (C) 2015 Champs-Libres Coopérative <info@champs-libres.coop>
 | 
			
		||||
 *
 | 
			
		||||
 * This program is free software: you can redistribute it and/or modify
 | 
			
		||||
 * it under the terms of the GNU Affero General Public License as published by
 | 
			
		||||
 * the Free Software Foundation, either version 3 of the License, or
 | 
			
		||||
 * (at your option) any later version.
 | 
			
		||||
 *
 | 
			
		||||
 * This program is distributed in the hope that it will be useful,
 | 
			
		||||
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
			
		||||
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
			
		||||
 * GNU Affero General Public License for more details.
 | 
			
		||||
 *
 | 
			
		||||
 * You should have received a copy of the GNU Affero General Public License
 | 
			
		||||
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
namespace Chill\MainBundle\Controller;
 | 
			
		||||
 | 
			
		||||
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
 | 
			
		||||
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
 | 
			
		||||
use Symfony\Component\HttpFoundation\Response;
 | 
			
		||||
use Symfony\Component\HttpFoundation\Request;
 | 
			
		||||
use Chill\MainBundle\Timeline\TimelineBuilder;
 | 
			
		||||
use Chill\MainBundle\Pagination\PaginatorFactory;
 | 
			
		||||
use Chill\PersonBundle\Security\Authorization\PersonVoter;
 | 
			
		||||
use Chill\MainBundle\Security\Authorization\AuthorizationHelper;
 | 
			
		||||
use Symfony\Component\Security\Core\Role\Role;
 | 
			
		||||
use Symfony\Component\Routing\Annotation\Route;
 | 
			
		||||
use Symfony\Component\Security\Core\Security;
 | 
			
		||||
 | 
			
		||||
class TimelineCenterController extends AbstractController
 | 
			
		||||
{
 | 
			
		||||
    
 | 
			
		||||
    protected TimelineBuilder $timelineBuilder;
 | 
			
		||||
    
 | 
			
		||||
    protected PaginatorFactory $paginatorFactory;
 | 
			
		||||
 | 
			
		||||
    private Security $security;
 | 
			
		||||
    
 | 
			
		||||
    public function __construct(
 | 
			
		||||
        TimelineBuilder $timelineBuilder,
 | 
			
		||||
        PaginatorFactory $paginatorFactory,
 | 
			
		||||
        Security $security
 | 
			
		||||
    ) {
 | 
			
		||||
        $this->timelineBuilder = $timelineBuilder;
 | 
			
		||||
        $this->paginatorFactory = $paginatorFactory;
 | 
			
		||||
        $this->security = $security;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * @Route("/{_locale}/center/timeline",
 | 
			
		||||
     *    name="chill_center_timeline",
 | 
			
		||||
     *    methods={"GET"}
 | 
			
		||||
     *  )
 | 
			
		||||
     */ 
 | 
			
		||||
    public function centerAction(Request $request)
 | 
			
		||||
    {
 | 
			
		||||
        // collect reachable center for each group
 | 
			
		||||
        $user = $this->security->getUser();
 | 
			
		||||
        $centers = [];
 | 
			
		||||
        foreach ($user->getGroupCenters() as $group) {
 | 
			
		||||
            $centers[] = $group->getCenter();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (0 === count($centers)) {
 | 
			
		||||
            throw $this->createNotFoundException();
 | 
			
		||||
        }
 | 
			
		||||
        
 | 
			
		||||
        $nbItems = $this->timelineBuilder->countItems('center', 
 | 
			
		||||
            [ 'centers' => $centers ]
 | 
			
		||||
            );
 | 
			
		||||
        
 | 
			
		||||
        $paginator = $this->paginatorFactory->create($nbItems);
 | 
			
		||||
        
 | 
			
		||||
        return $this->render('@ChillMain/Timeline/index.html.twig', array
 | 
			
		||||
            (
 | 
			
		||||
                'timeline' => $this->timelineBuilder->getTimelineHTML(
 | 
			
		||||
                    'center', 
 | 
			
		||||
                    [ 'centers' => $centers ],
 | 
			
		||||
                    $paginator->getCurrentPage()->getFirstItemNumber(),
 | 
			
		||||
                    $paginator->getItemsPerPage()
 | 
			
		||||
                    ),
 | 
			
		||||
                'nb_items' => $nbItems,
 | 
			
		||||
                'paginator' => $paginator
 | 
			
		||||
            )
 | 
			
		||||
        );
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -1,95 +0,0 @@
 | 
			
		||||
<?php
 | 
			
		||||
 | 
			
		||||
namespace Chill\MainBundle\DataFixtures\ORM;
 | 
			
		||||
 | 
			
		||||
use Doctrine\Common\DataFixtures\AbstractFixture;
 | 
			
		||||
use Doctrine\Common\DataFixtures\OrderedFixtureInterface;
 | 
			
		||||
use Symfony\Component\DependencyInjection\ContainerAwareInterface;
 | 
			
		||||
use Symfony\Component\DependencyInjection\ContainerInterface;
 | 
			
		||||
use Doctrine\Persistence\ObjectManager;
 | 
			
		||||
use Chill\MainBundle\DataFixtures\ORM\LoadPostalCodes;
 | 
			
		||||
use Chill\MainBundle\Entity\AddressReference;
 | 
			
		||||
use Chill\MainBundle\Doctrine\Model\Point;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Load reference addresses into database
 | 
			
		||||
 *
 | 
			
		||||
 * @author Champs Libres
 | 
			
		||||
 */
 | 
			
		||||
class LoadAddressReferences extends AbstractFixture implements ContainerAwareInterface, OrderedFixtureInterface {
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    protected $faker;
 | 
			
		||||
 | 
			
		||||
    public function __construct()
 | 
			
		||||
    {
 | 
			
		||||
        $this->faker = \Faker\Factory::create('fr_FR');
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     *
 | 
			
		||||
     * @var ContainerInterface
 | 
			
		||||
     */
 | 
			
		||||
    private $container;
 | 
			
		||||
 | 
			
		||||
    public function setContainer(ContainerInterface $container = null)
 | 
			
		||||
    {
 | 
			
		||||
        $this->container = $container;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function getOrder() {
 | 
			
		||||
        return 51;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Create a random point
 | 
			
		||||
     *
 | 
			
		||||
     * @return Point
 | 
			
		||||
     */
 | 
			
		||||
    private function getRandomPoint()
 | 
			
		||||
    {
 | 
			
		||||
        $lonBrussels = 4.35243;
 | 
			
		||||
        $latBrussels = 50.84676;
 | 
			
		||||
        $lon = $lonBrussels + 0.01 * rand(-5, 5);
 | 
			
		||||
        $lat = $latBrussels + 0.01 * rand(-5, 5);
 | 
			
		||||
        return Point::fromLonLat($lon, $lat);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Create a random reference address
 | 
			
		||||
     *
 | 
			
		||||
     * @return AddressReference
 | 
			
		||||
     */
 | 
			
		||||
    private function getRandomAddressReference()
 | 
			
		||||
    {
 | 
			
		||||
        $ar= new AddressReference();
 | 
			
		||||
 | 
			
		||||
        $ar->setRefId($this->faker->numerify('ref-id-######'));
 | 
			
		||||
        $ar->setStreet($this->faker->streetName);
 | 
			
		||||
        $ar->setStreetNumber(rand(0,199));
 | 
			
		||||
        $ar ->setPoint($this->getRandomPoint());
 | 
			
		||||
        $ar->setPostcode($this->getReference(
 | 
			
		||||
            LoadPostalCodes::$refs[array_rand(LoadPostalCodes::$refs)]
 | 
			
		||||
        ));
 | 
			
		||||
 | 
			
		||||
        $ar->setMunicipalityCode($ar->getPostcode()->getCode());
 | 
			
		||||
 | 
			
		||||
        return $ar
 | 
			
		||||
        ;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function load(ObjectManager $manager) {
 | 
			
		||||
 | 
			
		||||
        echo "loading some reference address... \n";
 | 
			
		||||
 | 
			
		||||
        for ($i=0; $i<10; $i++) {
 | 
			
		||||
            $ar = $this->getRandomAddressReference();
 | 
			
		||||
            $manager->persist($ar);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        $manager->flush();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
@@ -55,11 +55,11 @@ class LoadCenters extends AbstractFixture implements OrderedFixtureInterface
 | 
			
		||||
    public function load(ObjectManager $manager)
 | 
			
		||||
    {
 | 
			
		||||
        foreach (static::$centers as $new) {
 | 
			
		||||
            $center = new Center();
 | 
			
		||||
            $center->setName($new['name']);
 | 
			
		||||
            $centerA = new Center();
 | 
			
		||||
            $centerA->setName($new['name']);
 | 
			
		||||
 | 
			
		||||
            $manager->persist($center);
 | 
			
		||||
            $this->addReference($new['ref'], $center);
 | 
			
		||||
            $manager->persist($centerA);
 | 
			
		||||
            $this->addReference($new['ref'], $centerA);
 | 
			
		||||
            static::$refs[] = $new['ref'];
 | 
			
		||||
        }
 | 
			
		||||
        
 | 
			
		||||
 
 | 
			
		||||
@@ -35,9 +35,6 @@ use Chill\MainBundle\Doctrine\DQL\OverlapsI;
 | 
			
		||||
use Symfony\Component\DependencyInjection\Definition;
 | 
			
		||||
use Symfony\Component\DependencyInjection\Reference;
 | 
			
		||||
use Chill\MainBundle\Doctrine\DQL\Replace;
 | 
			
		||||
use Chill\MainBundle\Doctrine\Type\NativeDateIntervalType;
 | 
			
		||||
use Chill\MainBundle\Doctrine\Type\PointType;
 | 
			
		||||
use Symfony\Component\HttpFoundation\Request;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Class ChillMainExtension
 | 
			
		||||
@@ -50,11 +47,11 @@ class ChillMainExtension extends Extension implements PrependExtensionInterface,
 | 
			
		||||
{
 | 
			
		||||
    /**
 | 
			
		||||
     * widget factory
 | 
			
		||||
     *
 | 
			
		||||
     * 
 | 
			
		||||
     * @var WidgetFactoryInterface[]
 | 
			
		||||
     */
 | 
			
		||||
    protected $widgetFactories = array();
 | 
			
		||||
 | 
			
		||||
    
 | 
			
		||||
    /**
 | 
			
		||||
     * @param WidgetFactoryInterface $factory
 | 
			
		||||
     */
 | 
			
		||||
@@ -62,7 +59,7 @@ class ChillMainExtension extends Extension implements PrependExtensionInterface,
 | 
			
		||||
    {
 | 
			
		||||
        $this->widgetFactories[] = $factory;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    
 | 
			
		||||
    /**
 | 
			
		||||
     * @return WidgetFactoryInterface[]
 | 
			
		||||
     */
 | 
			
		||||
@@ -70,7 +67,7 @@ class ChillMainExtension extends Extension implements PrependExtensionInterface,
 | 
			
		||||
    {
 | 
			
		||||
        return $this->widgetFactories;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    
 | 
			
		||||
    /**
 | 
			
		||||
     * {@inheritDoc}
 | 
			
		||||
     * @param array $configs
 | 
			
		||||
@@ -82,31 +79,31 @@ class ChillMainExtension extends Extension implements PrependExtensionInterface,
 | 
			
		||||
        // configuration for main bundle
 | 
			
		||||
        $configuration = $this->getConfiguration($configs, $container);
 | 
			
		||||
        $config = $this->processConfiguration($configuration, $configs);
 | 
			
		||||
 | 
			
		||||
        
 | 
			
		||||
        $container->setParameter('chill_main.installation_name',
 | 
			
		||||
            $config['installation_name']);
 | 
			
		||||
 | 
			
		||||
        $container->setParameter('chill_main.available_languages',
 | 
			
		||||
            $config['available_languages']);
 | 
			
		||||
 | 
			
		||||
        $container->setParameter('chill_main.routing.resources',
 | 
			
		||||
            $config['routing']['resources']);
 | 
			
		||||
 | 
			
		||||
        
 | 
			
		||||
        $container->setParameter('chill_main.routing.resources', 
 | 
			
		||||
            $config['routing']['resources']); 
 | 
			
		||||
        
 | 
			
		||||
        $container->setParameter('chill_main.pagination.item_per_page',
 | 
			
		||||
            $config['pagination']['item_per_page']);
 | 
			
		||||
 | 
			
		||||
        $container->setParameter('chill_main.notifications',
 | 
			
		||||
        
 | 
			
		||||
        $container->setParameter('chill_main.notifications', 
 | 
			
		||||
            $config['notifications']);
 | 
			
		||||
 | 
			
		||||
        $container->setParameter('chill_main.redis',
 | 
			
		||||
        
 | 
			
		||||
        $container->setParameter('chill_main.redis', 
 | 
			
		||||
            $config['redis']);
 | 
			
		||||
 | 
			
		||||
        $container->setParameter('chill_main.phone_helper',
 | 
			
		||||
        
 | 
			
		||||
        $container->setParameter('chill_main.phone_helper', 
 | 
			
		||||
            $config['phone_helper'] ?? []);
 | 
			
		||||
 | 
			
		||||
        
 | 
			
		||||
        // add the key 'widget' without the key 'enable'
 | 
			
		||||
        $container->setParameter('chill_main.widgets',
 | 
			
		||||
            isset($config['widgets']['homepage']) ?
 | 
			
		||||
        $container->setParameter('chill_main.widgets', 
 | 
			
		||||
            isset($config['widgets']['homepage']) ? 
 | 
			
		||||
                array('homepage' => $config['widgets']['homepage']):
 | 
			
		||||
                array()
 | 
			
		||||
                );
 | 
			
		||||
@@ -134,11 +131,10 @@ class ChillMainExtension extends Extension implements PrependExtensionInterface,
 | 
			
		||||
        $loader->load('services/templating.yaml');
 | 
			
		||||
        $loader->load('services/timeline.yaml');
 | 
			
		||||
        $loader->load('services/search.yaml');
 | 
			
		||||
        $loader->load('services/serializer.yaml');
 | 
			
		||||
 | 
			
		||||
        $this->configureCruds($container, $config['cruds'], $config['apis'], $loader);
 | 
			
		||||
        
 | 
			
		||||
        $this->configureCruds($container, $config['cruds'], $loader);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    
 | 
			
		||||
    /**
 | 
			
		||||
     * @param array $config
 | 
			
		||||
     * @param ContainerBuilder $container
 | 
			
		||||
@@ -148,11 +144,11 @@ class ChillMainExtension extends Extension implements PrependExtensionInterface,
 | 
			
		||||
    {
 | 
			
		||||
        return new Configuration($this->widgetFactories, $container);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    
 | 
			
		||||
    /**
 | 
			
		||||
     * @param ContainerBuilder $container
 | 
			
		||||
     */
 | 
			
		||||
    public function prepend(ContainerBuilder $container)
 | 
			
		||||
    public function prepend(ContainerBuilder $container) 
 | 
			
		||||
    {
 | 
			
		||||
        //add installation_name and date_format to globals
 | 
			
		||||
        $chillMainConfig = $container->getExtensionConfig($this->getAlias());
 | 
			
		||||
@@ -167,185 +163,97 @@ class ChillMainExtension extends Extension implements PrependExtensionInterface,
 | 
			
		||||
            'form_themes' => array('@ChillMain/Form/fields.html.twig')
 | 
			
		||||
        );
 | 
			
		||||
        $container->prependExtensionConfig('twig', $twigConfig);
 | 
			
		||||
 | 
			
		||||
        
 | 
			
		||||
        //add DQL function to ORM (default entity_manager)
 | 
			
		||||
        $container
 | 
			
		||||
            ->prependExtensionConfig(
 | 
			
		||||
                'doctrine',
 | 
			
		||||
                [
 | 
			
		||||
                    'orm' => [
 | 
			
		||||
                        'dql' => [
 | 
			
		||||
                            'string_functions' => [
 | 
			
		||||
                                'unaccent' => Unaccent::class,
 | 
			
		||||
                                'GET_JSON_FIELD_BY_KEY' => GetJsonFieldByKey::class,
 | 
			
		||||
                                'AGGREGATE' => JsonAggregate::class,
 | 
			
		||||
                                'REPLACE' => Replace::class,
 | 
			
		||||
                            ],
 | 
			
		||||
                            'numeric_functions' => [
 | 
			
		||||
                                'JSONB_EXISTS_IN_ARRAY' => JsonbExistsInArray::class,
 | 
			
		||||
                                'SIMILARITY' => Similarity::class,
 | 
			
		||||
                                'OVERLAPSI' => OverlapsI::class,
 | 
			
		||||
                            ],
 | 
			
		||||
                        ],
 | 
			
		||||
                    ],
 | 
			
		||||
                ],
 | 
			
		||||
        );
 | 
			
		||||
 | 
			
		||||
        //add dbal types (default entity_manager)
 | 
			
		||||
        $container
 | 
			
		||||
            ->prependExtensionConfig(
 | 
			
		||||
                'doctrine',
 | 
			
		||||
                [
 | 
			
		||||
                   'dbal' => [
 | 
			
		||||
                        // This is mandatory since we are using postgis as database.
 | 
			
		||||
                        'mapping_types' => [
 | 
			
		||||
                            'geometry' => 'string',
 | 
			
		||||
                        ],
 | 
			
		||||
                        'types' => [
 | 
			
		||||
                            'dateinterval' => [
 | 
			
		||||
                                'class' => NativeDateIntervalType::class
 | 
			
		||||
                            ],
 | 
			
		||||
                            'point' => [
 | 
			
		||||
                                'class' => PointType::class
 | 
			
		||||
                            ]
 | 
			
		||||
                        ]
 | 
			
		||||
                    ]
 | 
			
		||||
        $container->prependExtensionConfig('doctrine', array(
 | 
			
		||||
           'orm' => array(
 | 
			
		||||
              'dql' => array(
 | 
			
		||||
                 'string_functions' => array(
 | 
			
		||||
                    'unaccent' => Unaccent::class,
 | 
			
		||||
                    'GET_JSON_FIELD_BY_KEY' => GetJsonFieldByKey::class,
 | 
			
		||||
                    'AGGREGATE' => JsonAggregate::class,
 | 
			
		||||
                    'REPLACE' => Replace::class,
 | 
			
		||||
                 ),
 | 
			
		||||
                 'numeric_functions' => [
 | 
			
		||||
                    'JSONB_EXISTS_IN_ARRAY' => JsonbExistsInArray::class,
 | 
			
		||||
                    'SIMILARITY' => Similarity::class,
 | 
			
		||||
                    'OVERLAPSI' => OverlapsI::class
 | 
			
		||||
                ]
 | 
			
		||||
        );
 | 
			
		||||
 | 
			
		||||
              )
 | 
			
		||||
           )
 | 
			
		||||
        ));
 | 
			
		||||
        
 | 
			
		||||
        //add dbal types (default entity_manager)
 | 
			
		||||
        $container->prependExtensionConfig('doctrine', array(
 | 
			
		||||
           'dbal' => [
 | 
			
		||||
               'types' => [
 | 
			
		||||
                   'dateinterval' => \Chill\MainBundle\Doctrine\Type\NativeDateIntervalType::class
 | 
			
		||||
               ]
 | 
			
		||||
           ]
 | 
			
		||||
        ));
 | 
			
		||||
        
 | 
			
		||||
        //add current route to chill main
 | 
			
		||||
        $container->prependExtensionConfig('chill_main', array(
 | 
			
		||||
           'routing' => array(
 | 
			
		||||
              'resources' => array(
 | 
			
		||||
                 '@ChillMainBundle/config/routes.yaml'
 | 
			
		||||
              )
 | 
			
		||||
 | 
			
		||||
              
 | 
			
		||||
           )
 | 
			
		||||
        ));
 | 
			
		||||
 | 
			
		||||
        
 | 
			
		||||
        //add a channel to log app events
 | 
			
		||||
        $container->prependExtensionConfig('monolog', array(
 | 
			
		||||
            'channels' => array('chill')
 | 
			
		||||
        ));
 | 
			
		||||
 | 
			
		||||
        //add crud api
 | 
			
		||||
        $this->prependCruds($container);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Load parameter for configuration and set parameters for api
 | 
			
		||||
     */
 | 
			
		||||
    protected function configureCruds(
 | 
			
		||||
        ContainerBuilder $container,
 | 
			
		||||
        array $crudConfig,
 | 
			
		||||
        array $apiConfig,
 | 
			
		||||
        Loader\YamlFileLoader $loader
 | 
			
		||||
    ): void
 | 
			
		||||
    {
 | 
			
		||||
        if (count($crudConfig) === 0) {
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        $loader->load('services/crud.yaml');
 | 
			
		||||
 | 
			
		||||
        $container->setParameter('chill_main_crud_route_loader_config', $crudConfig);
 | 
			
		||||
        $container->setParameter('chill_main_api_route_loader_config', $apiConfig);
 | 
			
		||||
 | 
			
		||||
        // Note: the controller are loaded inside compiler pass
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    
 | 
			
		||||
    /**
 | 
			
		||||
     * @param ContainerBuilder $container
 | 
			
		||||
     * @param array $config the config under 'cruds' key
 | 
			
		||||
     * @return null
 | 
			
		||||
     */
 | 
			
		||||
    protected function prependCruds(ContainerBuilder $container)
 | 
			
		||||
    protected function configureCruds(ContainerBuilder $container, $config, Loader\YamlFileLoader $loader)
 | 
			
		||||
    {
 | 
			
		||||
        $container->prependExtensionConfig('chill_main', [
 | 
			
		||||
            'apis' => [
 | 
			
		||||
                [
 | 
			
		||||
                    'class' => \Chill\MainBundle\Entity\Address::class,
 | 
			
		||||
                    'name' => 'address',
 | 
			
		||||
                    'base_path' => '/api/1.0/main/address',
 | 
			
		||||
                    'base_role' => 'ROLE_USER',
 | 
			
		||||
                    'actions' => [
 | 
			
		||||
                        '_index' => [
 | 
			
		||||
                            'methods' => [
 | 
			
		||||
                                Request::METHOD_GET => true,
 | 
			
		||||
                                Request::METHOD_HEAD => true
 | 
			
		||||
                            ],
 | 
			
		||||
                        ],
 | 
			
		||||
                        '_entity' => [
 | 
			
		||||
                            'methods' => [
 | 
			
		||||
                                Request::METHOD_GET => true,
 | 
			
		||||
                                Request::METHOD_POST => true,
 | 
			
		||||
                                Request::METHOD_HEAD => true
 | 
			
		||||
                            ]
 | 
			
		||||
                        ],
 | 
			
		||||
                    ]
 | 
			
		||||
                ],
 | 
			
		||||
                [
 | 
			
		||||
                    'controller' => \Chill\MainBundle\Controller\AddressReferenceAPIController::class,
 | 
			
		||||
                    'class' => \Chill\MainBundle\Entity\AddressReference::class,
 | 
			
		||||
                    'name' => 'address_reference',
 | 
			
		||||
                    'base_path' => '/api/1.0/main/address-reference',
 | 
			
		||||
                    '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
 | 
			
		||||
                            ]
 | 
			
		||||
                        ],
 | 
			
		||||
                    ]
 | 
			
		||||
                ],
 | 
			
		||||
                [
 | 
			
		||||
                    'controller' => \Chill\MainBundle\Controller\PostalCodeAPIController::class,
 | 
			
		||||
                    'class' => \Chill\MainBundle\Entity\PostalCode::class,
 | 
			
		||||
                    'name' => 'postal_code',
 | 
			
		||||
                    'base_path' => '/api/1.0/main/postal-code',
 | 
			
		||||
                    '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
 | 
			
		||||
                            ]
 | 
			
		||||
                        ],
 | 
			
		||||
                    ]
 | 
			
		||||
                ],
 | 
			
		||||
                [
 | 
			
		||||
                    'class' => \Chill\MainBundle\Entity\Country::class,
 | 
			
		||||
                    'name' => 'country',
 | 
			
		||||
                    'base_path' => '/api/1.0/main/country',
 | 
			
		||||
                    '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
 | 
			
		||||
                            ]
 | 
			
		||||
                        ],
 | 
			
		||||
                    ]
 | 
			
		||||
                ]
 | 
			
		||||
            ]
 | 
			
		||||
        ]);
 | 
			
		||||
        if (count($config) === 0) {
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
        
 | 
			
		||||
        $loader->load('services/crud.yaml');
 | 
			
		||||
        
 | 
			
		||||
        $container->setParameter('chill_main_crud_route_loader_config', $config);
 | 
			
		||||
        
 | 
			
		||||
        $definition = new Definition();
 | 
			
		||||
        $definition
 | 
			
		||||
            ->setClass(\Chill\MainBundle\CRUD\Routing\CRUDRoutesLoader::class)
 | 
			
		||||
            ->addArgument('%chill_main_crud_route_loader_config%')
 | 
			
		||||
            ;
 | 
			
		||||
        
 | 
			
		||||
        $container->setDefinition('chill_main_crud_route_loader', $definition);
 | 
			
		||||
        
 | 
			
		||||
        $alreadyExistingNames = [];
 | 
			
		||||
        
 | 
			
		||||
        foreach ($config as $crudEntry) {
 | 
			
		||||
            $controller = $crudEntry['controller'];
 | 
			
		||||
            $controllerServiceName = 'cscrud_'.$crudEntry['name'].'_controller';
 | 
			
		||||
            $name = $crudEntry['name'];
 | 
			
		||||
            
 | 
			
		||||
            // check for existing crud names
 | 
			
		||||
            if (\in_array($name, $alreadyExistingNames)) {
 | 
			
		||||
                throw new LogicException(sprintf("the name %s is defined twice in CRUD", $name));
 | 
			
		||||
            }
 | 
			
		||||
            
 | 
			
		||||
            if (!$container->has($controllerServiceName)) {
 | 
			
		||||
                $controllerDefinition = new Definition($controller);
 | 
			
		||||
                $controllerDefinition->addTag('controller.service_arguments');
 | 
			
		||||
                $controllerDefinition->setAutoconfigured(true);
 | 
			
		||||
                $controllerDefinition->setClass($crudEntry['controller']);
 | 
			
		||||
                $container->setDefinition($controllerServiceName, $controllerDefinition);
 | 
			
		||||
            }
 | 
			
		||||
            
 | 
			
		||||
            $container->setParameter('chill_main_crud_config_'.$name, $crudEntry);
 | 
			
		||||
            $container->getDefinition($controllerServiceName)
 | 
			
		||||
                ->addMethodCall('setCrudConfig', ['%chill_main_crud_config_'.$name.'%']);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -8,7 +8,6 @@ use Chill\MainBundle\DependencyInjection\Widget\Factory\WidgetFactoryInterface;
 | 
			
		||||
use Symfony\Component\Config\Definition\Builder\ArrayNodeDefinition;
 | 
			
		||||
use Chill\MainBundle\DependencyInjection\Widget\AddWidgetConfigurationTrait;
 | 
			
		||||
use Symfony\Component\DependencyInjection\ContainerBuilder;
 | 
			
		||||
use Symfony\Component\HttpFoundation\Request;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
@@ -141,7 +140,7 @@ class Configuration implements ConfigurationInterface
 | 
			
		||||
                                        ->scalarNode('controller_action')
 | 
			
		||||
                                            ->defaultNull()
 | 
			
		||||
                                            ->info('the method name to call in the route. Will be set to the action name if left empty.')
 | 
			
		||||
                                            ->example("action")
 | 
			
		||||
                                            ->example("'action'")
 | 
			
		||||
                                        ->end()
 | 
			
		||||
                                        ->scalarNode('path')
 | 
			
		||||
                                            ->defaultNull()
 | 
			
		||||
@@ -169,80 +168,6 @@ class Configuration implements ConfigurationInterface
 | 
			
		||||
                    ->end()
 | 
			
		||||
 | 
			
		||||
                ->end()
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
                ->arrayNode('apis')
 | 
			
		||||
                    ->defaultValue([])
 | 
			
		||||
                    ->arrayPrototype()
 | 
			
		||||
                        ->children()
 | 
			
		||||
                            ->scalarNode('class')->cannotBeEmpty()->isRequired()->end()
 | 
			
		||||
                            ->scalarNode('controller')
 | 
			
		||||
                                ->cannotBeEmpty()
 | 
			
		||||
                                ->defaultValue(\Chill\MainBundle\CRUD\Controller\ApiController::class)
 | 
			
		||||
                            ->end()
 | 
			
		||||
                            ->scalarNode('name')->cannotBeEmpty()->isRequired()->end()
 | 
			
		||||
                            ->scalarNode('base_path')->cannotBeEmpty()->isRequired()->end()
 | 
			
		||||
                            ->scalarNode('base_role')->defaultNull()->end()
 | 
			
		||||
                            ->arrayNode('actions')
 | 
			
		||||
                                ->useAttributeAsKey('name')
 | 
			
		||||
                                ->arrayPrototype()
 | 
			
		||||
                                    ->children()
 | 
			
		||||
                                        ->scalarNode('controller_action')
 | 
			
		||||
                                            ->defaultNull()
 | 
			
		||||
                                            ->info('the method name to call in the controller. Will be set to the concatenation '.
 | 
			
		||||
                                                'of action name + \'Api\' if left empty.')
 | 
			
		||||
                                            ->example("showApi")
 | 
			
		||||
                                        ->end()
 | 
			
		||||
                                        ->scalarNode('path')
 | 
			
		||||
                                            ->defaultNull()
 | 
			
		||||
                                            ->info('the path that will be **appended** after the base path. Do not forget to add ' .
 | 
			
		||||
                                                'arguments for the method. By default, will set to the action name, including an `{id}` '.
 | 
			
		||||
                                                'parameter. A suffix of action name will be appended, except if the action name '.
 | 
			
		||||
                                                'is "_entity".')
 | 
			
		||||
                                            ->example('/{id}/my-action')
 | 
			
		||||
                                        ->end()
 | 
			
		||||
                                        ->arrayNode('requirements')
 | 
			
		||||
                                            ->ignoreExtraKeys(false)
 | 
			
		||||
                                            ->info('the requirements for the route. Will be set to `[ \'id\' => \'\d+\' ]` if left empty.')
 | 
			
		||||
                                        ->end()
 | 
			
		||||
                                        ->enumNode('single-collection')
 | 
			
		||||
                                            ->values(['single', 'collection'])
 | 
			
		||||
                                            ->defaultValue('single')
 | 
			
		||||
                                            ->info('indicates if the returned object is a single element or a collection. '.
 | 
			
		||||
                                                    'If the action name is `_index`, this value will always be considered as '.
 | 
			
		||||
                                                    '`collection`')
 | 
			
		||||
                                        ->end()
 | 
			
		||||
                                        ->arrayNode('methods')
 | 
			
		||||
                                            ->addDefaultsIfNotSet()
 | 
			
		||||
                                            ->info('the allowed methods')
 | 
			
		||||
                                            ->children()
 | 
			
		||||
                                                ->booleanNode(Request::METHOD_GET)->defaultTrue()->end()
 | 
			
		||||
                                                ->booleanNode(Request::METHOD_HEAD)->defaultTrue()->end()
 | 
			
		||||
                                                ->booleanNode(Request::METHOD_POST)->defaultFalse()->end()
 | 
			
		||||
                                                ->booleanNode(Request::METHOD_DELETE)->defaultFalse()->end()
 | 
			
		||||
                                                ->booleanNode(Request::METHOD_PUT)->defaultFalse()->end()
 | 
			
		||||
                                                ->booleanNode(Request::METHOD_PATCH)->defaultFalse()->end()
 | 
			
		||||
                                            ->end()
 | 
			
		||||
                                        ->end()
 | 
			
		||||
                                        ->arrayNode('roles')
 | 
			
		||||
                                            ->addDefaultsIfNotSet()
 | 
			
		||||
                                            ->info("The role require for each http method")
 | 
			
		||||
                                            ->children()
 | 
			
		||||
                                                ->scalarNode(Request::METHOD_GET)->defaultNull()->end()
 | 
			
		||||
                                                ->scalarNode(Request::METHOD_HEAD)->defaultNull()->end()
 | 
			
		||||
                                                ->scalarNode(Request::METHOD_POST)->defaultNull()->end()
 | 
			
		||||
                                                ->scalarNode(Request::METHOD_DELETE)->defaultNull()->end()
 | 
			
		||||
                                                ->scalarNode(Request::METHOD_PUT)->defaultNull()->end()
 | 
			
		||||
                                                ->scalarNode(Request::METHOD_PATCH)->defaultNull()->end()
 | 
			
		||||
                                            ->end()
 | 
			
		||||
                                        ->end()
 | 
			
		||||
                                    ->end()
 | 
			
		||||
                                ->end()
 | 
			
		||||
                            ->end()
 | 
			
		||||
                        ->end()
 | 
			
		||||
                    ->end()
 | 
			
		||||
 | 
			
		||||
                ->end()
 | 
			
		||||
               ->end() // end of root/children
 | 
			
		||||
            ->end() // end of root
 | 
			
		||||
        ;
 | 
			
		||||
 
 | 
			
		||||
@@ -1,65 +0,0 @@
 | 
			
		||||
<?php
 | 
			
		||||
 | 
			
		||||
namespace Chill\MainBundle\Doctrine\Event;
 | 
			
		||||
 | 
			
		||||
use Chill\MainBundle\Entity\User;
 | 
			
		||||
use Doctrine\Common\EventSubscriber;
 | 
			
		||||
use Doctrine\ORM\Events;
 | 
			
		||||
use Doctrine\Persistence\Event\LifecycleEventArgs;
 | 
			
		||||
use Chill\MainBundle\Doctrine\Model\TrackCreationInterface;
 | 
			
		||||
use Chill\MainBundle\Doctrine\Model\TrackUpdateInterface;
 | 
			
		||||
use Symfony\Component\Security\Core\Security;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class TrackCreateUpdateSubscriber implements EventSubscriber
 | 
			
		||||
{
 | 
			
		||||
    private Security $security;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * @param Security $security
 | 
			
		||||
     */
 | 
			
		||||
    public function __construct(Security $security)
 | 
			
		||||
    {
 | 
			
		||||
        $this->security = $security;
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    /**
 | 
			
		||||
     * {@inheritDoc}
 | 
			
		||||
     */
 | 
			
		||||
    public function getSubscribedEvents()
 | 
			
		||||
    {
 | 
			
		||||
        return [
 | 
			
		||||
            Events::prePersist,
 | 
			
		||||
            Events::preUpdate
 | 
			
		||||
        ];
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function prePersist(LifecycleEventArgs $args): void
 | 
			
		||||
    {
 | 
			
		||||
        $object = $args->getObject();
 | 
			
		||||
 | 
			
		||||
        if ($object instanceof TrackCreationInterface
 | 
			
		||||
            && $this->security->getUser() instanceof User) {
 | 
			
		||||
            $object->setCreatedBy($this->security->getUser());
 | 
			
		||||
            $object->setCreatedAt(new \DateTimeImmutable('now'));
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        $this->onUpdate($object);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function preUpdate(LifecycleEventArgs $args): void
 | 
			
		||||
    {
 | 
			
		||||
        $object = $args->getObject();
 | 
			
		||||
 | 
			
		||||
        $this->onUpdate($object);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    protected function onUpdate(object $object): void
 | 
			
		||||
    {
 | 
			
		||||
        if ($object instanceof TrackUpdateInterface 
 | 
			
		||||
            && $this->security->getUser() instanceof User) {
 | 
			
		||||
            $object->setUpdatedBy($this->security->getUser());
 | 
			
		||||
            $object->setUpdatedAt(new \DateTimeImmutable('now'));
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -1,103 +0,0 @@
 | 
			
		||||
<?php
 | 
			
		||||
 | 
			
		||||
namespace Chill\MainBundle\Doctrine\Model;
 | 
			
		||||
 | 
			
		||||
use \JsonSerializable;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Description of Point
 | 
			
		||||
 *
 | 
			
		||||
 */
 | 
			
		||||
class Point implements JsonSerializable {
 | 
			
		||||
    private ?float $lat = null;
 | 
			
		||||
    private ?float $lon = null;
 | 
			
		||||
    public static string $SRID = '4326';
 | 
			
		||||
 | 
			
		||||
    private function __construct(?float $lon, ?float $lat)
 | 
			
		||||
    {
 | 
			
		||||
        $this->lat = $lat;
 | 
			
		||||
        $this->lon = $lon;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function toGeoJson(): string
 | 
			
		||||
    {
 | 
			
		||||
        $array = $this->toArrayGeoJson();
 | 
			
		||||
        return \json_encode($array);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function jsonSerialize(): array
 | 
			
		||||
    {
 | 
			
		||||
        return $this->toArrayGeoJson();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function toArrayGeoJson(): array
 | 
			
		||||
    {
 | 
			
		||||
        return [
 | 
			
		||||
            "type" => "Point",
 | 
			
		||||
            "coordinates" => [ $this->lon, $this->lat ]
 | 
			
		||||
        ];
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     *
 | 
			
		||||
     * @return string
 | 
			
		||||
     */
 | 
			
		||||
    public function toWKT(): string
 | 
			
		||||
    {
 | 
			
		||||
        return 'SRID='.self::$SRID.';POINT('.$this->lon.' '.$this->lat.')';
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     *
 | 
			
		||||
     * @param type $geojson
 | 
			
		||||
     * @return Point
 | 
			
		||||
     */
 | 
			
		||||
    public static function fromGeoJson(string $geojson): Point
 | 
			
		||||
    {
 | 
			
		||||
        $a = json_decode($geojson);
 | 
			
		||||
        //check if the geojson string is correct
 | 
			
		||||
        if (NULL === $a or !isset($a->type) or !isset($a->coordinates)){
 | 
			
		||||
            throw PointException::badJsonString($geojson);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if ($a->type != 'Point'){
 | 
			
		||||
            throw PointException::badGeoType();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        $lat = $a->coordinates[1];
 | 
			
		||||
        $lon = $a->coordinates[0];
 | 
			
		||||
 | 
			
		||||
        return Point::fromLonLat($lon, $lat);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public static function fromLonLat(float $lon, float $lat): Point
 | 
			
		||||
    {
 | 
			
		||||
        if (($lon > -180 && $lon < 180) && ($lat > -90 && $lat < 90))
 | 
			
		||||
        {
 | 
			
		||||
            return new Point($lon, $lat);
 | 
			
		||||
        } else {
 | 
			
		||||
            throw PointException::badCoordinates($lon, $lat);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public static function fromArrayGeoJson(array $array): Point
 | 
			
		||||
    {
 | 
			
		||||
        if ($array['type'] == 'Point' &&
 | 
			
		||||
                isset($array['coordinates']))
 | 
			
		||||
        {
 | 
			
		||||
            return self::fromLonLat($array['coordinates'][0], $array['coordinates'][1]);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function getLat(): float
 | 
			
		||||
    {
 | 
			
		||||
        return $this->lat;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function getLon(): float
 | 
			
		||||
    {
 | 
			
		||||
        return $this->lon;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@@ -1,27 +0,0 @@
 | 
			
		||||
<?php
 | 
			
		||||
 | 
			
		||||
namespace Chill\MainBundle\Doctrine\Model;
 | 
			
		||||
 | 
			
		||||
use \Exception;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Description of PointException
 | 
			
		||||
 *
 | 
			
		||||
 */
 | 
			
		||||
class PointException extends Exception {
 | 
			
		||||
 | 
			
		||||
    public static function badCoordinates($lon, $lat): self
 | 
			
		||||
    {
 | 
			
		||||
        return new self("Input coordinates are not valid in the used coordinate system (longitude = $lon , latitude = $lat)");
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public static function badJsonString($str): self
 | 
			
		||||
    {
 | 
			
		||||
        return new self("The JSON string is not valid: $str");
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public static function badGeoType(): self
 | 
			
		||||
    {
 | 
			
		||||
        return new self("The geoJSON object type is not valid");
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -1,12 +0,0 @@
 | 
			
		||||
<?php
 | 
			
		||||
 | 
			
		||||
namespace Chill\MainBundle\Doctrine\Model;
 | 
			
		||||
 | 
			
		||||
use Chill\MainBundle\Entity\User;
 | 
			
		||||
 | 
			
		||||
interface TrackCreationInterface
 | 
			
		||||
{
 | 
			
		||||
    public function setCreatedBy(User $user): self;
 | 
			
		||||
 | 
			
		||||
    public function setCreatedAt(\DateTimeInterface $datetime): self;
 | 
			
		||||
}
 | 
			
		||||
@@ -1,12 +0,0 @@
 | 
			
		||||
<?php
 | 
			
		||||
 | 
			
		||||
namespace Chill\MainBundle\Doctrine\Model;
 | 
			
		||||
 | 
			
		||||
use Chill\MainBundle\Entity\User;
 | 
			
		||||
 | 
			
		||||
interface TrackUpdateInterface
 | 
			
		||||
{
 | 
			
		||||
    public function setUpdatedBy(User $user): self;
 | 
			
		||||
 | 
			
		||||
    public function setUpdatedAt(\DateTimeInterface $datetime): self;
 | 
			
		||||
}
 | 
			
		||||
@@ -1,75 +0,0 @@
 | 
			
		||||
<?php
 | 
			
		||||
 | 
			
		||||
namespace Chill\MainBundle\Doctrine\Type;
 | 
			
		||||
 | 
			
		||||
use Chill\MainBundle\Doctrine\Model\Point;
 | 
			
		||||
use Doctrine\DBAL\Types\Type;
 | 
			
		||||
use Doctrine\DBAL\Platforms\AbstractPlatform;
 | 
			
		||||
use Chill\MainBundle\Doctrine\Model\PointException;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * A Type for Doctrine to implement the Geography Point type
 | 
			
		||||
 * implemented by Postgis on postgis+postgresql databases
 | 
			
		||||
 *
 | 
			
		||||
 */
 | 
			
		||||
class PointType extends Type {
 | 
			
		||||
 | 
			
		||||
    const POINT = 'point';
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     *
 | 
			
		||||
     * @param array $fieldDeclaration
 | 
			
		||||
     * @param AbstractPlatform $platform
 | 
			
		||||
     * @return type
 | 
			
		||||
     */
 | 
			
		||||
    public function getSqlDeclaration(array $fieldDeclaration, AbstractPlatform $platform)
 | 
			
		||||
    {
 | 
			
		||||
        return 'geometry(POINT,'.Point::$SRID.')';
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     *
 | 
			
		||||
     * @param type $value
 | 
			
		||||
     * @param AbstractPlatform $platform
 | 
			
		||||
     * @return Point
 | 
			
		||||
     */
 | 
			
		||||
    public function convertToPHPValue($value, AbstractPlatform $platform)
 | 
			
		||||
    {
 | 
			
		||||
        if ($value === NULL){
 | 
			
		||||
            return NULL;
 | 
			
		||||
        } else {
 | 
			
		||||
            return Point::fromGeoJson($value);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function getName()
 | 
			
		||||
    {
 | 
			
		||||
        return self::POINT;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function convertToDatabaseValue($value, AbstractPlatform $platform)
 | 
			
		||||
    {
 | 
			
		||||
        if ($value === NULL){
 | 
			
		||||
            return NULL;
 | 
			
		||||
        } else {
 | 
			
		||||
            return $value->toWKT();
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function canRequireSQLConversion()
 | 
			
		||||
    {
 | 
			
		||||
        return true;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function convertToPHPValueSQL($sqlExpr, $platform)
 | 
			
		||||
    {
 | 
			
		||||
        return 'ST_AsGeoJSON('.$sqlExpr.') ';
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function convertToDatabaseValueSQL($sqlExpr, AbstractPlatform $platform)
 | 
			
		||||
    {
 | 
			
		||||
        return $sqlExpr;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -4,9 +4,6 @@ namespace Chill\MainBundle\Entity;
 | 
			
		||||
 | 
			
		||||
use Doctrine\ORM\Mapping as ORM;
 | 
			
		||||
use Symfony\Component\Validator\Context\ExecutionContextInterface;
 | 
			
		||||
use Symfony\Component\Serializer\Annotation\Groups;
 | 
			
		||||
use Chill\MainBundle\Doctrine\Model\Point;
 | 
			
		||||
use Chill\ThirdPartyBundle\Entity\ThirdParty;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Address
 | 
			
		||||
@@ -23,7 +20,6 @@ class Address
 | 
			
		||||
     * @ORM\Id
 | 
			
		||||
     * @ORM\Column(name="id", type="integer")
 | 
			
		||||
     * @ORM\GeneratedValue(strategy="AUTO")
 | 
			
		||||
     * @groups({"write"})
 | 
			
		||||
     */
 | 
			
		||||
    private $id;
 | 
			
		||||
 | 
			
		||||
@@ -31,82 +27,23 @@ class Address
 | 
			
		||||
     * @var string
 | 
			
		||||
     *
 | 
			
		||||
     * @ORM\Column(type="string", length=255)
 | 
			
		||||
     * @groups({"write"})
 | 
			
		||||
     */
 | 
			
		||||
    private $street = '';
 | 
			
		||||
    private $streetAddress1 = '';
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * @var string
 | 
			
		||||
     *
 | 
			
		||||
     * @ORM\Column(type="string", length=255)
 | 
			
		||||
     * @groups({"write"})
 | 
			
		||||
     */
 | 
			
		||||
    private $streetNumber = '';
 | 
			
		||||
    private $streetAddress2 = '';
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * @var PostalCode
 | 
			
		||||
     *
 | 
			
		||||
     * @ORM\ManyToOne(targetEntity="Chill\MainBundle\Entity\PostalCode")
 | 
			
		||||
     * @groups({"write"})
 | 
			
		||||
     */
 | 
			
		||||
    private $postcode;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * @var string|null
 | 
			
		||||
     *
 | 
			
		||||
     * @ORM\Column(type="string", length=16, nullable=true)
 | 
			
		||||
     * @groups({"write"})
 | 
			
		||||
     */
 | 
			
		||||
    private $floor;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * @var string|null
 | 
			
		||||
     *
 | 
			
		||||
     * @ORM\Column(type="string", length=16, nullable=true)
 | 
			
		||||
     * @groups({"write"})
 | 
			
		||||
     */
 | 
			
		||||
    private $corridor;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * @var string|null
 | 
			
		||||
     *
 | 
			
		||||
     * @ORM\Column(type="string", length=16, nullable=true)
 | 
			
		||||
     * @groups({"write"})
 | 
			
		||||
     */
 | 
			
		||||
    private $steps;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * @var string|null
 | 
			
		||||
     *
 | 
			
		||||
     * @ORM\Column(type="string", length=255, nullable=true)
 | 
			
		||||
     * @groups({"write"})
 | 
			
		||||
     */
 | 
			
		||||
    private $buildingName;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * @var string|null
 | 
			
		||||
     *
 | 
			
		||||
     * @ORM\Column(type="string", length=16, nullable=true)
 | 
			
		||||
     * @groups({"write"})
 | 
			
		||||
     */
 | 
			
		||||
    private $flat;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * @var string|null
 | 
			
		||||
     *
 | 
			
		||||
     * @ORM\Column(type="string", length=255, nullable=true)
 | 
			
		||||
     * @groups({"write"})
 | 
			
		||||
     */
 | 
			
		||||
    private $distribution;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * @var string|null
 | 
			
		||||
     *
 | 
			
		||||
     * @ORM\Column(type="string", length=255, nullable=true)
 | 
			
		||||
     * @groups({"write"})
 | 
			
		||||
     */
 | 
			
		||||
    private $extra;
 | 
			
		||||
 | 
			
		||||
    
 | 
			
		||||
    /**
 | 
			
		||||
     * Indicates when the address starts validation. Used to build an history
 | 
			
		||||
     * of address. By default, the current date.
 | 
			
		||||
@@ -114,62 +51,29 @@ class Address
 | 
			
		||||
     * @var \DateTime
 | 
			
		||||
     *
 | 
			
		||||
     * @ORM\Column(type="date")
 | 
			
		||||
     * @groups({"write"})
 | 
			
		||||
     */
 | 
			
		||||
    private $validFrom;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Indicates when the address ends. Used to build an history
 | 
			
		||||
     * of address.
 | 
			
		||||
     *
 | 
			
		||||
     * @var \DateTime|null
 | 
			
		||||
     *
 | 
			
		||||
     * @ORM\Column(type="date", nullable=true)
 | 
			
		||||
     * @groups({"write"})
 | 
			
		||||
     */
 | 
			
		||||
    private $validTo;
 | 
			
		||||
 | 
			
		||||
    
 | 
			
		||||
    /**
 | 
			
		||||
     * True if the address is a "no address", aka homeless person, ...
 | 
			
		||||
     * @groups({"write"})
 | 
			
		||||
     *
 | 
			
		||||
     * @var bool
 | 
			
		||||
     */
 | 
			
		||||
    private $isNoAddress = false;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * A geospatial field storing the coordinates of the Address
 | 
			
		||||
     *
 | 
			
		||||
     * @var Point|null
 | 
			
		||||
     *
 | 
			
		||||
     * @ORM\Column(type="point", nullable=true)
 | 
			
		||||
     * @groups({"write"})
 | 
			
		||||
     */
 | 
			
		||||
    private $point;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * A ThirdParty reference for person's addresses that are linked to a third party
 | 
			
		||||
     *
 | 
			
		||||
     * @var ThirdParty|null
 | 
			
		||||
     *
 | 
			
		||||
     * @ORM\ManyToOne(targetEntity="Chill\ThirdPartyBundle\Entity\ThirdParty")
 | 
			
		||||
     * @groups({"write"})
 | 
			
		||||
     * @ORM\JoinColumn(nullable=true, onDelete="SET NULL")
 | 
			
		||||
     */
 | 
			
		||||
    private $linkedToThirdParty;
 | 
			
		||||
 | 
			
		||||
    
 | 
			
		||||
    /**
 | 
			
		||||
     * A list of metadata, added by customizable fields
 | 
			
		||||
     *
 | 
			
		||||
     * 
 | 
			
		||||
     * @var array
 | 
			
		||||
     */
 | 
			
		||||
    private $customs = [];
 | 
			
		||||
 | 
			
		||||
    
 | 
			
		||||
    public function __construct()
 | 
			
		||||
    {
 | 
			
		||||
        $this->validFrom = new \DateTime();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Get id
 | 
			
		||||
     *
 | 
			
		||||
@@ -181,7 +85,7 @@ class Address
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Set streetAddress1 (legacy function)
 | 
			
		||||
     * Set streetAddress1
 | 
			
		||||
     *
 | 
			
		||||
     * @param string $streetAddress1
 | 
			
		||||
     *
 | 
			
		||||
@@ -189,23 +93,23 @@ class Address
 | 
			
		||||
     */
 | 
			
		||||
    public function setStreetAddress1($streetAddress1)
 | 
			
		||||
    {
 | 
			
		||||
        $this->street = $streetAddress1 === NULL ? '' : $streetAddress1;
 | 
			
		||||
        $this->streetAddress1 = $streetAddress1 === NULL ? '' : $streetAddress1;
 | 
			
		||||
 | 
			
		||||
        return $this;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Get streetAddress1 (legacy function)
 | 
			
		||||
     * Get streetAddress1
 | 
			
		||||
     *
 | 
			
		||||
     * @return string
 | 
			
		||||
     */
 | 
			
		||||
    public function getStreetAddress1()
 | 
			
		||||
    {
 | 
			
		||||
        return $this->street;
 | 
			
		||||
        return $this->streetAddress1;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Set streetAddress2 (legacy function)
 | 
			
		||||
     * Set streetAddress2
 | 
			
		||||
     *
 | 
			
		||||
     * @param string $streetAddress2
 | 
			
		||||
     *
 | 
			
		||||
@@ -213,19 +117,19 @@ class Address
 | 
			
		||||
     */
 | 
			
		||||
    public function setStreetAddress2($streetAddress2)
 | 
			
		||||
    {
 | 
			
		||||
        $this->streetNumber = $streetAddress2 === NULL ? '' : $streetAddress2;
 | 
			
		||||
        $this->streetAddress2 = $streetAddress2 === NULL ? '' : $streetAddress2;
 | 
			
		||||
 | 
			
		||||
        return $this;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Get streetAddress2 (legacy function)
 | 
			
		||||
     * Get streetAddress2
 | 
			
		||||
     *
 | 
			
		||||
     * @return string
 | 
			
		||||
     */
 | 
			
		||||
    public function getStreetAddress2()
 | 
			
		||||
    {
 | 
			
		||||
        return $this->streetNumber;
 | 
			
		||||
        return $this->streetAddress2;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
@@ -251,7 +155,7 @@ class Address
 | 
			
		||||
    {
 | 
			
		||||
        return $this->postcode;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    
 | 
			
		||||
    /**
 | 
			
		||||
     * @return \DateTime
 | 
			
		||||
     */
 | 
			
		||||
@@ -269,19 +173,19 @@ class Address
 | 
			
		||||
        $this->validFrom = $validFrom;
 | 
			
		||||
        return $this;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    
 | 
			
		||||
    /**
 | 
			
		||||
     * Get IsNoAddress
 | 
			
		||||
     *
 | 
			
		||||
     * 
 | 
			
		||||
     * Indicate true if the address is a fake address (homeless, ...)
 | 
			
		||||
     *
 | 
			
		||||
     * 
 | 
			
		||||
     * @return bool
 | 
			
		||||
     */
 | 
			
		||||
    public function getIsNoAddress(): bool
 | 
			
		||||
    {
 | 
			
		||||
        return $this->isNoAddress;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    
 | 
			
		||||
    /**
 | 
			
		||||
     * @return bool
 | 
			
		||||
     */
 | 
			
		||||
@@ -292,9 +196,9 @@ class Address
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Set IsNoAddress
 | 
			
		||||
     *
 | 
			
		||||
     * 
 | 
			
		||||
     * Indicate true if the address is a fake address (homeless, ...)
 | 
			
		||||
     *
 | 
			
		||||
     * 
 | 
			
		||||
     * @param bool $isNoAddress
 | 
			
		||||
     * @return $this
 | 
			
		||||
     */
 | 
			
		||||
@@ -303,10 +207,10 @@ class Address
 | 
			
		||||
        $this->isNoAddress = $isNoAddress;
 | 
			
		||||
        return $this;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    
 | 
			
		||||
    /**
 | 
			
		||||
     * Get customs informations in the address
 | 
			
		||||
     *
 | 
			
		||||
     * 
 | 
			
		||||
     * @return array
 | 
			
		||||
     */
 | 
			
		||||
    public function getCustoms(): array
 | 
			
		||||
@@ -316,27 +220,27 @@ class Address
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Store custom informations in the address
 | 
			
		||||
     *
 | 
			
		||||
     * 
 | 
			
		||||
     * @param array $customs
 | 
			
		||||
     * @return $this
 | 
			
		||||
     */
 | 
			
		||||
    public function setCustoms(array $customs): self
 | 
			
		||||
    {
 | 
			
		||||
        $this->customs = $customs;
 | 
			
		||||
 | 
			
		||||
        
 | 
			
		||||
        return $this;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
        
 | 
			
		||||
    /**
 | 
			
		||||
     * Validate the address.
 | 
			
		||||
     *
 | 
			
		||||
     * 
 | 
			
		||||
     * Check that:
 | 
			
		||||
     *
 | 
			
		||||
     * 
 | 
			
		||||
     * * if the address is not home address:
 | 
			
		||||
     *     * the postal code is present
 | 
			
		||||
     *     * the valid from is not null
 | 
			
		||||
     *     * the address street 1 is greater than 2
 | 
			
		||||
     *
 | 
			
		||||
     * 
 | 
			
		||||
     * @param ExecutionContextInterface $context
 | 
			
		||||
     * @param array $payload
 | 
			
		||||
     */
 | 
			
		||||
@@ -348,18 +252,18 @@ class Address
 | 
			
		||||
                ->atPath('validFrom')
 | 
			
		||||
                ->addViolation();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        
 | 
			
		||||
        if ($this->isNoAddress()) {
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        
 | 
			
		||||
        if (empty($this->getStreetAddress1())) {
 | 
			
		||||
            $context
 | 
			
		||||
                ->buildViolation("address.street1-should-be-set")
 | 
			
		||||
                ->atPath('streetAddress1')
 | 
			
		||||
                ->addViolation();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        
 | 
			
		||||
        if (!$this->getPostcode() instanceof PostalCode) {
 | 
			
		||||
            $context
 | 
			
		||||
                ->buildViolation("address.postcode-should-be-set")
 | 
			
		||||
@@ -367,7 +271,7 @@ class Address
 | 
			
		||||
                ->addViolation();
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    
 | 
			
		||||
    /**
 | 
			
		||||
     * @param Address $original
 | 
			
		||||
     * @return Address
 | 
			
		||||
@@ -382,149 +286,5 @@ class Address
 | 
			
		||||
            ;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function getStreet(): ?string
 | 
			
		||||
    {
 | 
			
		||||
        return $this->street;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function setStreet(string $street): self
 | 
			
		||||
    {
 | 
			
		||||
        $this->street = $street;
 | 
			
		||||
 | 
			
		||||
        return $this;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function getStreetNumber(): ?string
 | 
			
		||||
    {
 | 
			
		||||
        return $this->streetNumber;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function setStreetNumber(string $streetNumber): self
 | 
			
		||||
    {
 | 
			
		||||
        $this->streetNumber = $streetNumber;
 | 
			
		||||
 | 
			
		||||
        return $this;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function getFloor(): ?string
 | 
			
		||||
    {
 | 
			
		||||
        return $this->floor;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function setFloor(?string $floor): self
 | 
			
		||||
    {
 | 
			
		||||
        $this->floor = $floor;
 | 
			
		||||
 | 
			
		||||
        return $this;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function getCorridor(): ?string
 | 
			
		||||
    {
 | 
			
		||||
        return $this->corridor;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function setCorridor(?string $corridor): self
 | 
			
		||||
    {
 | 
			
		||||
        $this->corridor = $corridor;
 | 
			
		||||
 | 
			
		||||
        return $this;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function getSteps(): ?string
 | 
			
		||||
    {
 | 
			
		||||
        return $this->steps;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function setSteps(?string $steps): self
 | 
			
		||||
    {
 | 
			
		||||
        $this->steps = $steps;
 | 
			
		||||
 | 
			
		||||
        return $this;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function getBuildingName(): ?string
 | 
			
		||||
    {
 | 
			
		||||
        return $this->buildingName;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function setBuildingName(?string $buildingName): self
 | 
			
		||||
    {
 | 
			
		||||
        $this->buildingName = $buildingName;
 | 
			
		||||
 | 
			
		||||
        return $this;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function getFlat(): ?string
 | 
			
		||||
    {
 | 
			
		||||
        return $this->flat;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function setFlat(?string $flat): self
 | 
			
		||||
    {
 | 
			
		||||
        $this->flat = $flat;
 | 
			
		||||
 | 
			
		||||
        return $this;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function getDistribution(): ?string
 | 
			
		||||
    {
 | 
			
		||||
        return $this->distribution;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function setDistribution(?string $distribution): self
 | 
			
		||||
    {
 | 
			
		||||
        $this->distribution = $distribution;
 | 
			
		||||
 | 
			
		||||
        return $this;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function getExtra(): ?string
 | 
			
		||||
    {
 | 
			
		||||
        return $this->extra;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function setExtra(?string $extra): self
 | 
			
		||||
    {
 | 
			
		||||
        $this->extra = $extra;
 | 
			
		||||
 | 
			
		||||
        return $this;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function getValidTo(): ?\DateTimeInterface
 | 
			
		||||
    {
 | 
			
		||||
        return $this->validTo;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function setValidTo(\DateTimeInterface $validTo): self
 | 
			
		||||
    {
 | 
			
		||||
        $this->validTo = $validTo;
 | 
			
		||||
 | 
			
		||||
        return $this;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function getPoint(): ?Point
 | 
			
		||||
    {
 | 
			
		||||
        return $this->point;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function setPoint(?Point $point): self
 | 
			
		||||
    {
 | 
			
		||||
        $this->point = $point;
 | 
			
		||||
 | 
			
		||||
        return $this;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function getLinkedToThirdParty()
 | 
			
		||||
    {
 | 
			
		||||
        return $this->linkedToThirdParty;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function setLinkedToThirdParty($linkedToThirdParty): self
 | 
			
		||||
    {
 | 
			
		||||
        $this->linkedToThirdParty = $linkedToThirdParty;
 | 
			
		||||
 | 
			
		||||
        return $this;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -1,173 +0,0 @@
 | 
			
		||||
<?php
 | 
			
		||||
 | 
			
		||||
namespace Chill\MainBundle\Entity;
 | 
			
		||||
 | 
			
		||||
use Doctrine\ORM\Mapping as ORM;
 | 
			
		||||
use Chill\MainBundle\Doctrine\Model\Point;
 | 
			
		||||
use Symfony\Component\Serializer\Annotation\Groups;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * @ORM\Entity()
 | 
			
		||||
 * @ORM\Table(name="chill_main_address_reference")
 | 
			
		||||
 * @ORM\HasLifecycleCallbacks()
 | 
			
		||||
 */
 | 
			
		||||
class AddressReference
 | 
			
		||||
{
 | 
			
		||||
    /**
 | 
			
		||||
     * @ORM\Id
 | 
			
		||||
     * @ORM\GeneratedValue
 | 
			
		||||
     * @ORM\Column(type="integer")
 | 
			
		||||
     * @groups({"read"})
 | 
			
		||||
     */
 | 
			
		||||
    private $id;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * @ORM\Column(type="string", length=255)
 | 
			
		||||
     * @groups({"read"})
 | 
			
		||||
     */
 | 
			
		||||
    private $refId;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * @ORM\Column(type="string", length=255, nullable=true)
 | 
			
		||||
     * @groups({"read"})
 | 
			
		||||
     */
 | 
			
		||||
    private $street;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * @ORM\Column(type="string", length=255, nullable=true)
 | 
			
		||||
     * @groups({"read"})
 | 
			
		||||
     */
 | 
			
		||||
    private $streetNumber;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * @var PostalCode
 | 
			
		||||
     *
 | 
			
		||||
     * @ORM\ManyToOne(targetEntity="Chill\MainBundle\Entity\PostalCode")
 | 
			
		||||
     * @groups({"read"})
 | 
			
		||||
     */
 | 
			
		||||
    private $postcode;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * @ORM\Column(type="string", length=255, nullable=true)
 | 
			
		||||
     * @groups({"read"})
 | 
			
		||||
     */
 | 
			
		||||
    private $municipalityCode;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * @ORM\Column(type="string", length=255, nullable=true)
 | 
			
		||||
     * @groups({"read"})
 | 
			
		||||
     */
 | 
			
		||||
    private $source;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * A geospatial field storing the coordinates of the Address
 | 
			
		||||
     *
 | 
			
		||||
     * @var Point
 | 
			
		||||
     *
 | 
			
		||||
     * @ORM\Column(type="point")
 | 
			
		||||
     * @groups({"read"})
 | 
			
		||||
     */
 | 
			
		||||
    private $point;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    public function getId(): ?int
 | 
			
		||||
    {
 | 
			
		||||
        return $this->id;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function getRefId(): ?string
 | 
			
		||||
    {
 | 
			
		||||
        return $this->refId;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function setRefId(string $refId): self
 | 
			
		||||
    {
 | 
			
		||||
        $this->refId = $refId;
 | 
			
		||||
 | 
			
		||||
        return $this;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function getStreet(): ?string
 | 
			
		||||
    {
 | 
			
		||||
        return $this->street;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function setStreet(?string $street): self
 | 
			
		||||
    {
 | 
			
		||||
        $this->street = $street;
 | 
			
		||||
 | 
			
		||||
        return $this;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function getStreetNumber(): ?string
 | 
			
		||||
    {
 | 
			
		||||
        return $this->streetNumber;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function setStreetNumber(?string $streetNumber): self
 | 
			
		||||
    {
 | 
			
		||||
        $this->streetNumber = $streetNumber;
 | 
			
		||||
 | 
			
		||||
        return $this;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Set postcode
 | 
			
		||||
     *
 | 
			
		||||
     * @param PostalCode $postcode
 | 
			
		||||
     *
 | 
			
		||||
     * @return Address
 | 
			
		||||
     */
 | 
			
		||||
    public function setPostcode(PostalCode $postcode = null)
 | 
			
		||||
    {
 | 
			
		||||
        $this->postcode = $postcode;
 | 
			
		||||
 | 
			
		||||
        return $this;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Get postcode
 | 
			
		||||
     *
 | 
			
		||||
     * @return PostalCode
 | 
			
		||||
     */
 | 
			
		||||
    public function getPostcode()
 | 
			
		||||
    {
 | 
			
		||||
        return $this->postcode;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function getMunicipalityCode(): ?string
 | 
			
		||||
    {
 | 
			
		||||
        return $this->municipalityCode;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function setMunicipalityCode(?string $municipalityCode): self
 | 
			
		||||
    {
 | 
			
		||||
        $this->municipalityCode = $municipalityCode;
 | 
			
		||||
 | 
			
		||||
        return $this;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function getSource(): ?string
 | 
			
		||||
    {
 | 
			
		||||
        return $this->source;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function setSource(?string $source): self
 | 
			
		||||
    {
 | 
			
		||||
        $this->source = $source;
 | 
			
		||||
 | 
			
		||||
        return $this;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function getPoint(): ?Point
 | 
			
		||||
    {
 | 
			
		||||
        return $this->point;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function setPoint(?Point $point): self
 | 
			
		||||
    {
 | 
			
		||||
        $this->point = $point;
 | 
			
		||||
 | 
			
		||||
        return $this;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -3,7 +3,6 @@
 | 
			
		||||
namespace Chill\MainBundle\Entity;
 | 
			
		||||
 | 
			
		||||
use Doctrine\ORM\Mapping as ORM;
 | 
			
		||||
use Symfony\Component\Serializer\Annotation\Groups;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Country
 | 
			
		||||
@@ -21,7 +20,6 @@ class Country
 | 
			
		||||
     * @ORM\Id
 | 
			
		||||
     * @ORM\Column(name="id", type="integer")
 | 
			
		||||
     * @ORM\GeneratedValue(strategy="AUTO")
 | 
			
		||||
     * @groups({"read"})
 | 
			
		||||
     */
 | 
			
		||||
    private $id;
 | 
			
		||||
 | 
			
		||||
@@ -29,16 +27,13 @@ class Country
 | 
			
		||||
     * @var string
 | 
			
		||||
     *
 | 
			
		||||
     * @ORM\Column(type="json_array")
 | 
			
		||||
     * @groups({"read"})
 | 
			
		||||
     *
 | 
			
		||||
     */
 | 
			
		||||
    private $name;
 | 
			
		||||
 | 
			
		||||
    
 | 
			
		||||
    /**
 | 
			
		||||
     * @var string
 | 
			
		||||
     *
 | 
			
		||||
     * @ORM\Column(type="string", length=3)
 | 
			
		||||
     * @groups({"read"})
 | 
			
		||||
     */
 | 
			
		||||
    private $countryCode;
 | 
			
		||||
 | 
			
		||||
@@ -46,7 +41,7 @@ class Country
 | 
			
		||||
    /**
 | 
			
		||||
     * Get id
 | 
			
		||||
     *
 | 
			
		||||
     * @return integer
 | 
			
		||||
     * @return integer 
 | 
			
		||||
     */
 | 
			
		||||
    public function getId()
 | 
			
		||||
    {
 | 
			
		||||
@@ -62,20 +57,20 @@ class Country
 | 
			
		||||
    public function setName($name)
 | 
			
		||||
    {
 | 
			
		||||
        $this->name = $name;
 | 
			
		||||
 | 
			
		||||
    
 | 
			
		||||
        return $this;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Get name
 | 
			
		||||
     *
 | 
			
		||||
     * @return string
 | 
			
		||||
     * @return string 
 | 
			
		||||
     */
 | 
			
		||||
    public function getName()
 | 
			
		||||
    {
 | 
			
		||||
        return $this->name;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    
 | 
			
		||||
    /**
 | 
			
		||||
     * @return string
 | 
			
		||||
     */
 | 
			
		||||
@@ -95,12 +90,12 @@ class Country
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     *
 | 
			
		||||
     * @param string $countryCode
 | 
			
		||||
     * @param string $countryCode            
 | 
			
		||||
     */
 | 
			
		||||
    public function setCountryCode($countryCode)
 | 
			
		||||
    {
 | 
			
		||||
        $this->countryCode = $countryCode;
 | 
			
		||||
        return $this;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -3,7 +3,6 @@
 | 
			
		||||
namespace Chill\MainBundle\Entity;
 | 
			
		||||
 | 
			
		||||
use Doctrine\ORM\Mapping as ORM;
 | 
			
		||||
use Symfony\Component\Serializer\Annotation\Groups;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * PostalCode
 | 
			
		||||
@@ -26,7 +25,6 @@ class PostalCode
 | 
			
		||||
     * @ORM\Id
 | 
			
		||||
     * @ORM\Column(name="id", type="integer")
 | 
			
		||||
     * @ORM\GeneratedValue(strategy="AUTO")
 | 
			
		||||
     * @groups({"read"})
 | 
			
		||||
     */
 | 
			
		||||
    private $id;
 | 
			
		||||
 | 
			
		||||
@@ -34,7 +32,6 @@ class PostalCode
 | 
			
		||||
     * @var string
 | 
			
		||||
     *
 | 
			
		||||
     * @ORM\Column(type="string", length=255, name="label")
 | 
			
		||||
     * @groups({"read"})
 | 
			
		||||
     */
 | 
			
		||||
    private $name;
 | 
			
		||||
 | 
			
		||||
@@ -42,7 +39,6 @@ class PostalCode
 | 
			
		||||
     * @var string
 | 
			
		||||
     *
 | 
			
		||||
     * @ORM\Column(type="string", length=100)
 | 
			
		||||
     * @groups({"read"})
 | 
			
		||||
     */
 | 
			
		||||
    private $code;
 | 
			
		||||
 | 
			
		||||
@@ -50,7 +46,6 @@ class PostalCode
 | 
			
		||||
     * @var Country
 | 
			
		||||
     *
 | 
			
		||||
     * @ORM\ManyToOne(targetEntity="Chill\MainBundle\Entity\Country")
 | 
			
		||||
     * @groups({"read"})
 | 
			
		||||
     */
 | 
			
		||||
    private $country;
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -24,16 +24,13 @@ use Doctrine\ORM\Mapping as ORM;
 | 
			
		||||
use Doctrine\Common\Collections\Collection;
 | 
			
		||||
use Doctrine\Common\Collections\ArrayCollection;
 | 
			
		||||
use Chill\MainBundle\Entity\RoleScope;
 | 
			
		||||
use Symfony\Component\Serializer\Annotation\Groups;
 | 
			
		||||
use Symfony\Component\Serializer\Annotation\DiscriminatorMap;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * @ORM\Entity()
 | 
			
		||||
 * @ORM\Table(name="scopes")
 | 
			
		||||
 * @ORM\Cache(usage="NONSTRICT_READ_WRITE", region="acl_cache_region")
 | 
			
		||||
 * @DiscriminatorMap(typeProperty="type", mapping={
 | 
			
		||||
 *    "scope"=Scope::class
 | 
			
		||||
 * })
 | 
			
		||||
 *
 | 
			
		||||
 * @author Julien Fastré <julien.fastre@champs-libres.coop>
 | 
			
		||||
 */
 | 
			
		||||
class Scope
 | 
			
		||||
{
 | 
			
		||||
@@ -43,7 +40,6 @@ class Scope
 | 
			
		||||
     * @ORM\Id
 | 
			
		||||
     * @ORM\Column(name="id", type="integer")
 | 
			
		||||
     * @ORM\GeneratedValue(strategy="AUTO")
 | 
			
		||||
     * @Groups({"read"})
 | 
			
		||||
     */
 | 
			
		||||
    private $id;
 | 
			
		||||
    
 | 
			
		||||
@@ -53,7 +49,6 @@ class Scope
 | 
			
		||||
     * @var array
 | 
			
		||||
     *
 | 
			
		||||
     * @ORM\Column(type="json_array")
 | 
			
		||||
     * @Groups({"read"})
 | 
			
		||||
     */
 | 
			
		||||
    private $name = [];
 | 
			
		||||
    
 | 
			
		||||
 
 | 
			
		||||
@@ -7,7 +7,6 @@ use Doctrine\Common\Collections\Collection;
 | 
			
		||||
use Doctrine\Common\Collections\ArrayCollection;
 | 
			
		||||
use Symfony\Component\Security\Core\User\AdvancedUserInterface;
 | 
			
		||||
use Symfony\Component\Validator\Context\ExecutionContextInterface;
 | 
			
		||||
use Symfony\Component\Serializer\Annotation\DiscriminatorMap;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * User
 | 
			
		||||
@@ -15,9 +14,6 @@ use Symfony\Component\Serializer\Annotation\DiscriminatorMap;
 | 
			
		||||
 * @ORM\Entity(repositoryClass="Chill\MainBundle\Repository\UserRepository")
 | 
			
		||||
 * @ORM\Table(name="users")
 | 
			
		||||
 * @ORM\Cache(usage="NONSTRICT_READ_WRITE", region="acl_cache_region")
 | 
			
		||||
 * @DiscriminatorMap(typeProperty="type", mapping={
 | 
			
		||||
 *    "user"=User::class
 | 
			
		||||
 * })
 | 
			
		||||
 */
 | 
			
		||||
class User implements AdvancedUserInterface {
 | 
			
		||||
    
 | 
			
		||||
 
 | 
			
		||||
@@ -33,8 +33,8 @@ use Symfony\Component\Form\Extension\Core\Type\ChoiceType;
 | 
			
		||||
 * A type to create/update Address entity
 | 
			
		||||
 *
 | 
			
		||||
 * Options:
 | 
			
		||||
 *
 | 
			
		||||
 * - `has_valid_from` (boolean): show if an entry "has valid from" must be
 | 
			
		||||
 * 
 | 
			
		||||
 * - `has_valid_from` (boolean): show if an entry "has valid from" must be 
 | 
			
		||||
 * shown.
 | 
			
		||||
 * - `null_if_empty` (boolean): replace the address type by null if the street
 | 
			
		||||
 * or the postCode is empty. This is useful when the address is not required and
 | 
			
		||||
@@ -45,10 +45,10 @@ class AddressType extends AbstractType
 | 
			
		||||
    public function buildForm(FormBuilderInterface $builder, array $options)
 | 
			
		||||
    {
 | 
			
		||||
        $builder
 | 
			
		||||
              ->add('street', TextType::class, array(
 | 
			
		||||
              ->add('streetAddress1', TextType::class, array(
 | 
			
		||||
                 'required' => !$options['has_no_address'] // true if has no address is false
 | 
			
		||||
              ))
 | 
			
		||||
              ->add('streetNumber', TextType::class, array(
 | 
			
		||||
              ->add('streetAddress2', TextType::class, array(
 | 
			
		||||
                 'required' => false
 | 
			
		||||
              ))
 | 
			
		||||
              ->add('postCode', PostalCodeType::class, array(
 | 
			
		||||
@@ -57,7 +57,7 @@ class AddressType extends AbstractType
 | 
			
		||||
                 'required' => !$options['has_no_address'] // true if has no address is false
 | 
			
		||||
              ))
 | 
			
		||||
            ;
 | 
			
		||||
 | 
			
		||||
        
 | 
			
		||||
        if ($options['has_valid_from']) {
 | 
			
		||||
            $builder
 | 
			
		||||
              ->add('validFrom', DateType::class, array(
 | 
			
		||||
@@ -67,7 +67,7 @@ class AddressType extends AbstractType
 | 
			
		||||
                 )
 | 
			
		||||
              );
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        
 | 
			
		||||
        if ($options['has_no_address']) {
 | 
			
		||||
            $builder
 | 
			
		||||
                ->add('isNoAddress', ChoiceType::class, [
 | 
			
		||||
@@ -79,12 +79,12 @@ class AddressType extends AbstractType
 | 
			
		||||
                    'label' => 'address.address_homeless'
 | 
			
		||||
                ]);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        
 | 
			
		||||
        if ($options['null_if_empty'] === TRUE) {
 | 
			
		||||
            $builder->setDataMapper(new AddressDataMapper());
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    
 | 
			
		||||
    public function configureOptions(OptionsResolver $resolver)
 | 
			
		||||
    {
 | 
			
		||||
        $resolver
 | 
			
		||||
 
 | 
			
		||||
@@ -27,7 +27,6 @@ use Symfony\Component\Form\FormBuilderInterface;
 | 
			
		||||
use Chill\MainBundle\Form\Type\DataTransformer\ObjectToIdTransformer;
 | 
			
		||||
use Doctrine\Persistence\ObjectManager;
 | 
			
		||||
use Chill\MainBundle\Form\Type\Select2ChoiceType;
 | 
			
		||||
use Chill\MainBundle\Templating\TranslatableStringHelper;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Extends choice to allow adding select2 library on widget
 | 
			
		||||
@@ -42,26 +41,15 @@ class Select2CountryType extends AbstractType
 | 
			
		||||
     */
 | 
			
		||||
    private $requestStack;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     *
 | 
			
		||||
     * @var TranslatableStringHelper
 | 
			
		||||
     */
 | 
			
		||||
    protected $translatableStringHelper;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * @var ObjectManager
 | 
			
		||||
     */
 | 
			
		||||
    private $em;
 | 
			
		||||
 | 
			
		||||
    public function __construct(
 | 
			
		||||
        RequestStack $requestStack,
 | 
			
		||||
        ObjectManager $em,
 | 
			
		||||
        TranslatableStringHelper $translatableStringHelper
 | 
			
		||||
        )
 | 
			
		||||
    public function __construct(RequestStack $requestStack,ObjectManager $em)
 | 
			
		||||
    {
 | 
			
		||||
        $this->requestStack = $requestStack;
 | 
			
		||||
        $this->em = $em;
 | 
			
		||||
        $this->translatableStringHelper = $translatableStringHelper;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function getBlockPrefix()
 | 
			
		||||
@@ -87,7 +75,7 @@ class Select2CountryType extends AbstractType
 | 
			
		||||
        $choices = array();
 | 
			
		||||
 | 
			
		||||
        foreach ($countries as $c) {
 | 
			
		||||
            $choices[$c->getId()] = $this->translatableStringHelper->localize($c->getName());
 | 
			
		||||
            $choices[$c->getId()] = $c->getName()[$locale];
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        asort($choices, SORT_STRING | SORT_FLAG_CASE);
 | 
			
		||||
 
 | 
			
		||||
@@ -27,7 +27,6 @@ use Symfony\Component\Form\FormBuilderInterface;
 | 
			
		||||
use Chill\MainBundle\Form\Type\DataTransformer\MultipleObjectsToIdTransformer;
 | 
			
		||||
use Doctrine\Persistence\ObjectManager;
 | 
			
		||||
use Chill\MainBundle\Form\Type\Select2ChoiceType;
 | 
			
		||||
use Chill\MainBundle\Templating\TranslatableStringHelper;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Extends choice to allow adding select2 library on widget for languages (multiple)
 | 
			
		||||
@@ -44,21 +43,10 @@ class Select2LanguageType extends AbstractType
 | 
			
		||||
     */
 | 
			
		||||
    private $em;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     *
 | 
			
		||||
     * @var TranslatableStringHelper
 | 
			
		||||
     */
 | 
			
		||||
    protected $translatableStringHelper;
 | 
			
		||||
 | 
			
		||||
    public function __construct(
 | 
			
		||||
        RequestStack $requestStack,
 | 
			
		||||
        ObjectManager $em,
 | 
			
		||||
        TranslatableStringHelper $translatableStringHelper
 | 
			
		||||
        )
 | 
			
		||||
    public function __construct(RequestStack $requestStack,ObjectManager $em)
 | 
			
		||||
    {
 | 
			
		||||
        $this->requestStack = $requestStack;
 | 
			
		||||
        $this->em = $em;
 | 
			
		||||
        $this->translatableStringHelper = $translatableStringHelper;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function getBlockPrefix()
 | 
			
		||||
@@ -84,7 +72,7 @@ class Select2LanguageType extends AbstractType
 | 
			
		||||
        $choices = array();
 | 
			
		||||
 | 
			
		||||
        foreach ($languages as $l) {
 | 
			
		||||
            $choices[$l->getId()] = $this->translatableStringHelper->localize($l->getName());
 | 
			
		||||
            $choices[$l->getId()] = $l->getName()[$locale];
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        asort($choices, SORT_STRING | SORT_FLAG_CASE);
 | 
			
		||||
 
 | 
			
		||||
@@ -104,7 +104,7 @@ class Mailer
 | 
			
		||||
     * @param \User $to
 | 
			
		||||
     * @param array $subject Subject of the message [ 0 => $message (required), 1 => $parameters (optional), 3 => $domain (optional) ]
 | 
			
		||||
     * @param array $bodies The bodies. An array where keys are the contentType and values the bodies
 | 
			
		||||
     * @param callable $callback a callback to customize the message (add attachment, etc.)
 | 
			
		||||
     * @param \callable $callback a callback to customize the message (add attachment, etc.)
 | 
			
		||||
     */
 | 
			
		||||
    public function sendNotification(
 | 
			
		||||
        $recipient,
 | 
			
		||||
 
 | 
			
		||||
@@ -1,50 +0,0 @@
 | 
			
		||||
<?php
 | 
			
		||||
 | 
			
		||||
namespace Chill\MainBundle\Repository;
 | 
			
		||||
 | 
			
		||||
use Chill\MainBundle\Entity\AddressReference;
 | 
			
		||||
use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository;
 | 
			
		||||
use Doctrine\Persistence\ManagerRegistry;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * @method AddressReference|null find($id, $lockMode = null, $lockVersion = null)
 | 
			
		||||
 * @method AddressReference|null findOneBy(array $criteria, array $orderBy = null)
 | 
			
		||||
 * @method AddressReference[]    findAll()
 | 
			
		||||
 * @method AddressReference[]    findBy(array $criteria, array $orderBy = null, $limit = null, $offset = null)
 | 
			
		||||
 */
 | 
			
		||||
class AddressReferenceRepository extends ServiceEntityRepository
 | 
			
		||||
{
 | 
			
		||||
    public function __construct(ManagerRegistry $registry)
 | 
			
		||||
    {
 | 
			
		||||
        parent::__construct($registry, AddressReference::class);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // /**
 | 
			
		||||
    //  * @return AddressReference[] Returns an array of AddressReference objects
 | 
			
		||||
    //  */
 | 
			
		||||
    /*
 | 
			
		||||
    public function findByExampleField($value)
 | 
			
		||||
    {
 | 
			
		||||
        return $this->createQueryBuilder('a')
 | 
			
		||||
            ->andWhere('a.exampleField = :val')
 | 
			
		||||
            ->setParameter('val', $value)
 | 
			
		||||
            ->orderBy('a.id', 'ASC')
 | 
			
		||||
            ->setMaxResults(10)
 | 
			
		||||
            ->getQuery()
 | 
			
		||||
            ->getResult()
 | 
			
		||||
        ;
 | 
			
		||||
    }
 | 
			
		||||
    */
 | 
			
		||||
 | 
			
		||||
    /*
 | 
			
		||||
    public function findOneBySomeField($value): ?AddressReference
 | 
			
		||||
    {
 | 
			
		||||
        return $this->createQueryBuilder('a')
 | 
			
		||||
            ->andWhere('a.exampleField = :val')
 | 
			
		||||
            ->setParameter('val', $value)
 | 
			
		||||
            ->getQuery()
 | 
			
		||||
            ->getOneOrNullResult()
 | 
			
		||||
        ;
 | 
			
		||||
    }
 | 
			
		||||
    */
 | 
			
		||||
}
 | 
			
		||||
@@ -21,7 +21,9 @@ global.chill = chill;
 | 
			
		||||
/*
 | 
			
		||||
 * load requirements in chill entrypoint
 | 
			
		||||
 */
 | 
			
		||||
require('./scss/chillmain.scss');
 | 
			
		||||
 | 
			
		||||
require('./sass/scratch.scss');
 | 
			
		||||
 | 
			
		||||
require('./css/chillmain.css');
 | 
			
		||||
require('./css/pikaday.css');
 | 
			
		||||
 | 
			
		||||
@@ -35,11 +37,10 @@ require('./modules/download-report/index.js');
 | 
			
		||||
require('./modules/select_interactive_loading/index.js');
 | 
			
		||||
require('./modules/export-list/export-list.scss');
 | 
			
		||||
require('./modules/entity/index.js');
 | 
			
		||||
//require('./modules/tabs/index.js');
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * load img
 | 
			
		||||
 */
 | 
			
		||||
require('./img/favicon.ico');
 | 
			
		||||
require('./img/logo-chill-sans-slogan_white.png');
 | 
			
		||||
require('./img/logo-chill-outil-accompagnement_white.png');
 | 
			
		||||
require('./img/logo-chill-outil-accompagnement_white.png');
 | 
			
		||||
@@ -1,4 +0,0 @@
 | 
			
		||||
/*
 | 
			
		||||
 *  These custom styles will override bootstrap enabled stylesheets
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
@@ -1,47 +0,0 @@
 | 
			
		||||
/*
 | 
			
		||||
 *  Enable / disable bootstrap assets
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
@import "bootstrap/scss/functions";
 | 
			
		||||
 | 
			
		||||
/* replace variables */
 | 
			
		||||
// @import "bootstrap/scss/variables";
 | 
			
		||||
@import "custom/_variables";
 | 
			
		||||
 | 
			
		||||
@import "bootstrap/scss/mixins";
 | 
			
		||||
// @import "bootstrap/scss/root";
 | 
			
		||||
// @import "bootstrap/scss/reboot";
 | 
			
		||||
// @import "bootstrap/scss/type";
 | 
			
		||||
// @import "bootstrap/scss/images";
 | 
			
		||||
// @import "bootstrap/scss/code";
 | 
			
		||||
// @import "bootstrap/scss/grid";
 | 
			
		||||
// @import "bootstrap/scss/tables";
 | 
			
		||||
// @import "bootstrap/scss/forms";
 | 
			
		||||
// @import "bootstrap/scss/buttons";
 | 
			
		||||
// @import "bootstrap/scss/transitions";
 | 
			
		||||
// @import "bootstrap/scss/dropdown";
 | 
			
		||||
// @import "bootstrap/scss/button-group";
 | 
			
		||||
// @import "bootstrap/scss/input-group";
 | 
			
		||||
// @import "bootstrap/scss/custom-forms";
 | 
			
		||||
@import "bootstrap/scss/nav";
 | 
			
		||||
// @import "bootstrap/scss/navbar";
 | 
			
		||||
// @import "bootstrap/scss/card";
 | 
			
		||||
// @import "bootstrap/scss/breadcrumb";
 | 
			
		||||
// @import "bootstrap/scss/pagination";
 | 
			
		||||
@import "bootstrap/scss/badge";
 | 
			
		||||
// @import "bootstrap/scss/jumbotron";
 | 
			
		||||
// @import "bootstrap/scss/alert";
 | 
			
		||||
// @import "bootstrap/scss/progress";
 | 
			
		||||
// @import "bootstrap/scss/media";
 | 
			
		||||
// @import "bootstrap/scss/list-group";
 | 
			
		||||
// @import "bootstrap/scss/close";
 | 
			
		||||
// @import "bootstrap/scss/toasts";
 | 
			
		||||
@import "bootstrap/scss/modal";
 | 
			
		||||
// @import "bootstrap/scss/tooltip";
 | 
			
		||||
// @import "bootstrap/scss/popover";
 | 
			
		||||
// @import "bootstrap/scss/carousel";
 | 
			
		||||
// @import "bootstrap/scss/spinners";
 | 
			
		||||
@import "bootstrap/scss/utilities";
 | 
			
		||||
// @import "bootstrap/scss/print";
 | 
			
		||||
 | 
			
		||||
@import "custom";
 | 
			
		||||
@@ -0,0 +1,42 @@
 | 
			
		||||
/*
 | 
			
		||||
*   when bootstrap.css comes after chill.css
 | 
			
		||||
*   we have to disable conflict classes
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
@import "bootstrap/scss/functions";
 | 
			
		||||
@import "bootstrap/scss/variables";
 | 
			
		||||
@import "bootstrap/scss/mixins";
 | 
			
		||||
@import "bootstrap/scss/root";
 | 
			
		||||
//@import "bootstrap/scss/reboot";  // h1, h2, h3, ...
 | 
			
		||||
//@import "bootstrap/scss/type";    // h1, h2, h3, ...
 | 
			
		||||
@import "bootstrap/scss/images";
 | 
			
		||||
@import "bootstrap/scss/code";
 | 
			
		||||
//@import "bootstrap/scss/grid";    // container
 | 
			
		||||
@import "bootstrap/scss/tables";
 | 
			
		||||
@import "bootstrap/scss/forms";
 | 
			
		||||
@import "bootstrap/scss/buttons";
 | 
			
		||||
@import "bootstrap/scss/transitions";
 | 
			
		||||
@import "bootstrap/scss/dropdown";
 | 
			
		||||
@import "bootstrap/scss/button-group";
 | 
			
		||||
@import "bootstrap/scss/input-group";
 | 
			
		||||
@import "bootstrap/scss/custom-forms";
 | 
			
		||||
@import "bootstrap/scss/nav";
 | 
			
		||||
@import "bootstrap/scss/navbar";
 | 
			
		||||
@import "bootstrap/scss/card";
 | 
			
		||||
@import "bootstrap/scss/breadcrumb";
 | 
			
		||||
@import "bootstrap/scss/pagination";
 | 
			
		||||
@import "bootstrap/scss/badge";
 | 
			
		||||
@import "bootstrap/scss/jumbotron";
 | 
			
		||||
@import "bootstrap/scss/alert";
 | 
			
		||||
@import "bootstrap/scss/progress";
 | 
			
		||||
@import "bootstrap/scss/media";
 | 
			
		||||
@import "bootstrap/scss/list-group";
 | 
			
		||||
@import "bootstrap/scss/close";
 | 
			
		||||
@import "bootstrap/scss/toasts";
 | 
			
		||||
@import "bootstrap/scss/modal";
 | 
			
		||||
@import "bootstrap/scss/tooltip";
 | 
			
		||||
@import "bootstrap/scss/popover";
 | 
			
		||||
@import "bootstrap/scss/carousel";
 | 
			
		||||
@import "bootstrap/scss/spinners";
 | 
			
		||||
@import "bootstrap/scss/utilities";
 | 
			
		||||
@import "bootstrap/scss/print";
 | 
			
		||||
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							@@ -1,9 +1,9 @@
 | 
			
		||||
// Compile all bootstrap assets from nodes-modules
 | 
			
		||||
//require('bootstrap/scss/bootstrap.scss')
 | 
			
		||||
 | 
			
		||||
// Or compile bootstrap only enabled assets
 | 
			
		||||
require('./bootstrap.scss');
 | 
			
		||||
// Compile custom styles to adapt bootstrap in chill context
 | 
			
		||||
require('./custom.scss')
 | 
			
		||||
 | 
			
		||||
// You can specify which plugins you need
 | 
			
		||||
//import { Tooltip, Toast, Popover } from 'bootstrap';
 | 
			
		||||
import Modal from 'bootstrap/js/dist/modal';
 | 
			
		||||
//import Alert from 'bootstrap/js/dist/alert';
 | 
			
		||||
@@ -1,2 +0,0 @@
 | 
			
		||||
 | 
			
		||||
@import '../../../fonts/OpenSans/OpenSans';
 | 
			
		||||
@@ -1 +0,0 @@
 | 
			
		||||
require('./scratch.scss');
 | 
			
		||||
@@ -1,9 +1,3 @@
 | 
			
		||||
/*
 | 
			
		||||
 * NOTE 2021.04
 | 
			
		||||
 * scss/chill.scss is the main sass file for the new chill.2
 | 
			
		||||
 * scratch will be replaced by bootstrap, please avoid to edit in modules/scratch/_custom.scss
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
// YOUR CUSTOM SCSS
 | 
			
		||||
@import 'custom/config/colors';
 | 
			
		||||
@import 'custom/config/variables';
 | 
			
		||||
@@ -162,6 +156,7 @@ dl.chill_view_data {
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
blockquote.chill-user-quote,
 | 
			
		||||
div.chill-user-quote {
 | 
			
		||||
    border-left: 10px solid $chill-yellow;
 | 
			
		||||
@@ -169,12 +164,12 @@ div.chill-user-quote {
 | 
			
		||||
    padding: 0.5em 10px;
 | 
			
		||||
    quotes: "\201C""\201D""\2018""\2019";
 | 
			
		||||
    background-color: $chill-llight-gray;
 | 
			
		||||
 | 
			
		||||
    
 | 
			
		||||
    blockquote {
 | 
			
		||||
        margin: 1.5em 10px;
 | 
			
		||||
        padding: 0.5em 10px;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    
 | 
			
		||||
    blockquote:before {
 | 
			
		||||
        color: #ccc;
 | 
			
		||||
        content: open-quote;
 | 
			
		||||
@@ -187,4 +182,5 @@ div.chill-user-quote {
 | 
			
		||||
 | 
			
		||||
.chill-no-data-statement {
 | 
			
		||||
    font-style: italic;
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
Some files were not shown because too many files have changed in this diff Show More
		Reference in New Issue
	
	Block a user