cs: Fix code style (safe rules only).

This commit is contained in:
Pol Dellaiera
2021-11-23 14:06:38 +01:00
parent 149d7ce991
commit 8f96a1121d
1223 changed files with 65199 additions and 64625 deletions

View File

@@ -1,33 +1,19 @@
<?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;
use Symfony\Component\DependencyInjection\Alias;
/**
*
* Chill is a software for social workers
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/
namespace Chill\MainBundle\CRUD\CompilerPass;
use Symfony\Component\DependencyInjection\Alias;
use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Definition;
class CRUDControllerCompilerPass implements CompilerPassInterface
{
public function process(ContainerBuilder $container)
@@ -45,15 +31,15 @@ class CRUDControllerCompilerPass implements CompilerPassInterface
}
/**
* Add a controller for each definition, and add a methodCall to inject crud configuration to controller
* 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';
$controllerServiceName = 'cs' . $apiOrCrud . '_' . $crudEntry['name'] . '_controller';
// create config parameter in container
$param = 'chill_main_'.$apiOrCrud.'_config_'.$crudEntry['name'];
$param = 'chill_main_' . $apiOrCrud . '_config_' . $crudEntry['name'];
$container->setParameter($param, $crudEntry);
if ($container->hasDefinition($controllerClass)) {
@@ -63,8 +49,7 @@ class CRUDControllerCompilerPass implements CompilerPassInterface
// add the "addMethodCall"
$container->getDefinition($controllerClass)
->addMethodCall('setCrudConfig', ['%'.$param.'%']);
->addMethodCall('setCrudConfig', ['%' . $param . '%']);
} else {
$controller = new Definition($controllerClass);
@@ -72,10 +57,9 @@ class CRUDControllerCompilerPass implements CompilerPassInterface
$controller->setAutoconfigured(true);
$controller->setPublic(true);
$controller->addMethodCall('setCrudConfig', ['%'.$param.'%']);
$controller->addMethodCall('setCrudConfig', ['%' . $param . '%']);
$container->setDefinition($controllerServiceName, $controller);
}
}
}

View File

@@ -1,96 +1,63 @@
<?php
/**
* Chill is a software for social workers
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/
declare(strict_types=1);
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\CRUD\Resolver\Resolver;
use Chill\MainBundle\Pagination\PaginatorFactory;
use Chill\MainBundle\Pagination\PaginatorInterface;
use Chill\MainBundle\Security\Authorization\AuthorizationHelper;
use Chill\MainBundle\CRUD\Resolver\Resolver;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Serializer\SerializerInterface;
use Symfony\Component\Translation\TranslatorInterface;
use Symfony\Component\Validator\Validator\ValidatorInterface;
use function array_merge;
abstract class AbstractCRUDController extends AbstractController
{
/**
* The crud configuration
* The crud configuration.
*
* This configuration si defined by `chill_main['crud']` or `chill_main['apis']`
*/
protected array $crudConfig = [];
/**
* get the instance of the entity with the given id
*
* @throw Symfony\Component\HttpKernel\Exception\NotFoundHttpException if the object is not found
*/
protected function getEntity($action, string $id, Request $request): object
public static function getSubscribedServices(): array
{
$e = $this
->getDoctrine()
->getRepository($this->getEntityClass())
->find($id);
return array_merge(
parent::getSubscribedServices(),
[
'chill_main.paginator_factory' => PaginatorFactory::class,
if (null === $e) {
throw $this->createNotFoundException(sprintf("The object %s for id %s is not found", $this->getEntityClass(), $id));
}
return $e;
}
protected function createEntity(string $action, Request $request): object
{
$class = $this->getEntityClass();
return new $class;
'translator' => TranslatorInterface::class,
AuthorizationHelper::class => AuthorizationHelper::class,
EventDispatcherInterface::class => EventDispatcherInterface::class,
Resolver::class => Resolver::class,
SerializerInterface::class => SerializerInterface::class,
'validator' => ValidatorInterface::class,
]
);
}
/**
* Count the number of entities
* Set the crud configuration.
*
* By default, count all entities. You can customize the query by
* using the method `customizeQuery`.
* Used by the container to inject configuration for this crud.
*/
protected function countEntities(string $action, Request $request, $_format): int
public function setCrudConfig(array $config): void
{
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;
$this->crudConfig = $config;
}
/**
@@ -117,16 +84,157 @@ abstract class AbstractCRUDController extends AbstractController
return $qb;
}
protected function customizeQuery(string $action, Request $request, $query): void {}
/**
* 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.
*
* @param mixed|null $entity
*
* @throws \Symfony\Component\Security\Core\Exception\AccessDeniedHttpException
*/
protected function checkACL(string $action, Request $request, string $_format, $entity = null)
{
// @TODO: Implements abstract getRoleFor method or do it in the interface.
$this->denyAccessUnlessGranted($this->getRoleFor($action, $request, $entity, $_format), $entity);
}
/**
* Count the number of entities.
*
* By default, count all entities. You can customize the query by
* using the method `customizeQuery`.
*
* @param mixed $_format
*/
protected function countEntities(string $action, Request $request, $_format): int
{
return $this->buildQueryEntities($action, $request)
->select('COUNT(e)')
->getQuery()
->getSingleScalarResult();
}
protected function createEntity(string $action, Request $request): object
{
$class = $this->getEntityClass();
return new $class();
}
protected function customizeQuery(string $action, Request $request, $query): void
{
}
protected function getActionConfig(string $action)
{
return $this->crudConfig['actions'][$action];
}
/**
* @return string The crud name.
*/
protected function getCrudName(): string
{
return $this->crudConfig['name'];
}
/**
* get the instance of the entity with the given id.
*
* @throw Symfony\Component\HttpKernel\Exception\NotFoundHttpException if the object is not found
*
* @param mixed $action
*/
protected function getEntity($action, string $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;
}
/**
* Get the FQDN of the class.
*
* @return class-string The FQDN of the class
*/
protected function getEntityClass(): string
{
return $this->crudConfig['class'];
}
protected function getPaginatorFactory(): PaginatorFactory
{
return $this->container->get('chill_main.paginator_factory');
}
/**
* Get the result of the query.
*
* @param mixed $query
*/
protected function getQueryResult(string $action, Request $request, string $_format, int $totalItems, PaginatorInterface $paginator, $query)
{
return $query->getQuery()->getResult();
}
protected function getValidator(): ValidatorInterface
{
return $this->get('validator');
}
/**
* Called on post check ACL.
*
* @param mixed $entity
*/
protected function onPostCheckACL(string $action, Request $request, string $_format, $entity): ?Response
{
return null;
}
/**
* Called on post fetch entity.
*
* @param mixed $entity
* @param mixed $_format
*/
protected function onPostFetchEntity(string $action, Request $request, $entity, $_format): ?Response
{
return null;
}
/**
* Method used by indexAction.
*
* @param mixed $query
*/
protected function onPostIndexBuildQuery(string $action, Request $request, string $_format, int $totalItems, PaginatorInterface $paginator, $query): ?Response
{
return null;
}
/**
* Method used by indexAction.
*
* @param mixed $entities
*/
protected function onPostIndexFetchQuery(string $action, Request $request, string $_format, int $totalItems, PaginatorInterface $paginator, $entities): ?Response
{
return null;
}
protected function onPreIndex(string $action, Request $request, string $_format): ?Response
{
return null;
@@ -141,111 +249,33 @@ abstract class AbstractCRUDController extends AbstractController
}
/**
* 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 FQDN of the class.
* Add ordering fields in the query build by self::queryEntities.
*
* @return class-string The FQDN of the class
* @param mixed $query
* @param mixed $_format
*/
protected function getEntityClass(): string
protected function orderQuery(string $action, $query, Request $request, PaginatorInterface $paginator, $_format)
{
return $this->crudConfig['class'];
return $query;
}
/**
* 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.
* Query the entity.
*
* By default, check the role given by `getRoleFor` for the value given in
* $entity.
* By default, get all entities. You can customize the query by using the
* method `customizeQuery`.
*
* Throw an \Symfony\Component\Security\Core\Exception\AccessDeniedHttpException
* if not accessible.
* The method `orderEntity` is called internally to order entities.
*
* @throws \Symfony\Component\Security\Core\Exception\AccessDeniedHttpException
* It returns, by default, a query builder.
*/
protected function checkACL(string $action, Request $request, string $_format, $entity = null)
protected function queryEntities(string $action, Request $request, string $_format, PaginatorInterface $paginator)
{
// @TODO: Implements abstract getRoleFor method or do it in the interface.
$this->denyAccessUnlessGranted($this->getRoleFor($action, $request, $entity, $_format), $entity);
}
$query = $this->buildQueryEntities($action, $request)
->setFirstResult($paginator->getCurrentPage()->getFirstItemNumber())
->setMaxResults($paginator->getItemsPerPage());
/**
* @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;
}
protected function getPaginatorFactory(): PaginatorFactory
{
return $this->container->get('chill_main.paginator_factory');
}
protected function getValidator(): ValidatorInterface
{
return $this->get('validator');
}
public static function getSubscribedServices(): array
{
return \array_merge(
parent::getSubscribedServices(),
[
'chill_main.paginator_factory' => PaginatorFactory::class,
'translator' => TranslatorInterface::class,
AuthorizationHelper::class => AuthorizationHelper::class,
EventDispatcherInterface::class => EventDispatcherInterface::class,
Resolver::class => Resolver::class,
SerializerInterface::class => SerializerInterface::class,
'validator' => ValidatorInterface::class,
]
);
// allow to order queries and return the new query
return $this->orderQuery($action, $query, $request, $paginator, $_format);
}
}

View File

@@ -1,80 +1,38 @@
<?php
/**
* Chill is a software for social workers
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/
declare(strict_types=1);
namespace Chill\MainBundle\CRUD\Controller;
use Chill\MainBundle\Pagination\PaginatorInterface;
use Chill\MainBundle\Serializer\Model\Collection;
use Exception;
use LogicException;
use RuntimeException;
use Symfony\Component\HttpFoundation\Exception\BadRequestException;
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;
use Symfony\Component\Serializer\Normalizer\AbstractNormalizer;
use Symfony\Component\Serializer\SerializerInterface;
use Symfony\Component\Validator\ConstraintViolationListInterface;
use function array_merge;
use function ucfirst;
class ApiController extends AbstractCRUDController
{
/**
* The view action.
* Base method for handling api 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);
$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
* @param mixed $id
* @param mixed $_format
*
* @return void
*/
@@ -84,163 +42,45 @@ class ApiController extends AbstractCRUDController
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);
case Request::METHOD_DELETE:
return $this->entityDelete('_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");
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);
$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)
);
}
public function entityDelete($action, Request $request, $id, string $_format): Response
{
$entity = $this->getEntity($action, $id, $request);
if (NULL === $entity) {
throw $this->createNotFoundException(sprintf("The %s with id %s "
. "is not found", $this->getCrudName(), $id));
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;
}
@@ -248,6 +88,7 @@ class ApiController extends AbstractCRUDController
$errors = $this->validate($action, $request, $_format, $entity);
$response = $this->onAfterValidation($action, $request, $_format, $entity, $errors);
if ($response instanceof Response) {
return $response;
}
@@ -263,6 +104,7 @@ class ApiController extends AbstractCRUDController
$this->getDoctrine()->getManager()->flush();
$response = $this->onAfterFlush($action, $request, $_format, $entity, $errors);
if ($response instanceof Response) {
return $response;
}
@@ -270,51 +112,89 @@ class ApiController extends AbstractCRUDController
return $this->json(Response::HTTP_OK);
}
protected function onAfterValidation(string $action, Request $request, string $_format, $entity, ConstraintViolationListInterface $errors, array $more = []): ?Response
public function entityPost(Request $request, $_format): Response
{
return null;
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 onAfterFlush(string $action, Request $request, string $_format, $entity, ConstraintViolationListInterface $errors, array $more = []): ?Response
public function entityPut($action, Request $request, $id, string $_format): Response
{
return null;
}
$entity = $this->getEntity($action, $id, $request);
protected function getValidationGroups(string $action, Request $request, string $_format, $entity): ?array
{
return null;
}
$postFetch = $this->onPostFetchEntity($action, $request, $entity, $_format);
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;
if ($postFetch instanceof Response) {
return $postFetch;
}
$context = \array_merge(
$default,
$this->getContextForSerialization($action, $request, $_format, $entity)
);
if (null === $entity) {
throw $this->createNotFoundException(sprintf('The %s with id %s '
. 'is not found', $this->getCrudName(), $id));
}
return $this->getSerializer()->deserialize($request->getContent(), $this->getEntityClass(), $_format, $context);
$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)
);
}
/**
* Base action for indexing entities
* Base action for indexing entities.
*/
public function indexApi(Request $request, string $_format)
{
@@ -322,82 +202,15 @@ class ApiController extends AbstractCRUDController
case Request::METHOD_GET:
case REQUEST::METHOD_HEAD:
return $this->indexApiAction('_index', $request, $_format);
default:
throw $this->createNotFoundException("This method is not supported");
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
*/
protected function indexApiAction($action, Request $request, $_format)
public function onBeforeSerialize(string $action, Request $request, $_format, $entity): ?Response
{
$this->onPreIndex($action, $request, $_format);
$response = $this->checkACL($action, $request, $_format);
if ($response instanceof Response) {
return $response;
}
$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);
return null;
}
/**
@@ -420,36 +233,38 @@ class ApiController extends AbstractCRUDController
*
* @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)
* @param bool $forcePersist force to persist the created element (only for POST request)
* @param mixed $id
* @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, array $postedDataContext = [], bool $forcePersist = false): 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;
}
@@ -457,25 +272,30 @@ class ApiController extends AbstractCRUDController
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);
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);
$entity->{'remove' . ucfirst($property)}($postedData);
break;
case Request::METHOD_POST:
$entity->{'add'.\ucfirst($property)}($postedData);
$entity->{'add' . ucfirst($property)}($postedData);
break;
default:
throw new BadRequestException("this method is not supported");
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;
}
@@ -491,8 +311,8 @@ class ApiController extends AbstractCRUDController
$this->getDoctrine()->getManager()->flush();
$response = $this->onAfterFlush($action, $request, $_format, $entity, $errors, [$postedData]);
if ($response instanceof Response) {
return $response;
}
@@ -500,6 +320,7 @@ class ApiController extends AbstractCRUDController
switch ($request->getMethod()) {
case Request::METHOD_DELETE:
return $this->json('', Response::HTTP_OK);
case Request::METHOD_POST:
return $this->json(
$postedData,
@@ -509,12 +330,308 @@ class ApiController extends AbstractCRUDController
);
}
throw new \Exception('Unable to handle such request method.');
throw new Exception('Unable to handle such request method.');
}
/**
* Serialize collections
* Deserialize the content of the request into the class associated with the curd.
*
* @param mixed|null $entity
*/
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);
}
/**
* 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`
*
* @param mixed $id
* @param mixed $_format
*/
protected function entityGet(string $action, Request $request, $id, $_format = 'html'): 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;
}
if ('json' === $_format) {
$context = $this->getContextForSerialization($action, $request, $_format, $entity);
return $this->json($entity, Response::HTTP_OK, [], $context);
}
throw new \Symfony\Component\HttpFoundation\Exception\BadRequestException('This format 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)
);
}
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.
*
* @param mixed $entity
*/
protected function getContextForSerializationPostAlter(string $action, Request $request, string $_format, $entity, array $more = []): array
{
return ['groups' => ['read']];
}
/**
* get the role given from the config.
*
* @param mixed $entity
* @param mixed $_format
*/
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');
}
protected function getValidationGroups(string $action, Request $request, string $_format, $entity): ?array
{
return null;
}
/**
* 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 mixed $_format
*/
protected function indexApiAction($action, Request $request, $_format)
{
$this->onPreIndex($action, $request, $_format);
$response = $this->checkACL($action, $request, $_format);
if ($response instanceof Response) {
return $response;
}
$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);
}
protected function onAfterFlush(string $action, Request $request, string $_format, $entity, ConstraintViolationListInterface $errors, array $more = []): ?Response
{
return null;
}
protected function onAfterValidation(string $action, Request $request, string $_format, $entity, ConstraintViolationListInterface $errors, array $more = []): ?Response
{
return null;
}
/**
* Serialize collections.
*
* @param mixed $entities
*/
protected function serializeCollection(string $action, Request $request, string $_format, PaginatorInterface $paginator, $entities): Response
{
@@ -525,55 +642,10 @@ class ApiController extends AbstractCRUDController
return $this->json($model, Response::HTTP_OK, [], $context);
}
protected function getContextForSerialization(string $action, Request $request, string $_format, $entity): array
protected function validate(string $action, Request $request, string $_format, $entity, array $more = []): ConstraintViolationListInterface
{
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");
}
}
$validationGroups = $this->getValidationGroups($action, $request, $_format, $entity);
/**
* 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');
return $this->getValidator()->validate($entity, null, $validationGroups);
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -1,33 +1,18 @@
<?php
/*
/**
* Chill is a software for social workers
*
* Copyright (C) 2020, Champs Libres Cooperative SCRLFS, <http://www.champs-libres.coop>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/
namespace Chill\MainBundle\CRUD\Form;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\Form\Extension\Core\Type\HiddenType;
/**
* Class CRUDDeleteEntityForm
*
* @package Chill\MainBundle\CRUD\Form
* Class CRUDDeleteEntityForm.
*/
class CRUDDeleteEntityForm extends AbstractType
{

View File

@@ -1,122 +1,114 @@
<?php
/*
/**
* Chill is a software for social workers
*
* Copyright (C) 2019, Champs Libres Cooperative SCRLFS, <http://www.champs-libres.coop>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/
namespace Chill\MainBundle\CRUD\Resolver;
use Doctrine\ORM\EntityManagerInterface;
use Symfony\Component\PropertyAccess\PropertyAccess;
use LogicException;
use function array_key_exists;
use function strtoupper;
/**
* Class Resolver
*
* @package Chill\MainBundle\CRUD\Resolver
* Class Resolver.
*/
class Resolver
{
/**
* @var EntityManagerInterface
* The key to get the role necessary for the action.
*/
protected $em;
public const ROLE = 'role';
/**
* @var \Symfony\Component\PropertyAccess\PropertyAccessor
* @deprecated
*/
protected $propertyAccess;
public const ROLE_EDIT = 'role.edit';
/**
* @deprecated
*/
public const ROLE_VIEW = 'role.view';
/**
* @var array
*/
protected $crudConfig;
/**
* @deprecated
* @var EntityManagerInterface
*/
const ROLE_VIEW = 'role.view';
protected $em;
/**
* @deprecated
* @var \Symfony\Component\PropertyAccess\PropertyAccessor
*/
const ROLE_EDIT = 'role.edit';
/**
* The key to get the role necessary for the action
*/
const ROLE = 'role';
protected $propertyAccess;
/**
* Resolver constructor.
*
* @param EntityManagerInterface $em
* @param array $crudConfig
*/
function __construct(EntityManagerInterface $em, array $crudConfig)
public function __construct(EntityManagerInterface $em, array $crudConfig)
{
$this->em = $em;
foreach($crudConfig as $conf) {
foreach ($crudConfig as $conf) {
$this->crudConfig[$conf['name']] = $conf;
}
}
/**
* @param $key
* @param $crudName
* @param null $action
* @return string
*/
public function getConfigValue($key, $crudName, $action = null)
{
$config = $this->crudConfig[$crudName];
switch ($key) {
case self::ROLE:
return $config['actions'][$action]['role'] ?? $this->buildDefaultRole($crudName, $action);
}
}
/**
* @param $crudName
* @param $action
*
* @return string
*/
public function buildDefaultRole($crudName, $action)
{
if (empty($this->crudConfig[$crudName]['base_role'])) {
throw new \LogicException(sprintf("the base role is not defined. You must define "
. "on or override %s or %s methods", __METHOD__, "getRoleFor"));
throw new LogicException(sprintf('the base role is not defined. You must define '
. 'on or override %s or %s methods', __METHOD__, 'getRoleFor'));
}
return \strtoupper(
$this->crudConfig[$crudName]['base_role'].
'_'.
$action);
return strtoupper(
$this->crudConfig[$crudName]['base_role'] .
'_' .
$action
);
}
/**
* @param $key
* @param $crudName
* @param null $action
*
* @return string
*/
public function getConfigValue($key, $crudName, $action = null)
{
$config = $this->crudConfig[$crudName];
switch ($key) {
case self::ROLE:
return $config['actions'][$action]['role'] ?? $this->buildDefaultRole($crudName, $action);
}
}
/**
* @param $crudName
* @param $action
*
* @return bool
*/
public function hasAction($crudName, $action)
{
return \array_key_exists($action,
$this->crudConfig[$crudName]['actions']);
return array_key_exists(
$action,
$this->crudConfig[$crudName]['actions']
);
}
}

View File

@@ -1,32 +1,42 @@
<?php
/**
* Chill is a software for social workers
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/
declare(strict_types=1);
namespace Chill\MainBundle\CRUD\Routing;
use RuntimeException;
use Symfony\Component\Config\Loader\Loader;
use Symfony\Component\HttpFoundation\Request;
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;
use function array_filter;
use function array_keys;
use function array_search;
use function in_array;
class CRUDRoutesLoader extends Loader
{
protected array $crudConfig = [];
protected array $apiCrudConfig = [];
private bool $isLoaded = false;
private const ALL_INDEX_METHODS = [Request::METHOD_GET, Request::METHOD_HEAD];
private const ALL_SINGLE_METHODS = [
Request::METHOD_GET,
Request::METHOD_POST,
Request::METHOD_PUT,
Request::METHOD_DELETE
Request::METHOD_DELETE,
];
private const ALL_INDEX_METHODS = [ Request::METHOD_GET, Request::METHOD_HEAD ];
protected array $apiCrudConfig = [];
protected array $crudConfig = [];
private bool $isLoaded = false;
public function __construct(array $crudConfig, array $apiCrudConfig)
{
@@ -37,22 +47,15 @@ class CRUDRoutesLoader extends Loader
}
/**
* Load routes for CRUD and CRUD Api.
*
* @param mixed $resource
* @param null $type
* @return bool
*/
public function supports($resource, $type = null)
{
return 'CRUD' === $type;
}
/**
* Load routes for CRUD and CRUD Api
* @param mixed|null $type
*/
public function load($resource, $type = null): RouteCollection
{
if (true === $this->isLoaded) {
throw new \RuntimeException('Do not add the "CRUD" loader twice');
throw new RuntimeException('Do not add the "CRUD" loader twice');
}
$collection = new RouteCollection();
@@ -60,6 +63,7 @@ class CRUDRoutesLoader extends Loader
foreach ($this->crudConfig as $crudConfig) {
$collection->addCollection($this->loadCrudConfig($crudConfig));
}
foreach ($this->apiCrudConfig as $crudConfig) {
$collection->addCollection($this->loadApi($crudConfig));
}
@@ -68,56 +72,30 @@ class CRUDRoutesLoader extends Loader
}
/**
* Load routes for CRUD (without api)
* @param mixed $resource
* @param null $type
*
* @param $crudConfig
* @return RouteCollection
* @return bool
*/
protected function loadCrudConfig($crudConfig): RouteCollection
public function supports($resource, $type = null)
{
$collection = new RouteCollection();
$controller ='cscrud_'.$crudConfig['name'].'_controller';
foreach ($crudConfig['actions'] as $name => $action) {
// defaults (controller name)
$defaults = [
'_controller' => $controller.':'.($action['controller_action'] ?? $name)
];
if ($name === 'index') {
$path = "{_locale}".$crudConfig['base_path'];
$route = new Route($path, $defaults);
} elseif ($name === 'new') {
$path = "{_locale}".$crudConfig['base_path'].'/'.$name;
$route = new Route($path, $defaults);
} else {
$path = "{_locale}".$crudConfig['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);
}
return $collection;
return 'CRUD' === $type;
}
/**
* Load routes for api single
* Load routes for api single.
*
* @param $crudConfig
* @return RouteCollection
*/
protected function loadApi(array $crudConfig): RouteCollection
{
$collection = new RouteCollection();
$controller = 'csapi_'.$crudConfig['name'].'_controller';
$controller = 'csapi_' . $crudConfig['name'] . '_controller';
foreach ($crudConfig['actions'] as $name => $action) {
// filter only on single actions
$singleCollection = $action['single_collection'] ?? $name === '_entity' ? 'single' : NULL;
$singleCollection = $action['single_collection'] ?? '_entity' === $name ? 'single' : null;
if ('collection' === $singleCollection) {
// continue;
}
@@ -126,46 +104,61 @@ class CRUDRoutesLoader extends Loader
switch ($name) {
case '_entity':
$controllerAction = 'entityApi';
break;
case '_index':
$controllerAction = 'indexApi';
break;
default:
$controllerAction = $name.'Api';
$controllerAction = $name . 'Api';
break;
}
$defaults = [
'_controller' => $controller.':'.($action['controller_action'] ?? $controllerAction)
'_controller' => $controller . ':' . ($action['controller_action'] ?? $controllerAction),
];
// path are rewritten
// if name === 'default', we rewrite it to nothing :-)
$localName = \in_array($name, [ '_entity', '_index' ]) ? '' : '/'.$name;
$localName = in_array($name, ['_entity', '_index']) ? '' : '/' . $name;
if ('collection' === $action['single_collection'] || '_index' === $name) {
$localPath = $action['path'] ?? $localName.'.{_format}';
$localPath = $action['path'] ?? $localName . '.{_format}';
} else {
$localPath = $action['path'] ?? '/{id}'.$localName.'.{_format}';
$localPath = $action['path'] ?? '/{id}' . $localName . '.{_format}';
}
$path = $crudConfig['base_path'].$localPath;
$path = $crudConfig['base_path'] . $localPath;
$requirements = $action['requirements'] ?? [ '{id}' => '\d+' ];
$requirements = $action['requirements'] ?? ['{id}' => '\d+'];
$methods = \array_keys(\array_filter($action['methods'], function($value, $key) { return $value; },
ARRAY_FILTER_USE_BOTH));
$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");
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 ('_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) {
@@ -177,7 +170,43 @@ class CRUDRoutesLoader extends Loader
$route = new Route($path, $defaults, $requirements);
$route->setMethods($methods);
$collection->add('chill_api_single_'.$crudConfig['name'].'_'.$name, $route);
$collection->add('chill_api_single_' . $crudConfig['name'] . '_' . $name, $route);
}
return $collection;
}
/**
* Load routes for CRUD (without api).
*
* @param $crudConfig
*/
protected function loadCrudConfig($crudConfig): RouteCollection
{
$collection = new RouteCollection();
$controller = 'cscrud_' . $crudConfig['name'] . '_controller';
foreach ($crudConfig['actions'] as $name => $action) {
// defaults (controller name)
$defaults = [
'_controller' => $controller . ':' . ($action['controller_action'] ?? $name),
];
if ('index' === $name) {
$path = '{_locale}' . $crudConfig['base_path'];
$route = new Route($path, $defaults);
} elseif ('new' === $name) {
$path = '{_locale}' . $crudConfig['base_path'] . '/' . $name;
$route = new Route($path, $defaults);
} else {
$path = '{_locale}' . $crudConfig['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);
}
return $collection;
@@ -185,14 +214,14 @@ class CRUDRoutesLoader extends Loader
private function createEntityPostRoute(string $name, $crudConfig, array $action, $controller): Route
{
$localPath = $action['path'].'.{_format}';
$localPath = $action['path'] . '.{_format}';
$defaults = [
'_controller' => $controller.':'.($action['controller_action'] ?? 'entityPost')
'_controller' => $controller . ':' . ($action['controller_action'] ?? 'entityPost'),
];
$path = $crudConfig['base_path'].$localPath;
$path = $crudConfig['base_path'] . $localPath;
$requirements = $action['requirements'] ?? [];
$route = new Route($path, $defaults, $requirements);
$route->setMethods([ Request::METHOD_POST ]);
$route->setMethods([Request::METHOD_POST]);
return $route;
}

View File

@@ -1,36 +1,21 @@
<?php
/*
/**
* Chill is a software for social workers
*
* Copyright (C) 2019, Champs Libres Cooperative SCRLFS, <http://www.champs-libres.coop>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/
namespace Chill\MainBundle\CRUD\Templating;
use Chill\MainBundle\CRUD\Resolver\Resolver;
use Twig\TwigFilter;
use Twig\TwigFunction;
use Twig\Extension\AbstractExtension;
use Twig\Environment;
use Twig\TwigFunction;
/**
* Class TwigCRUDResolver
* Twig filters to display data in crud template
*
* @package Chill\MainBundle\CRUD\Templating
* Twig filters to display data in crud template.
*/
class TwigCRUDResolver extends AbstractExtension
{
@@ -38,49 +23,54 @@ class TwigCRUDResolver extends AbstractExtension
* @var Resolver
*/
protected $resolver;
/**
* TwigCRUDResolver constructor.
*
* @param Resolver $resolver
*/
function __construct(Resolver $resolver)
public function __construct(Resolver $resolver)
{
$this->resolver = $resolver;
}
/**
* @return array|TwigFunction[]
*/
public function getFunctions()
{
return [
new TwigFunction('chill_crud_config', [$this, 'getConfig'],
['is_safe' => 'html']),
new TwigFunction('chill_crud_action_exists', [$this, 'hasAction'],
[]),
];
}
/**
* @param $configKey
* @param $crudName
* @param null $action
*
* @return string
*/
public function getConfig($configKey, $crudName, $action = null)
{
return $this->resolver->getConfigValue($configKey, $crudName, $action);
}
/**
* @return array|TwigFunction[]
*/
public function getFunctions()
{
return [
new TwigFunction(
'chill_crud_config',
[$this, 'getConfig'],
['is_safe' => 'html']
),
new TwigFunction(
'chill_crud_action_exists',
[$this, 'hasAction'],
[]
),
];
}
/**
* @param $crudName
* @param $action
*
* @return bool
*/
public function hasAction($crudName, $action)
{
return $this->resolver->hasAction($crudName, $action);
}
}

View File

@@ -1,27 +1,33 @@
<?php
/*
*
/**
* Chill is a software for social workers
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/
namespace Chill\MainBundle\Center;
/**
* Interface to declare a groups of centers.
*
* This interface is used to declare a groups of centers in
*
* This interface is used to declare a groups of centers in
* `Chill\MainBundle\Form\Export\PickCenterType`.
*
*/
interface GroupingCenterInterface
{
/**
* @return string[]
*/
public function getGroups($authorizedCenters = null): array;
/**
*
* @param string $group
*
* @return \Chill\MainBundle\Entity\Center[]
*/
public function getCentersForGroup($group);
/**
* @param mixed|null $authorizedCenters
*
* @return string[]
*/
public function getGroups($authorizedCenters = null): array;
}

View File

@@ -1,30 +1,34 @@
<?php
/**
* Chill is a software for social workers
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/
namespace Chill\MainBundle;
use Chill\MainBundle\CRUD\CompilerPass\CRUDControllerCompilerPass;
use Chill\MainBundle\DependencyInjection\CompilerPass\ACLFlagsCompilerPass;
use Chill\MainBundle\DependencyInjection\CompilerPass\ExportsCompilerPass;
use Chill\MainBundle\DependencyInjection\CompilerPass\GroupingCenterCompilerPass;
use Chill\MainBundle\DependencyInjection\CompilerPass\MenuCompilerPass;
use Chill\MainBundle\DependencyInjection\CompilerPass\NotificationCounterCompilerPass;
use Chill\MainBundle\DependencyInjection\CompilerPass\SearchableServicesCompilerPass;
use Chill\MainBundle\DependencyInjection\CompilerPass\TimelineCompilerClass;
use Chill\MainBundle\DependencyInjection\CompilerPass\WidgetsCompilerPass;
use Chill\MainBundle\DependencyInjection\ConfigConsistencyCompilerPass;
use Chill\MainBundle\DependencyInjection\RoleProvidersCompilerPass;
use Chill\MainBundle\Routing\LocalMenuBuilderInterface;
use Chill\MainBundle\Search\SearchApiInterface;
use Chill\MainBundle\Search\SearchInterface;
use Chill\MainBundle\Security\Authorization\ChillVoterInterface;
use Chill\MainBundle\Security\ProvideRoleInterface;
use Chill\MainBundle\Security\Resolver\CenterResolverInterface;
use Chill\MainBundle\Security\Resolver\ScopeResolverInterface;
use Chill\MainBundle\Templating\Entity\ChillEntityRenderInterface;
use Symfony\Component\HttpKernel\Bundle\Bundle;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Chill\MainBundle\DependencyInjection\CompilerPass\SearchableServicesCompilerPass;
use Chill\MainBundle\DependencyInjection\ConfigConsistencyCompilerPass;
use Chill\MainBundle\DependencyInjection\CompilerPass\TimelineCompilerClass;
use Chill\MainBundle\DependencyInjection\RoleProvidersCompilerPass;
use Chill\MainBundle\DependencyInjection\CompilerPass\ExportsCompilerPass;
use Chill\MainBundle\DependencyInjection\CompilerPass\WidgetsCompilerPass;
use Chill\MainBundle\DependencyInjection\CompilerPass\NotificationCounterCompilerPass;
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;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\HttpKernel\Bundle\Bundle;
class ChillMainBundle extends Bundle
{

View File

@@ -1,47 +1,47 @@
<?php
/**
* Chill is a software for social workers
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/
declare(strict_types=1);
namespace Chill\MainBundle\Command;
use Chill\MainBundle\Entity\Center;
use Chill\MainBundle\Entity\GroupCenter;
use Chill\MainBundle\Entity\PermissionsGroup;
use Chill\MainBundle\Entity\User;
use Chill\MainBundle\Repository\UserRepository;
use Doctrine\ORM\EntityManagerInterface;
use Exception;
use League\Csv\Reader;
use League\Csv\Writer;
use Psr\Log\LoggerInterface;
use RuntimeException;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Output\OutputInterface;
use League\Csv\Reader;
use Doctrine\ORM\EntityManagerInterface;
use Chill\MainBundle\Entity\Center;
use Symfony\Component\Console\Question\ConfirmationQuestion;
use Chill\MainBundle\Entity\User;
use Symfony\Component\Validator\Validator\ValidatorInterface;
use Symfony\Component\Validator\ConstraintViolationListInterface;
use Psr\Log\LoggerInterface;
use Symfony\Component\Security\Core\Encoder\UserPasswordEncoderInterface;
use Chill\MainBundle\Entity\GroupCenter;
use Chill\MainBundle\Entity\PermissionsGroup;
use Symfony\Component\Console\Question\ChoiceQuestion;
use League\Csv\Writer;
use Symfony\Component\Console\Question\ConfirmationQuestion;
use Symfony\Component\Security\Core\Encoder\UserPasswordEncoderInterface;
use Symfony\Component\Validator\ConstraintViolationListInterface;
use Symfony\Component\Validator\Validator\ValidatorInterface;
use function array_key_exists;
use function array_keys;
use function array_merge;
use function bin2hex;
use function implode;
use function random_bytes;
use function trim;
class ChillImportUsersCommand extends Command
{
protected EntityManagerInterface $em;
protected ValidatorInterface $validator;
protected LoggerInterface $logger;
protected UserPasswordEncoderInterface $passwordEncoder;
protected UserRepository $userRepository;
protected bool $doChanges = true;
protected OutputInterface $tempOutput;
protected InputInterface $tempInput;
/**
* Centers and aliases.
*
@@ -49,12 +49,28 @@ class ChillImportUsersCommand extends Command
*/
protected array $centers;
protected array $permissionGroups;
protected bool $doChanges = true;
protected EntityManagerInterface $em;
protected array $groupCenters;
protected LoggerInterface $logger;
protected Writer $output;
protected UserPasswordEncoderInterface $passwordEncoder;
protected array $permissionGroups;
protected InputInterface $tempInput;
protected OutputInterface $tempOutput;
protected UserRepository $userRepository;
protected ValidatorInterface $validator;
public function __construct(
EntityManagerInterface $em,
LoggerInterface $logger,
@@ -71,6 +87,27 @@ class ChillImportUsersCommand extends Command
parent::__construct('chill:main:import-users');
}
protected function appendUserToFile(User $user)
{
$this->output->insertOne([
$user->getEmail(),
$user->getUsername(),
$user->getId(),
]);
}
protected function concatenateViolations(ConstraintViolationListInterface $list)
{
$str = [];
foreach ($list as $e) {
/* @var $e \Symfony\Component\Validator\ConstraintViolationInterface */
$str[] = $e->getMessage();
}
return implode(';', $str);
}
protected function configure()
{
$this
@@ -82,6 +119,99 @@ class ChillImportUsersCommand extends Command
->addOption('csv-dump', null, InputOption::VALUE_REQUIRED, 'A path to dump a summary of the created file');
}
protected function createOrGetGroupCenter(Center $center, PermissionsGroup $pg): GroupCenter
{
if (array_key_exists($center->getId(), $this->groupCenters)) {
if (array_key_exists($pg->getId(), $this->groupCenters[$center->getId()])) {
return $this->groupCenters[$center->getId()][$pg->getId()];
}
}
$repository = $this->em->getRepository(GroupCenter::class);
$groupCenter = $repository->findOneBy([
'center' => $center,
'permissionsGroup' => $pg,
]);
if (null === $groupCenter) {
$groupCenter = new GroupCenter();
$groupCenter
->setCenter($center)
->setPermissionsGroup($pg);
$this->em->persist($groupCenter);
}
$this->groupCenters[$center->getId()][$pg->getId()] = $groupCenter;
return $groupCenter;
}
protected function createUser($offset, $data)
{
$user = new User();
$user
->setEmail(trim($data['email']))
->setUsername(trim($data['username']))
->setEnabled(true)
->setPassword($this->passwordEncoder->encodePassword(
$user,
bin2hex(random_bytes(32))
));
$errors = $this->validator->validate($user);
if ($errors->count() > 0) {
$errorMessages = $this->concatenateViolations($errors);
$this->tempOutput->writeln(sprintf('%d errors found with user with username "%s" at line %d', $errors->count(), $data['username'], $offset));
$this->tempOutput->writeln($errorMessages);
throw new RuntimeException('Found errors while creating an user. '
. 'Watch messages in command output');
}
$pgs = $this->getPermissionGroup($data['permission group']);
$centers = $this->getCenters($data['center']);
foreach ($pgs as $pg) {
foreach ($centers as $center) {
$groupcenter = $this->createOrGetGroupCenter($center, $pg);
if (false === $user->getGroupCenters()->contains($groupcenter)) {
$user->addGroupCenter($groupcenter);
}
}
}
if ($this->doChanges) {
$this->em->persist($user);
$this->em->flush();
}
$this->logger->notice('Create user', [
'username' => $user->getUsername(),
'id' => $user->getId(),
'nb_of_groupCenters' => $user->getGroupCenters()->count(),
]);
return $user;
}
protected function doesUserExists($data)
{
if ($this->userRepository->countByUsernameOrEmail($data['username']) > 0) {
return true;
}
if ($this->userRepository->countByUsernameOrEmail($data['email']) > 0) {
return true;
}
return false;
}
protected function execute(InputInterface $input, OutputInterface $output)
{
$this->tempOutput = $output;
@@ -99,221 +229,11 @@ class ChillImportUsersCommand extends Command
try {
$this->loadUsers();
}
catch(\Exception $e) {
} catch (Exception $e) {
throw $e;
}
}
protected function prepareWriter()
{
$this->output = $output = Writer::createFromPath($this->tempInput
->getOption('csv-dump'), 'a+');
$output->insertOne([
'email',
'username',
'id'
]);
}
protected function appendUserToFile(User $user)
{
$this->output->insertOne( [
$user->getEmail(),
$user->getUsername(),
$user->getId()
]);
}
protected function loadUsers()
{
$reader = Reader::createFromPath($this->tempInput->getArgument('csvfile'));
$reader->setHeaderOffset(0);
foreach ($reader->getRecords() as $line => $r) {
$this->logger->debug("starting handling new line", [
'line' => $line
]);
if ($this->doesUserExists($r)) {
$this->tempOutput->writeln(sprintf("User with username '%s' already "
. "exists, skipping", $r["username"]));
$this->logger->info("One user already exists, skipping creation", [
'username_in_file' => $r['username'],
'email_in_file' => $r['email'],
'line' => $line
]);
continue;
}
$user = $this->createUser($line, $r);
$this->appendUserToFile($user);
}
}
protected function doesUserExists($data)
{
if ($this->userRepository->countByUsernameOrEmail($data['username']) > 0) {
return true;
}
if ($this->userRepository->countByUsernameOrEmail($data['email']) > 0) {
return true;
}
return false;
}
protected function createUser($offset, $data)
{
$user = new User();
$user
->setEmail(\trim($data['email']))
->setUsername(\trim($data['username']))
->setEnabled(true)
->setPassword($this->passwordEncoder->encodePassword($user,
\bin2hex(\random_bytes(32))))
;
$errors = $this->validator->validate($user);
if ($errors->count() > 0) {
$errorMessages = $this->concatenateViolations($errors);
$this->tempOutput->writeln(sprintf("%d errors found with user with username \"%s\" at line %d", $errors->count(), $data['username'], $offset));
$this->tempOutput->writeln($errorMessages);
throw new \RuntimeException("Found errors while creating an user. "
. "Watch messages in command output");
}
$pgs = $this->getPermissionGroup($data['permission group']);
$centers = $this->getCenters($data['center']);
foreach($pgs as $pg) {
foreach ($centers as $center) {
$groupcenter = $this->createOrGetGroupCenter($center, $pg);
if (FALSE === $user->getGroupCenters()->contains($groupcenter)) {
$user->addGroupCenter($groupcenter);
}
}
}
if ($this->doChanges) {
$this->em->persist($user);
$this->em->flush();
}
$this->logger->notice("Create user", [
'username' => $user->getUsername(),
'id' => $user->getId(),
'nb_of_groupCenters' => $user->getGroupCenters()->count()
]);
return $user;
}
protected function getPermissionGroup($alias)
{
if (\array_key_exists($alias, $this->permissionGroups)) {
return $this->permissionGroups[$alias];
}
$permissionGroupsByName = [];
foreach($this->em->getRepository(PermissionsGroup::class)
->findAll() as $permissionGroup) {
$permissionGroupsByName[$permissionGroup->getName()] = $permissionGroup;
}
if (count($permissionGroupsByName) === 0) {
throw new \RuntimeException("no permission groups found. Create them "
. "before importing users");
}
$question = new ChoiceQuestion("To which permission groups associate with \"$alias\" ?",
\array_keys($permissionGroupsByName));
$question
->setMultiselect(true)
->setAutocompleterValues(\array_keys($permissionGroupsByName))
->setNormalizer(function($value) {
if (NULL === $value) { return ''; }
return \trim($value);
})
;
$helper = $this->getHelper('question');
$keys = $helper->ask($this->tempInput, $this->tempOutput, $question);
$this->tempOutput->writeln("You have chosen ".\implode(", ", $keys));
if ($helper->ask($this->tempInput, $this->tempOutput,
new ConfirmationQuestion("Are you sure ?", true))) {
foreach ($keys as $key) {
$this->permissionGroups[$alias][] = $permissionGroupsByName[$key];
}
return $this->permissionGroups[$alias];
}
$this->logger->error('Error while responding to a a question');
$this->tempOutput->writeln('Ok, I accept, but I do not know what to do. Please try again.');
throw new \RuntimeException('Error while responding to a question');
}
protected function createOrGetGroupCenter(Center $center, PermissionsGroup $pg): GroupCenter
{
if (\array_key_exists($center->getId(), $this->groupCenters)) {
if (\array_key_exists($pg->getId(), $this->groupCenters[$center->getId()])) {
return $this->groupCenters[$center->getId()][$pg->getId()];
}
}
$repository = $this->em->getRepository(GroupCenter::class);
$groupCenter = $repository->findOneBy(array(
'center' => $center,
'permissionsGroup' => $pg
));
if ($groupCenter === NULL) {
$groupCenter = new GroupCenter();
$groupCenter
->setCenter($center)
->setPermissionsGroup($pg)
;
$this->em->persist($groupCenter);
}
$this->groupCenters[$center->getId()][$pg->getId()] = $groupCenter;
return $groupCenter;
}
protected function prepareGroupingCenters()
{
$reader = Reader::createFromPath($this->tempInput->getOption('grouping-centers'));
$reader->setHeaderOffset(0);
foreach ($reader->getRecords() as $r) {
$this->centers[$r['alias']] =
\array_merge(
$this->centers[$r['alias']] ?? [],
$this->getCenters($r['center']
)
);
}
}
/**
* return a list of centers matching the name of alias.
*
@@ -326,14 +246,15 @@ class ChillImportUsersCommand extends Command
* and suggested to user
*
* @param string $name the name of the center or the alias regrouping center
*
* @return Center[]
*/
protected function getCenters($name)
{
// sanitize
$name = \trim($name);
$name = trim($name);
if (\array_key_exists($name, $this->centers)) {
if (array_key_exists($name, $this->centers)) {
return $this->centers[$name];
}
@@ -351,23 +272,23 @@ class ChillImportUsersCommand extends Command
$center = (new Center())
->setName($name);
$this->tempOutput->writeln("Center with name \"$name\" not found.");
$this->tempOutput->writeln("Center with name \"{$name}\" not found.");
$qFormatter = $this->getHelper('question');
$question = new ConfirmationQuestion("Create a center with name \"$name\" ?", true);
$question = new ConfirmationQuestion("Create a center with name \"{$name}\" ?", true);
if ($qFormatter->ask($this->tempInput, $this->tempOutput, $question)) {
$this->centers[$name] = [ $center ];
$this->centers[$name] = [$center];
$errors = $this->validator->validate($center);
if ($errors->count() > 0) {
$errorMessages = $this->concatenateViolations($errors);
$this->tempOutput->writeln(sprintf("%d errors found with center with name \"%s\"", $errors->count(), $name));
$this->tempOutput->writeln(sprintf('%d errors found with center with name "%s"', $errors->count(), $name));
$this->tempOutput->writeln($errorMessages);
throw new \RuntimeException("Found errors while creating one center. "
. "Watch messages in command output");
throw new RuntimeException('Found errors while creating one center. '
. 'Watch messages in command output');
}
$this->em->persist($center);
@@ -378,16 +299,115 @@ class ChillImportUsersCommand extends Command
return null;
}
protected function concatenateViolations(ConstraintViolationListInterface $list)
protected function getPermissionGroup($alias)
{
$str = [];
foreach ($list as $e) {
/* @var $e \Symfony\Component\Validator\ConstraintViolationInterface */
$str[] = $e->getMessage();
if (array_key_exists($alias, $this->permissionGroups)) {
return $this->permissionGroups[$alias];
}
return \implode(";", $str);
$permissionGroupsByName = [];
foreach ($this->em->getRepository(PermissionsGroup::class)
->findAll() as $permissionGroup) {
$permissionGroupsByName[$permissionGroup->getName()] = $permissionGroup;
}
if (count($permissionGroupsByName) === 0) {
throw new RuntimeException('no permission groups found. Create them '
. 'before importing users');
}
$question = new ChoiceQuestion(
"To which permission groups associate with \"{$alias}\" ?",
array_keys($permissionGroupsByName)
);
$question
->setMultiselect(true)
->setAutocompleterValues(array_keys($permissionGroupsByName))
->setNormalizer(function ($value) {
if (null === $value) {
return '';
}
return trim($value);
});
$helper = $this->getHelper('question');
$keys = $helper->ask($this->tempInput, $this->tempOutput, $question);
$this->tempOutput->writeln('You have chosen ' . implode(', ', $keys));
if ($helper->ask(
$this->tempInput,
$this->tempOutput,
new ConfirmationQuestion('Are you sure ?', true)
)) {
foreach ($keys as $key) {
$this->permissionGroups[$alias][] = $permissionGroupsByName[$key];
}
return $this->permissionGroups[$alias];
}
$this->logger->error('Error while responding to a a question');
$this->tempOutput->writeln('Ok, I accept, but I do not know what to do. Please try again.');
throw new RuntimeException('Error while responding to a question');
}
protected function loadUsers()
{
$reader = Reader::createFromPath($this->tempInput->getArgument('csvfile'));
$reader->setHeaderOffset(0);
foreach ($reader->getRecords() as $line => $r) {
$this->logger->debug('starting handling new line', [
'line' => $line,
]);
if ($this->doesUserExists($r)) {
$this->tempOutput->writeln(sprintf("User with username '%s' already "
. 'exists, skipping', $r['username']));
$this->logger->info('One user already exists, skipping creation', [
'username_in_file' => $r['username'],
'email_in_file' => $r['email'],
'line' => $line,
]);
continue;
}
$user = $this->createUser($line, $r);
$this->appendUserToFile($user);
}
}
protected function prepareGroupingCenters()
{
$reader = Reader::createFromPath($this->tempInput->getOption('grouping-centers'));
$reader->setHeaderOffset(0);
foreach ($reader->getRecords() as $r) {
$this->centers[$r['alias']] =
array_merge(
$this->centers[$r['alias']] ?? [],
$this->getCenters(
$r['center']
)
);
}
}
protected function prepareWriter()
{
$this->output = $output = Writer::createFromPath($this->tempInput
->getOption('csv-dump'), 'a+');
$output->insertOne([
'email',
'username',
'id',
]);
}
}

View File

@@ -1,88 +1,92 @@
<?php
/**
* Chill is a software for social workers
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/
namespace Chill\MainBundle\Command;
use Chill\MainBundle\Entity\User;
use Chill\MainBundle\Notification\Mailer;
use Chill\MainBundle\Security\PasswordRecover\RecoverPasswordHelper;
use DateTime;
use Doctrine\ORM\EntityManagerInterface;
use Exception;
use InvalidArgumentException;
use League\Csv\Reader;
use Psr\Log\LoggerInterface;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Output\OutputInterface;
use League\Csv\Reader;
use Psr\Log\LoggerInterface;
use Doctrine\ORM\EntityManagerInterface;
use Chill\MainBundle\Entity\User;
use Chill\MainBundle\Notification\Mailer;
use Chill\MainBundle\Security\PasswordRecover\RecoverPasswordHelper;
use Chill\MainBundle\Security\PasswordRecover\PasswordRecoverEvent;
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
use function array_key_exists;
use function array_merge;
use function in_array;
use function trim;
/**
* Class ChillUserSendRenewPasswordCodeCommand
*
* @package Chill\MainBundle\Command
* Class ChillUserSendRenewPasswordCodeCommand.
*/
class ChillUserSendRenewPasswordCodeCommand extends Command
{
/**
*
* @var LoggerInterface
*/
protected $logger;
/**
*
* @var EntityManagerInterface
*/
protected $em;
/**
*
* @var Mailer
*/
protected $mailer;
/**
*
* @var RecoverPasswordHelper
*/
protected $recoverPasswordHelper;
/**
*
* @var EventDispatcherInterface
*/
protected $eventDispatcher;
/**
* The current input interface
* @var LoggerInterface
*/
protected $logger;
/**
* @var Mailer
*/
protected $mailer;
/**
* @var RecoverPasswordHelper
*/
protected $recoverPasswordHelper;
/**
* The current input interface.
*
* @var InputInterface
*/
private $input;
/**
* The current output interface
* The current output interface.
*
* @var OutputInterface
*/
private $output;
public function __construct(
LoggerInterface $logger,
EntityManagerInterface $em,
RecoverPasswordHelper $recoverPasswordHelper,
LoggerInterface $logger,
EntityManagerInterface $em,
RecoverPasswordHelper $recoverPasswordHelper,
EventDispatcherInterface $eventDispatcher
) {
$this->logger = $logger;
$this->em = $em;
$this->recoverPasswordHelper = $recoverPasswordHelper;
$this->eventDispatcher = $eventDispatcher;
parent::__construct();
}
protected function configure()
{
$this
@@ -91,113 +95,114 @@ class ChillUserSendRenewPasswordCodeCommand extends Command
->addArgument('csvfile', InputArgument::REQUIRED, 'CSV file with the list of users')
->addOption('template', null, InputOption::VALUE_REQUIRED, 'Template for email')
->addOption('expiration', null, InputOption::VALUE_REQUIRED, 'Expiration of the link, as an unix timestamp')
->addOption('subject', null, InputOption::VALUE_REQUIRED, 'Subject of the email', 'Recover your password')
;
->addOption('subject', null, InputOption::VALUE_REQUIRED, 'Subject of the email', 'Recover your password');
}
protected function execute(InputInterface $input, OutputInterface $output)
{
$this->input = $input;
$this->output = $output;
$reader = $this->getReader();
foreach($reader->getRecords() as $offset => $r) {
foreach ($reader->getRecords() as $offset => $r) {
$user = $this->getUser($r);
if ($user === null) {
if (null === $user) {
$this->onUserNotFound($r, $offset);
continue;
}
$this->sendRecoverCode($user);
}
}
protected function sendRecoverCode(User $user)
{
if (empty($user->getEmail())) {
$this->logger->alert("User without email", [
'user_id' => $user->getId(),
'username' => $user->getUsername()
]);
return;
}
$template = $this->input->getOption('template');
$expiration = \DateTime::createFromFormat('U',
$this->input->getOption('expiration'));
$this->recoverPasswordHelper
->sendRecoverEmail(
$user,
$expiration,
$template,
[ 'expiration' => $expiration],
false,
[ '_locale' => 'fr' ],
$this->input->getOption('subject')
);
}
protected function onUserNotFound($row, $offset)
{
$this->logger->alert('User not found', \array_merge([
'offset' => $offset
], $row));
}
protected function getUser($row)
{
/* @var $userRepository \Chill\MainBundle\Repository\UserRepository */
$userRepository = $this->em->getRepository(User::class);
try {
if (\array_key_exists('email', $row)) {
return $userRepository->findOneByUsernameOrEmail(\trim($row['email']));
}
} catch (\Doctrine\ORM\NoResultException $e) {
// continue, we will try username
}
try {
if (\array_key_exists('username', $row)) {
return $userRepository->findOneByUsernameOrEmail(\trim($row['username']));
}
} catch (\Doctrine\ORM\NoResultException $e) {
return null;
}
}
/**
*
* @throws Exception
*
* @return Reader
* @throws \Exception
*/
protected function getReader()
{
try {
$reader = Reader::createFromPath($this->input->getArgument('csvfile'));
} catch (\Exception $e) {
$this->logger->error("The csv file could not be read", [
'path' => $this->input->getArgument('csvfile')
} catch (Exception $e) {
$this->logger->error('The csv file could not be read', [
'path' => $this->input->getArgument('csvfile'),
]);
throw $e;
}
$reader->setHeaderOffset(0);
$headers = $reader->getHeader();
if (FALSE === \in_array('username', $headers)
&& FALSE === \in_array('email', $headers)) {
throw new \InvalidArgumentException("The csv file does not have an "
. "username or email header");
if (false === in_array('username', $headers)
&& false === in_array('email', $headers)) {
throw new InvalidArgumentException('The csv file does not have an '
. 'username or email header');
}
return $reader;
}
protected function getUser($row)
{
/* @var $userRepository \Chill\MainBundle\Repository\UserRepository */
$userRepository = $this->em->getRepository(User::class);
try {
if (array_key_exists('email', $row)) {
return $userRepository->findOneByUsernameOrEmail(trim($row['email']));
}
} catch (\Doctrine\ORM\NoResultException $e) {
// continue, we will try username
}
try {
if (array_key_exists('username', $row)) {
return $userRepository->findOneByUsernameOrEmail(trim($row['username']));
}
} catch (\Doctrine\ORM\NoResultException $e) {
return null;
}
}
protected function onUserNotFound($row, $offset)
{
$this->logger->alert('User not found', array_merge([
'offset' => $offset,
], $row));
}
protected function sendRecoverCode(User $user)
{
if (empty($user->getEmail())) {
$this->logger->alert('User without email', [
'user_id' => $user->getId(),
'username' => $user->getUsername(),
]);
return;
}
$template = $this->input->getOption('template');
$expiration = DateTime::createFromFormat(
'U',
$this->input->getOption('expiration')
);
$this->recoverPasswordHelper
->sendRecoverEmail(
$user,
$expiration,
$template,
['expiration' => $expiration],
false,
['_locale' => 'fr'],
$this->input->getOption('subject')
);
}
}

View File

@@ -1,69 +1,57 @@
<?php
/*
* Copyright (C) 2014, Champs Libres Cooperative SCRLFS, <http://www.champs-libres.coop>
/**
* Chill is a software for social workers
*
* This program is free software: you can redistribute it and/or modify
* 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/>.
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/
namespace Chill\MainBundle\Command;
use Doctrine\ORM\EntityManager;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Intl\Intl;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Intl\Intl;
/*
* Load or update the languages entities command
*/
class LoadAndUpdateLanguagesCommand extends Command
{
public const INCLUDE_ANCIENT = 'include_ancient';
public const INCLUDE_REGIONAL_VERSION = 'include_regional';
// Array of ancien languages (to exclude)
private $ancientToExclude = ['ang', 'egy', 'fro', 'goh', 'grc', 'la', 'non', 'peo', 'pro', 'sga',
'dum', 'enm', 'frm', 'gmh', 'mga', 'akk', 'phn', 'zxx', 'got', 'und', ];
private $availableLanguages;
/**
* @var EntityManager
*/
private $entityManager;
private $availableLanguages;
// The regional version of language are language with _ in the code
// This array contains regional code to not exclude
private $regionalVersionToInclude = ["ro_MD"];
private $regionalVersionToInclude = ['ro_MD'];
// Array of ancien languages (to exclude)
private $ancientToExclude = ["ang", "egy", "fro", "goh", "grc", "la", "non", "peo", "pro", "sga",
"dum", "enm", "frm", "gmh", "mga", "akk", "phn", "zxx", "got", "und"];
const INCLUDE_REGIONAL_VERSION = 'include_regional';
const INCLUDE_ANCIENT = 'include_ancient';
/**
* LoadCountriesCommand constructor.
*
* @param EntityManager $entityManager
* @param $availableLanguages
*/
public function __construct(EntityManager $entityManager, $availableLanguages)
{
$this->entityManager=$entityManager;
$this->availableLanguages=$availableLanguages;
$this->entityManager = $entityManager;
$this->availableLanguages = $availableLanguages;
parent::__construct();
}
/*
* (non-PHPdoc)
* @see \Symfony\Component\Console\Command\Command::configure()
@@ -72,23 +60,24 @@ class LoadAndUpdateLanguagesCommand extends Command
{
$this
->setName('chill:main:languages:populate')
->setDescription('Load or update languages in db. This command does not delete existing '.
->setDescription('Load or update languages in db. This command does not delete existing ' .
'languages, but will update names according to available languages')
->addOption(
self::INCLUDE_REGIONAL_VERSION,
null,
InputOption::VALUE_NONE,
'Include the regional languages. The regional languages are languages with code containing _ excepted '
. implode(',', $this->regionalVersionToInclude) . '.')
self::INCLUDE_REGIONAL_VERSION,
null,
InputOption::VALUE_NONE,
'Include the regional languages. The regional languages are languages with code containing _ excepted '
. implode(',', $this->regionalVersionToInclude) . '.'
)
->addOption(
self::INCLUDE_ANCIENT,
null,
InputOption::VALUE_NONE,
'Include the ancient languages that are languages with code '
. implode(', ', $this->ancientToExclude) . '.')
;
self::INCLUDE_ANCIENT,
null,
InputOption::VALUE_NONE,
'Include the ancient languages that are languages with code '
. implode(', ', $this->ancientToExclude) . '.'
);
}
/*
* (non-PHPdoc)
* @see \Symfony\Component\Console\Command\Command::execute()
@@ -98,7 +87,7 @@ class LoadAndUpdateLanguagesCommand extends Command
$em = $this->entityManager;
$chillAvailableLanguages = $this->availableLanguages;
$languageBundle = Intl::getLanguageBundle();
$languages = array();
$languages = [];
foreach ($chillAvailableLanguages as $avLang) {
$languages[$avLang] = $languageBundle->getLanguageNames($avLang);
@@ -109,25 +98,25 @@ class LoadAndUpdateLanguagesCommand extends Command
foreach ($languageCodes as $code) {
$excludeCode = (
(
! $input->getOption(self::INCLUDE_REGIONAL_VERSION)
!$input->getOption(self::INCLUDE_REGIONAL_VERSION)
and strpos($code, '_')
and !in_array($code, $this->regionalVersionToInclude)
) or (
! $input->getOption(self::INCLUDE_ANCIENT)
!$input->getOption(self::INCLUDE_ANCIENT)
and in_array($code, $this->ancientToExclude)
)
);
$langageDB = $em->getRepository('ChillMainBundle:Language')->find($code);
if(! $excludeCode) {
if (! $langageDB) {
if (!$excludeCode) {
if (!$langageDB) {
$langageDB = new \Chill\MainBundle\Entity\Language();
$langageDB->setId($code);
$em->persist($langageDB);
}
$avLangNames = array();
$avLangNames = [];
foreach ($chillAvailableLanguages as $avLang) {
$avLangNames[$avLang] = $languages[$avLang][$code];
@@ -135,10 +124,10 @@ class LoadAndUpdateLanguagesCommand extends Command
$langageDB->setName($avLangNames);
} else {
if($langageDB) {
if ($langageDB) {
$em->remove($langageDB);
}
echo "Code excluded : ".$code." - ".$languageBundle->getLanguageName($code)."\n";
echo 'Code excluded : ' . $code . ' - ' . $languageBundle->getLanguageName($code) . "\n";
}
}

View File

@@ -1,74 +1,41 @@
<?php
/**
* Chill is a software for social workers
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/
namespace Chill\MainBundle\Command;
use Doctrine\ORM\EntityManager;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Intl\Intl;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Intl\Intl;
/**
*
* @author Julien Fastré <julien.fastre@champs-libres.coop
*
*/
class LoadCountriesCommand extends Command
{
private $availableLanguages;
/**
* @var EntityManager
*/
private $entityManager;
private $availableLanguages;
/**
* LoadCountriesCommand constructor.
*
* @param EntityManager $entityManager
* @param $availableLanguages
*/
public function __construct(EntityManager $entityManager, $availableLanguages)
{
$this->entityManager=$entityManager;
$this->availableLanguages=$availableLanguages;
$this->entityManager = $entityManager;
$this->availableLanguages = $availableLanguages;
parent::__construct();
}
/*
* (non-PHPdoc)
* @see \Symfony\Component\Console\Command\Command::configure()
*/
protected function configure()
{
$this->setName('chill:main:countries:populate')
->setDescription('Load or update countries in db. This command does not delete existing countries, '.
'but will update names according to available languages');
}
/*
* (non-PHPdoc)
* @see \Symfony\Component\Console\Command\Command::execute()
*/
protected function execute(InputInterface $input, OutputInterface $output)
{
$countries = static::prepareCountryList($this->availableLanguages);
$em = $this->entityManager;
foreach($countries as $country) {
$countryStored = $em->getRepository('ChillMainBundle:Country')
->findOneBy(array('countryCode' => $country->getCountryCode()));
if (NULL === $countryStored) {
$em->persist($country);
} else {
$countryStored->setName($country->getName());
}
}
$em->flush();
}
public static function prepareCountryList($languages)
{
$regionBundle = Intl::getRegionBundle();
@@ -78,10 +45,10 @@ class LoadCountriesCommand extends Command
$countries[$language] = $regionBundle->getCountryNames($language);
}
$countryEntities = array();
$countryEntities = [];
foreach ($countries[$languages[0]] as $countryCode => $name) {
$names = array();
$names = [];
foreach ($languages as $language) {
$names[$language] = $countries[$language][$countryCode];
@@ -94,4 +61,38 @@ class LoadCountriesCommand extends Command
return $countryEntities;
}
/*
* (non-PHPdoc)
* @see \Symfony\Component\Console\Command\Command::configure()
*/
protected function configure()
{
$this->setName('chill:main:countries:populate')
->setDescription('Load or update countries in db. This command does not delete existing countries, ' .
'but will update names according to available languages');
}
/*
* (non-PHPdoc)
* @see \Symfony\Component\Console\Command\Command::execute()
*/
protected function execute(InputInterface $input, OutputInterface $output)
{
$countries = static::prepareCountryList($this->availableLanguages);
$em = $this->entityManager;
foreach ($countries as $country) {
$countryStored = $em->getRepository('ChillMainBundle:Country')
->findOneBy(['countryCode' => $country->getCountryCode()]);
if (null === $countryStored) {
$em->persist($country);
} else {
$countryStored->setName($country->getName());
}
}
$em->flush();
}
}

View File

@@ -1,20 +1,28 @@
<?php
/**
* Chill is a software for social workers
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/
declare(strict_types=1);
namespace Chill\MainBundle\Command;
use Chill\MainBundle\Doctrine\Model\Point;
use Chill\MainBundle\Entity\Country;
use Doctrine\ORM\EntityManager;
use Chill\MainBundle\Entity\PostalCode;
use Doctrine\ORM\EntityManagerInterface;
use Exception;
use RuntimeException;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Filesystem\Filesystem;
use Chill\MainBundle\Entity\PostalCode;
use Symfony\Component\Validator\Validator\ValidatorInterface;
class LoadPostalCodesCommand extends Command
@@ -33,38 +41,38 @@ class LoadPostalCodesCommand extends Command
protected function configure()
{
$this->setName('chill:main:postal-code:populate')
->setDescription("Add the postal code from a csv file.")
->setHelp("This script will try to avoid existing postal code "
->setDescription('Add the postal code from a csv file.')
->setHelp('This script will try to avoid existing postal code '
. "using the postal code and name. \n"
. "The CSV file must have the following columns: "
. "postal code, label, country code."
. "Optionally, the csv file can have the following "
. "columns after the country code: reference code, latitude, longitude, source. "
. "The latitude and longitude columns are supposed to be in WGS84 and expressed in decimal degrees. "
. "The CSV file should not have any header row.")
->addArgument('csv_file', InputArgument::REQUIRED, "the path to "
. "the csv file. See the help for specifications.")
->addOption(
'delimiter',
'd',
InputOption::VALUE_OPTIONAL,
"The delimiter character of the csv file",
",")
->addOption(
'enclosure',
null,
InputOption::VALUE_OPTIONAL,
"The enclosure character of the csv file",
'"'
)
->addOption(
'escape',
null,
InputOption::VALUE_OPTIONAL,
"The escape character of the csv file",
"\\"
)
;
. 'The CSV file must have the following columns: '
. 'postal code, label, country code.'
. 'Optionally, the csv file can have the following '
. 'columns after the country code: reference code, latitude, longitude, source. '
. 'The latitude and longitude columns are supposed to be in WGS84 and expressed in decimal degrees. '
. 'The CSV file should not have any header row.')
->addArgument('csv_file', InputArgument::REQUIRED, 'the path to '
. 'the csv file. See the help for specifications.')
->addOption(
'delimiter',
'd',
InputOption::VALUE_OPTIONAL,
'The delimiter character of the csv file',
','
)
->addOption(
'enclosure',
null,
InputOption::VALUE_OPTIONAL,
'The enclosure character of the csv file',
'"'
)
->addOption(
'escape',
null,
InputOption::VALUE_OPTIONAL,
'The escape character of the csv file',
'\\'
);
}
protected function execute(InputInterface $input, OutputInterface $output)
@@ -79,90 +87,77 @@ class LoadPostalCodesCommand extends Command
$num = 0;
$line = 0;
while (($row = fgetcsv(
$csv,
0,
$input->getOption('delimiter'),
$input->getOption('enclosure'),
$input->getOption('escape'))) !== false) {
try{
while (false !== ($row = fgetcsv(
$csv,
0,
$input->getOption('delimiter'),
$input->getOption('enclosure'),
$input->getOption('escape')
))) {
try {
$this->addPostalCode($row, $output);
$num++;
++$num;
} catch (ExistingPostalCodeException $ex) {
$output->writeln('<warning> on line '.$line.' : '.$ex->getMessage().'</warning>');
$output->writeln('<warning> on line ' . $line . ' : ' . $ex->getMessage() . '</warning>');
} catch (CountryCodeNotFoundException $ex) {
$output->writeln('<warning> on line '.$line.' : '.$ex->getMessage().'</warning>');
$output->writeln('<warning> on line ' . $line . ' : ' . $ex->getMessage() . '</warning>');
} catch (PostalCodeNotValidException $ex) {
$output->writeln('<warning> on line '.$line.' : '.$ex->getMessage().'</warning>');
$output->writeln('<warning> on line ' . $line . ' : ' . $ex->getMessage() . '</warning>');
}
$line ++;
++$line;
}
$this->entityManager->flush();
$output->writeln('<info>'.$num.' were added !</info>');
}
private function getCSVResource(InputInterface $input)
{
$fs = new Filesystem();
$filename = $input->getArgument('csv_file');
if (!$fs->exists($filename)) {
throw new \RuntimeException("The file does not exists or you do not "
. "have the right to read it.");
}
$resource = fopen($filename, 'r');
if ($resource == FALSE) {
throw new \RuntimeException("The file '$filename' could not be opened.");
}
return $resource;
$output->writeln('<info>' . $num . ' were added !</info>');
}
private function addPostalCode($row, OutputInterface $output)
{
if ($output->getVerbosity() >= OutputInterface::VERBOSITY_VERBOSE) {
$output->writeln('handling row: '. $row[0].' | '. $row[1].' | '. $row[2]);
$output->writeln('handling row: ' . $row[0] . ' | ' . $row[1] . ' | ' . $row[2]);
}
$em = $this->entityManager;
$country = $em
->getRepository(Country::class)
->findOneBy(array('countryCode' => $row[2]));
->getRepository(Country::class)
->findOneBy(['countryCode' => $row[2]]);
if ($country === NULL) {
throw new CountryCodeNotFoundException(sprintf("The country with code %s is not found. Aborting to insert postal code with %s - %s",
$row[2], $row[0], $row[1]));
if (null === $country) {
throw new CountryCodeNotFoundException(sprintf(
'The country with code %s is not found. Aborting to insert postal code with %s - %s',
$row[2],
$row[0],
$row[1]
));
}
// try to find an existing postal code
$existingPC = $em
->getRepository(PostalCode::class)
->findBy(array('code' => $row[0], 'name' => $row[1]));
->getRepository(PostalCode::class)
->findBy(['code' => $row[0], 'name' => $row[1]]);
if (count($existingPC) > 0) {
throw new ExistingPostalCodeException(sprintf("A postal code with code : %s and name : %s already exists, skipping",
$row[0], $row[1]));
throw new ExistingPostalCodeException(sprintf(
'A postal code with code : %s and name : %s already exists, skipping',
$row[0],
$row[1]
));
}
$postalCode = (new PostalCode())
->setCode($row[0])
->setName($row[1])
->setCountry($country)
;
->setCode($row[0])
->setName($row[1])
->setCountry($country);
if (NULL != $row[3]){
if (null != $row[3]) {
$postalCode->setRefPostalCodeId($row[3]);
}
if (NULL != $row[4] & NULL != $row[5]){
if (null != $row[4] & null != $row[5]) {
$postalCode->setCenter(Point::fromLonLat((float) $row[5], (float) $row[4]));
}
if (NULL != $row[6]){
if (null != $row[6]) {
$postalCode->setPostalCodeSource($row[6]);
}
@@ -171,35 +166,53 @@ class LoadPostalCodesCommand extends Command
if ($errors->count() == 0) {
$em->persist($postalCode);
} else {
$msg = "";
$msg = '';
foreach ($errors as $error) {
$msg .= " ".$error->getMessage();
$msg .= ' ' . $error->getMessage();
}
throw new PostalCodeNotValidException($msg);
}
if ($output->getVerbosity() >= OutputInterface::VERBOSITY_VERBOSE) {
$output->writeln(sprintf('Creating postal code with code: %s, name: %s, countryCode: %s',
$postalCode->getCode(), $postalCode->getName(), $postalCode->getCountry()->getCountryCode()));
$output->writeln(sprintf(
'Creating postal code with code: %s, name: %s, countryCode: %s',
$postalCode->getCode(),
$postalCode->getName(),
$postalCode->getCountry()->getCountryCode()
));
}
}
private function getCSVResource(InputInterface $input)
{
$fs = new Filesystem();
$filename = $input->getArgument('csv_file');
if (!$fs->exists($filename)) {
throw new RuntimeException('The file does not exists or you do not '
. 'have the right to read it.');
}
$resource = fopen($filename, 'r');
if (false == $resource) {
throw new RuntimeException("The file '{$filename}' could not be opened.");
}
return $resource;
}
}
class ExistingPostalCodeException extends \Exception
class ExistingPostalCodeException extends Exception
{
}
class CountryCodeNotFoundException extends \Exception
class CountryCodeNotFoundException extends Exception
{
}
class PostalCodeNotValidException extends \Exception
class PostalCodeNotValidException extends Exception
{
}

View File

@@ -1,101 +1,55 @@
<?php
/*
/**
* Chill is a software for social workers
* Copyright (C) 2014 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/>.
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/
namespace Chill\MainBundle\Command;
use Chill\MainBundle\Entity\User;
use Doctrine\ORM\EntityManager;
use LogicException;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Console\Input\InputArgument;
use Chill\MainBundle\Entity\User;
use Symfony\Component\Security\Core\Encoder\EncoderFactory;
use Symfony\Component\Security\Core\Encoder\MessageDigestPasswordEncoder;
use Symfony\Component\Security\Core\Security;
/**
* Class SetPasswordCommand
*
* @package Chill\MainBundle\Command
* @author Julien Fastré <julien.fastre@champs-libres.coop>
* Class SetPasswordCommand.
*/
class SetPasswordCommand extends Command
{
/**
* @var EntityManager
*/
private $entityManager;
/**
* SetPasswordCommand constructor.
*
* @param EntityManager $entityManager
*/
public function __construct(EntityManager $entityManager)
{
$this->entityManager = $entityManager;
parent::__construct();
}
public function configure()
{
$this->setName('chill:user:set_password')
->setDescription('set a password to user')
->addArgument('username', InputArgument::REQUIRED, 'the user\'s '
. 'username you want to change password')
->addArgument('password', InputArgument::OPTIONAL, 'the new password')
;
}
public function execute(InputInterface $input, OutputInterface $output)
{
$user = $this->_getUser($input->getArgument('username'));
if ($user === NULL) {
throw new \LogicException("The user with username '".
$input->getArgument('username')."' is not found");
}
$password = $input->getArgument('password');
if ($password === NULL) {
$dialog = $this->getHelperSet()->get('dialog');
$password = $dialog->askHiddenResponse($output, "<question>the new password :"
. "</question>");
}
$this->_setPassword($user, $password);
}
public function _getUser($username)
{
return $this->entityManager
->getRepository('ChillMainBundle:User')
->findOneBy(array('username' => $username));
->findOneBy(['username' => $username]);
}
public function _setPassword(User $user, $password)
{
$defaultEncoder = new MessageDigestPasswordEncoder('sha512', true, 5000);
$encoders = [
User::class => $defaultEncoder
User::class => $defaultEncoder,
];
$encoderFactory = new EncoderFactory($encoders);
$user->setPassword(
@@ -103,4 +57,33 @@ class SetPasswordCommand extends Command
);
$this->entityManager->flush($user);
}
public function configure()
{
$this->setName('chill:user:set_password')
->setDescription('set a password to user')
->addArgument('username', InputArgument::REQUIRED, 'the user\'s '
. 'username you want to change password')
->addArgument('password', InputArgument::OPTIONAL, 'the new password');
}
public function execute(InputInterface $input, OutputInterface $output)
{
$user = $this->_getUser($input->getArgument('username'));
if (null === $user) {
throw new LogicException("The user with username '" .
$input->getArgument('username') . "' is not found");
}
$password = $input->getArgument('password');
if (null === $password) {
$dialog = $this->getHelperSet()->get('dialog');
$password = $dialog->askHiddenResponse($output, '<question>the new password :'
. '</question>');
}
$this->_setPassword($user, $password);
}
}

View File

@@ -1,5 +1,12 @@
<?php
/**
* Chill is a software for social workers
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/
namespace Chill\MainBundle\Controller;
use Chill\MainBundle\CRUD\Controller\ApiController;
@@ -12,12 +19,10 @@ use Symfony\Component\Serializer\Normalizer\AbstractNormalizer;
class AddressApiController extends ApiController
{
/**
* Duplicate an existing address
* Duplicate an existing address.
*
* @Route("/api/1.0/main/address/{id}/duplicate.json", name="chill_api_main_address_duplicate",
* methods={"POST"})
*
* @param Address $address
* methods={"POST"})
*/
public function duplicate(Address $address): JsonResponse
{
@@ -30,9 +35,7 @@ class AddressApiController extends ApiController
$em->flush();
return $this->json($new, Response::HTTP_OK, [], [
AbstractNormalizer::GROUPS => ['read']
AbstractNormalizer::GROUPS => ['read'],
]);
}
}

View File

@@ -1,5 +1,12 @@
<?php
/**
* Chill is a software for social workers
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/
namespace Chill\MainBundle\Controller;
use Chill\MainBundle\CRUD\Controller\ApiController;
@@ -7,23 +14,16 @@ use Chill\MainBundle\Pagination\PaginatorInterface;
use Symfony\Component\HttpFoundation\Request;
/**
* Class AddressReferenceAPIController
*
* @package Chill\MainBundle\Controller
* @author Champs Libres
* Class AddressReferenceAPIController.
*/
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'));
->setParameter('postal_code', $request->query->get('postal_code'));
}
}
protected function orderQuery(string $action, $query, Request $request, PaginatorInterface $paginator, $_format)
@@ -33,5 +33,4 @@ class AddressReferenceAPIController extends ApiController
return $query;
}
}

View File

@@ -1,22 +1,10 @@
<?php
/*
/**
* Chill is a software for social workers
*
* Copyright (C) 2014, Champs Libres Cooperative SCRLFS, <http://www.champs-libres.coop>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/
namespace Chill\MainBundle\Controller;
@@ -27,7 +15,6 @@ use Symfony\Component\Routing\Annotation\Route;
class AdminController extends AbstractController
{
/**
* @Route("/{_locale}/admin", name="chill_main_admin_central")
*/
@@ -36,14 +23,13 @@ class AdminController extends AbstractController
return $this->render('@ChillMain/Admin/index.html.twig');
}
public function indexPermissionsAction()
{
return $this->render('@ChillMain/Admin/layout_permissions.html.twig');
}
public function indexLocationsAction()
{
return $this->render('@ChillMain/Admin/layout_location.html.twig');
}
public function indexPermissionsAction()
{
return $this->render('@ChillMain/Admin/layout_permissions.html.twig');
}
}

View File

@@ -1,5 +1,12 @@
<?php
/**
* Chill is a software for social workers
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/
declare(strict_types=1);
namespace Chill\MainBundle\Controller;
@@ -8,5 +15,4 @@ use Chill\MainBundle\CRUD\Controller\CRUDController;
class AdminCountryCRUDController extends CRUDController
{
}

View File

@@ -1,40 +1,28 @@
<?php
/**
* Chill is a software for social workers
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/
namespace Chill\MainBundle\Controller;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\Form\Extension\Core\Type\SubmitType;
use Chill\MainBundle\Entity\Center;
use Chill\MainBundle\Form\CenterType;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\Form\Extension\Core\Type\SubmitType;
use Symfony\Component\HttpFoundation\Request;
/**
* Class CenterController
*
* @package Chill\MainBundle\Controller
* Class CenterController.
*/
class CenterController extends AbstractController
{
/**
* Lists all Center entities.
*
*/
public function indexAction()
{
$em = $this->getDoctrine()->getManager();
$entities = $em->getRepository('ChillMainBundle:Center')->findAll();
return $this->render('@ChillMain/Center/index.html.twig', array(
'entities' => $entities,
));
}
/**
* Creates a new Center entity.
*
*/
public function createAction(Request $request)
{
@@ -47,71 +35,19 @@ class CenterController extends AbstractController
$em->persist($center);
$em->flush();
return $this->redirect($this->generateUrl('admin_center_show', array('id' => $center->getId())));
return $this->redirect($this->generateUrl('admin_center_show', ['id' => $center->getId()]));
}
return $this->render('@ChillMain/Center/new.html.twig', array(
return $this->render('@ChillMain/Center/new.html.twig', [
'entity' => $center,
'form' => $form->createView(),
));
}
/**
* Creates a form to create a Center entity.
*
* @param Center $center The entity
*
* @return \Symfony\Component\Form\Form The form
*/
private function createCreateForm(Center $center)
{
$form = $this->createForm(CenterType::class, $center, array(
'action' => $this->generateUrl('admin_center_create'),
'method' => 'POST',
));
$form->add('submit', SubmitType::class, array('label' => 'Create'));
return $form;
}
/**
* Displays a form to create a new Center entity.
*
*/
public function newAction()
{
$center = new Center();
$form = $this->createCreateForm($center);
return $this->render('@ChillMain/Center/new.html.twig', array(
'entity' => $center,
'form' => $form->createView(),
));
}
/**
* Finds and displays a Center entity.
*
*/
public function showAction($id)
{
$em = $this->getDoctrine()->getManager();
$center = $em->getRepository('ChillMainBundle:Center')->find($id);
if (!$center) {
throw $this->createNotFoundException('Unable to find Center entity.');
}
return $this->render('@ChillMain/Center/show.html.twig', array(
'entity' => $center
));
'form' => $form->createView(),
]);
}
/**
* Displays a form to edit an existing Center entity.
*
* @param mixed $id
*/
public function editAction($id)
{
@@ -124,33 +60,65 @@ class CenterController extends AbstractController
}
$editForm = $this->createEditForm($center);
return $this->render('@ChillMain/Center/edit.html.twig', array(
'entity' => $center,
'edit_form' => $editForm->createView()
));
return $this->render('@ChillMain/Center/edit.html.twig', [
'entity' => $center,
'edit_form' => $editForm->createView(),
]);
}
/**
* Creates a form to edit a Center entity.
*
* @param Center $center The entity
*
* @return \Symfony\Component\Form\Form The form
*/
private function createEditForm(Center $center)
* Lists all Center entities.
*/
public function indexAction()
{
$form = $this->createForm(CenterType::class, $center, array(
'action' => $this->generateUrl('admin_center_update', array('id' => $center->getId())),
'method' => 'PUT',
));
$em = $this->getDoctrine()->getManager();
$form->add('submit', SubmitType::class, array('label' => 'Update'));
$entities = $em->getRepository('ChillMainBundle:Center')->findAll();
return $form;
return $this->render('@ChillMain/Center/index.html.twig', [
'entities' => $entities,
]);
}
/**
* Displays a form to create a new Center entity.
*/
public function newAction()
{
$center = new Center();
$form = $this->createCreateForm($center);
return $this->render('@ChillMain/Center/new.html.twig', [
'entity' => $center,
'form' => $form->createView(),
]);
}
/**
* Finds and displays a Center entity.
*
* @param mixed $id
*/
public function showAction($id)
{
$em = $this->getDoctrine()->getManager();
$center = $em->getRepository('ChillMainBundle:Center')->find($id);
if (!$center) {
throw $this->createNotFoundException('Unable to find Center entity.');
}
return $this->render('@ChillMain/Center/show.html.twig', [
'entity' => $center,
]);
}
/**
* Edits an existing Center entity.
*
* @param mixed $id
*/
public function updateAction(Request $request, $id)
{
@@ -168,12 +136,50 @@ class CenterController extends AbstractController
if ($editForm->isValid()) {
$em->flush();
return $this->redirect($this->generateUrl('admin_center_edit', array('id' => $id)));
return $this->redirect($this->generateUrl('admin_center_edit', ['id' => $id]));
}
return $this->render('@ChillMain/Center/edit.html.twig', array(
'entity' => $center,
'edit_form' => $editForm->createView()
));
return $this->render('@ChillMain/Center/edit.html.twig', [
'entity' => $center,
'edit_form' => $editForm->createView(),
]);
}
/**
* Creates a form to create a Center entity.
*
* @param Center $center The entity
*
* @return \Symfony\Component\Form\Form The form
*/
private function createCreateForm(Center $center)
{
$form = $this->createForm(CenterType::class, $center, [
'action' => $this->generateUrl('admin_center_create'),
'method' => 'POST',
]);
$form->add('submit', SubmitType::class, ['label' => 'Create']);
return $form;
}
/**
* Creates a form to edit a Center entity.
*
* @param Center $center The entity
*
* @return \Symfony\Component\Form\Form The form
*/
private function createEditForm(Center $center)
{
$form = $this->createForm(CenterType::class, $center, [
'action' => $this->generateUrl('admin_center_update', ['id' => $center->getId()]),
'method' => 'PUT',
]);
$form->add('submit', SubmitType::class, ['label' => 'Update']);
return $form;
}
}

View File

@@ -1,23 +1,27 @@
<?php
/**
* Chill is a software for social workers
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/
namespace Chill\MainBundle\Controller;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
/**
* Class DefaultController
*
* @package Chill\MainBundle\Controller
* Class DefaultController.
*/
class DefaultController extends AbstractController
{
public function indexAction()
{
{
if ($this->isGranted('ROLE_ADMIN')) {
return $this->redirectToRoute('chill_main_admin_central', [], 302);
}
return $this->render('@ChillMain/layout.html.twig');
}
@@ -25,62 +29,61 @@ class DefaultController extends AbstractController
{
return $this->redirect($this->generateUrl('chill_main_homepage'));
}
public function testAction()
{
return $this->render('@ChillMain/Tabs/index.html.twig', [
'tabs' => [
'test1' => [
[
'name' => "Link 1",
'content' => "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Vitae auctor eu augue ut. Elementum nisi quis eleifend quam. Faucibus purus in massa tempor nec. Turpis massa sed elementum tempus egestas sed sed risus. Etiam sit amet nisl purus in mollis nunc sed id. Enim nunc faucibus a pellentesque sit amet porttitor eget. Risus nec feugiat in fermentum posuere. Augue mauris augue neque gravida. Sollicitudin aliquam ultrices sagittis orci a scelerisque purus semper eget. Id leo in vitae turpis massa sed elementum tempus egestas. Mauris commodo quis imperdiet massa. Fames ac turpis egestas integer eget aliquet nibh praesent. Urna porttitor rhoncus dolor purus non enim praesent elementum. Donec enim diam vulputate ut pharetra sit. Auctor neque vitae tempus quam. Mattis rhoncus urna neque viverra justo nec ultrices.",
'name' => 'Link 1',
'content' => 'Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Vitae auctor eu augue ut. Elementum nisi quis eleifend quam. Faucibus purus in massa tempor nec. Turpis massa sed elementum tempus egestas sed sed risus. Etiam sit amet nisl purus in mollis nunc sed id. Enim nunc faucibus a pellentesque sit amet porttitor eget. Risus nec feugiat in fermentum posuere. Augue mauris augue neque gravida. Sollicitudin aliquam ultrices sagittis orci a scelerisque purus semper eget. Id leo in vitae turpis massa sed elementum tempus egestas. Mauris commodo quis imperdiet massa. Fames ac turpis egestas integer eget aliquet nibh praesent. Urna porttitor rhoncus dolor purus non enim praesent elementum. Donec enim diam vulputate ut pharetra sit. Auctor neque vitae tempus quam. Mattis rhoncus urna neque viverra justo nec ultrices.',
],
[
'name' => "Link 2",
'content' => "Dui sapien eget mi proin sed libero. Neque volutpat ac tincidunt vitae semper quis lectus nulla. Turpis nunc eget lorem dolor. Phasellus egestas tellus rutrum tellus. Diam sit amet nisl suscipit adipiscing bibendum est ultricies integer. Duis ultricies lacus sed turpis tincidunt id. Nisl suscipit adipiscing bibendum est ultricies integer. Elementum nibh tellus molestie nunc non blandit massa enim. Faucibus in ornare quam viverra orci sagittis eu. Neque volutpat ac tincidunt vitae semper quis lectus nulla. Accumsan sit amet nulla facilisi morbi. Leo vel fringilla est ullamcorper eget nulla facilisi etiam dignissim. Amet est placerat in egestas erat imperdiet sed euismod. Quis auctor elit sed vulputate mi. Mauris nunc congue nisi vitae suscipit tellus mauris a diam. At volutpat diam ut venenatis. Facilisis gravida neque convallis a cras semper.",
'name' => 'Link 2',
'content' => 'Dui sapien eget mi proin sed libero. Neque volutpat ac tincidunt vitae semper quis lectus nulla. Turpis nunc eget lorem dolor. Phasellus egestas tellus rutrum tellus. Diam sit amet nisl suscipit adipiscing bibendum est ultricies integer. Duis ultricies lacus sed turpis tincidunt id. Nisl suscipit adipiscing bibendum est ultricies integer. Elementum nibh tellus molestie nunc non blandit massa enim. Faucibus in ornare quam viverra orci sagittis eu. Neque volutpat ac tincidunt vitae semper quis lectus nulla. Accumsan sit amet nulla facilisi morbi. Leo vel fringilla est ullamcorper eget nulla facilisi etiam dignissim. Amet est placerat in egestas erat imperdiet sed euismod. Quis auctor elit sed vulputate mi. Mauris nunc congue nisi vitae suscipit tellus mauris a diam. At volutpat diam ut venenatis. Facilisis gravida neque convallis a cras semper.',
],
[
'name' => "Link 3",
'content' => "In ornare quam viverra orci sagittis eu volutpat. Ac tincidunt vitae semper quis lectus nulla at volutpat. Placerat duis ultricies lacus sed turpis tincidunt. Augue interdum velit euismod in pellentesque. Felis eget nunc lobortis mattis aliquam. Volutpat lacus laoreet non curabitur gravida arcu. Gravida cum sociis natoque penatibus et magnis dis parturient montes. Nisl pretium fusce id velit ut tortor. Nunc scelerisque viverra mauris in aliquam sem fringilla ut. Magna eget est lorem ipsum dolor sit. Non consectetur a erat nam at lectus urna. Eget est lorem ipsum dolor sit amet consectetur adipiscing elit. Sed velit dignissim sodales ut.",
'name' => 'Link 3',
'content' => 'In ornare quam viverra orci sagittis eu volutpat. Ac tincidunt vitae semper quis lectus nulla at volutpat. Placerat duis ultricies lacus sed turpis tincidunt. Augue interdum velit euismod in pellentesque. Felis eget nunc lobortis mattis aliquam. Volutpat lacus laoreet non curabitur gravida arcu. Gravida cum sociis natoque penatibus et magnis dis parturient montes. Nisl pretium fusce id velit ut tortor. Nunc scelerisque viverra mauris in aliquam sem fringilla ut. Magna eget est lorem ipsum dolor sit. Non consectetur a erat nam at lectus urna. Eget est lorem ipsum dolor sit amet consectetur adipiscing elit. Sed velit dignissim sodales ut.',
],
[
'name' => "Link 4",
'content' => "Ut tellus elementum sagittis vitae et. Vitae purus faucibus ornare suspendisse sed nisi lacus sed viverra. Hendrerit gravida rutrum quisque non tellus orci ac auctor augue. Eleifend quam adipiscing vitae proin sagittis nisl rhoncus mattis rhoncus. Dictumst quisque sagittis purus sit. Suspendisse sed nisi lacus sed viverra. Pretium quam vulputate dignissim suspendisse in est ante. Id eu nisl nunc mi ipsum. Ut venenatis tellus in metus vulputate. Ut morbi tincidunt augue interdum velit euismod.",
'name' => 'Link 4',
'content' => 'Ut tellus elementum sagittis vitae et. Vitae purus faucibus ornare suspendisse sed nisi lacus sed viverra. Hendrerit gravida rutrum quisque non tellus orci ac auctor augue. Eleifend quam adipiscing vitae proin sagittis nisl rhoncus mattis rhoncus. Dictumst quisque sagittis purus sit. Suspendisse sed nisi lacus sed viverra. Pretium quam vulputate dignissim suspendisse in est ante. Id eu nisl nunc mi ipsum. Ut venenatis tellus in metus vulputate. Ut morbi tincidunt augue interdum velit euismod.',
],
[
'name' => "Link 5",
'content' => "Vel elit scelerisque mauris pellentesque pulvinar. Ornare suspendisse sed nisi lacus sed viverra tellus. Massa tincidunt dui ut ornare lectus sit. Congue nisi vitae suscipit tellus mauris a diam. At auctor urna nunc id cursus metus aliquam. Viverra accumsan in nisl nisi scelerisque eu ultrices vitae. Mattis aliquam faucibus purus in massa tempor nec feugiat. Et leo duis ut diam quam. Auctor augue mauris augue neque. Purus ut faucibus pulvinar elementum integer enim neque volutpat. Scelerisque felis imperdiet proin fermentum leo. Diam sit amet nisl suscipit adipiscing bibendum est ultricies. Consectetur libero id faucibus nisl tincidunt. Vel fringilla est ullamcorper eget nulla facilisi. Pharetra diam sit amet nisl suscipit adipiscing. Dignissim diam quis enim lobortis. Auctor eu augue ut lectus arcu bibendum at varius.",
]
'name' => 'Link 5',
'content' => 'Vel elit scelerisque mauris pellentesque pulvinar. Ornare suspendisse sed nisi lacus sed viverra tellus. Massa tincidunt dui ut ornare lectus sit. Congue nisi vitae suscipit tellus mauris a diam. At auctor urna nunc id cursus metus aliquam. Viverra accumsan in nisl nisi scelerisque eu ultrices vitae. Mattis aliquam faucibus purus in massa tempor nec feugiat. Et leo duis ut diam quam. Auctor augue mauris augue neque. Purus ut faucibus pulvinar elementum integer enim neque volutpat. Scelerisque felis imperdiet proin fermentum leo. Diam sit amet nisl suscipit adipiscing bibendum est ultricies. Consectetur libero id faucibus nisl tincidunt. Vel fringilla est ullamcorper eget nulla facilisi. Pharetra diam sit amet nisl suscipit adipiscing. Dignissim diam quis enim lobortis. Auctor eu augue ut lectus arcu bibendum at varius.',
],
],
'test2' => [
[
'name' => "Link 1",
'link' => "http://localhost",
'content' => "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Vitae auctor eu augue ut. Elementum nisi quis eleifend quam. Faucibus purus in massa tempor nec. Turpis massa sed elementum tempus egestas sed sed risus. Etiam sit amet nisl purus in mollis nunc sed id. Enim nunc faucibus a pellentesque sit amet porttitor eget. Risus nec feugiat in fermentum posuere. Augue mauris augue neque gravida. Sollicitudin aliquam ultrices sagittis orci a scelerisque purus semper eget. Id leo in vitae turpis massa sed elementum tempus egestas. Mauris commodo quis imperdiet massa. Fames ac turpis egestas integer eget aliquet nibh praesent. Urna porttitor rhoncus dolor purus non enim praesent elementum. Donec enim diam vulputate ut pharetra sit. Auctor neque vitae tempus quam. Mattis rhoncus urna neque viverra justo nec ultrices.",
'name' => 'Link 1',
'link' => 'http://localhost',
'content' => 'Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Vitae auctor eu augue ut. Elementum nisi quis eleifend quam. Faucibus purus in massa tempor nec. Turpis massa sed elementum tempus egestas sed sed risus. Etiam sit amet nisl purus in mollis nunc sed id. Enim nunc faucibus a pellentesque sit amet porttitor eget. Risus nec feugiat in fermentum posuere. Augue mauris augue neque gravida. Sollicitudin aliquam ultrices sagittis orci a scelerisque purus semper eget. Id leo in vitae turpis massa sed elementum tempus egestas. Mauris commodo quis imperdiet massa. Fames ac turpis egestas integer eget aliquet nibh praesent. Urna porttitor rhoncus dolor purus non enim praesent elementum. Donec enim diam vulputate ut pharetra sit. Auctor neque vitae tempus quam. Mattis rhoncus urna neque viverra justo nec ultrices.',
],
[
'name' => "Link 2",
'name' => 'Link 2',
//'link' => "http://localhost",
'content' => "Dui sapien eget mi proin sed libero. Neque volutpat ac tincidunt vitae semper quis lectus nulla. Turpis nunc eget lorem dolor. Phasellus egestas tellus rutrum tellus. Diam sit amet nisl suscipit adipiscing bibendum est ultricies integer. Duis ultricies lacus sed turpis tincidunt id. Nisl suscipit adipiscing bibendum est ultricies integer. Elementum nibh tellus molestie nunc non blandit massa enim. Faucibus in ornare quam viverra orci sagittis eu. Neque volutpat ac tincidunt vitae semper quis lectus nulla. Accumsan sit amet nulla facilisi morbi. Leo vel fringilla est ullamcorper eget nulla facilisi etiam dignissim. Amet est placerat in egestas erat imperdiet sed euismod. Quis auctor elit sed vulputate mi. Mauris nunc congue nisi vitae suscipit tellus mauris a diam. At volutpat diam ut venenatis. Facilisis gravida neque convallis a cras semper.",
'content' => 'Dui sapien eget mi proin sed libero. Neque volutpat ac tincidunt vitae semper quis lectus nulla. Turpis nunc eget lorem dolor. Phasellus egestas tellus rutrum tellus. Diam sit amet nisl suscipit adipiscing bibendum est ultricies integer. Duis ultricies lacus sed turpis tincidunt id. Nisl suscipit adipiscing bibendum est ultricies integer. Elementum nibh tellus molestie nunc non blandit massa enim. Faucibus in ornare quam viverra orci sagittis eu. Neque volutpat ac tincidunt vitae semper quis lectus nulla. Accumsan sit amet nulla facilisi morbi. Leo vel fringilla est ullamcorper eget nulla facilisi etiam dignissim. Amet est placerat in egestas erat imperdiet sed euismod. Quis auctor elit sed vulputate mi. Mauris nunc congue nisi vitae suscipit tellus mauris a diam. At volutpat diam ut venenatis. Facilisis gravida neque convallis a cras semper.',
],
[
'name' => "Link 3",
'name' => 'Link 3',
//'link' => "http://localhost",
'content' => "In ornare quam viverra orci sagittis eu volutpat. Ac tincidunt vitae semper quis lectus nulla at volutpat. Placerat duis ultricies lacus sed turpis tincidunt. Augue interdum velit euismod in pellentesque. Felis eget nunc lobortis mattis aliquam. Volutpat lacus laoreet non curabitur gravida arcu. Gravida cum sociis natoque penatibus et magnis dis parturient montes. Nisl pretium fusce id velit ut tortor. Nunc scelerisque viverra mauris in aliquam sem fringilla ut. Magna eget est lorem ipsum dolor sit. Non consectetur a erat nam at lectus urna. Eget est lorem ipsum dolor sit amet consectetur adipiscing elit. Sed velit dignissim sodales ut.",
'content' => 'In ornare quam viverra orci sagittis eu volutpat. Ac tincidunt vitae semper quis lectus nulla at volutpat. Placerat duis ultricies lacus sed turpis tincidunt. Augue interdum velit euismod in pellentesque. Felis eget nunc lobortis mattis aliquam. Volutpat lacus laoreet non curabitur gravida arcu. Gravida cum sociis natoque penatibus et magnis dis parturient montes. Nisl pretium fusce id velit ut tortor. Nunc scelerisque viverra mauris in aliquam sem fringilla ut. Magna eget est lorem ipsum dolor sit. Non consectetur a erat nam at lectus urna. Eget est lorem ipsum dolor sit amet consectetur adipiscing elit. Sed velit dignissim sodales ut.',
],
[
'name' => "Link 4",
'link' => "http://localhost",
'name' => 'Link 4',
'link' => 'http://localhost',
//'content' => "Ut tellus elementum sagittis vitae et. Vitae purus faucibus ornare suspendisse sed nisi lacus sed viverra. Hendrerit gravida rutrum quisque non tellus orci ac auctor augue. Eleifend quam adipiscing vitae proin sagittis nisl rhoncus mattis rhoncus. Dictumst quisque sagittis purus sit. Suspendisse sed nisi lacus sed viverra. Pretium quam vulputate dignissim suspendisse in est ante. Id eu nisl nunc mi ipsum. Ut venenatis tellus in metus vulputate. Ut morbi tincidunt augue interdum velit euismod.",
],
[
'name' => "Link 5",
'name' => 'Link 5',
//'link' => "http://localhost",
'content' => "Vel elit scelerisque mauris pellentesque pulvinar. Ornare suspendisse sed nisi lacus sed viverra tellus. Massa tincidunt dui ut ornare lectus sit. Congue nisi vitae suscipit tellus mauris a diam. At auctor urna nunc id cursus metus aliquam. Viverra accumsan in nisl nisi scelerisque eu ultrices vitae. Mattis aliquam faucibus purus in massa tempor nec feugiat. Et leo duis ut diam quam. Auctor augue mauris augue neque. Purus ut faucibus pulvinar elementum integer enim neque volutpat. Scelerisque felis imperdiet proin fermentum leo. Diam sit amet nisl suscipit adipiscing bibendum est ultricies. Consectetur libero id faucibus nisl tincidunt. Vel fringilla est ullamcorper eget nulla facilisi. Pharetra diam sit amet nisl suscipit adipiscing. Dignissim diam quis enim lobortis. Auctor eu augue ut lectus arcu bibendum at varius.",
]
]
]
'content' => 'Vel elit scelerisque mauris pellentesque pulvinar. Ornare suspendisse sed nisi lacus sed viverra tellus. Massa tincidunt dui ut ornare lectus sit. Congue nisi vitae suscipit tellus mauris a diam. At auctor urna nunc id cursus metus aliquam. Viverra accumsan in nisl nisi scelerisque eu ultrices vitae. Mattis aliquam faucibus purus in massa tempor nec feugiat. Et leo duis ut diam quam. Auctor augue mauris augue neque. Purus ut faucibus pulvinar elementum integer enim neque volutpat. Scelerisque felis imperdiet proin fermentum leo. Diam sit amet nisl suscipit adipiscing bibendum est ultricies. Consectetur libero id faucibus nisl tincidunt. Vel fringilla est ullamcorper eget nulla facilisi. Pharetra diam sit amet nisl suscipit adipiscing. Dignissim diam quis enim lobortis. Auctor eu augue ut lectus arcu bibendum at varius.',
],
],
],
]);
}
}

View File

@@ -1,86 +1,67 @@
<?php
/*
/**
* Chill is a software for social workers
*
* Copyright (C) 2014-2015, Champs Libres Cooperative SCRLFS,
* <http://www.champs-libres.coop>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/
namespace Chill\MainBundle\Controller;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\Request;
use Chill\MainBundle\Export\ExportManager;
use Chill\MainBundle\Form\Type\Export\ExportType;
use Chill\MainBundle\Form\Type\Export\FormatterType;
use Symfony\Component\Form\Extension\Core\Type\FormType;
use Chill\MainBundle\Form\Type\Export\PickCenterType;
use Symfony\Component\Form\Extension\Core\Type\SubmitType;
use Chill\MainBundle\Export\ExportManager;
use Psr\Log\LoggerInterface;
use Symfony\Component\HttpFoundation\Session\SessionInterface;
use Symfony\Component\Form\FormFactoryInterface;
use Chill\MainBundle\Redis\ChillRedis;
use LogicException;
use Psr\Log\LoggerInterface;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\Form\Extension\Core\Type\FormType;
use Symfony\Component\Form\Extension\Core\Type\SubmitType;
use Symfony\Component\Form\FormFactoryInterface;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Session\SessionInterface;
use Symfony\Component\Translation\TranslatorInterface;
use function serialize;
use function unserialize;
/**
* Class ExportController
* Controller used for exporting data.
*
* @package Chill\MainBundle\Controller
*/
class ExportController extends AbstractController
{
/**
*
* @var ExportManager
*/
protected $exportManager;
/**
*
* @var LoggerInterface
*/
protected $logger;
/**
*
* @var SessionInterface
*/
protected $session;
/**
*
* @var FormFactoryInterface
*/
protected $formFactory;
/**
* @var LoggerInterface
*/
protected $logger;
/**
*
* @var ChillRedis
*/
protected $redis;
/**
* @var SessionInterface
*/
protected $session;
/**
*
* @var TranslatorInterface
*/
protected $translator;
public function __construct(
ChillRedis $chillRedis,
ExportManager $exportManager,
@@ -97,11 +78,63 @@ class ExportController extends AbstractController
$this->translator = $translator;
}
public function downloadResultAction(Request $request, $alias)
{
/* @var $exportManager \Chill\MainBundle\Export\ExportManager */
$exportManager = $this->exportManager;
$key = $request->query->get('key', null);
[$dataCenters, $dataExport, $dataFormatter] = $this->rebuildData($key);
$formatterAlias = $exportManager->getFormatterAlias($dataExport['export']);
if (null !== $formatterAlias) {
$formater = $exportManager->getFormatter($formatterAlias);
} else {
$formater = null;
}
$viewVariables = [
'alias' => $alias,
'export' => $exportManager->getExport($alias),
];
if ($formater instanceof \Chill\MainBundle\Export\Formatter\CSVListFormatter) {
// due to a bug in php, we add the mime type in the download view
$viewVariables['mime_type'] = 'text/csv';
}
return $this->render('@ChillMain/Export/download.html.twig', $viewVariables);
}
/**
* Render the list of available exports
* Generate a report.
*
* This action must work with GET queries.
*
* @param string $alias
*
* @return \Symfony\Component\HttpFoundation\Response
*/
public function generateAction(Request $request, $alias)
{
/* @var $exportManager \Chill\MainBundle\Export\ExportManager */
$exportManager = $this->exportManager;
$key = $request->query->get('key', null);
[$dataCenters, $dataExport, $dataFormatter] = $this->rebuildData($key);
return $exportManager->generate(
$alias,
$dataCenters['centers'],
$dataExport['export'],
null !== $dataFormatter ? $dataFormatter['formatter'] : []
);
}
/**
* Render the list of available exports.
*
* @param Request $request
* @return \Symfony\Component\HttpFoundation\Response
*/
public function indexAction(Request $request)
@@ -109,14 +142,14 @@ class ExportController extends AbstractController
$exportManager = $this->exportManager;
$exports = $exportManager->getExportsGrouped(true);
return $this->render('@ChillMain/Export/layout.html.twig', array(
'grouped_exports' => $exports
));
return $this->render('@ChillMain/Export/layout.html.twig', [
'grouped_exports' => $exports,
]);
}
/**
* handle the step to build a query for an export
* handle the step to build a query for an export.
*
* This action has three steps :
*
@@ -129,6 +162,7 @@ class ExportController extends AbstractController
*
* @param string $request
* @param Request $alias
*
* @return \Symfony\Component\HttpFoundation\Response
*/
public function newAction(Request $request, $alias)
@@ -137,7 +171,7 @@ class ExportController extends AbstractController
$exportManager = $this->exportManager;
$export = $exportManager->getExport($alias);
if ($exportManager->isGrantedForElement($export) === FALSE) {
if ($exportManager->isGrantedForElement($export) === false) {
throw $this->createAccessDeniedException('The user does not have access to this export');
}
@@ -146,77 +180,86 @@ class ExportController extends AbstractController
switch ($step) {
case 'centers':
return $this->selectCentersStep($request, $export, $alias);
case 'export':
return $this->exportFormStep($request, $export, $alias);
break;
case 'formatter':
return $this->formatterFormStep($request, $export, $alias);
break;
case 'generate':
return $this->forwardToGenerate($request, $export, $alias);
break;
default:
throw $this->createNotFoundException("The given step '$step' is invalid");
throw $this->createNotFoundException("The given step '{$step}' is invalid");
}
}
/**
*
* @param Request $request
* @param \Chill\MainBundle\Export\ExportInterface|\Chill\MainBundle\Export\DirectExportInterface $export
* create a form to show on different steps.
*
* @param string $alias
* @return Response
* @throws type
* @param array $data the data from previous step. Required for steps 'formatter' and 'generate_formatter'
*
* @return \Symfony\Component\Form\Form
*/
protected function selectCentersStep(Request $request, $export, $alias)
protected function createCreateFormExport($alias, $step, $data = [])
{
/* @var $exportManager \Chill\MainBundle\Export\ExportManager */
$exportManager = $this->exportManager;
$isGenerate = strpos($step, 'generate_') === 0;
$form = $this->createCreateFormExport($alias, 'centers');
$builder = $this->formFactory
->createNamedBuilder(null, FormType::class, [], [
'method' => $isGenerate ? 'GET' : 'POST',
'csrf_protection' => $isGenerate ? false : true,
]);
if ($request->getMethod() === 'POST') {
$form->handleRequest($request);
if ($form->isValid()) {
$this->logger->debug('form centers is valid', array(
'location' => __METHOD__));
$data = $form->getData();
// check ACL
if ($exportManager->isGrantedForElement($export, NULL,
$exportManager->getPickedCenters($data['centers'])) === FALSE) {
throw $this->createAccessDeniedException('you do not have '
. 'access to this export for those centers');
}
$this->session->set('centers_step_raw',
$request->request->all());
$this->session->set('centers_step', $data);
return $this->redirectToRoute('chill_main_export_new', array(
'step' => $this->getNextStep('centers', $export),
'alias' => $alias
));
}
if ('centers' === $step or 'generate_centers' === $step) {
$builder->add('centers', PickCenterType::class, [
'export_alias' => $alias,
]);
}
return $this->render('@ChillMain/Export/new_centers_step.html.twig',
array(
'form' => $form->createView(),
'export' => $export
));
if ('export' === $step or 'generate_export' === $step) {
$builder->add('export', ExportType::class, [
'export_alias' => $alias,
'picked_centers' => $exportManager->getPickedCenters($data['centers']),
]);
}
if ('formatter' === $step or 'generate_formatter' === $step) {
$builder->add('formatter', FormatterType::class, [
'formatter_alias' => $exportManager
->getFormatterAlias($data['export']),
'export_alias' => $alias,
'aggregator_aliases' => $exportManager
->getUsedAggregatorsAliases($data['export']),
]);
}
$builder->add('submit', SubmitType::class, [
'label' => 'Generate',
]);
return $builder->getForm();
}
/**
* Render the export form
* Render the export form.
*
* When the method is POST, the form is stored if valid, and a redirection
* is done to next step.
*
* @param string $alias
* @param \Chill\MainBundle\Export\ExportInterface|\Chill\MainBundle\Export\DirectExportInterface $export
* @param \Chill\MainBundle\Export\DirectExportInterface|\Chill\MainBundle\Export\ExportInterface $export
*
* @return \Symfony\Component\HttpFoundation\Response
*/
protected function exportFormStep(Request $request, $export, $alias)
@@ -226,12 +269,11 @@ class ExportController extends AbstractController
// check we have data from the previous step (export step)
$data = $this->session->get('centers_step', null);
if ($data === null) {
return $this->redirectToRoute('chill_main_export_new', array(
'step' => $this->getNextStep('export', $export, true),
'alias' => $alias
));
if (null === $data) {
return $this->redirectToRoute('chill_main_export_new', [
'step' => $this->getNextStep('export', $export, true),
'alias' => $alias,
]);
}
$export = $exportManager->getExport($alias);
@@ -240,123 +282,36 @@ class ExportController extends AbstractController
if ($request->getMethod() === 'POST') {
$form->handleRequest($request);
if ($form->isValid()) {
$this->logger->debug('form export is valid', array(
'location' => __METHOD__));
if ($form->isValid()) {
$this->logger->debug('form export is valid', [
'location' => __METHOD__, ]);
// store data for reusing in next steps
$data = $form->getData();
$this->session->set('export_step_raw',
$request->request->all());
$this->session->set(
'export_step_raw',
$request->request->all()
);
$this->session->set('export_step', $data);
//redirect to next step
return $this->redirect(
$this->generateUrl('chill_main_export_new', array(
'step' => $this->getNextStep('export', $export),
'alias' => $alias
)));
} else {
$this->logger->debug('form export is invalid', array(
'location' => __METHOD__));
$this->generateUrl('chill_main_export_new', [
'step' => $this->getNextStep('export', $export),
'alias' => $alias,
])
);
}
$this->logger->debug('form export is invalid', [
'location' => __METHOD__, ]);
}
return $this->render('@ChillMain/Export/new.html.twig', array(
return $this->render('@ChillMain/Export/new.html.twig', [
'form' => $form->createView(),
'export_alias' => $alias,
'export' => $export
));
}
/**
* create a form to show on different steps.
*
* @param string $alias
* @param string $step, can either be 'export', 'formatter', 'generate_export' or 'generate_formatter' (last two are used by generate action)
* @param array $data the data from previous step. Required for steps 'formatter' and 'generate_formatter'
* @return \Symfony\Component\Form\Form
*/
protected function createCreateFormExport($alias, $step, $data = array())
{
/* @var $exportManager \Chill\MainBundle\Export\ExportManager */
$exportManager = $this->exportManager;
$isGenerate = strpos($step, 'generate_') === 0;
$builder = $this->formFactory
->createNamedBuilder(null, FormType::class, array(), array(
'method' => $isGenerate ? 'GET' : 'POST',
'csrf_protection' => $isGenerate ? false : true,
));
if ($step === 'centers' or $step === 'generate_centers') {
$builder->add('centers', PickCenterType::class, array(
'export_alias' => $alias
));
}
if ($step === 'export' or $step === 'generate_export') {
$builder->add('export', ExportType::class, array(
'export_alias' => $alias,
'picked_centers' => $exportManager->getPickedCenters($data['centers'])
));
}
if ($step === 'formatter' or $step === 'generate_formatter') {
$builder->add('formatter', FormatterType::class, array(
'formatter_alias' => $exportManager
->getFormatterAlias($data['export']),
'export_alias' => $alias,
'aggregator_aliases' => $exportManager
->getUsedAggregatorsAliases($data['export'])
));
}
$builder->add('submit', SubmitType::class, array(
'label' => 'Generate'
));
return $builder->getForm();
}
/**
* get the next step. If $reverse === true, the previous step is returned.
*
* This method provides a centralized way of handling next/previous step.
*
* @param string $step the current step
* @param \Chill\MainBundle\Export\ExportInterface|\Chill\MainBundle\Export\DirectExportInterface $export
* @param boolean $reverse set to true to get the previous step
* @return string the next/current step
* @throws \LogicException if there is no step before or after the given step
*/
private function getNextStep($step, $export, $reverse = false)
{
switch($step) {
case 'centers':
if ($reverse !== false) {
throw new \LogicException("there is no step before 'export'");
}
return 'export';
case 'export':
if ($export instanceof \Chill\MainBundle\Export\ExportInterface) {
return $reverse ? 'centers' : 'formatter';
} elseif ($export instanceof \Chill\MainBundle\Export\DirectExportInterface) {
return $reverse ? 'centers' : 'generate';
}
case 'formatter' :
return $reverse ? 'export' : 'generate';
case 'generate' :
if ($reverse === false) {
throw new \LogicException("there is no step after 'generate'");
}
return 'formatter';
default:
throw new \LogicException("the step $step is not defined.");
}
'export' => $export,
]);
}
/**
@@ -365,23 +320,21 @@ class ExportController extends AbstractController
* If the form is posted and valid, store the data in session and
* redirect to the next step.
*
* @param Request $request
* @param \Chill\MainBundle\Export\ExportInterface|\Chill\MainBundle\Export\DirectExportInterface $export
* @param \Chill\MainBundle\Export\DirectExportInterface|\Chill\MainBundle\Export\ExportInterface $export
* @param string $alias
*
* @return \Symfony\Component\HttpFoundation\Response
*/
protected function formatterFormStep(Request $request, $export, $alias)
{
// check we have data from the previous step (export step)
$data = $this->session->get('export_step', null);
if ($data === null) {
return $this->redirectToRoute('chill_main_export_new', array(
'step' => $this->getNextStep('formatter', $export, true),
'alias' => $alias
));
if (null === $data) {
return $this->redirectToRoute('chill_main_export_new', [
'step' => $this->getNextStep('formatter', $export, true),
'alias' => $alias,
]);
}
$form = $this->createCreateFormExport($alias, 'formatter', $data);
@@ -392,23 +345,29 @@ class ExportController extends AbstractController
if ($form->isValid()) {
$dataFormatter = $form->getData();
$this->session->set('formatter_step', $dataFormatter);
$this->session->set('formatter_step_raw',
$request->request->all());
$this->session->set(
'formatter_step_raw',
$request->request->all()
);
//redirect to next step
return $this->redirect($this->generateUrl('chill_main_export_new',
array(
'alias' => $alias,
'step' => $this->getNextStep('formatter', $export)
)));
return $this->redirect($this->generateUrl(
'chill_main_export_new',
[
'alias' => $alias,
'step' => $this->getNextStep('formatter', $export),
]
));
}
}
return $this->render('@ChillMain/Export/new_formatter_step.html.twig',
array(
'form' => $form->createView(),
'export' => $export
));
return $this->render(
'@ChillMain/Export/new_formatter_step.html.twig',
[
'form' => $form->createView(),
'export' => $export,
]
);
}
/**
@@ -417,9 +376,9 @@ class ExportController extends AbstractController
*
* The data from previous steps is removed from session.
*
* @param Request $request
* @param \Chill\MainBundle\Export\ExportInterface|\Chill\MainBundle\Export\DirectExportInterface $export
* @param \Chill\MainBundle\Export\DirectExportInterface|\Chill\MainBundle\Export\ExportInterface $export
* @param string $alias
*
* @return \Symfony\Component\HttpFoundation\RedirectResponse
*/
protected function forwardToGenerate(Request $request, $export, $alias)
@@ -428,22 +387,22 @@ class ExportController extends AbstractController
$dataFormatter = $this->session->get('formatter_step_raw', null);
$dataExport = $this->session->get('export_step_raw', null);
if ($dataFormatter === NULL and $export instanceof \Chill\MainBundle\Export\ExportInterface) {
return $this->redirectToRoute('chill_main_export_new', array(
'alias' => $alias, 'step' => $this->getNextStep('generate', $export, true)
));
if (null === $dataFormatter and $export instanceof \Chill\MainBundle\Export\ExportInterface) {
return $this->redirectToRoute('chill_main_export_new', [
'alias' => $alias, 'step' => $this->getNextStep('generate', $export, true),
]);
}
$parameters = [
'formatter' => $dataFormatter ?? [],
'export' => $dataExport ?? [],
'centers' => $dataCenters ?? [],
'alias' => $alias
];
'formatter' => $dataFormatter ?? [],
'export' => $dataExport ?? [],
'centers' => $dataCenters ?? [],
'alias' => $alias,
];
unset($parameters['_token']);
$key = md5(uniqid(rand(), false));
$this->redis->setEx($key, 3600, \serialize($parameters));
$this->redis->setEx($key, 3600, serialize($parameters));
// remove data from session
$this->session->remove('export_step_raw');
@@ -451,56 +410,30 @@ class ExportController extends AbstractController
$this->session->remove('formatter_step_raw');
$this->session->remove('formatter_step');
return $this->redirectToRoute('chill_main_export_download', [ 'key' => $key, 'alias' => $alias ]);
return $this->redirectToRoute('chill_main_export_download', ['key' => $key, 'alias' => $alias]);
}
/**
* Generate a report.
*
* This action must work with GET queries.
*
* @param Request $request
* @param string $alias
* @return \Symfony\Component\HttpFoundation\Response
*/
public function generateAction(Request $request, $alias)
{
/* @var $exportManager \Chill\MainBundle\Export\ExportManager */
$exportManager = $this->exportManager;
$key = $request->query->get('key', null);
list($dataCenters, $dataExport, $dataFormatter) = $this->rebuildData($key);
$r = $exportManager->generate(
$alias,
$dataCenters['centers'],
$dataExport['export'],
$dataFormatter !== NULL ? $dataFormatter['formatter'] : []
);
return $r;
}
protected function rebuildData($key)
{
if ($key === NULL) {
throw $this->createNotFoundException("key does not exists");
if (null === $key) {
throw $this->createNotFoundException('key does not exists');
}
if ($this->redis->exists($key) !== 1) {
$this->addFlash('error', $this->translator->trans("This report is not available any more"));
throw $this->createNotFoundException("key does not exists");
$this->addFlash('error', $this->translator->trans('This report is not available any more'));
throw $this->createNotFoundException('key does not exists');
}
$serialized = $this->redis->get($key);
if ($serialized === false) {
throw new \LogicException("the key could not be reached from redis");
if (false === $serialized) {
throw new LogicException('the key could not be reached from redis');
}
$rawData = \unserialize($serialized);
$rawData = unserialize($serialized);
$alias = $rawData['alias'];
$formCenters = $this->createCreateFormExport($alias, 'generate_centers');
$formCenters->submit($rawData['centers']);
$dataCenters = $formCenters->getData();
@@ -510,40 +443,119 @@ class ExportController extends AbstractController
$dataExport = $formExport->getData();
if (count($rawData['formatter']) > 0) {
$formFormatter = $this->createCreateFormExport($alias, 'generate_formatter',
$dataExport);
$formFormatter = $this->createCreateFormExport(
$alias,
'generate_formatter',
$dataExport
);
$formFormatter->submit($rawData['formatter']);
$dataFormatter = $formFormatter->getData();
}
return [$dataCenters, $dataExport, $dataFormatter ?? null];
}
public function downloadResultAction(Request $request, $alias)
{
/**
* @param \Chill\MainBundle\Export\DirectExportInterface|\Chill\MainBundle\Export\ExportInterface $export
* @param string $alias
*
* @throws type
*
* @return Response
*/
protected function selectCentersStep(Request $request, $export, $alias)
{
/* @var $exportManager \Chill\MainBundle\Export\ExportManager */
$exportManager = $this->exportManager;
$key = $request->query->get('key', null);
list($dataCenters, $dataExport, $dataFormatter) = $this->rebuildData($key);
$formatterAlias = $exportManager->getFormatterAlias($dataExport['export']);
if ($formatterAlias !== null) {
$formater = $exportManager->getFormatter($formatterAlias);
} else {
$formater = null;
$form = $this->createCreateFormExport($alias, 'centers');
if ($request->getMethod() === 'POST') {
$form->handleRequest($request);
if ($form->isValid()) {
$this->logger->debug('form centers is valid', [
'location' => __METHOD__, ]);
$data = $form->getData();
// check ACL
if ($exportManager->isGrantedForElement(
$export,
null,
$exportManager->getPickedCenters($data['centers'])
) === false) {
throw $this->createAccessDeniedException('you do not have '
. 'access to this export for those centers');
}
$this->session->set(
'centers_step_raw',
$request->request->all()
);
$this->session->set('centers_step', $data);
return $this->redirectToRoute('chill_main_export_new', [
'step' => $this->getNextStep('centers', $export),
'alias' => $alias,
]);
}
}
$viewVariables = [
'alias' => $alias,
'export' => $exportManager->getExport($alias)
];
if ($formater instanceof \Chill\MainBundle\Export\Formatter\CSVListFormatter) {
// due to a bug in php, we add the mime type in the download view
$viewVariables['mime_type'] = 'text/csv';
return $this->render(
'@ChillMain/Export/new_centers_step.html.twig',
[
'form' => $form->createView(),
'export' => $export,
]
);
}
/**
* get the next step. If $reverse === true, the previous step is returned.
*
* This method provides a centralized way of handling next/previous step.
*
* @param string $step the current step
* @param \Chill\MainBundle\Export\DirectExportInterface|\Chill\MainBundle\Export\ExportInterface $export
* @param bool $reverse set to true to get the previous step
*
* @throws LogicException if there is no step before or after the given step
*
* @return string the next/current step
*/
private function getNextStep($step, $export, $reverse = false)
{
switch ($step) {
case 'centers':
if (false !== $reverse) {
throw new LogicException("there is no step before 'export'");
}
return 'export';
case 'export':
if ($export instanceof \Chill\MainBundle\Export\ExportInterface) {
return $reverse ? 'centers' : 'formatter';
}
if ($export instanceof \Chill\MainBundle\Export\DirectExportInterface) {
return $reverse ? 'centers' : 'generate';
}
// no break
case 'formatter':
return $reverse ? 'export' : 'generate';
case 'generate':
if (false === $reverse) {
throw new LogicException("there is no step after 'generate'");
}
return 'formatter';
default:
throw new LogicException("the step {$step} is not defined.");
}
return $this->render("@ChillMain/Export/download.html.twig", $viewVariables);
}
}

View File

@@ -1,15 +1,21 @@
<?php
/**
* Chill is a software for social workers
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/
namespace Chill\MainBundle\Controller;
use Chill\MainBundle\CRUD\Controller\ApiController;
use DateInterval;
use DateTime;
use Symfony\Component\HttpFoundation\Request;
/**
* Class LocationApiController
*
* @package Chill\MainBundle\Controller
* @author Champs Libres
* Class LocationApiController.
*/
class LocationApiController extends ApiController
{
@@ -27,10 +33,10 @@ class LocationApiController extends ApiController
$query->expr()->neq('e.name', ':emptyString'),
)
))
->setParameters([
'user' => $this->getUser(),
'dateBefore' => (new \DateTime())->sub(new \DateInterval('P6M')),
'emptyString' => '',
]);
->setParameters([
'user' => $this->getUser(),
'dateBefore' => (new DateTime())->sub(new DateInterval('P6M')),
'emptyString' => '',
]);
}
}
}

View File

@@ -1,5 +1,12 @@
<?php
/**
* Chill is a software for social workers
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/
namespace Chill\MainBundle\Controller;
use Chill\MainBundle\CRUD\Controller\CRUDController;
@@ -7,11 +14,6 @@ use Symfony\Component\HttpFoundation\Request;
class LocationController extends CRUDController
{
protected function customizeQuery(string $action, Request $request, $query): void
{
$query->where('e.availableForUsers = true'); //TODO not working
}
protected function createEntity(string $action, Request $request): object
{
$entity = parent::createEntity($action, $request);
@@ -20,4 +22,9 @@ class LocationController extends CRUDController
return $entity;
}
protected function customizeQuery(string $action, Request $request, $query): void
{
$query->where('e.availableForUsers = true'); //TODO not working
}
}

View File

@@ -1,15 +1,19 @@
<?php
/**
* Chill is a software for social workers
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/
namespace Chill\MainBundle\Controller;
use Chill\MainBundle\CRUD\Controller\ApiController;
use Symfony\Component\HttpFoundation\Request;
/**
* Class LocationTypeApiController
*
* @package Chill\MainBundle\Controller
* @author Champs Libres
* Class LocationTypeApiController.
*/
class LocationTypeApiController extends ApiController
{
@@ -22,4 +26,4 @@ class LocationTypeApiController extends ApiController
)
);
}
}
}

View File

@@ -1,10 +1,16 @@
<?php
/**
* Chill is a software for social workers
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/
namespace Chill\MainBundle\Controller;
use Chill\MainBundle\CRUD\Controller\CRUDController;
class LocationTypeController extends CRUDController
{
}
}

View File

@@ -1,5 +1,12 @@
<?php
/**
* Chill is a software for social workers
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/
namespace Chill\MainBundle\Controller;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
@@ -8,41 +15,34 @@ use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Security\Http\Authentication\AuthenticationUtils;
/**
* Class LoginController
*
* @package Chill\MainBundle\Controller
* Class LoginController.
*/
class LoginController extends AbstractController
{
/**
*
* @var AuthenticationUtils
*/
protected $helper;
public function __construct(AuthenticationUtils $helper)
{
$this->helper = $helper;
}
/**
* Show a login form
*
* @param Request $request
* Show a login form.
*
* @return Response
*/
public function loginAction(Request $request)
{
return $this->render('@ChillMain/Login/login.html.twig', array(
return $this->render('@ChillMain/Login/login.html.twig', [
'last_username' => $this->helper->getLastUsername(),
'error' => $this->helper->getLastAuthenticationError()
));
'error' => $this->helper->getLastAuthenticationError(),
]);
}
public function LoginCheckAction(Request $request)
{
}
}

View File

@@ -1,23 +1,28 @@
<?php
/**
* Chill is a software for social workers
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/
namespace Chill\MainBundle\Controller;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
/**
* Class MenuController
*
* @package Chill\MainBundle\Controller
* Class MenuController.
*/
class MenuController extends AbstractController
{
public function writeMenuAction($menu, $layout, $activeRouteKey = null, array $args = array() )
public function writeMenuAction($menu, $layout, $activeRouteKey = null, array $args = [])
{
return $this->render($layout, array(
return $this->render($layout, [
'menu_composer' => $this->get('chill.main.menu_composer'),
'menu' => $menu,
'args' => $args,
'activeRouteKey' => $activeRouteKey
));
'activeRouteKey' => $activeRouteKey,
]);
}
}

View File

@@ -1,14 +1,20 @@
<?php
/**
* Chill is a software for social workers
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/
namespace Chill\MainBundle\Controller;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Chill\MainBundle\Repository\NotificationRepository;
use Chill\MainBundle\Notification\NotificationRenderer;
use Symfony\Component\Security\Core\Security;
use Symfony\Component\Routing\Annotation\Route;
use Chill\MainBundle\Pagination\PaginatorFactory;
use Chill\MainBundle\Repository\NotificationRepository;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\Routing\Annotation\Route;
use Symfony\Component\Security\Core\Security;
/**
* @Route("/{_locale}/notification")
@@ -22,13 +28,14 @@ class NotificationController extends AbstractController
$this->security = $security;
}
/**
* @Route("/show", name="chill_main_notification_show")
*/
public function showAction(
NotificationRepository $notificationRepository, NotificationRenderer $notificationRenderer,
PaginatorFactory $paginatorFactory)
NotificationRepository $notificationRepository,
NotificationRenderer $notificationRenderer,
PaginatorFactory $paginatorFactory
)
{
$currentUser = $this->security->getUser();
@@ -37,15 +44,17 @@ class NotificationController extends AbstractController
$notifications = $notificationRepository->findAllForAttendee(
$currentUser,
$limit=$paginator->getItemsPerPage(),
$offset= $paginator->getCurrentPage()->getFirstItemNumber());
$limit = $paginator->getItemsPerPage(),
$offset = $paginator->getCurrentPage()->getFirstItemNumber()
);
$templateData = [];
$templateData = array();
foreach ($notifications as $notification) {
$data = [
'template' => $notificationRenderer->getTemplate($notification),
'template_data' => $notificationRenderer->getTemplateData($notification),
'notification' => $notification
'notification' => $notification,
];
$templateData[] = $data;
}

View File

@@ -1,72 +1,71 @@
<?php
/**
* Chill is a software for social workers
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/
namespace Chill\MainBundle\Controller;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\Form\Extension\Core\Type\SubmitType;
use Chill\MainBundle\Form\UserPasswordType;
use Chill\MainBundle\Entity\User;
use Symfony\Component\Security\Core\Encoder\UserPasswordEncoderInterface;
use Symfony\Component\Translation\TranslatorInterface;
use Psr\Log\LoggerInterface;
use Symfony\Component\Form\Extension\Core\Type\TextType;
use Symfony\Component\Validator\Constraints\Callback;
use Symfony\Component\Validator\Context\ExecutionContextInterface;
use Chill\MainBundle\Security\PasswordRecover\RecoverPasswordHelper;
use Symfony\Component\HttpFoundation\Response;
use Chill\MainBundle\Security\PasswordRecover\TokenManager;
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
use Chill\MainBundle\Form\UserPasswordType;
use Chill\MainBundle\Security\PasswordRecover\PasswordRecoverEvent;
use Chill\MainBundle\Security\PasswordRecover\PasswordRecoverVoter;
use Chill\MainBundle\Security\PasswordRecover\RecoverPasswordHelper;
use Chill\MainBundle\Security\PasswordRecover\TokenManager;
use DateInterval;
use DateTimeImmutable;
use Psr\Log\LoggerInterface;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
use Symfony\Component\Form\Extension\Core\Type\SubmitType;
use Symfony\Component\Form\Extension\Core\Type\TextType;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Security\Core\Encoder\UserPasswordEncoderInterface;
use Symfony\Component\Translation\TranslatorInterface;
use Symfony\Component\Validator\Constraints\Callback;
use Symfony\Component\Validator\Context\ExecutionContextInterface;
/**
* Class PasswordController
*
* @package Chill\MainBundle\Controller
* Class PasswordController.
*/
class PasswordController extends AbstractController
{
/**
* @var UserPasswordEncoderInterface
*/
protected $passwordEncoder;
/**
* @var TranslatorInterface
*/
protected $translator;
/**
* @var LoggerInterface
*/
protected $chillLogger;
/**
* @var RecoverPasswordHelper
*/
protected $recoverPasswordHelper;
/**
* @var TokenManager
*/
protected $tokenManager;
/**
* @var EventDispatcherInterface
*/
protected $eventDispatcher;
/**
* @var UserPasswordEncoderInterface
*/
protected $passwordEncoder;
/**
* @var RecoverPasswordHelper
*/
protected $recoverPasswordHelper;
/**
* @var TokenManager
*/
protected $tokenManager;
/**
* @var TranslatorInterface
*/
protected $translator;
/**
* PasswordController constructor.
*
* @param LoggerInterface $chillLogger
* @param UserPasswordEncoderInterface $passwordEncoder
* @param RecoverPasswordHelper $recoverPasswordHelper
* @param TokenManager $tokenManager
* @param TranslatorInterface $translator
* @param EventDispatcherInterface $eventDispatcher
*/
public function __construct(
LoggerInterface $chillLogger,
@@ -83,9 +82,163 @@ class PasswordController extends AbstractController
$this->recoverPasswordHelper = $recoverPasswordHelper;
$this->eventDispatcher = $eventDispatcher;
}
/**
* @return Response
*/
public function changeConfirmedAction()
{
return $this->render('@ChillMain/Password/recover_password_changed.html.twig');
}
/**
* @return Response|\Symfony\Component\HttpFoundation\RedirectResponse
*/
public function recoverAction(Request $request)
{
if (false === $this->isGranted(PasswordRecoverVoter::ASK_TOKEN)) {
return new Response($this->translator->trans('You are not allowed '
. 'to try to recover password, due to mitigating possible '
. 'attack. Try to contact your system administrator'), Response::HTTP_FORBIDDEN);
}
$query = $request->query;
$username = $query->get(TokenManager::USERNAME_CANONICAL);
$hash = $query->getAlnum(TokenManager::HASH);
$token = $query->getAlnum(TokenManager::TOKEN);
$timestamp = $query->getInt(TokenManager::TIMESTAMP);
$user = $this->getDoctrine()->getRepository(User::class)
->findOneByUsernameCanonical($username);
if (null === $user) {
$this->eventDispatcher->dispatch(
PasswordRecoverEvent::INVALID_TOKEN,
new PasswordRecoverEvent($token, null, $request->getClientIp())
);
throw $this->createNotFoundException(sprintf('User %s not found', $username));
}
if (true !== $this->tokenManager->verify($hash, $token, $user, $timestamp)) {
$this->eventDispatcher->dispatch(
PasswordRecoverEvent::INVALID_TOKEN,
new PasswordRecoverEvent($token, $user, $request->getClientIp())
);
return new Response('Invalid token', Response::HTTP_FORBIDDEN);
}
$form = $this->passwordForm($user);
$form->remove('actual_password');
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
$password = $form->get('new_password')->getData();
$user->setPassword($this->passwordEncoder->encodePassword($user, $password));
// logging for prod
$this
->chillLogger
->notice(
'setting new password for user',
[
'user' => $user->getUsername(),
]
);
$this->getDoctrine()->getManager()->flush();
return $this->redirectToRoute('password_request_recover_changed');
}
return $this->render('@ChillMain/Password/recover_password_form.html.twig', [
'form' => $form->createView(),
]);
}
/**
* @throws \Doctrine\ORM\NoResultException
* @throws \Doctrine\ORM\NonUniqueResultException
*
* @return Response|\Symfony\Component\HttpFoundation\RedirectResponse
*/
public function requestRecoverAction(Request $request)
{
if (false === $this->isGranted(PasswordRecoverVoter::ASK_TOKEN)) {
return new Response($this->translator->trans('You are not allowed '
. 'to try to recover password, due to mitigating possible '
. 'attack. Try to contact your system administrator'), Response::HTTP_FORBIDDEN);
}
$form = $this->requestRecoverForm();
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
/* @var $qb \Doctrine\ORM\QueryBuilder */
$qb = $this->getDoctrine()->getManager()
->createQueryBuilder();
$qb->select('u')
->from(User::class, 'u')
->where($qb->expr()->eq('u.usernameCanonical', 'UNACCENT(LOWER(:pattern))'))
->orWhere($qb->expr()->eq('u.emailCanonical', 'UNACCENT(LOWER(:pattern))'))
->setParameter('pattern', $form->get('username_or_email')->getData());
$user = $qb->getQuery()->getSingleResult();
if (empty($user->getEmail())) {
$this->addFlash('error', $this->translator->trans('This account does not have an email address. '
. 'Please ask your administrator to renew your password.'));
} else {
if (false === $this->isGranted(PasswordRecoverVoter::ASK_TOKEN, $user)) {
return new Response($this->translator->trans('You are not allowed '
. 'to try to recover password, due to mitigating possible '
. 'attack. Try to contact your system administrator'), Response::HTTP_FORBIDDEN);
}
$this->recoverPasswordHelper->sendRecoverEmail(
$user,
(new DateTimeImmutable('now'))->add(new DateInterval('PT30M'))
);
// logging for prod
$this
->chillLogger
->notice(
'Sending an email for password recovering',
[
'user' => $user->getUsername(),
]
);
$this->eventDispatcher->dispatch(
PasswordRecoverEvent::ASK_TOKEN_SUCCESS,
new PasswordRecoverEvent(null, $user, $request->getClientIp())
);
return $this->redirectToRoute('password_request_recover_confirm');
}
} elseif ($form->isSubmitted() && false === $form->isValid()) {
$this->eventDispatcher->dispatch(
PasswordRecoverEvent::ASK_TOKEN_INVALID_FORM,
new PasswordRecoverEvent(null, null, $request->getClientIp())
);
}
return $this->render('@ChillMain/Password/request_recover_password.html.twig', [
'form' => $form->createView(),
]);
}
/**
* @return Response
*/
public function requestRecoverConfirmAction()
{
return $this->render('@ChillMain/Password/request_recover_password_confirm.html.twig');
}
/**
* @param Request $request
* @return Response
*/
public function UserPasswordAction(Request $request)
@@ -107,11 +260,11 @@ class PasswordController extends AbstractController
->chillLogger
->notice(
'update password for an user',
array(
'method' => $request->getMethod(),
'user' => $user->getUsername()
)
);
[
'method' => $request->getMethod(),
'user' => $user->getUsername(),
]
);
$user->setPassword($this->passwordEncoder->encodePassword($user, $password));
@@ -119,186 +272,16 @@ class PasswordController extends AbstractController
$em->flush();
$this->addFlash('success', $this->translator->trans('Password successfully updated!'));
return $this->redirectToRoute('change_my_password');
return $this->redirectToRoute('change_my_password');
}
// render into a template
return $this->render('@ChillMain/Password/password.html.twig', array(
'form' => $form->createView()
));
}
/**
* @param User $user
* @return \Symfony\Component\Form\Form
*/
private function passwordForm(User $user)
{
return $this
->createForm(
UserPasswordType::class,
[],
[ 'user' => $user ]
)
->add('submit', SubmitType::class, array('label' => 'Change password'))
;
}
/**
* @param Request $request
* @return \Symfony\Component\HttpFoundation\RedirectResponse|Response
*/
public function recoverAction(Request $request)
{
if (FALSE === $this->isGranted(PasswordRecoverVoter::ASK_TOKEN)) {
return (new Response($this->translator->trans("You are not allowed "
. "to try to recover password, due to mitigating possible "
. "attack. Try to contact your system administrator"), Response::HTTP_FORBIDDEN));
}
$query = $request->query;
$username = $query->get(TokenManager::USERNAME_CANONICAL);
$hash = $query->getAlnum(TokenManager::HASH);
$token = $query->getAlnum(TokenManager::TOKEN);
$timestamp = $query->getInt(TokenManager::TIMESTAMP);
$user = $this->getDoctrine()->getRepository(User::class)
->findOneByUsernameCanonical($username);
if (NULL === $user) {
$this->eventDispatcher->dispatch(PasswordRecoverEvent::INVALID_TOKEN,
new PasswordRecoverEvent($token, null, $request->getClientIp()));
throw $this->createNotFoundException(sprintf('User %s not found', $username));
}
if (TRUE !== $this->tokenManager->verify($hash, $token, $user, $timestamp)) {
$this->eventDispatcher->dispatch(PasswordRecoverEvent::INVALID_TOKEN,
new PasswordRecoverEvent($token, $user, $request->getClientIp()));
return new Response("Invalid token", Response::HTTP_FORBIDDEN);
}
$form = $this->passwordForm($user);
$form->remove('actual_password');
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
$password = $form->get('new_password')->getData();
$user->setPassword($this->passwordEncoder->encodePassword($user, $password));
// logging for prod
$this
->chillLogger
->notice(
'setting new password for user',
array(
'user' => $user->getUsername()
)
);
$this->getDoctrine()->getManager()->flush();
return $this->redirectToRoute('password_request_recover_changed');
}
return $this->render('@ChillMain/Password/recover_password_form.html.twig', [
'form' => $form->createView()
]);
}
/**
* @return Response
*/
public function changeConfirmedAction()
{
return $this->render('@ChillMain/Password/recover_password_changed.html.twig');
}
/**
* @param Request $request
* @return \Symfony\Component\HttpFoundation\RedirectResponse|Response
* @throws \Doctrine\ORM\NoResultException
* @throws \Doctrine\ORM\NonUniqueResultException
*/
public function requestRecoverAction(Request $request)
{
if (FALSE === $this->isGranted(PasswordRecoverVoter::ASK_TOKEN)) {
return (new Response($this->translator->trans("You are not allowed "
. "to try to recover password, due to mitigating possible "
. "attack. Try to contact your system administrator"), Response::HTTP_FORBIDDEN));
}
$form = $this->requestRecoverForm();
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
/* @var $qb \Doctrine\ORM\QueryBuilder */
$qb = $this->getDoctrine()->getManager()
->createQueryBuilder();
$qb->select('u')
->from(User::class, 'u')
->where($qb->expr()->eq('u.usernameCanonical', 'UNACCENT(LOWER(:pattern))'))
->orWhere($qb->expr()->eq('u.emailCanonical', 'UNACCENT(LOWER(:pattern))' ))
->setParameter('pattern', $form->get('username_or_email')->getData())
;
$user = $qb->getQuery()->getSingleResult();
if (empty($user->getEmail())) {
$this->addFlash('error', $this->translator->trans('This account does not have an email address. '
. 'Please ask your administrator to renew your password.'));
} else {
if (FALSE === $this->isGranted(PasswordRecoverVoter::ASK_TOKEN, $user)) {
return (new Response($this->translator->trans("You are not allowed "
. "to try to recover password, due to mitigating possible "
. "attack. Try to contact your system administrator"), Response::HTTP_FORBIDDEN));
}
$this->recoverPasswordHelper->sendRecoverEmail($user,
(new \DateTimeImmutable('now'))->add(new \DateInterval('PT30M')));
// logging for prod
$this
->chillLogger
->notice(
'Sending an email for password recovering',
array(
'user' => $user->getUsername()
)
);
$this->eventDispatcher->dispatch(
PasswordRecoverEvent::ASK_TOKEN_SUCCESS,
new PasswordRecoverEvent(null, $user, $request->getClientIp())
);
return $this->redirectToRoute('password_request_recover_confirm');
}
} elseif ($form->isSubmitted() && FALSE === $form->isValid()) {
$this->eventDispatcher->dispatch(
PasswordRecoverEvent::ASK_TOKEN_INVALID_FORM,
new PasswordRecoverEvent(null, null, $request->getClientIp())
);
}
return $this->render('@ChillMain/Password/request_recover_password.html.twig', [
'form' => $form->createView()
return $this->render('@ChillMain/Password/password.html.twig', [
'form' => $form->createView(),
]);
}
/**
* @return Response
*/
public function requestRecoverConfirmAction()
{
return $this->render('@ChillMain/Password/request_recover_password_confirm.html.twig');
}
/**
* @return \Symfony\Component\Form\FormInterface
*/
@@ -310,27 +293,40 @@ class PasswordController extends AbstractController
'label' => 'Username or email',
'constraints' => [
new Callback([
'callback' => function($pattern, ExecutionContextInterface $context, $payload) {
'callback' => function ($pattern, ExecutionContextInterface $context, $payload) {
$qb = $this->getDoctrine()->getManager()
->createQueryBuilder();
->createQueryBuilder();
$qb->select('COUNT(u)')
->from(User::class, 'u')
->where($qb->expr()->eq('u.usernameCanonical', 'UNACCENT(LOWER(:pattern))'))
->orWhere($qb->expr()->eq('u.emailCanonical', 'UNACCENT(LOWER(:pattern))' ))
->setParameter('pattern', $pattern)
;
->orWhere($qb->expr()->eq('u.emailCanonical', 'UNACCENT(LOWER(:pattern))'))
->setParameter('pattern', $pattern);
if ((int) $qb->getQuery()->getSingleScalarResult() !== 1) {
$context->addViolation('This username or email does not exists');
}
}
])
]
},
]),
],
])
->add('submit', SubmitType::class, [
'label' => 'Request recover'
'label' => 'Request recover',
]);
return $builder->getForm();
}
/**
* @return \Symfony\Component\Form\Form
*/
private function passwordForm(User $user)
{
return $this
->createForm(
UserPasswordType::class,
[],
['user' => $user]
)
->add('submit', SubmitType::class, ['label' => 'Change password']);
}
}

View File

@@ -1,62 +1,62 @@
<?php
/**
* Chill is a software for social workers
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/
namespace Chill\MainBundle\Controller;
use Chill\MainBundle\Entity\PermissionsGroup;
use Chill\MainBundle\Entity\RoleScope;
use Chill\MainBundle\Entity\Scope;
use Chill\MainBundle\Form\PermissionsGroupType;
use Chill\MainBundle\Form\Type\ComposedRoleScopeType;
use Chill\MainBundle\Security\RoleProvider;
use Chill\MainBundle\Templating\TranslatableStringHelper;
use RuntimeException;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\Form\Extension\Core\Type\SubmitType;
use Chill\MainBundle\Entity\RoleScope;
use Chill\MainBundle\Entity\PermissionsGroup;
use Chill\MainBundle\Form\PermissionsGroupType;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\Security\Core\Role\Role;
use Symfony\Component\Security\Core\Role\RoleHierarchy;
use Chill\MainBundle\Entity\Scope;
use Chill\MainBundle\Form\Type\ComposedRoleScopeType;
use Symfony\Component\Validator\Validator\ValidatorInterface;
use Symfony\Contracts\Translation\TranslatorInterface;
/**
* Class PermissionsGroupController
*
* @package Chill\MainBundle\Controller
* Class PermissionsGroupController.
*/
class PermissionsGroupController extends AbstractController
{
/**
* @var RoleHierarchy
*/
private $roleHierarchy;
/**
* @var RoleProvider
*/
private $roleProvider;
/**
* @var TranslatableStringHelper
*/
private $translatableStringHelper;
/**
* @var RoleProvider $roleProvider
*/
private $roleProvider;
/**
* @var RoleHierarchy $roleHierarchy
*/
private $roleHierarchy;
/**
* @var TranslatorInterface
*/
private $translator;
/**
* @var ValidatorInterface
*/
private $validator;
/**
* PermissionsGroupController constructor.
*
* @param TranslatableStringHelper $translatableStringHelper
* @param RoleProvider $roleProvider
* @param RoleHierarchy $roleHierarchy
* @param TranslatorInterface $translator
* @param ValidatorInterface $validator
*/
public function __construct(
TranslatableStringHelper $translatableStringHelper,
@@ -64,33 +64,105 @@ class PermissionsGroupController extends AbstractController
RoleHierarchy $roleHierarchy,
TranslatorInterface $translator,
ValidatorInterface $validator
)
{
) {
$this->translatableStringHelper = $translatableStringHelper;
$this->roleProvider = $roleProvider;
$this->roleHierarchy = $roleHierarchy;
$this->translator = $translator;
$this->validator = $validator;
}
/**
* Lists all PermissionsGroup entities.
* @param int $id
*
* @throws type
*
* @return Respon
*/
public function indexAction()
public function addLinkRoleScopeAction(Request $request, $id)
{
$em = $this->getDoctrine()->getManager();
$entities = $em->getRepository('ChillMainBundle:PermissionsGroup')->findAll();
$permissionsGroup = $em->getRepository('ChillMainBundle:PermissionsGroup')->find($id);
return $this->render('@ChillMain/PermissionsGroup/index.html.twig', array(
'entities' => $entities,
));
if (!$permissionsGroup) {
throw $this->createNotFoundException('Unable to find PermissionsGroup entity.');
}
$form = $this->createAddRoleScopeForm($permissionsGroup);
$form->handleRequest($request);
if ($form->isValid()) {
$roleScope = $this->getPersistentRoleScopeBy(
$form['composed_role_scope']->getData()->getRole(),
$form['composed_role_scope']->getData()->getScope()
);
$permissionsGroup->addRoleScope($roleScope);
$violations = $this->validator->validate($permissionsGroup);
if ($violations->count() === 0) {
$em->flush();
$this->addFlash(
'notice',
$this->translator->trans('The permissions have been added')
);
return $this->redirect($this->generateUrl(
'admin_permissionsgroup_edit',
['id' => $id]
));
}
foreach ($violations as $error) {
$this->addFlash('error', $error->getMessage());
}
} else {
foreach ($form->getErrors() as $error) {
$this->addFlash('error', $error->getMessage());
}
}
$editForm = $this->createEditForm($permissionsGroup);
$deleteRoleScopesForm = [];
foreach ($permissionsGroup->getRoleScopes() as $roleScope) {
$deleteRoleScopesForm[$roleScope->getId()] = $this->createDeleteRoleScopeForm(
$permissionsGroup,
$roleScope
);
}
$addRoleScopesForm = $this->createAddRoleScopeForm($permissionsGroup);
// sort role scope by title
$roleProvider = $this->roleProvider;
$roleScopesSorted = [];
foreach ($permissionsGroup->getRoleScopes()->toArray() as $roleScope) {
/* @var $roleScope RoleScope */
$title = $roleProvider->getRoleTitle($roleScope->getRole());
$roleScopesSorted[$title][] = $roleScope;
}
ksort($roleScopesSorted);
return $this->render('@ChillMain/PermissionsGroup/edit.html.twig', [
'entity' => $permissionsGroup,
'edit_form' => $editForm->createView(),
'role_scopes_sorted' => $roleScopesSorted,
'expanded_roles' => $this->getExpandedRoles($permissionsGroup->getRoleScopes()->toArray()),
'delete_role_scopes_form' => array_map(function ($form) {
return $form->createView();
}, $deleteRoleScopesForm),
'add_role_scopes_form' => $addRoleScopesForm->createView(),
]);
}
/**
* Creates a new PermissionsGroup entity.
*
*/
public function createAction(Request $request)
{
@@ -103,284 +175,24 @@ class PermissionsGroupController extends AbstractController
$em->persist($permissionsGroup);
$em->flush();
return $this->redirect($this->generateUrl('admin_permissionsgroup_edit',
array('id' => $permissionsGroup->getId())));
return $this->redirect($this->generateUrl(
'admin_permissionsgroup_edit',
['id' => $permissionsGroup->getId()]
));
}
return $this->render('@ChillMain/PermissionsGroup/new.html.twig', array(
return $this->render('@ChillMain/PermissionsGroup/new.html.twig', [
'entity' => $permissionsGroup,
'form' => $form->createView(),
));
'form' => $form->createView(),
]);
}
/**
* Creates a form to create a PermissionsGroup entity.
*
* @param PermissionsGroup $permissionsGroup The entity
*
* @return \Symfony\Component\Form\Form The form
*/
private function createCreateForm(PermissionsGroup $permissionsGroup)
{
$form = $this->createForm(PermissionsGroupType::class, $permissionsGroup, array(
'action' => $this->generateUrl('admin_permissionsgroup_create'),
'method' => 'POST',
));
$form->add('submit', SubmitType::class, array('label' => 'Create'));
return $form;
}
/**
* Displays a form to create a new PermissionsGroup entity.
*
*/
public function newAction()
{
$permissionsGroup = new PermissionsGroup();
$form = $this->createCreateForm($permissionsGroup);
return $this->render('@ChillMain/PermissionsGroup/new.html.twig', array(
'entity' => $permissionsGroup,
'form' => $form->createView(),
));
}
/**
* Finds and displays a PermissionsGroup entity.
*
*/
public function showAction($id)
{
$em = $this->getDoctrine()->getManager();
$permissionsGroup = $em->getRepository('ChillMainBundle:PermissionsGroup')->find($id);
if (!$permissionsGroup) {
throw $this->createNotFoundException('Unable to find PermissionsGroup entity.');
}
$translatableStringHelper = $this->translatableStringHelper;
$roleScopes = $permissionsGroup->getRoleScopes()->toArray();
// sort $roleScopes by name
usort($roleScopes,
function(RoleScope $a, RoleScope $b) use ($translatableStringHelper) {
if ($a->getScope() === NULL) {
return 1;
}
if ($b->getScope() === NULL) {
return +1;
}
return strcmp(
$translatableStringHelper->localize($a->getScope()->getName()),
$translatableStringHelper->localize($b->getScope()->getName())
);
});
// sort role scope by title
$roleProvider = $this->roleProvider;
$roleScopesSorted = array();
foreach($roleScopes as $roleScope) {
/* @var $roleScope RoleScope */
$title = $roleProvider->getRoleTitle($roleScope->getRole());
$roleScopesSorted[$title][] = $roleScope;
}
ksort($roleScopesSorted);
return $this->render('@ChillMain/PermissionsGroup/show.html.twig', array(
'entity' => $permissionsGroup,
'role_scopes_sorted' => $roleScopesSorted,
'expanded_roles' => $this->getExpandedRoles($roleScopes)
));
}
/**
* expand roleScopes to be easily shown in template
*
* @param array $roleScopes
* @return array
*/
private function getExpandedRoles(array $roleScopes)
{
$expandedRoles = array();
foreach ($roleScopes as $roleScope) {
if (!array_key_exists($roleScope->getRole(), $expandedRoles)) {
$expandedRoles[$roleScope->getRole()] =
array_map(
function(Role $role) {
return $role->getRole();
},
$this->roleHierarchy
->getReachableRoles(
array(new Role($roleScope->getRole()))
)
);
}
}
return $expandedRoles;
}
/**
* Displays a form to edit an existing PermissionsGroup entity.
*
*/
public function editAction($id)
{
$em = $this->getDoctrine()->getManager();
$permissionsGroup = $em->getRepository('ChillMainBundle:PermissionsGroup')->find($id);
if (!$permissionsGroup) {
throw $this->createNotFoundException('Unable to find PermissionsGroup entity.');
}
// create all the forms
$editForm = $this->createEditForm($permissionsGroup);
$deleteRoleScopesForm = array();
foreach ($permissionsGroup->getRoleScopes() as $roleScope) {
$deleteRoleScopesForm[$roleScope->getId()] = $this->createDeleteRoleScopeForm(
$permissionsGroup, $roleScope);
}
$addRoleScopesForm = $this->createAddRoleScopeForm($permissionsGroup);
// sort role scope by title
$roleProvider = $this->roleProvider;
$roleScopesSorted = array();
foreach($permissionsGroup->getRoleScopes()->toArray() as $roleScope) {
/* @var $roleScope RoleScope */
$title = $roleProvider->getRoleTitle($roleScope->getRole());
$roleScopesSorted[$title][] = $roleScope;
}
ksort($roleScopesSorted);
return $this->render('@ChillMain/PermissionsGroup/edit.html.twig', array(
'entity' => $permissionsGroup,
'role_scopes_sorted' => $roleScopesSorted,
'edit_form' => $editForm->createView(),
'expanded_roles' => $this->getExpandedRoles($permissionsGroup->getRoleScopes()->toArray()),
'delete_role_scopes_form' => array_map( function($form) {
return $form->createView();
}, $deleteRoleScopesForm),
'add_role_scopes_form' => $addRoleScopesForm->createView()
));
}
/**
* Creates a form to edit a PermissionsGroup entity.
*
* @param PermissionsGroup $permissionsGroup The entity
*
* @return \Symfony\Component\Form\Form The form
*/
private function createEditForm(PermissionsGroup $permissionsGroup)
{
$form = $this->createForm(PermissionsGroupType::class, $permissionsGroup, array(
'action' => $this->generateUrl('admin_permissionsgroup_update', array('id' => $permissionsGroup->getId())),
'method' => 'PUT',
));
$form->add('submit', SubmitType::class, array('label' => 'Update'));
return $form;
}
/**
* Edits an existing PermissionsGroup entity.
*
*/
public function updateAction(Request $request, $id)
{
$em = $this->getDoctrine()->getManager();
$permissionsGroup = $em
->getRepository('ChillMainBundle:PermissionsGroup')
->find($id);
if (!$permissionsGroup) {
throw $this->createNotFoundException('Unable to find Permissions'
. 'Group entity.');
}
$editForm = $this->createEditForm($permissionsGroup);
$editForm->handleRequest($request);
if ($editForm->isValid()) {
$em->flush();
return $this->redirect($this->generateUrl('admin_permissionsgroup_edit', array('id' => $id)));
}
$deleteRoleScopesForm = array();
foreach ($permissionsGroup->getRoleScopes() as $roleScope) {
$deleteRoleScopesForm[$roleScope->getId()] = $this->createDeleteRoleScopeForm(
$permissionsGroup, $roleScope);
}
$addRoleScopesForm = $this->createAddRoleScopeForm($permissionsGroup);
// sort role scope by title
$roleProvider = $this->roleProvider;
$roleScopesSorted = array();
foreach($permissionsGroup->getRoleScopes()->toArray() as $roleScope) {
/* @var $roleScope RoleScope */
$title = $roleProvider->getRoleTitle($roleScope->getRole());
$roleScopesSorted[$title][] = $roleScope;
}
ksort($roleScopesSorted);
return $this->render('@ChillMain/PermissionsGroup/edit.html.twig', array(
'entity' => $permissionsGroup,
'role_scopes_sorted' => $roleScopesSorted,
'edit_form' => $editForm->createView(),
'expanded_roles' => $this->getExpandedRoles($permissionsGroup->getRoleScopes()->toArray()),
'delete_role_scopes_form' => array_map( function($form) {
return $form->createView();
}, $deleteRoleScopesForm),
'add_role_scopes_form' => $addRoleScopesForm->createView()
));
}
/**
* get a role scope by his parameters. The role scope is persisted if it
* doesn't exists in database.
*
* @param Scope $scope
* @param string $role
* @return RoleScope
*/
protected function getPersistentRoleScopeBy($role, Scope $scope = null)
{
$em = $this->getDoctrine()->getManager();
$roleScope = $em->getRepository('ChillMainBundle:RoleScope')
->findOneBy(array('role' => $role, 'scope' => $scope));
if ($roleScope === NULL) {
$roleScope = (new RoleScope())
->setRole($role)
->setScope($scope)
;
$em->persist($roleScope);
}
return $roleScope;
}
/**
* remove an association between permissionsGroup and roleScope
* remove an association between permissionsGroup and roleScope.
*
* @param int $pgid permissionsGroup id
* @param int $rsid roleScope id
*
* @return redirection to edit form
*/
public function deleteLinkRoleScopeAction($pgid, $rsid)
@@ -400,48 +212,56 @@ class PermissionsGroupController extends AbstractController
try {
$permissionsGroup->removeRoleScope($roleScope);
} catch (\RuntimeException $ex) {
$this->addFlash('notice',
} catch (RuntimeException $ex) {
$this->addFlash(
'notice',
$this->translator->trans("The role '%role%' and circle "
. "'%scope%' is not associated with this permission group", array(
. "'%scope%' is not associated with this permission group", [
'%role%' => $this->translator->trans($roleScope->getRole()),
'%scope%' => $this->translatableStringHelper
->localize($roleScope->getScope()->getName())
)));
->localize($roleScope->getScope()->getName()),
])
);
return $this->redirect($this->generateUrl('admin_permissionsgroup_edit',
array('id' => $pgid)));
return $this->redirect($this->generateUrl(
'admin_permissionsgroup_edit',
['id' => $pgid]
));
}
$em->flush();
if ($roleScope->getScope() !== NULL ) {
$this->addFlash('notice',
if ($roleScope->getScope() !== null) {
$this->addFlash(
'notice',
$this->translator->trans("The role '%role%' on circle "
. "'%scope%' has been removed", array(
. "'%scope%' has been removed", [
'%role%' => $this->translator->trans($roleScope->getRole()),
'%scope%' => $this->translatableStringHelper
->localize($roleScope->getScope()->getName())
)));
->localize($roleScope->getScope()->getName()),
])
);
} else {
$this->addFlash('notice',
$this->translator->trans("The role '%role%' has been removed", array(
'%role%' => $this->translator->trans($roleScope->getRole())
)));
$this->addFlash(
'notice',
$this->translator->trans("The role '%role%' has been removed", [
'%role%' => $this->translator->trans($roleScope->getRole()),
])
);
}
return $this->redirect($this->generateUrl('admin_permissionsgroup_edit',
array('id' => $pgid)));
return $this->redirect($this->generateUrl(
'admin_permissionsgroup_edit',
['id' => $pgid]
));
}
/**
* Displays a form to edit an existing PermissionsGroup entity.
*
* @param Request $request
* @param int $id
* @return Respon
* @throws type
* @param mixed $id
*/
public function addLinkRoleScopeAction(Request $request, $id)
public function editAction($id)
{
$em = $this->getDoctrine()->getManager();
@@ -451,71 +271,249 @@ class PermissionsGroupController extends AbstractController
throw $this->createNotFoundException('Unable to find PermissionsGroup entity.');
}
$form = $this->createAddRoleScopeForm($permissionsGroup);
$form->handleRequest($request);
if ($form->isValid()) {
$roleScope = $this->getPersistentRoleScopeBy(
$form['composed_role_scope']->getData()->getRole(),
$form['composed_role_scope']->getData()->getScope()
);
$permissionsGroup->addRoleScope($roleScope);
$violations = $this->validator->validate($permissionsGroup);
if ($violations->count() === 0) {
$em->flush();
$this->addFlash('notice',
$this->translator->trans("The permissions have been added"));
return $this->redirect($this->generateUrl('admin_permissionsgroup_edit',
array('id' => $id)));
} else {
foreach($violations as $error) {
$this->addFlash('error', $error->getMessage());
}
}
} else {
foreach ($form->getErrors() as $error) {
$this->addFlash('error', $error->getMessage());
}
}
// create all the forms
$editForm = $this->createEditForm($permissionsGroup);
$deleteRoleScopesForm = array();
$deleteRoleScopesForm = [];
foreach ($permissionsGroup->getRoleScopes() as $roleScope) {
$deleteRoleScopesForm[$roleScope->getId()] = $this->createDeleteRoleScopeForm(
$permissionsGroup, $roleScope);
$permissionsGroup,
$roleScope
);
}
$addRoleScopesForm = $this->createAddRoleScopeForm($permissionsGroup);
// sort role scope by title
$roleProvider = $this->roleProvider;
$roleScopesSorted = array();
foreach($permissionsGroup->getRoleScopes()->toArray() as $roleScope) {
$roleScopesSorted = [];
foreach ($permissionsGroup->getRoleScopes()->toArray() as $roleScope) {
/* @var $roleScope RoleScope */
$title = $roleProvider->getRoleTitle($roleScope->getRole());
$roleScopesSorted[$title][] = $roleScope;
}
ksort($roleScopesSorted);
return $this->render('@ChillMain/PermissionsGroup/edit.html.twig', array(
'entity' => $permissionsGroup,
'edit_form' => $editForm->createView(),
return $this->render('@ChillMain/PermissionsGroup/edit.html.twig', [
'entity' => $permissionsGroup,
'role_scopes_sorted' => $roleScopesSorted,
'edit_form' => $editForm->createView(),
'expanded_roles' => $this->getExpandedRoles($permissionsGroup->getRoleScopes()->toArray()),
'delete_role_scopes_form' => array_map( function($form) {
'delete_role_scopes_form' => array_map(function ($form) {
return $form->createView();
}, $deleteRoleScopesForm),
'add_role_scopes_form' => $addRoleScopesForm->createView()
));
'add_role_scopes_form' => $addRoleScopesForm->createView(),
]);
}
/**
* Lists all PermissionsGroup entities.
*/
public function indexAction()
{
$em = $this->getDoctrine()->getManager();
$entities = $em->getRepository('ChillMainBundle:PermissionsGroup')->findAll();
return $this->render('@ChillMain/PermissionsGroup/index.html.twig', [
'entities' => $entities,
]);
}
/**
* Displays a form to create a new PermissionsGroup entity.
*/
public function newAction()
{
$permissionsGroup = new PermissionsGroup();
$form = $this->createCreateForm($permissionsGroup);
return $this->render('@ChillMain/PermissionsGroup/new.html.twig', [
'entity' => $permissionsGroup,
'form' => $form->createView(),
]);
}
/**
* Finds and displays a PermissionsGroup entity.
*
* @param mixed $id
*/
public function showAction($id)
{
$em = $this->getDoctrine()->getManager();
$permissionsGroup = $em->getRepository('ChillMainBundle:PermissionsGroup')->find($id);
if (!$permissionsGroup) {
throw $this->createNotFoundException('Unable to find PermissionsGroup entity.');
}
$translatableStringHelper = $this->translatableStringHelper;
$roleScopes = $permissionsGroup->getRoleScopes()->toArray();
// sort $roleScopes by name
usort(
$roleScopes,
function (RoleScope $a, RoleScope $b) use ($translatableStringHelper) {
if ($a->getScope() === null) {
return 1;
}
if ($b->getScope() === null) {
return +1;
}
return strcmp(
$translatableStringHelper->localize($a->getScope()->getName()),
$translatableStringHelper->localize($b->getScope()->getName())
);
}
);
// sort role scope by title
$roleProvider = $this->roleProvider;
$roleScopesSorted = [];
foreach ($roleScopes as $roleScope) {
/* @var $roleScope RoleScope */
$title = $roleProvider->getRoleTitle($roleScope->getRole());
$roleScopesSorted[$title][] = $roleScope;
}
ksort($roleScopesSorted);
return $this->render('@ChillMain/PermissionsGroup/show.html.twig', [
'entity' => $permissionsGroup,
'role_scopes_sorted' => $roleScopesSorted,
'expanded_roles' => $this->getExpandedRoles($roleScopes),
]);
}
/**
* Edits an existing PermissionsGroup entity.
*
* @param mixed $id
*/
public function updateAction(Request $request, $id)
{
$em = $this->getDoctrine()->getManager();
$permissionsGroup = $em
->getRepository('ChillMainBundle:PermissionsGroup')
->find($id);
if (!$permissionsGroup) {
throw $this->createNotFoundException('Unable to find Permissions'
. 'Group entity.');
}
$editForm = $this->createEditForm($permissionsGroup);
$editForm->handleRequest($request);
if ($editForm->isValid()) {
$em->flush();
return $this->redirect($this->generateUrl('admin_permissionsgroup_edit', ['id' => $id]));
}
$deleteRoleScopesForm = [];
foreach ($permissionsGroup->getRoleScopes() as $roleScope) {
$deleteRoleScopesForm[$roleScope->getId()] = $this->createDeleteRoleScopeForm(
$permissionsGroup,
$roleScope
);
}
$addRoleScopesForm = $this->createAddRoleScopeForm($permissionsGroup);
// sort role scope by title
$roleProvider = $this->roleProvider;
$roleScopesSorted = [];
foreach ($permissionsGroup->getRoleScopes()->toArray() as $roleScope) {
/* @var $roleScope RoleScope */
$title = $roleProvider->getRoleTitle($roleScope->getRole());
$roleScopesSorted[$title][] = $roleScope;
}
ksort($roleScopesSorted);
return $this->render('@ChillMain/PermissionsGroup/edit.html.twig', [
'entity' => $permissionsGroup,
'role_scopes_sorted' => $roleScopesSorted,
'edit_form' => $editForm->createView(),
'expanded_roles' => $this->getExpandedRoles($permissionsGroup->getRoleScopes()->toArray()),
'delete_role_scopes_form' => array_map(function ($form) {
return $form->createView();
}, $deleteRoleScopesForm),
'add_role_scopes_form' => $addRoleScopesForm->createView(),
]);
}
/**
* get a role scope by his parameters. The role scope is persisted if it
* doesn't exists in database.
*
* @param Scope $scope
* @param string $role
*
* @return RoleScope
*/
protected function getPersistentRoleScopeBy($role, ?Scope $scope = null)
{
$em = $this->getDoctrine()->getManager();
$roleScope = $em->getRepository('ChillMainBundle:RoleScope')
->findOneBy(['role' => $role, 'scope' => $scope]);
if (null === $roleScope) {
$roleScope = (new RoleScope())
->setRole($role)
->setScope($scope);
$em->persist($roleScope);
}
return $roleScope;
}
/**
* creates a form to add a role scope to permissionsgroup.
*
* @return \Symfony\Component\Form\Form The form
*/
private function createAddRoleScopeForm(PermissionsGroup $permissionsGroup)
{
return $this->createFormBuilder()
->setAction($this->generateUrl(
'admin_permissionsgroup_add_role_scope',
['id' => $permissionsGroup->getId()]
))
->setMethod('PUT')
->add('composed_role_scope', ComposedRoleScopeType::class)
->add('submit', SubmitType::class, ['label' => 'Add permission'])
->getForm();
}
/**
* Creates a form to create a PermissionsGroup entity.
*
* @param PermissionsGroup $permissionsGroup The entity
*
* @return \Symfony\Component\Form\Form The form
*/
private function createCreateForm(PermissionsGroup $permissionsGroup)
{
$form = $this->createForm(PermissionsGroupType::class, $permissionsGroup, [
'action' => $this->generateUrl('admin_permissionsgroup_create'),
'method' => 'POST',
]);
$form->add('submit', SubmitType::class, ['label' => 'Create']);
return $form;
}
/**
@@ -525,35 +523,64 @@ class PermissionsGroupController extends AbstractController
*
* @return \Symfony\Component\Form\Form The form
*/
private function createDeleteRoleScopeForm(PermissionsGroup $permissionsGroup,
RoleScope $roleScope)
private function createDeleteRoleScopeForm(
PermissionsGroup $permissionsGroup,
RoleScope $roleScope
)
{
return $this->createFormBuilder()
->setAction($this->generateUrl('admin_permissionsgroup_delete_role_scope',
array('pgid' => $permissionsGroup->getId(), 'rsid' => $roleScope->getId())))
->setAction($this->generateUrl(
'admin_permissionsgroup_delete_role_scope',
['pgid' => $permissionsGroup->getId(), 'rsid' => $roleScope->getId()]
))
->setMethod('DELETE')
->add('submit', SubmitType::class, array('label' => 'Delete'))
->getForm()
;
->add('submit', SubmitType::class, ['label' => 'Delete'])
->getForm();
}
/**
* creates a form to add a role scope to permissionsgroup
* Creates a form to edit a PermissionsGroup entity.
*
* @param PermissionsGroup $permissionsGroup The entity
*
* @param PermissionsGroup $permissionsGroup
* @return \Symfony\Component\Form\Form The form
*/
private function createAddRoleScopeForm(PermissionsGroup $permissionsGroup)
private function createEditForm(PermissionsGroup $permissionsGroup)
{
return $this->createFormBuilder()
->setAction($this->generateUrl('admin_permissionsgroup_add_role_scope',
array('id' => $permissionsGroup->getId())))
->setMethod('PUT')
->add('composed_role_scope', ComposedRoleScopeType::class)
->add('submit', SubmitType::class, array('label' => 'Add permission'))
->getForm()
;
$form = $this->createForm(PermissionsGroupType::class, $permissionsGroup, [
'action' => $this->generateUrl('admin_permissionsgroup_update', ['id' => $permissionsGroup->getId()]),
'method' => 'PUT',
]);
$form->add('submit', SubmitType::class, ['label' => 'Update']);
return $form;
}
/**
* expand roleScopes to be easily shown in template.
*
* @return array
*/
private function getExpandedRoles(array $roleScopes)
{
$expandedRoles = [];
foreach ($roleScopes as $roleScope) {
if (!array_key_exists($roleScope->getRole(), $expandedRoles)) {
$expandedRoles[$roleScope->getRole()] =
array_map(
function (Role $role) {
return $role->getRole();
},
$this->roleHierarchy
->getReachableRoles(
[new Role($roleScope->getRole())]
)
);
}
}
return $expandedRoles;
}
}

View File

@@ -1,27 +1,27 @@
<?php
/**
* Chill is a software for social workers
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/
namespace Chill\MainBundle\Controller;
use Chill\MainBundle\CRUD\Controller\ApiController;
use Symfony\Component\HttpFoundation\Request;
/**
* Class PostalCodeAPIController
*
* @package Chill\MainBundle\Controller
* @author Champs Libres
* Class PostalCodeAPIController.
*/
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'));
->setParameter('country', $request->query->get('country'));
}
}
}

View File

@@ -1,90 +1,76 @@
<?php
/*
* Chill is a software for social workers
*
* Copyright (C) 2018, Champs Libres Cooperative SCRLFS, <http://www.champs-libres.coop>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
namespace Chill\MainBundle\Controller;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\Routing\Annotation\Route;
use Chill\MainBundle\Entity\PostalCode;
use Symfony\Component\HttpFoundation\JsonResponse;
use Chill\MainBundle\Templating\TranslatableStringHelper;
use Doctrine\ORM\Query;
/**
* Class PostalCodeController
* Chill is a software for social workers
*
* @package Chill\MainBundle\Controller
* @author Julien Fastré <julien.fastre@champs-libres.coop>
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/
namespace Chill\MainBundle\Controller;
use Chill\MainBundle\Entity\PostalCode;
use Chill\MainBundle\Templating\TranslatableStringHelper;
use Doctrine\ORM\Query;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\Routing\Annotation\Route;
use function array_map;
/**
* Class PostalCodeController.
*/
class PostalCodeController extends AbstractController
{
/**
*
* @var TranslatableStringHelper
*/
protected $translatableStringHelper;
public function __construct(TranslatableStringHelper $translatableStringHelper)
{
$this->translatableStringHelper = $translatableStringHelper;
}
/**
*
* @Route(
* "{_locale}/postalcode/search"
* "{_locale}/postalcode/search"
* )
* @param Request $request
*
* @return JsonResponse
*/
public function searchAction(Request $request)
{
$pattern = $request->query->getAlnum('q', '');
if (empty($pattern)) {
return new JsonResponse(["results" => [], "pagination" => [ "more" => false]]);
return new JsonResponse(['results' => [], 'pagination' => ['more' => false]]);
}
$query = $this->getDoctrine()->getManager()
->createQuery(sprintf(
"SELECT p.id AS id, p.name AS name, p.code AS code, "
. "country.name AS country_name, "
. "country.countryCode AS country_code "
. "FROM %s p "
. "JOIN p.country country "
. "WHERE LOWER(p.name) LIKE LOWER(:pattern) OR LOWER(p.code) LIKE LOWER(:pattern) "
. "ORDER BY code"
, PostalCode::class)
)
->setParameter('pattern', '%'.$pattern.'%')
->setMaxResults(30)
;
$results = \array_map(function($row) {
->createQuery(
sprintf(
'SELECT p.id AS id, p.name AS name, p.code AS code, '
. 'country.name AS country_name, '
. 'country.countryCode AS country_code '
. 'FROM %s p '
. 'JOIN p.country country '
. 'WHERE LOWER(p.name) LIKE LOWER(:pattern) OR LOWER(p.code) LIKE LOWER(:pattern) '
. 'ORDER BY code',
PostalCode::class
)
)
->setParameter('pattern', '%' . $pattern . '%')
->setMaxResults(30);
$results = array_map(function ($row) {
$row['country_name'] = $this->translatableStringHelper->localize($row['country_name']);
$row['text'] = $row['code']." ".$row["name"]." (".$row['country_name'].")";
$row['text'] = $row['code'] . ' ' . $row['name'] . ' (' . $row['country_name'] . ')';
return $row;
}, $query->getResult(Query::HYDRATE_ARRAY));
return new JsonResponse([ 'results' => $results, "pagination" => [ "more" => false ] ]);
return new JsonResponse(['results' => $results, 'pagination' => ['more' => false]]);
}
}

View File

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

View File

@@ -1,62 +1,47 @@
<?php
/*
/**
* Chill is a software for social workers
*
* Copyright (C) 2014, Champs Libres Cooperative SCRLFS, <http://www.champs-libres.coop>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/
namespace Chill\MainBundle\Controller;
use Chill\MainBundle\Pagination\PaginatorFactory;
use Chill\MainBundle\Search\ParsingException;
use Chill\MainBundle\Search\SearchApi;
use Chill\MainBundle\Search\SearchApiNoQueryException;
use Chill\MainBundle\Serializer\Model\Collection;
use GuzzleHttp\Psr7\Response;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\Request;
use Chill\MainBundle\Search\SearchInterface;
use Chill\MainBundle\Search\SearchProvider;
use Chill\MainBundle\Search\UnknowSearchDomainException;
use Chill\MainBundle\Search\UnknowSearchNameException;
use Chill\MainBundle\Search\ParsingException;
use Chill\MainBundle\Search\SearchInterface;
use Symfony\Component\Form\Extension\Core\Type\SubmitType;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\Form\Extension\Core\Type\FormType;
use Symfony\Component\Form\Extension\Core\Type\SubmitType;
use Symfony\Component\HttpFoundation\Exception\BadRequestException;
use Symfony\Component\HttpFoundation\JsonResponse;
use Chill\MainBundle\Search\SearchProvider;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpKernel\Exception\BadRequestHttpException;
use Symfony\Contracts\Translation\TranslatorInterface;
use Chill\MainBundle\Pagination\PaginatorFactory;
use Chill\MainBundle\Search\SearchApi;
use Symfony\Component\HttpFoundation\Exception\BadRequestException;
use function key;
use function reset;
/**
* Class SearchController
*
* @package Chill\MainBundle\Controller
* Class SearchController.
*/
class SearchController extends AbstractController
{
protected SearchProvider $searchProvider;
protected TranslatorInterface $translator;
protected PaginatorFactory $paginatorFactory;
protected SearchApi $searchApi;
function __construct(
protected SearchProvider $searchProvider;
protected TranslatorInterface $translator;
public function __construct(
SearchProvider $searchProvider,
TranslatorInterface $translator,
PaginatorFactory $paginatorFactory,
@@ -68,127 +53,6 @@ class SearchController extends AbstractController
$this->searchApi = $searchApi;
}
public function searchAction(Request $request, $_format)
{
$pattern = $request->query->get('q', '');
if ($pattern === ''){
switch($_format) {
case 'html':
return $this->render('@ChillMain/Search/error.html.twig',
array(
'message' => $this->translator->trans("Your search is empty. "
. "Please provide search terms."),
'pattern' => $pattern
));
case 'json':
return new JsonResponse([
'results' => [],
'pagination' => [ 'more' => false ]
]);
}
}
$name = $request->query->get('name', NULL);
try {
if ($name === NULL) {
if ($_format === 'json') {
return new JsonResponse('Currently, we still do not aggregate results '
. 'from different providers', JsonResponse::HTTP_BAD_REQUEST);
}
// no specific search selected. Rendering result in "preview" mode
$results = $this->searchProvider
->getSearchResults(
$pattern,
0,
5,
array(SearchInterface::SEARCH_PREVIEW_OPTION => true)
);
} else {
// we want search on a specific search provider. Display full results.
$results = [$this->searchProvider
->getResultByName(
$pattern,
$name,
$this->paginatorFactory->getCurrentPageFirstItemNumber(),
$this->paginatorFactory->getCurrentItemsPerPage(),
array(
SearchInterface::SEARCH_PREVIEW_OPTION => false,
SearchInterface::REQUEST_QUERY_PARAMETERS => $request
->get(SearchInterface::REQUEST_QUERY_KEY_ADD_PARAMETERS, [])
),
$_format
)];
if ($_format === 'json') {
return new JsonResponse(\reset($results));
}
}
} catch (UnknowSearchDomainException $ex) {
return $this->render('@ChillMain/Search/error.html.twig',
array(
"message" => $this->translator->trans("The domain %domain% "
. "is unknow. Please check your search.", array('%domain%' => $ex->getDomain())),
'pattern' => $pattern
));
} catch (UnknowSearchNameException $ex) {
throw $this->createNotFoundException("The name ".$ex->getName()." is not found");
} catch (ParsingException $ex) {
return $this->render('@ChillMain/Search/error.html.twig',
array(
"message" => $this->translator->trans('Invalid terms').
": ".$this->translator->trans($ex->getMessage()),
'pattern' => $pattern
));
}
return $this->render('@ChillMain/Search/list.html.twig',
array('results' => $results, 'pattern' => $pattern)
);
}
public function searchApi(Request $request, $_format): JsonResponse
{
//TODO this is an incomplete implementation
$query = $request->query->get('q', '');
$types = $request->query->get('type', []);
if (count($types) === 0) {
throw new BadRequestException("The request must contains at "
." one type");
}
try {
$collection = $this->searchApi->getResults($query, $types, []);
} catch (SearchApiNoQueryException $e) {
throw new BadRequestHttpException($e->getMessage(), $e);
}
return $this->json($collection, \Symfony\Component\HttpFoundation\Response::HTTP_OK, [], [ "groups" => ["read"]]);
}
public function advancedSearchListAction(Request $request)
{
/* @var $variable Chill\MainBundle\Search\SearchProvider */
$searchProvider = $this->searchProvider;
$advancedSearchProviders = $searchProvider
->getHasAdvancedFormSearchServices();
if(\count($advancedSearchProviders) === 1) {
\reset($advancedSearchProviders);
return $this->redirectToRoute('chill_main_advanced_search', [
'name' => \key($advancedSearchProviders)
]);
}
return $this->render('@ChillMain/Search/choose_list.html.twig');
}
public function advancedSearchAction($name, Request $request)
{
try {
@@ -196,16 +60,16 @@ class SearchController extends AbstractController
$searchProvider = $this->searchProvider;
/* @var $variable Chill\MainBundle\Search\HasAdvancedSearchFormInterface */
$search = $this->searchProvider
->getHasAdvancedFormByName($name);
->getHasAdvancedFormByName($name);
} catch (\Chill\MainBundle\Search\UnknowSearchNameException $e) {
throw $this->createNotFoundException("no advanced search for "
. "$name");
throw $this->createNotFoundException('no advanced search for '
. "{$name}");
}
if ($request->query->has('q')) {
$data = $search->convertTermsToFormData($searchProvider->parse(
$request->query->get('q')));
$request->query->get('q')
));
}
$form = $this->createAdvancedSearchForm($name, $data ?? []);
@@ -219,17 +83,146 @@ class SearchController extends AbstractController
->convertFormDataToQuery($form->getData());
return $this->redirectToRoute('chill_main_search', [
'q' => $pattern, 'name' => $name
'q' => $pattern, 'name' => $name,
]);
}
}
return $this->render('@ChillMain/Search/advanced_search.html.twig',
return $this->render(
'@ChillMain/Search/advanced_search.html.twig',
[
'form' => $form->createView(),
'name' => $name,
'title' => $search->getAdvancedSearchTitle()
'title' => $search->getAdvancedSearchTitle(),
]
);
}
public function advancedSearchListAction(Request $request)
{
/* @var $variable Chill\MainBundle\Search\SearchProvider */
$searchProvider = $this->searchProvider;
$advancedSearchProviders = $searchProvider
->getHasAdvancedFormSearchServices();
if (\count($advancedSearchProviders) === 1) {
reset($advancedSearchProviders);
return $this->redirectToRoute('chill_main_advanced_search', [
'name' => key($advancedSearchProviders),
]);
}
return $this->render('@ChillMain/Search/choose_list.html.twig');
}
public function searchAction(Request $request, $_format)
{
$pattern = $request->query->get('q', '');
if ('' === $pattern) {
switch ($_format) {
case 'html':
return $this->render(
'@ChillMain/Search/error.html.twig',
[
'message' => $this->translator->trans('Your search is empty. '
. 'Please provide search terms.'),
'pattern' => $pattern,
]
);
case 'json':
return new JsonResponse([
'results' => [],
'pagination' => ['more' => false],
]);
}
}
$name = $request->query->get('name', null);
try {
if (null === $name) {
if ('json' === $_format) {
return new JsonResponse('Currently, we still do not aggregate results '
. 'from different providers', JsonResponse::HTTP_BAD_REQUEST);
}
// no specific search selected. Rendering result in "preview" mode
$results = $this->searchProvider
->getSearchResults(
$pattern,
0,
5,
[SearchInterface::SEARCH_PREVIEW_OPTION => true]
);
} else {
// we want search on a specific search provider. Display full results.
$results = [$this->searchProvider
->getResultByName(
$pattern,
$name,
$this->paginatorFactory->getCurrentPageFirstItemNumber(),
$this->paginatorFactory->getCurrentItemsPerPage(),
[
SearchInterface::SEARCH_PREVIEW_OPTION => false,
SearchInterface::REQUEST_QUERY_PARAMETERS => $request
->get(SearchInterface::REQUEST_QUERY_KEY_ADD_PARAMETERS, []),
],
$_format
), ];
if ('json' === $_format) {
return new JsonResponse(reset($results));
}
}
} catch (UnknowSearchDomainException $ex) {
return $this->render(
'@ChillMain/Search/error.html.twig',
[
'message' => $this->translator->trans('The domain %domain% '
. 'is unknow. Please check your search.', ['%domain%' => $ex->getDomain()]),
'pattern' => $pattern,
]
);
} catch (UnknowSearchNameException $ex) {
throw $this->createNotFoundException('The name ' . $ex->getName() . ' is not found');
} catch (ParsingException $ex) {
return $this->render(
'@ChillMain/Search/error.html.twig',
[
'message' => $this->translator->trans('Invalid terms') .
': ' . $this->translator->trans($ex->getMessage()),
'pattern' => $pattern,
]
);
}
return $this->render(
'@ChillMain/Search/list.html.twig',
['results' => $results, 'pattern' => $pattern]
);
}
public function searchApi(Request $request, $_format): JsonResponse
{
//TODO this is an incomplete implementation
$query = $request->query->get('q', '');
$types = $request->query->get('type', []);
if (count($types) === 0) {
throw new BadRequestException('The request must contains at '
. ' one type');
}
try {
$collection = $this->searchApi->getResults($query, $types, []);
} catch (SearchApiNoQueryException $e) {
throw new BadRequestHttpException($e->getMessage(), $e);
}
return $this->json($collection, \Symfony\Component\HttpFoundation\Response::HTTP_OK, [], ['groups' => ['read']]);
}
protected function createAdvancedSearchForm($name, array $data = [])
@@ -240,19 +233,17 @@ class SearchController extends AbstractController
null,
FormType::class,
$data,
[ 'method' => Request::METHOD_POST ]
['method' => Request::METHOD_POST]
);
$this->searchProvider
->getHasAdvancedFormByName($name)
->buildForm($builder)
;
->buildForm($builder);
$builder->add('submit', SubmitType::class, [
'label' => 'Search'
'label' => 'Search',
]);
return $builder->getForm();
}
}

View File

@@ -1,45 +1,29 @@
<?php
/*
* Copyright (C) 2015 Champs-Libres Coopérative <info@champs-libres.coop>
/**
* Chill is a software for social workers
*
* 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/>.
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/
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 Chill\MainBundle\Timeline\TimelineBuilder;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\Routing\Annotation\Route;
use Symfony\Component\Security\Core\Security;
class TimelineCenterController extends AbstractController
{
protected TimelineBuilder $timelineBuilder;
protected PaginatorFactory $paginatorFactory;
protected TimelineBuilder $timelineBuilder;
private Security $security;
public function __construct(
TimelineBuilder $timelineBuilder,
PaginatorFactory $paginatorFactory,
@@ -52,15 +36,16 @@ class TimelineCenterController extends AbstractController
/**
* @Route("/{_locale}/center/timeline",
* name="chill_center_timeline",
* methods={"GET"}
* )
*/
* 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();
}
@@ -68,24 +53,26 @@ class TimelineCenterController extends AbstractController
if (0 === count($centers)) {
throw $this->createNotFoundException();
}
$nbItems = $this->timelineBuilder->countItems('center',
[ 'centers' => $centers ]
);
$nbItems = $this->timelineBuilder->countItems(
'center',
['centers' => $centers]
);
$paginator = $this->paginatorFactory->create($nbItems);
return $this->render('@ChillMain/Timeline/index.html.twig', array
(
return $this->render(
'@ChillMain/Timeline/index.html.twig',
[
'timeline' => $this->timelineBuilder->getTimelineHTML(
'center',
[ 'centers' => $centers ],
'center',
['centers' => $centers],
$paginator->getCurrentPage()->getFirstItemNumber(),
$paginator->getItemsPerPage()
),
),
'nb_items' => $nbItems,
'paginator' => $paginator
)
'paginator' => $paginator,
]
);
}
}

View File

@@ -1,30 +1,19 @@
<?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\Controller;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Chill\MainBundle\Templating\UI\CountNotificationUser;
/**
* Class UIController
* Chill is a software for social workers
*
* @package Chill\MainBundle\Controller
* @author Julien Fastré <julien.fastre@champs-libres.coop>
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/
namespace Chill\MainBundle\Controller;
use Chill\MainBundle\Templating\UI\CountNotificationUser;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
/**
* Class UIController.
*/
class UIController extends AbstractController
{
@@ -32,9 +21,9 @@ class UIController extends AbstractController
CountNotificationUser $counter
) {
$nb = $counter->getSumNotification($this->getUser());
return $this->render('@ChillMain/UI/notification_user_counter.html.twig', [
'nb' => $nb
'nb' => $nb,
]);
}
}

View File

@@ -1,9 +1,15 @@
<?php
/**
* Chill is a software for social workers
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/
namespace Chill\MainBundle\Controller;
use Chill\MainBundle\CRUD\Controller\ApiController;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\Routing\Annotation\Route;
@@ -11,17 +17,22 @@ class UserApiController extends ApiController
{
/**
* @Route(
* "/api/1.0/main/whoami.{_format}",
* name="chill_main_user_whoami",
* requirements={
* "_format": "json"
* }
* )
* "/api/1.0/main/whoami.{_format}",
* name="chill_main_user_whoami",
* requirements={
* "_format": "json"
* }
* )
*
* @param mixed $_format
*/
public function whoami($_format): JsonResponse
{
return $this->json($this->getUser(), JsonResponse::HTTP_OK, [],
[ "groups" => [ "read" ] ]);
return $this->json(
$this->getUser(),
JsonResponse::HTTP_OK,
[],
['groups' => ['read']]
);
}
}

View File

@@ -1,42 +1,46 @@
<?php
/**
* Chill is a software for social workers
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/
declare(strict_types=1);
namespace Chill\MainBundle\Controller;
use Chill\MainBundle\CRUD\Controller\AbstractCRUDController;
use Chill\MainBundle\CRUD\Controller\CRUDController;
use Chill\MainBundle\Entity\GroupCenter;
use Chill\MainBundle\Entity\User;
use Chill\MainBundle\Form\Type\ComposedGroupCenterType;
use Chill\MainBundle\Form\UserCurrentLocationType;
use Chill\MainBundle\Form\UserPasswordType;
use Chill\MainBundle\Form\UserType;
use Chill\MainBundle\Pagination\PaginatorInterface;
use Doctrine\ORM\EntityManagerInterface;
use Psr\Log\LoggerInterface;
use RuntimeException;
use Symfony\Component\Form\Extension\Core\Type\SubmitType;
use Symfony\Component\Form\Form;
use Symfony\Component\Form\FormInterface;
use Symfony\Component\HttpFoundation\RedirectResponse;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\Form\Extension\Core\Type\SubmitType;
use Chill\MainBundle\Entity\User;
use Chill\MainBundle\Form\UserType;
use Chill\MainBundle\Entity\GroupCenter;
use Chill\MainBundle\Form\Type\ComposedGroupCenterType;
use Chill\MainBundle\Form\UserCurrentLocationType;
use Chill\MainBundle\Form\UserPasswordType;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Annotation\Route;
use Symfony\Component\Security\Core\Encoder\UserPasswordEncoderInterface;
use Symfony\Component\Validator\Validator\ValidatorInterface;
use Symfony\Component\Routing\Annotation\Route;
use Sensio\Bundle\FrameworkExtraBundle\Request\ParamConverter;
class UserController extends CRUDController
{
const FORM_GROUP_CENTER_COMPOSED = 'composed_groupcenter';
public const FORM_GROUP_CENTER_COMPOSED = 'composed_groupcenter';
private LoggerInterface $logger;
private ValidatorInterface $validator;
private UserPasswordEncoderInterface $passwordEncoder;
private ValidatorInterface $validator;
public function __construct(
LoggerInterface $chillLogger,
ValidatorInterface $validator,
@@ -47,149 +51,11 @@ class UserController extends CRUDController
$this->passwordEncoder = $passwordEncoder;
}
protected function createFormFor(string $action, $entity, string $formClass = null, array $formOptions = []): FormInterface
{
// for "new", add special config
if ('new' === $action) {
return $this->createForm(UserType::class, $entity, array(
'is_creation' => true
));
}
// default behaviour
return parent::createFormFor($action, $entity, $formClass, $formOptions);
}
protected function onPrePersist(string $action, $entity, FormInterface $form, Request $request)
{
// for "new", encode the password
if ('new' === $action) {
$entity->setPassword($this->passwordEncoder
->encodePassword($entity, $form['plainPassword']->getData()));
}
// default behaviour
parent::onPrePersist($action, $entity, $form, $request);
}
protected function orderQuery(string $action, $query, Request $request, PaginatorInterface $paginator)
{
$query->addOrderBy('e.usernameCanonical', 'ASC');
return parent::orderQuery($action, $query, $request, $paginator);
}
protected function generateTemplateParameter(string $action, $entity, Request $request, array $defaultTemplateParameters = [])
{
// add mini-forms for edit action
if ("edit" === $action) {
return array_merge(
$defaultTemplateParameters,
[
'add_groupcenter_form' => $this->createAddLinkGroupCenterForm($entity, $request)->createView(),
'delete_groupcenter_form' => array_map(
function (\Symfony\Component\Form\Form $form) {
return $form->createView();
},
iterator_to_array($this->getDeleteLinkGroupCenterByUser($entity, $request), true)
)
]
);
}
// default behaviour
return parent::generateTemplateParameter($action, $entity, $request, $defaultTemplateParameters);
}
/**
* Displays a form to edit the user password.
*
* @Route("/{_locale}/admin/user/{id}/edit_password", name="admin_user_edit_password")
*/
public function editPasswordAction(User $user, Request $request)
{
$editForm = $this->createEditPasswordForm($user);
$editForm->handleRequest($request);
if ($editForm->isSubmitted() && $editForm->isValid()) {
$password = $editForm->get('new_password')->getData();
// logging for prod
$this->logger->info('update password for an user', [
'by' => $this->getUser()->getUsername(),
'user' => $user->getUsername()
]);
$user->setPassword($this->passwordEncoder->encodePassword($user, $password));
$this->getDoctrine()->getManager()->flush();
$this->addFlash('success', $this->get('translator')->trans('Password successfully updated!'));
return $this->redirect(
$request->query->has('returnPath') ? $request->query->get('returnPath') :
$this->generateUrl('chill_crud_admin_user_edit', ['id' => $user->getId()])
);
}
return $this->render('@ChillMain/User/edit_password.html.twig', [
'entity' => $user,
'edit_form' => $editForm->createView()
]);
}
private function createEditPasswordForm(User $user): FormInterface
{
return $this->createForm(
UserPasswordType::class,
null,
[
'user' => $user
]
)
->add('submit', SubmitType::class, array('label' => 'Change password'))
->remove('actual_password');
}
/**
* @Route("/{_locale}/admin/main/user/{uid}/delete_link_groupcenter/{gcid}",
* name="admin_user_delete_groupcenter")
*/
public function deleteLinkGroupCenterAction($uid, $gcid, Request $request): RedirectResponse
{
$em = $this->getDoctrine()->getManager();
$user = $em->getRepository('ChillMainBundle:User')->find($uid);
if (!$user) {
throw $this->createNotFoundException('Unable to find User entity.');
}
$groupCenter = $em->getRepository('ChillMainBundle:GroupCenter')
->find($gcid);
if (!$groupCenter) {
throw $this->createNotFoundException('Unable to find groupCenter entity');
}
try {
$user->removeGroupCenter($groupCenter);
} catch (\RuntimeException $ex) {
$this->addFlash('error', $this->get('translator')->trans($ex->getMessage()));
return $this->redirect($this->generateUrl('chill_crud_admin_user_edit', array('id' => $uid)));
}
$em->flush();
$this->addFlash('success', $this->get('translator')
->trans('The permissions where removed.'));
return $this->redirect($this->generateUrl('chill_crud_admin_user_edit', array('id' => $uid)));
}
/**
* @Route("/{_locale}/admin/main/user/{uid}/add_link_groupcenter",
* name="admin_user_add_groupcenter")
* name="admin_user_add_groupcenter")
*
* @param mixed $uid
*/
public function addLinkGroupCenterAction(Request $request, $uid): Response
{
@@ -231,76 +97,54 @@ class UserController extends CRUDController
}
return $this->render('@ChillMain/User/edit.html.twig', [
'entity' => $user,
'edit_form' => $this->createEditForm($user)->createView(),
'entity' => $user,
'edit_form' => $this->createEditForm($user)->createView(),
'add_groupcenter_form' => $this->createAddLinkGroupCenterForm($user, $request)->createView(),
'delete_groupcenter_form' => array_map(
static fn (Form $form) => $form->createView(),
iterator_to_array($this->getDeleteLinkGroupCenterByUser($user, $request), true)
)
),
]);
}
private function getPersistedGroupCenter(GroupCenter $groupCenter)
/**
* @Route("/{_locale}/admin/main/user/{uid}/delete_link_groupcenter/{gcid}",
* name="admin_user_delete_groupcenter")
*
* @param mixed $uid
* @param mixed $gcid
*/
public function deleteLinkGroupCenterAction($uid, $gcid, Request $request): RedirectResponse
{
$em = $this->getDoctrine()->getManager();
$groupCenterManaged = $em->getRepository('ChillMainBundle:GroupCenter')
->findOneBy(array(
'center' => $groupCenter->getCenter(),
'permissionsGroup' => $groupCenter->getPermissionsGroup()
));
$user = $em->getRepository('ChillMainBundle:User')->find($uid);
if (!$groupCenterManaged) {
$em->persist($groupCenter);
return $groupCenter;
if (!$user) {
throw $this->createNotFoundException('Unable to find User entity.');
}
return $groupCenterManaged;
}
$groupCenter = $em->getRepository('ChillMainBundle:GroupCenter')
->find($gcid);
/**
* Creates a form to delete a link to a GroupCenter
*
* @param mixed $permissionsGroup The entity id
*/
private function createDeleteLinkGroupCenterForm(User $user, GroupCenter $groupCenter, $request): FormInterface
{
$returnPathParams = $request->query->has('returnPath') ? ['returnPath' => $request->query->get('returnPath')] : [];
return $this->createFormBuilder()
->setAction($this->generateUrl(
'admin_user_delete_groupcenter',
array_merge($returnPathParams, ['uid' => $user->getId(), 'gcid' => $groupCenter->getId()])
))
->setMethod('DELETE')
->add('submit', SubmitType::class, array('label' => 'Delete'))
->getForm();
}
/**
* Create a form to add a link to a groupcenter.
*/
private function createAddLinkGroupCenterForm(User $user, Request $request): FormInterface
{
$returnPathParams = $request->query->has('returnPath') ? ['returnPath' => $request->query->get('returnPath')] : [];
return $this->createFormBuilder()
->setAction($this->generateUrl(
'admin_user_add_groupcenter',
array_merge($returnPathParams, ['uid' => $user->getId()])
))
->setMethod('POST')
->add(self::FORM_GROUP_CENTER_COMPOSED, ComposedGroupCenterType::class)
->add('submit', SubmitType::class, array('label' => 'Add a new groupCenter'))
->getForm();
}
private function getDeleteLinkGroupCenterByUser(User $user, Request $request)
{
foreach ($user->getGroupCenters() as $groupCenter) {
yield $groupCenter->getId() => $this->createDeleteLinkGroupCenterForm($user, $groupCenter, $request);
if (!$groupCenter) {
throw $this->createNotFoundException('Unable to find groupCenter entity');
}
try {
$user->removeGroupCenter($groupCenter);
} catch (RuntimeException $ex) {
$this->addFlash('error', $this->get('translator')->trans($ex->getMessage()));
return $this->redirect($this->generateUrl('chill_crud_admin_user_edit', ['id' => $uid]));
}
$em->flush();
$this->addFlash('success', $this->get('translator')
->trans('The permissions where removed.'));
return $this->redirect($this->generateUrl('chill_crud_admin_user_edit', ['id' => $uid]));
}
/**
@@ -312,8 +156,8 @@ class UserController extends CRUDController
{
$user = $this->getUser();
$form = $this->createForm(UserCurrentLocationType::class, $user)
->add('submit', SubmitType::class, ['label' => 'Save'])
->handleRequest($request);
->add('submit', SubmitType::class, ['label' => 'Save'])
->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
$currentLocation = $form->get('currentLocation')->getData();
@@ -330,8 +174,174 @@ class UserController extends CRUDController
}
return $this->render('@ChillMain/User/edit_current_location.html.twig', [
'entity' => $user,
'edit_form' => $form->createView()
'entity' => $user,
'edit_form' => $form->createView(),
]);
}
/**
* Displays a form to edit the user password.
*
* @Route("/{_locale}/admin/user/{id}/edit_password", name="admin_user_edit_password")
*/
public function editPasswordAction(User $user, Request $request)
{
$editForm = $this->createEditPasswordForm($user);
$editForm->handleRequest($request);
if ($editForm->isSubmitted() && $editForm->isValid()) {
$password = $editForm->get('new_password')->getData();
// logging for prod
$this->logger->info('update password for an user', [
'by' => $this->getUser()->getUsername(),
'user' => $user->getUsername(),
]);
$user->setPassword($this->passwordEncoder->encodePassword($user, $password));
$this->getDoctrine()->getManager()->flush();
$this->addFlash('success', $this->get('translator')->trans('Password successfully updated!'));
return $this->redirect(
$request->query->has('returnPath') ? $request->query->get('returnPath') :
$this->generateUrl('chill_crud_admin_user_edit', ['id' => $user->getId()])
);
}
return $this->render('@ChillMain/User/edit_password.html.twig', [
'entity' => $user,
'edit_form' => $editForm->createView(),
]);
}
protected function createFormFor(string $action, $entity, ?string $formClass = null, array $formOptions = []): FormInterface
{
// for "new", add special config
if ('new' === $action) {
return $this->createForm(UserType::class, $entity, [
'is_creation' => true,
]);
}
// default behaviour
return parent::createFormFor($action, $entity, $formClass, $formOptions);
}
protected function generateTemplateParameter(string $action, $entity, Request $request, array $defaultTemplateParameters = [])
{
// add mini-forms for edit action
if ('edit' === $action) {
return array_merge(
$defaultTemplateParameters,
[
'add_groupcenter_form' => $this->createAddLinkGroupCenterForm($entity, $request)->createView(),
'delete_groupcenter_form' => array_map(
function (Form $form) {
return $form->createView();
},
iterator_to_array($this->getDeleteLinkGroupCenterByUser($entity, $request), true)
),
]
);
}
// default behaviour
return parent::generateTemplateParameter($action, $entity, $request, $defaultTemplateParameters);
}
protected function onPrePersist(string $action, $entity, FormInterface $form, Request $request)
{
// for "new", encode the password
if ('new' === $action) {
$entity->setPassword($this->passwordEncoder
->encodePassword($entity, $form['plainPassword']->getData()));
}
// default behaviour
parent::onPrePersist($action, $entity, $form, $request);
}
protected function orderQuery(string $action, $query, Request $request, PaginatorInterface $paginator)
{
$query->addOrderBy('e.usernameCanonical', 'ASC');
return parent::orderQuery($action, $query, $request, $paginator);
}
/**
* Create a form to add a link to a groupcenter.
*/
private function createAddLinkGroupCenterForm(User $user, Request $request): FormInterface
{
$returnPathParams = $request->query->has('returnPath') ? ['returnPath' => $request->query->get('returnPath')] : [];
return $this->createFormBuilder()
->setAction($this->generateUrl(
'admin_user_add_groupcenter',
array_merge($returnPathParams, ['uid' => $user->getId()])
))
->setMethod('POST')
->add(self::FORM_GROUP_CENTER_COMPOSED, ComposedGroupCenterType::class)
->add('submit', SubmitType::class, ['label' => 'Add a new groupCenter'])
->getForm();
}
/**
* Creates a form to delete a link to a GroupCenter.
*
* @param mixed $request
*/
private function createDeleteLinkGroupCenterForm(User $user, GroupCenter $groupCenter, $request): FormInterface
{
$returnPathParams = $request->query->has('returnPath') ? ['returnPath' => $request->query->get('returnPath')] : [];
return $this->createFormBuilder()
->setAction($this->generateUrl(
'admin_user_delete_groupcenter',
array_merge($returnPathParams, ['uid' => $user->getId(), 'gcid' => $groupCenter->getId()])
))
->setMethod('DELETE')
->add('submit', SubmitType::class, ['label' => 'Delete'])
->getForm();
}
private function createEditPasswordForm(User $user): FormInterface
{
return $this->createForm(
UserPasswordType::class,
null,
[
'user' => $user,
]
)
->add('submit', SubmitType::class, ['label' => 'Change password'])
->remove('actual_password');
}
private function getDeleteLinkGroupCenterByUser(User $user, Request $request)
{
foreach ($user->getGroupCenters() as $groupCenter) {
yield $groupCenter->getId() => $this->createDeleteLinkGroupCenterForm($user, $groupCenter, $request);
}
}
private function getPersistedGroupCenter(GroupCenter $groupCenter)
{
$em = $this->getDoctrine()->getManager();
$groupCenterManaged = $em->getRepository('ChillMainBundle:GroupCenter')
->findOneBy([
'center' => $groupCenter->getCenter(),
'permissionsGroup' => $groupCenter->getPermissionsGroup(),
]);
if (!$groupCenterManaged) {
$em->persist($groupCenter);
return $groupCenter;
}
return $groupCenterManaged;
}
}

View File

@@ -1,34 +1,39 @@
<?php
/**
* Chill is a software for social workers
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/
namespace Chill\MainBundle\DataFixtures\ORM;
use Doctrine\Common\DataFixtures\AbstractFixture;
use Doctrine\Common\DataFixtures\OrderedFixtureInterface;
use Doctrine\Persistence\ObjectManager;
use Symfony\Component\Intl\Intl;
use Chill\MainBundle\Entity\Notification;
use DateTimeImmutable;
use Doctrine\Persistence\ObjectManager;
/**
* Load notififications into database
* Load notififications into database.
*/
trait LoadAbstractNotificationsTrait
{
public function load(ObjectManager $manager)
{
return;
foreach ($this->notifs as $notif) {
$entityId = $this->getReference($notif['entityRef'])->getId();
print('Adding notification for '.$notif['entityClass'].'(entity id:'.$entityId.")\n");
echo 'Adding notification for ' . $notif['entityClass'] . '(entity id:' . $entityId . ")\n";
$newNotif = (new Notification())
->setMessage($notif['message'])
->setSender($this->getReference($notif['sender']))
->setRelatedEntityClass($notif['entityClass'])
->setRelatedEntityId($entityId)
->setDate(new \DateTimeImmutable('now'))
->setRead([])
;
->setDate(new DateTimeImmutable('now'))
->setRead([]);
foreach ($notif['addressees'] as $addressee) {
$newNotif->addAddressee($this->getReference($addressee));

View File

@@ -1,49 +1,85 @@
<?php
/**
* Chill is a software for social workers
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/
namespace Chill\MainBundle\DataFixtures\ORM;
use Chill\MainBundle\Doctrine\Model\Point;
use Chill\MainBundle\Entity\AddressReference;
use Doctrine\Common\DataFixtures\AbstractFixture;
use Doctrine\Common\DataFixtures\OrderedFixtureInterface;
use Doctrine\Persistence\ObjectManager;
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
* Load reference addresses into database.
*/
class LoadAddressReferences extends AbstractFixture implements ContainerAwareInterface, OrderedFixtureInterface {
class LoadAddressReferences extends AbstractFixture implements ContainerAwareInterface, OrderedFixtureInterface
{
protected $faker;
/**
* @var ContainerInterface
*/
private $container;
public function __construct()
{
$this->faker = \Faker\Factory::create('fr_FR');
}
/**
*
* @var ContainerInterface
*/
private $container;
public function getOrder()
{
return 51;
}
public function setContainer(ContainerInterface $container = null)
public function load(ObjectManager $manager)
{
echo "loading some reference address... \n";
for ($i = 0; 10 > $i; ++$i) {
$ar = $this->getRandomAddressReference();
$manager->persist($ar);
}
$manager->flush();
}
public function setContainer(?ContainerInterface $container = null)
{
$this->container = $container;
}
public function getOrder() {
return 51;
/**
* 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;
}
/**
* Create a random point
* Create a random point.
*
* @return Point
*/
@@ -53,43 +89,7 @@ class LoadAddressReferences extends AbstractFixture implements ContainerAwareInt
$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();
}
}

View File

@@ -1,57 +1,39 @@
<?php
/*
* Chill is a suite of a modules, Chill is a software for social workers
* Copyright (C) 2014, Champs Libres Cooperative SCRLFS, <http://www.champs-libres.coop>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
/**
* Chill is a software for social workers
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/
namespace Chill\MainBundle\DataFixtures\ORM;
use Chill\MainBundle\Entity\Center;
use Doctrine\Common\DataFixtures\AbstractFixture;
use Doctrine\Common\DataFixtures\OrderedFixtureInterface;
use Doctrine\Persistence\ObjectManager;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Symfony\Component\DependencyInjection\ContainerAwareInterface;
use Chill\MainBundle\Entity\Center;
/**
*
*
* @author Julien Fastré <julien.fastre@champs-libres.coop>
*/
class LoadCenters extends AbstractFixture implements OrderedFixtureInterface
{
public static $centers = [
[
'name' => 'Center A',
'ref' => 'centerA',
],
[
'name' => 'Center B',
'ref' => 'centerB',
],
];
public static $refs = [];
public function getOrder()
{
return 100;
}
public static $centers = array(
array(
'name' => 'Center A',
'ref' => 'centerA'
),
array(
'name' => 'Center B',
'ref' => 'centerB'
)
);
public static $refs = array();
public function load(ObjectManager $manager)
{
foreach (static::$centers as $new) {
@@ -62,7 +44,7 @@ class LoadCenters extends AbstractFixture implements OrderedFixtureInterface
$this->addReference($new['ref'], $center);
static::$refs[] = $new['ref'];
}
$manager->flush();
}
}

View File

@@ -1,5 +1,12 @@
<?php
/**
* Chill is a software for social workers
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/
namespace Chill\MainBundle\DataFixtures\ORM;
use Chill\MainBundle\Entity\Civility;
@@ -17,18 +24,18 @@ class LoadCivility extends Fixture implements FixtureGroupInterface
public function load(ObjectManager $manager): void
{
$civilities = [
['name' => ['fr' => "Monsieur" ], 'abbrev' => ['fr' => 'M.']],
['name' => ['fr' => "Madame" ], 'abbrev' => ['fr' => 'Mme']],
['name' => ['fr' => "Docteur" ], 'abbrev' => ['fr' => 'Dr']],
['name' => ['fr' => "Professeur" ], 'abbrev' => ['fr' => 'Pr']],
['name' => ['fr' => "Madame la Directrice" ], 'abbrev' => ['fr' => 'Mme']],
['name' => ['fr' => "Monsieur le Directeur" ], 'abbrev' => ['fr' => 'M.']],
['name' => ['fr' => "Madame la Maire" ]],
['name' => ['fr' => "Monsieur le Maire" ]],
['name' => ['fr' => "Maître" ], 'abbrev' => ['fr' => 'Me']],
['name' => ['fr' => 'Monsieur'], 'abbrev' => ['fr' => 'M.']],
['name' => ['fr' => 'Madame'], 'abbrev' => ['fr' => 'Mme']],
['name' => ['fr' => 'Docteur'], 'abbrev' => ['fr' => 'Dr']],
['name' => ['fr' => 'Professeur'], 'abbrev' => ['fr' => 'Pr']],
['name' => ['fr' => 'Madame la Directrice'], 'abbrev' => ['fr' => 'Mme']],
['name' => ['fr' => 'Monsieur le Directeur'], 'abbrev' => ['fr' => 'M.']],
['name' => ['fr' => 'Madame la Maire']],
['name' => ['fr' => 'Monsieur le Maire']],
['name' => ['fr' => 'Maître'], 'abbrev' => ['fr' => 'Me']],
];
foreach ( $civilities as $val) {
foreach ($civilities as $val) {
$civility = (new Civility())
->setName($val['name'])
->setAbbreviation($val['abbrev'] ?? [])

View File

@@ -1,48 +1,51 @@
<?php
/**
* Chill is a software for social workers
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/
namespace Chill\MainBundle\DataFixtures\ORM;
use Chill\MainBundle\Command\LoadCountriesCommand;
use Doctrine\Common\DataFixtures\AbstractFixture;
use Doctrine\Common\DataFixtures\OrderedFixtureInterface;
use Doctrine\Persistence\ObjectManager;
use Symfony\Component\DependencyInjection\ContainerAwareInterface;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Doctrine\Persistence\ObjectManager;
use Chill\MainBundle\Command\LoadCountriesCommand;
/**
* Load countries into database
*
* @author Julien Fastré <julien arobase fastre point info>
* Load countries into database.
*/
class LoadCountries extends AbstractFixture implements ContainerAwareInterface, OrderedFixtureInterface {
class LoadCountries extends AbstractFixture implements ContainerAwareInterface, OrderedFixtureInterface
{
/**
*
* @var ContainerInterface
*/
private $container;
public function setContainer(ContainerInterface $container = null)
public function getOrder()
{
return 20;
}
public function load(ObjectManager $manager)
{
echo "loading countries... \n";
$languages = $this->container->getParameter('chill_main.available_languages');
foreach (LoadCountriesCommand::prepareCountryList($languages) as $country) {
$manager->persist($country);
}
$manager->flush();
}
public function setContainer(?ContainerInterface $container = null)
{
$this->container = $container;
}
public function getOrder() {
return 20;
}
public function load(ObjectManager $manager) {
echo "loading countries... \n";
$languages = $this->container->getParameter('chill_main.available_languages');
foreach (LoadCountriesCommand::prepareCountryList($languages) as $country){
$manager->persist($country);
}
$manager->flush();
}
}

View File

@@ -1,45 +1,27 @@
<?php
/*
* Chill is a suite of a modules, Chill is a software for social workers
* Copyright (C) 2014, Champs Libres Cooperative SCRLFS, <http://www.champs-libres.coop>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
/**
* Chill is a software for social workers
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/
namespace Chill\MainBundle\DataFixtures\ORM;
use Chill\MainBundle\Entity\GroupCenter;
use Doctrine\Common\DataFixtures\AbstractFixture;
use Doctrine\Common\DataFixtures\OrderedFixtureInterface;
use Doctrine\Persistence\ObjectManager;
use Chill\MainBundle\Entity\GroupCenter;
use Chill\MainBundle\DataFixtures\ORM\LoadCenters;
use Chill\MainBundle\DataFixtures\ORM\LoadPermissionsGroup;
/**
*
*
* @author Julien Fastré <julien.fastre@champs-libres.coop>
*/
class LoadGroupCenters extends AbstractFixture implements OrderedFixtureInterface
{
public static $refs = [];
public function getOrder()
{
return 500;
}
public static $refs = array();
public function load(ObjectManager $manager)
{
@@ -48,16 +30,16 @@ class LoadGroupCenters extends AbstractFixture implements OrderedFixtureInterfac
$GroupCenter = new GroupCenter();
$GroupCenter->setCenter($this->getReference($centerRef));
$GroupCenter->setPermissionsGroup($this->getReference($permissionGroupRef));
$manager->persist($GroupCenter);
$reference = $centerRef.'_'.$permissionGroupRef;
$reference = $centerRef . '_' . $permissionGroupRef;
$this->addReference($reference, $GroupCenter);
static::$refs[] = $reference;
echo "Creating $reference... \n";
echo "Creating {$reference}... \n";
}
}
$manager->flush();
}
}

View File

@@ -1,60 +1,57 @@
<?php
/**
* Chill is a software for social workers
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/
namespace Chill\MainBundle\DataFixtures\ORM;
use Chill\MainBundle\Entity\Language;
use Doctrine\Common\DataFixtures\AbstractFixture;
use Doctrine\Common\DataFixtures\OrderedFixtureInterface;
use Doctrine\Persistence\ObjectManager;
use Symfony\Component\DependencyInjection\ContainerAwareInterface;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Doctrine\Persistence\ObjectManager;
use Symfony\Component\Intl\Intl;
use Chill\MainBundle\Entity\Language;
/**
* Load languages into database
*
* @author Julien Fastré <julien arobase fastre point info>
* Load languages into database.
*/
class LoadLanguages extends AbstractFixture implements ContainerAwareInterface, OrderedFixtureInterface
{
// The regional version of language are language with _ in the code
// This array contains regional code to not exclude
private $regionalVersionToInclude = ["ro_MD"];
// Array of ancien languages (to exclude)
private $ancientToExclude = ["ang", "egy", "fro", "goh", "grc", "la", "non", "peo", "pro", "sga",
"dum", "enm", "frm", "gmh", "mga", "akk", "phn", "zxx", "got", "und"];
private $ancientToExclude = ['ang', 'egy', 'fro', 'goh', 'grc', 'la', 'non', 'peo', 'pro', 'sga',
'dum', 'enm', 'frm', 'gmh', 'mga', 'akk', 'phn', 'zxx', 'got', 'und', ];
/**
*
* @var ContainerInterface
*/
private $container;
public function setContainer(ContainerInterface $container = null)
{
$this->container = $container;
}
// The regional version of language are language with _ in the code
// This array contains regional code to not exclude
private $regionalVersionToInclude = ['ro_MD'];
public function getOrder() {
public function getOrder()
{
return 10;
}
public function load(ObjectManager $manager) {
public function load(ObjectManager $manager)
{
echo "loading languages... \n";
foreach (Intl::getLanguageBundle()->getLanguageNames() as $code => $language) {
if (
!in_array($code, $this->regionalVersionToInclude)
&&
!in_array($code, $this->ancientToExclude)
&& !in_array($code, $this->ancientToExclude)
) {
$lang = (new Language())
->setId($code)
->setName($this->prepareName($code))
;
->setId($code)
->setName($this->prepareName($code));
$manager->persist($lang);
}
}
@@ -62,12 +59,18 @@ class LoadLanguages extends AbstractFixture implements ContainerAwareInterface,
$manager->flush();
}
public function setContainer(?ContainerInterface $container = null)
{
$this->container = $container;
}
/**
* Prepare names for languages.
*
* @return string[] languages name indexed by available language code
*/
private function prepareName(string $languageCode): array {
private function prepareName(string $languageCode): array
{
$names = [];
foreach ($this->container->getParameter('chill_main.available_languages') as $lang) {
@@ -76,6 +79,4 @@ class LoadLanguages extends AbstractFixture implements ContainerAwareInterface,
return $names;
}
}

View File

@@ -1,57 +1,56 @@
<?php
/**
* Chill is a software for social workers
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/
namespace Chill\MainBundle\DataFixtures\ORM;
use Chill\MainBundle\Entity\LocationType;
use Doctrine\Common\DataFixtures\AbstractFixture;
use Doctrine\Common\DataFixtures\OrderedFixtureInterface;
use Doctrine\Persistence\ObjectManager;
use Symfony\Component\DependencyInjection\ContainerAwareInterface;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Doctrine\Persistence\ObjectManager;
use Chill\MainBundle\Entity\LocationType;
/**
* Load location types into database
*
* @author Champs Libres
* Load location types into database.
*/
class LoadLocationType extends AbstractFixture implements ContainerAwareInterface, OrderedFixtureInterface {
class LoadLocationType extends AbstractFixture implements ContainerAwareInterface, OrderedFixtureInterface
{
/**
*
* @var ContainerInterface
*/
private $container;
public function setContainer(ContainerInterface $container = null)
public function getOrder()
{
$this->container = $container;
}
public function getOrder() {
return 52;
}
public function load(ObjectManager $manager): void {
public function load(ObjectManager $manager): void
{
echo "loading some location type... \n";
$arr = [
[
'name' => ['fr' => 'Mairie'],
'address_required' => LocationType::STATUS_OPTIONAL
'address_required' => LocationType::STATUS_OPTIONAL,
],
[
'name' => ['fr' => 'Guichet d\'accueil'],
'address_required' => LocationType::STATUS_OPTIONAL
'address_required' => LocationType::STATUS_OPTIONAL,
],
[
'name' => ['fr' => 'Domicile de l\'usager'],
'address_required' => LocationType::STATUS_REQUIRED
'address_required' => LocationType::STATUS_REQUIRED,
],
[
'name' => ['fr' => 'Centre d\'aide sociale'],
'address_required' => LocationType::STATUS_OPTIONAL
'address_required' => LocationType::STATUS_OPTIONAL,
],
];
@@ -66,4 +65,9 @@ class LoadLocationType extends AbstractFixture implements ContainerAwareInterfac
$manager->flush();
}
}
public function setContainer(?ContainerInterface $container = null)
{
$this->container = $container;
}
}

View File

@@ -1,87 +1,72 @@
<?php
/*
* Chill is a suite of a modules, Chill is a software for social workers
* Copyright (C) 2014, Champs Libres Cooperative SCRLFS, <http://www.champs-libres.coop>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
/**
* Chill is a software for social workers
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/
namespace Chill\MainBundle\DataFixtures\ORM;
use Chill\MainBundle\Entity\PermissionsGroup;
use Doctrine\Common\DataFixtures\AbstractFixture;
use Doctrine\Common\DataFixtures\OrderedFixtureInterface;
use Doctrine\Persistence\ObjectManager;
use Chill\MainBundle\Entity\PermissionsGroup;
/**
*
*
* @author Julien Fastré <julien.fastre@champs-libres.coop>
*/
class LoadPermissionsGroup extends AbstractFixture implements OrderedFixtureInterface
{
public static $permissionGroup = [
[
'name' => 'social',
'role_scopes' => [
'role_scope_CHILL_FOO_EDIT_social',
'role_scope_CHILL_FOO_SEE_administrative',
'role_scope_CHILL_FOO_EDIT_all',
],
],
[
'name' => 'administrative',
'role_scopes' => [
'role_scope_CHILL_FOO_SEE_social',
'role_scope_CHILL_FOO_EDIT_administrative',
'role_scope_CHILL_FOO_EDIT_all',
],
],
[
'name' => 'direction',
'role_scopes' => [
'role_scope_CHILL_FOO_EDIT_all',
'role_scope_CHILL_FOO_SEE_DETAILS_social',
'role_scope_CHILL_FOO_SEE_DETAILS_administrative',
],
],
];
public static $refs = [];
public function getOrder()
{
return 400;
}
public static $permissionGroup = array(
array(
'name' => 'social',
'role_scopes' => array(
'role_scope_CHILL_FOO_EDIT_social',
'role_scope_CHILL_FOO_SEE_administrative',
"role_scope_CHILL_FOO_EDIT_all"
)
),
array(
'name' => 'administrative',
'role_scopes' => array(
"role_scope_CHILL_FOO_SEE_social",
"role_scope_CHILL_FOO_EDIT_administrative",
"role_scope_CHILL_FOO_EDIT_all"
)
),
array(
'name' => 'direction',
'role_scopes' => array(
"role_scope_CHILL_FOO_EDIT_all",
"role_scope_CHILL_FOO_SEE_DETAILS_social",
"role_scope_CHILL_FOO_SEE_DETAILS_administrative"
)
)
);
public static $refs = array();
public function load(ObjectManager $manager)
{
foreach (static::$permissionGroup as $new) {
$permissionGroup = new PermissionsGroup();
$permissionGroup->setName($new['name']);
foreach ($new['role_scopes'] as $roleScopeRef) {
$permissionGroup->addRoleScope($this->getReference($roleScopeRef));
}
$manager->persist($permissionGroup);
$reference = 'permission_group_'.$new['name'];
echo "Creating $reference \n";
$reference = 'permission_group_' . $new['name'];
echo "Creating {$reference} \n";
$this->setReference($reference, $permissionGroup);
static::$refs[] = $reference;
}
$manager->flush();
}
}

View File

@@ -1,48 +1,334 @@
<?php
/*
/**
* Chill is a software for social workers
*
* Copyright (C) 2014-2016, 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/>.
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/
namespace Chill\MainBundle\DataFixtures\ORM;
use Chill\MainBundle\Doctrine\Model\Point;
use Chill\MainBundle\Entity\Country;
use Chill\MainBundle\Entity\PostalCode;
use Doctrine\Common\DataFixtures\AbstractFixture;
use Doctrine\Common\DataFixtures\OrderedFixtureInterface;
use Doctrine\Persistence\ObjectManager;
use Chill\MainBundle\Entity\PostalCode;
use function strtolower;
use function ucwords;
/**
* Description of LoadPostalCodes
*
* @author Julien Fastré <julien.fastre@champs-libres.coop>
* @author Champs Libres <info@champs-libres.coop>
* Description of LoadPostalCodes.
*/
class LoadPostalCodes extends AbstractFixture implements OrderedFixtureInterface
{
public static $refs = [];
private static $postalCodeBelgium = <<<'EOF'
1000,BRUXELLES,BE
1020,BRUXELLES,BE
1030,SCHAERBEEK,BE
1040,ETTERBEEK,BE
1050,IXELLES,BE
1060,SAINT-GILLES,BE
1070,ANDERLECHT,BE
1080,MOLENBEEK-SAINT-JEAN,BE
1081,KOEKELBERG,BE
1082,BERCHEM-SAINTE-AGATHE,BE
1083,GANSHOREN,BE
1090,JETTE,BE
1120,BRUXELLES,BE
1130,BRUXELLES,BE
1140,EVERE,BE
1150,WOLUWE-SAINT-PIERRE,BE
1160,AUDERGHEM,BE
1170,WATERMAEL-BOITSFORT,BE
1180,UCCLE,BE
1190,FOREST,BE
1200,WOLUWE-SAINT-LAMBERT,BE
1210,SAINT-JOSSE-TEN-NOODE,BE
1300,WAVRE,BE
1300,WAVRE,BE
1301,WAVRE,BE
1310,LA HULPE,BE
1315,INCOURT,BE
1315,INCOURT,BE
1315,INCOURT,BE
1315,INCOURT,BE
1315,INCOURT,BE
1320,BEAUVECHAIN,BE
EOF;
private static $postalCodeFrance = <<<'EOF'
85000,LA ROCHE SUR YON,FR,85191,46.6675261644,-1.4077954093,INSEE
85000,MOUILLERON LE CAPTIF,FR,85155,46.7104764993,-1.46129661418,INSEE
85100,LES SABLES D OLONNE,FR,85194,46.5007612799,-1.79255128677,INSEE
85110,STE CECILE,FR,85202,46.7309688326,-1.12107316048,INSEE
85110,LA JAUDONNIERE,FR,85115,46.6488761831,-0.962477574588,INSEE
85110,ST GERMAIN DE PRINCAY,FR,85220,46.7356314659,-1.04299885081,INSEE
85110,MONSIREIGNE,FR,85145,46.7383480028,-0.931953130855,INSEE
85110,ST VINCENT STERLANGES,FR,85276,46.7397220689,-1.08371759277,INSEE
85110,SIGOURNAIS,FR,85282,46.7140097406,-0.98747730882,INSEE
85110,CHANTONNAY,FR,85051,46.6690167793,-1.04372588019,INSEE
85110,ST PROUANT,FR,85266,46.7502017421,-0.974504061491,INSEE
85120,LA CHAPELLE AUX LYS,FR,85053,46.6221916887,-0.642706103195,INSEE
85120,VOUVANT,FR,85305,46.5626835135,-0.764380170382,INSEE
85120,ANTIGNY,FR,85005,46.6191770822,-0.767030058653,INSEE
85120,ST MAURICE DES NOUES,FR,85251,46.5955876221,-0.724327725888,INSEE
85120,LOGE FOUGEREUSE,FR,85125,46.6180854641,-0.6899276733,INSEE
85120,LA TARDIERE,FR,85289,46.663737434,-0.727562430214,INSEE
85120,LA CHATAIGNERAIE,FR,85059,46.6416143401,-0.739561966419,INSEE
85120,ST HILAIRE DE VOUST,FR,85229,46.5914988312,-0.651486245674,INSEE
85120,BREUIL BARRET,FR,85037,46.6503266235,-0.671948654426,INSEE
85120,ST PIERRE DU CHEMIN,FR,85264,46.6957771744,-0.701777715154,INSEE
85130,LA GAUBRETIERE,FR,85097,46.9345007303,-1.05578200702,INSEE
85130,ST MARTIN DES TILLEULS,FR,85247,46.9711539531,-1.06282621567,INSEE
85130,TIFFAUGES,FR,85293,47.0020573556,-1.09858009203,INSEE
85130,CHANVERRIE,FR,85302,46.9634774521,-0.985340006089,INSEE
85130,BAZOGES EN PAILLERS,FR,85013,46.9213757643,-1.14415666313,INSEE
85130,LES LANDES GENUSSON,FR,85119,46.9663828627,-1.12900644447,INSEE
85130,ST AUBIN DES ORMEAUX,FR,85198,46.9958175597,-1.04216568722,INSEE
85140,ESSARTS EN BOCAGE,FR,85084,46.7806739038,-1.22925967851,INSEE
85140,LA MERLATIERE,FR,85142,46.7557703112,-1.29794577,INSEE
85140,ST MARTIN DES NOYERS,FR,85246,46.7239461187,-1.20379080965,INSEE
85140,CHAUCHE,FR,85064,46.8282791899,-1.27090860656,INSEE
85150,ST MATHURIN,FR,85250,46.5686332748,-1.70787622288,INSEE
85150,MARTINET,FR,85138,46.6620680463,-1.6772013304,INSEE
85150,STE FLAIVE DES LOUPS,FR,85211,46.611019489,-1.58031627863,INSEE
85150,STE FOY,FR,85214,46.5327600427,-1.69243074733,INSEE
85150,ST JULIEN DES LANDES,FR,85236,46.6395925444,-1.7159724914,INSEE
85150,ST GEORGES DE POINTINDOUX,FR,85218,46.6423470977,-1.62881823574,INSEE
85150,LE GIROUARD,FR,85099,46.5726064909,-1.58872487716,INSEE
85150,LANDERONDE,FR,85118,46.6549237031,-1.57351777893,INSEE
85150,LES ACHARDS,FR,85152,46.6163645636,-1.65038156849,INSEE
85150,VAIRE,FR,85298,46.6055340621,-1.74863672042,INSEE
85160,ST JEAN DE MONTS,FR,85234,46.8021968737,-2.04839789308,INSEE
85170,BELLEVIGNY,FR,85019,46.7756383534,-1.43313700054,INSEE
85170,LE POIRE SUR VIE,FR,85178,46.769919754,-1.50488626452,INSEE
85170,BEAUFOU,FR,85015,46.8191122027,-1.52479250801,INSEE
85170,DOMPIERRE SUR YON,FR,85081,46.7599858068,-1.37275519417,INSEE
85170,LES LUCS SUR BOULOGNE,FR,85129,46.8527299002,-1.48398928084,INSEE
85170,ST DENIS LA CHEVASSE,FR,85208,46.8325959261,-1.3830312677,INSEE
85180,LES SABLES D OLONNE,FR,85194,46.5007612799,-1.79255128677,INSEE
85190,AIZENAY,FR,85003,46.7384516809,-1.62702889721,INSEE
85190,VENANSAULT,FR,85300,46.685677363,-1.54112129191,INSEE
85190,MACHE,FR,85130,46.771364944,-1.69526445062,INSEE
85190,BEAULIEU SOUS LA ROCHE,FR,85016,46.6872087211,-1.62355064963,INSEE
85190,LA GENETOUZE,FR,85098,46.7244524541,-1.50410719693,INSEE
85200,PISSOTTE,FR,85176,46.5010870694,-0.808352236192,INSEE
85200,AUCHAY SUR VENDEE,FR,85009,46.4474386161,-0.876574265149,INSEE
85200,FONTENAY LE COMTE,FR,85092,46.4563186117,-0.793449510859,INSEE
85200,MERVENT,FR,85143,46.5325327351,-0.748519927998,INSEE
85200,DOIX LES FONTAINES,FR,85080,46.3849492327,-0.806840287485,INSEE
85200,LONGEVES,FR,85126,46.4722105292,-0.858917690239,INSEE
85200,ST MARTIN DE FRAIGNEAU,FR,85244,46.4289052087,-0.758948963227,INSEE
85200,SERIGNE,FR,85281,46.5054321828,-0.848819460581,INSEE
85200,BOURNEAU,FR,85033,46.5476882922,-0.813838020265,INSEE
85200,ST MICHEL LE CLOUCQ,FR,85256,46.4861591475,-0.743056336646,INSEE
85200,MONTREUIL,FR,85148,46.3973419593,-0.840846860992,INSEE
85200,L ORBRIE,FR,85167,46.4997145725,-0.77427886573,INSEE
85210,ST JEAN DE BEUGNE,FR,85233,46.5196817523,-1.10826075013,INSEE
85210,ST MARTIN LARS EN STE HERMINE,FR,85248,46.5970244335,-0.976384286709,INSEE
85210,LA REORTHE,FR,85188,46.6113748938,-1.04881036553,INSEE
85210,ST AUBIN LA PLAINE,FR,85199,46.5040293195,-1.06506577005,INSEE
85210,ST JUIRE CHAMPGILLON,FR,85235,46.5882648491,-1.00959676911,INSEE
85210,LA CHAPELLE THEMER,FR,85056,46.5639307793,-0.960376685588,INSEE
85210,ST ETIENNE DE BRILLOUET,FR,85209,46.5138850327,-1.01157660374,INSEE
85210,STE HERMINE,FR,85223,46.5572659953,-1.07210861039,INSEE
85210,THIRE,FR,85290,46.5433098199,-1.00699777534,INSEE
85220,ST MAIXENT SUR VIE,FR,85239,46.7329496925,-1.82595152879,INSEE
85220,LA CHAIZE GIRAUD,FR,85045,46.6476375058,-1.81865076161,INSEE
85220,LANDEVIEILLE,FR,85120,46.6444349925,-1.7854367847,INSEE
85220,L AIGUILLON SUR VIE,FR,85002,46.6706426618,-1.82599992318,INSEE
85220,COEX,FR,85070,46.7078707764,-1.75788339462,INSEE
85220,ST REVEREND,FR,85268,46.7057741864,-1.83155480996,INSEE
85220,APREMONT,FR,85006,46.7572682339,-1.74841313647,INSEE
85220,LA CHAPELLE HERMIER,FR,85054,46.6826679204,-1.72083372442,INSEE
85220,COMMEQUIERS,FR,85071,46.7674752232,-1.82534079642,INSEE
85230,BEAUVOIR SUR MER,FR,85018,46.9086155426,-2.06349351302,INSEE
85230,BOUIN,FR,85029,46.9815930867,-2.00423808381,INSEE
85230,ST URBAIN,FR,85273,46.8818371328,-2.01607828912,INSEE
85230,ST GERVAIS,FR,85221,46.9285711589,-1.98059327519,INSEE
85240,MARILLET,FR,85136,46.5667525381,-0.634287713939,INSEE
85240,ST HILAIRE DES LOGES,FR,85227,46.4747117878,-0.650611151998,INSEE
85240,FAYMOREAU,FR,85087,46.5427361252,-0.624271378946,INSEE
85240,XANTON CHASSENON,FR,85306,46.4519408659,-0.706316598666,INSEE
85240,FOUSSAIS PAYRE,FR,85094,46.5230750581,-0.687135962627,INSEE
85240,RIVES D AUTISE,FR,85162,46.424726987,-0.665995249042,INSEE
85240,PUY DE SERRE,FR,85184,46.5650384637,-0.680144631346,INSEE
85250,ST ANDRE GOULE D OIE,FR,85196,46.8410224478,-1.19644211396,INSEE
85250,LA RABATELIERE,FR,85186,46.8584147661,-1.2569733759,INSEE
85250,CHAVAGNES EN PAILLERS,FR,85065,46.8951394423,-1.24054768713,INSEE
85250,ST FULGENT,FR,85215,46.8705618525,-1.16246465678,INSEE
85250,VENDRENNES,FR,85301,46.8226741756,-1.11650982164,INSEE
85260,LA COPECHAGNIERE,FR,85072,46.8523980181,-1.34349746898,INSEE
85260,L HERBERGEMENT,FR,85108,46.9166207979,-1.37033557148,INSEE
85260,MONTREVERD,FR,85197,46.9277672307,-1.4126154924,INSEE
85260,LES BROUZILS,FR,85038,46.8854235235,-1.33186892233,INSEE
85270,NOTRE DAME DE RIEZ,FR,85189,46.7532179022,-1.8935292542,INSEE
85270,ST HILAIRE DE RIEZ,FR,85226,46.7432732188,-1.96439228965,INSEE
85280,LA FERRIERE,FR,85089,46.7215872927,-1.33469332327,INSEE
85290,MORTAGNE SUR SEVRE,FR,85151,46.9910941319,-0.946500033344,INSEE
85290,ST LAURENT SUR SEVRE,FR,85238,46.9506837971,-0.901123752328,INSEE
85300,CHALLANS,FR,85047,46.8354416653,-1.84036683139,INSEE
85300,FROIDFOND,FR,85095,46.8789464367,-1.75511438567,INSEE
85300,SOULLANS,FR,85284,46.7951288466,-1.91392699457,INSEE
85300,LE PERRIER,FR,85172,46.8196487652,-1.97926629071,INSEE
85300,SALLERTAINE,FR,85280,46.8659054157,-1.94894081389,INSEE
85310,LA CHAIZE LE VICOMTE,FR,85046,46.6729533879,-1.29188591019,INSEE
85310,NESMY,FR,85160,46.5921936479,-1.40947698594,INSEE
85310,RIVES DE L YON,FR,85213,46.605637391,-1.3354497172,INSEE
85310,LE TABLIER,FR,85285,46.5596307281,-1.32788759657,INSEE
85320,CHATEAU GUIBERT,FR,85061,46.5741109302,-1.25524886228,INSEE
85320,LES PINEAUX,FR,85175,46.599225902,-1.17865799724,INSEE
85320,ROSNAY,FR,85193,46.5324344973,-1.3007139449,INSEE
85320,BESSAY,FR,85023,46.5397253861,-1.17028433093,INSEE
85320,LA BRETONNIERE LA CLAYE,FR,85036,46.4879459421,-1.26773426545,INSEE
85320,CORPE,FR,85073,46.5050234767,-1.17034425311,INSEE
85320,MAREUIL SUR LAY DISSAIS,FR,85135,46.5335825488,-1.22688907859,INSEE
85320,PEAULT,FR,85171,46.502029199,-1.22708559855,INSEE
85320,LA COUTURE,FR,85074,46.523938732,-1.26493227292,INSEE
85320,MOUTIERS SUR LE LAY,FR,85157,46.5651677306,-1.16826489836,INSEE
85320,STE PEXINE,FR,85261,46.5596018797,-1.12406235901,INSEE
85330,NOIRMOUTIER EN L ILE,FR,85163,47.0086655085,-2.26243620205,INSEE
85340,L ILE D OLONNE,FR,85112,46.570163703,-1.7737502368,INSEE
85340,LES SABLES D OLONNE,FR,85194,46.5007612799,-1.79255128677,INSEE
85350,L ILE D YEU,FR,85113,46.7093514816,-2.34712702345,INSEE
85360,LA TRANCHE SUR MER,FR,85294,46.3564601605,-1.43136322126,INSEE
85370,MOUZEUIL ST MARTIN,FR,85158,46.4591118412,-0.984449849889,INSEE
85370,NALLIERS,FR,85159,46.4658962703,-1.03958611312,INSEE
85370,LE LANGON,FR,85121,46.4393119039,-0.947017086151,INSEE
85390,BAZOGES EN PAREDS,FR,85014,46.6602005512,-0.914053446792,INSEE
85390,ST MAURICE LE GIRARD,FR,85252,46.6398624578,-0.810875649028,INSEE
85390,TALLUD STE GEMME,FR,85287,46.6949386862,-0.886169517112,INSEE
85390,CHAVAGNES LES REDOUX,FR,85066,46.7101499475,-0.915900131393,INSEE
85390,CHEFFOIS,FR,85067,46.6786935635,-0.782949851125,INSEE
85390,MOUILLERON ST GERMAIN,FR,85154,46.6612700667,-0.846784201071,INSEE
85400,STE GEMME LA PLAINE,FR,85216,46.4732196212,-1.11103084694,INSEE
85400,LAIROUX,FR,85117,46.4496842668,-1.27114022202,INSEE
85400,LUCON,FR,85128,46.4510564854,-1.16449285012,INSEE
85400,LES MAGNILS REIGNIERS,FR,85131,46.4635045649,-1.210635375,INSEE
85400,CHASNAIS,FR,85058,46.4459908481,-1.2385924923,INSEE
85410,ST LAURENT DE LA SALLE,FR,85237,46.5854041653,-0.922177315485,INSEE
85410,LA CAILLERE ST HILAIRE,FR,85040,46.6293907412,-0.933153931505,INSEE
85410,ST CYR DES GATS,FR,85205,46.572397925,-0.86344873853,INSEE
85410,THOUARSAIS BOUILDROUX,FR,85292,46.6062740621,-0.873461023865,INSEE
85410,CEZAIS,FR,85041,46.5917363748,-0.802618133558,INSEE
85410,ST SULPICE EN PAREDS,FR,85271,46.6130038733,-0.8310839288,INSEE
85420,LE MAZEAU,FR,85139,46.3298580373,-0.672957405035,INSEE
85420,LIEZ,FR,85123,46.3698532376,-0.70502476758,INSEE
85420,BOUILLE COURDAULT,FR,85028,46.3847932448,-0.684917815779,INSEE
85420,DAMVIX,FR,85078,46.32063079,-0.743504259797,INSEE
85420,MAILLE,FR,85132,46.3417503082,-0.787487297301,INSEE
85420,ST PIERRE LE VIEUX,FR,85265,46.4009643491,-0.742816267425,INSEE
85420,ST SIGISMOND,FR,85269,46.3368577973,-0.707293731101,INSEE
85420,MAILLEZAIS,FR,85133,46.3642178261,-0.750260780443,INSEE
85420,RIVES D AUTISE,FR,85162,46.424726987,-0.665995249042,INSEE
85430,AUBIGNY LES CLOUZEAUX,FR,85008,46.6028241769,-1.46743549114,INSEE
85430,NIEUL LE DOLENT,FR,85161,46.5676509922,-1.51560194548,INSEE
85430,LA BOISSIERE DES LANDES,FR,85026,46.5581861734,-1.44371985689,INSEE
85440,ST HILAIRE LA FORET,FR,85231,46.4551155186,-1.53048160541,INSEE
85440,TALMONT ST HILAIRE,FR,85288,46.475786445,-1.62751498166,INSEE
85440,POIROUX,FR,85179,46.5107890457,-1.53929317556,INSEE
85440,GROSBREUIL,FR,85103,46.5390090882,-1.6072005484,INSEE
85440,AVRILLE,FR,85010,46.4744272125,-1.49524360118,INSEE
85450,CHAMPAGNE LES MARAIS,FR,85049,46.3735020647,-1.13380723653,INSEE
85450,LA TAILLEE,FR,85286,46.3852513569,-0.941017792066,INSEE
85450,CHAILLE LES MARAIS,FR,85042,46.3853555319,-1.01044079362,INSEE
85450,VOUILLE LES MARAIS,FR,85304,46.3891941167,-0.968106001439,INSEE
85450,MOREILLES,FR,85149,46.4218721314,-1.09404530407,INSEE
85450,PUYRAVAULT,FR,85185,46.3653834101,-1.09115660367,INSEE
85450,STE RADEGONDE DES NOYERS,FR,85267,46.3694246909,-1.06671995264,INSEE
85460,LA FAUTE SUR MER,FR,85307,46.3199919131,-1.31487049579,INSEE
85460,L AIGUILLON SUR MER,FR,85001,46.304138479,-1.2623239198,INSEE
85470,BRETIGNOLLES SUR MER,FR,85035,46.6374826705,-1.86324200464,INSEE
85470,BREM SUR MER,FR,85243,46.6118566989,-1.81003917923,INSEE
85480,BOURNEZEAU,FR,85034,46.6296975315,-1.14101742229,INSEE
85480,FOUGERE,FR,85093,46.6617881911,-1.23612691916,INSEE
85480,ST HILAIRE LE VOUHIS,FR,85232,46.6859198669,-1.15222590884,INSEE
85480,THORIGNY,FR,85291,46.6179795025,-1.24888057642,INSEE
85490,BENET,FR,85020,46.368873213,-0.613959918706,INSEE
85500,BEAUREPAIRE,FR,85017,46.9050210355,-1.10144867013,INSEE
85500,ST PAUL EN PAREDS,FR,85259,46.8303789022,-0.964515191283,INSEE
85500,LES HERBIERS,FR,85109,46.8666125813,-1.02216086186,INSEE
85500,MESNARD LA BAROTIERE,FR,85144,46.851716793,-1.10954466033,INSEE
85500,CHANVERRIE,FR,85302,46.9634774521,-0.985340006089,INSEE
85510,ROCHETREJOUX,FR,85192,46.7852546732,-0.996743019108,INSEE
85510,LE BOUPERE,FR,85031,46.7877960262,-0.930897406714,INSEE
85520,JARD SUR MER,FR,85114,46.4246376808,-1.60014921643,INSEE
85520,ST VINCENT SUR JARD,FR,85278,46.4297504489,-1.54956205778,INSEE
85530,LA BRUFFIERE,FR,85039,47.0148006973,-1.18329758318,INSEE
85540,LE CHAMP ST PERE,FR,85050,46.5157210212,-1.33946630196,INSEE
85540,LE GIVRE,FR,85101,46.4729146043,-1.40256149118,INSEE
85540,MOUTIERS LES MAUXFAITS,FR,85156,46.489279204,-1.43622387207,INSEE
85540,ST VINCENT SUR GRAON,FR,85277,46.5034756656,-1.382954206,INSEE
85540,LA JONCHERE,FR,85116,46.4358647401,-1.38517843312,INSEE
85540,ST BENOIST SUR MER,FR,85201,46.4266286403,-1.3399129604,INSEE
85540,CURZON,FR,85077,46.4512376923,-1.30138059216,INSEE
85540,ST AVAUGOURD DES LANDES,FR,85200,46.5136722903,-1.47528120789,INSEE
85540,ST CYR EN TALMONDAIS,FR,85206,46.4597334032,-1.33722144355,INSEE
85550,LA BARRE DE MONTS,FR,85012,46.8722784154,-2.09984018879,INSEE
85560,LE BERNARD,FR,85022,46.44832528,-1.43979865314,INSEE
85560,LONGEVILLE SUR MER,FR,85127,46.4091029013,-1.47711855345,INSEE
85570,POUILLE,FR,85181,46.5022256779,-0.955223380119,INSEE
85570,ST VALERIEN,FR,85274,46.5348508899,-0.944470507825,INSEE
85570,L HERMENAULT,FR,85110,46.5156262822,-0.898430664265,INSEE
85570,PETOSSE,FR,85174,46.4796848965,-0.911734176662,INSEE
85570,ST MARTIN DES FONTAINES,FR,85245,46.5464637508,-0.907394581139,INSEE
85570,MARSAIS STE RADEGONDE,FR,85137,46.5380790745,-0.868868309437,INSEE
85580,ST DENIS DU PAYRE,FR,85207,46.4118936776,-1.27222282402,INSEE
85580,ST MICHEL EN L HERM,FR,85255,46.3366903175,-1.2483968538,INSEE
85580,TRIAIZE,FR,85297,46.3792685111,-1.19928351422,INSEE
85580,GRUES,FR,85104,46.3813091348,-1.32364519268,INSEE
85590,TREIZE VENTS,FR,85296,46.9168130123,-0.845959158017,INSEE
85590,LES EPESSES,FR,85082,46.8917166066,-0.903422756546,INSEE
85590,MALLIEVRE,FR,85134,46.9112847287,-0.864977836096,INSEE
85590,ST MALO DU BOIS,FR,85240,46.9248120291,-0.914182961099,INSEE
85590,ST MARS LA REORTHE,FR,85242,46.8597253005,-0.925777900202,INSEE
85600,LA BOISSIERE DE MONTAIGU,FR,85025,46.9451858636,-1.1916392484,INSEE
85600,MONTAIGU VENDEE,FR,85146,46.9759800852,-1.31364530268,INSEE
85600,TREIZE SEPTIERS,FR,85295,46.9975586143,-1.23193361154,INSEE
85610,CUGAND,FR,85076,47.0602388146,-1.25289811103,INSEE
85610,LA BERNARDIERE,FR,85021,47.0361828072,-1.27390355206,INSEE
85620,ROCHESERVIERE,FR,85190,46.9274273036,-1.50132208111,INSEE
85630,BARBATRE,FR,85011,46.9335754783,-2.16743559847,INSEE
85640,MOUCHAMPS,FR,85153,46.7870550926,-1.05454102867,INSEE
85660,ST PHILBERT DE BOUAINE,FR,85262,46.9927907526,-1.5073882242,INSEE
85670,LA CHAPELLE PALLUAU,FR,85055,46.7873638997,-1.62492863273,INSEE
85670,FALLERON,FR,85086,46.8623928354,-1.70108938038,INSEE
85670,ST ETIENNE DU BOIS,FR,85210,46.8418481774,-1.59617737479,INSEE
85670,ST PAUL MONT PENIT,FR,85260,46.8070059547,-1.66964833149,INSEE
85670,ST CHRISTOPHE DU LIGNERON,FR,85204,46.8151386519,-1.74035413493,INSEE
85670,GRAND LANDES,FR,85102,46.8483283063,-1.64453002578,INSEE
85670,PALLUAU,FR,85169,46.8063002019,-1.60225256402,INSEE
85680,LA GUERINIERE,FR,85106,46.9669962053,-2.2302799245,INSEE
85690,NOTRE DAME DE MONTS,FR,85164,46.8424284611,-2.10928732775,INSEE
85700,SEVREMONT,FR,85090,46.8211105864,-0.854584153953,INSEE
85700,LA MEILLERAIE TILLAY,FR,85140,46.742582825,-0.85478763606,INSEE
85700,MONTOURNAIS,FR,85147,46.7502937556,-0.770013941158,INSEE
85700,POUZAUGES,FR,85182,46.7812581702,-0.828778359084,INSEE
85700,REAUMUR,FR,85187,46.7145137269,-0.816742537248,INSEE
85700,MENOMBLET,FR,85141,46.7301338667,-0.728654955878,INSEE
85700,ST MESMIN,FR,85254,46.8005779435,-0.748892533741,INSEE
85710,BOIS DE CENE,FR,85024,46.9479643351,-1.89668693466,INSEE
85710,CHATEAUNEUF,FR,85062,46.916944435,-1.9261131832,INSEE
85710,LA GARNACHE,FR,85096,46.8977541296,-1.82443040539,INSEE
85740,L EPINE,FR,85083,46.9843405667,-2.26449527608,INSEE
85750,ANGLES,FR,85004,46.3870511077,-1.40049386944,INSEE
85770,LES VELLUIRE SUR VENDEE,FR,85177,46.4190919441,-0.910475769222,INSEE
85770,VIX,FR,85303,46.3543018169,-0.856628326667,INSEE
85770,LE GUE DE VELLUIRE,FR,85105,46.3675950645,-0.905432724485,INSEE
85770,L ILE D ELLE,FR,85111,46.3334258655,-0.919100677098,INSEE
85800,ST GILLES CROIX DE VIE,FR,85222,46.6904708814,-1.91946363327,INSEE
85800,LE FENOUILLER,FR,85088,46.7161264566,-1.89206667498,INSEE
85800,GIVRAND,FR,85100,46.6822701061,-1.8787272243,INSEE
EOF;
public function getOrder()
{
return 50;
}
public static $refs = [];
public function load(ObjectManager $manager)
{
@@ -51,342 +337,40 @@ class LoadPostalCodes extends AbstractFixture implements OrderedFixtureInterface
$this->loadPostalCodeCSV($manager, self::$postalCodeFrance, 'FR');
}
private function loadPostalCodeCSV(ObjectManager $manager, string $csv, string $countryCode) {
private function loadPostalCodeCSV(ObjectManager $manager, string $csv, string $countryCode)
{
$lines = str_getcsv($csv, "\n");
$country = $manager->getRepository(Country::class)
->findOneBy(['countryCode' => $countryCode]);
foreach($lines as $line) {
$code = str_getcsv($line);
->findOneBy(['countryCode' => $countryCode]);
foreach ($lines as $line) {
$code = str_getcsv($line);
$c = new PostalCode();
$c->setCountry($country)
->setCode($code[0])
->setName(\ucwords(\strtolower($code[1])))
;
->setCode($code[0])
->setName(ucwords(strtolower($code[1])));
if (NULL != $code[3]){
if (null != $code[3]) {
$c->setRefPostalCodeId($code[3]);
}
if (NULL != $code[4] & NULL != $code[5]){
if (null != $code[4] & null != $code[5]) {
$c->setCenter(Point::fromLonLat((float) $code[5], (float) $code[4]));
}
if (NULL != $code[6]){
if (null != $code[6]) {
$c->setPostalCodeSource($code[6]);
}
$manager->persist($c);
$ref = 'postal_code_'.$code[0];
if (! $this->hasReference($ref)) {
$ref = 'postal_code_' . $code[0];
if (!$this->hasReference($ref)) {
$this->addReference($ref, $c);
self::$refs[] = $ref;
}
}
$manager->flush();
}
private static $postalCodeBelgium = <<<EOF
1000,BRUXELLES,BE
1020,BRUXELLES,BE
1030,SCHAERBEEK,BE
1040,ETTERBEEK,BE
1050,IXELLES,BE
1060,SAINT-GILLES,BE
1070,ANDERLECHT,BE
1080,MOLENBEEK-SAINT-JEAN,BE
1081,KOEKELBERG,BE
1082,BERCHEM-SAINTE-AGATHE,BE
1083,GANSHOREN,BE
1090,JETTE,BE
1120,BRUXELLES,BE
1130,BRUXELLES,BE
1140,EVERE,BE
1150,WOLUWE-SAINT-PIERRE,BE
1160,AUDERGHEM,BE
1170,WATERMAEL-BOITSFORT,BE
1180,UCCLE,BE
1190,FOREST,BE
1200,WOLUWE-SAINT-LAMBERT,BE
1210,SAINT-JOSSE-TEN-NOODE,BE
1300,WAVRE,BE
1300,WAVRE,BE
1301,WAVRE,BE
1310,LA HULPE,BE
1315,INCOURT,BE
1315,INCOURT,BE
1315,INCOURT,BE
1315,INCOURT,BE
1315,INCOURT,BE
1320,BEAUVECHAIN,BE
EOF;
private static $postalCodeFrance = <<<EOF
85000,LA ROCHE SUR YON,FR,85191,46.6675261644,-1.4077954093,INSEE
85000,MOUILLERON LE CAPTIF,FR,85155,46.7104764993,-1.46129661418,INSEE
85100,LES SABLES D OLONNE,FR,85194,46.5007612799,-1.79255128677,INSEE
85110,STE CECILE,FR,85202,46.7309688326,-1.12107316048,INSEE
85110,LA JAUDONNIERE,FR,85115,46.6488761831,-0.962477574588,INSEE
85110,ST GERMAIN DE PRINCAY,FR,85220,46.7356314659,-1.04299885081,INSEE
85110,MONSIREIGNE,FR,85145,46.7383480028,-0.931953130855,INSEE
85110,ST VINCENT STERLANGES,FR,85276,46.7397220689,-1.08371759277,INSEE
85110,SIGOURNAIS,FR,85282,46.7140097406,-0.98747730882,INSEE
85110,CHANTONNAY,FR,85051,46.6690167793,-1.04372588019,INSEE
85110,ST PROUANT,FR,85266,46.7502017421,-0.974504061491,INSEE
85120,LA CHAPELLE AUX LYS,FR,85053,46.6221916887,-0.642706103195,INSEE
85120,VOUVANT,FR,85305,46.5626835135,-0.764380170382,INSEE
85120,ANTIGNY,FR,85005,46.6191770822,-0.767030058653,INSEE
85120,ST MAURICE DES NOUES,FR,85251,46.5955876221,-0.724327725888,INSEE
85120,LOGE FOUGEREUSE,FR,85125,46.6180854641,-0.6899276733,INSEE
85120,LA TARDIERE,FR,85289,46.663737434,-0.727562430214,INSEE
85120,LA CHATAIGNERAIE,FR,85059,46.6416143401,-0.739561966419,INSEE
85120,ST HILAIRE DE VOUST,FR,85229,46.5914988312,-0.651486245674,INSEE
85120,BREUIL BARRET,FR,85037,46.6503266235,-0.671948654426,INSEE
85120,ST PIERRE DU CHEMIN,FR,85264,46.6957771744,-0.701777715154,INSEE
85130,LA GAUBRETIERE,FR,85097,46.9345007303,-1.05578200702,INSEE
85130,ST MARTIN DES TILLEULS,FR,85247,46.9711539531,-1.06282621567,INSEE
85130,TIFFAUGES,FR,85293,47.0020573556,-1.09858009203,INSEE
85130,CHANVERRIE,FR,85302,46.9634774521,-0.985340006089,INSEE
85130,BAZOGES EN PAILLERS,FR,85013,46.9213757643,-1.14415666313,INSEE
85130,LES LANDES GENUSSON,FR,85119,46.9663828627,-1.12900644447,INSEE
85130,ST AUBIN DES ORMEAUX,FR,85198,46.9958175597,-1.04216568722,INSEE
85140,ESSARTS EN BOCAGE,FR,85084,46.7806739038,-1.22925967851,INSEE
85140,LA MERLATIERE,FR,85142,46.7557703112,-1.29794577,INSEE
85140,ST MARTIN DES NOYERS,FR,85246,46.7239461187,-1.20379080965,INSEE
85140,CHAUCHE,FR,85064,46.8282791899,-1.27090860656,INSEE
85150,ST MATHURIN,FR,85250,46.5686332748,-1.70787622288,INSEE
85150,MARTINET,FR,85138,46.6620680463,-1.6772013304,INSEE
85150,STE FLAIVE DES LOUPS,FR,85211,46.611019489,-1.58031627863,INSEE
85150,STE FOY,FR,85214,46.5327600427,-1.69243074733,INSEE
85150,ST JULIEN DES LANDES,FR,85236,46.6395925444,-1.7159724914,INSEE
85150,ST GEORGES DE POINTINDOUX,FR,85218,46.6423470977,-1.62881823574,INSEE
85150,LE GIROUARD,FR,85099,46.5726064909,-1.58872487716,INSEE
85150,LANDERONDE,FR,85118,46.6549237031,-1.57351777893,INSEE
85150,LES ACHARDS,FR,85152,46.6163645636,-1.65038156849,INSEE
85150,VAIRE,FR,85298,46.6055340621,-1.74863672042,INSEE
85160,ST JEAN DE MONTS,FR,85234,46.8021968737,-2.04839789308,INSEE
85170,BELLEVIGNY,FR,85019,46.7756383534,-1.43313700054,INSEE
85170,LE POIRE SUR VIE,FR,85178,46.769919754,-1.50488626452,INSEE
85170,BEAUFOU,FR,85015,46.8191122027,-1.52479250801,INSEE
85170,DOMPIERRE SUR YON,FR,85081,46.7599858068,-1.37275519417,INSEE
85170,LES LUCS SUR BOULOGNE,FR,85129,46.8527299002,-1.48398928084,INSEE
85170,ST DENIS LA CHEVASSE,FR,85208,46.8325959261,-1.3830312677,INSEE
85180,LES SABLES D OLONNE,FR,85194,46.5007612799,-1.79255128677,INSEE
85190,AIZENAY,FR,85003,46.7384516809,-1.62702889721,INSEE
85190,VENANSAULT,FR,85300,46.685677363,-1.54112129191,INSEE
85190,MACHE,FR,85130,46.771364944,-1.69526445062,INSEE
85190,BEAULIEU SOUS LA ROCHE,FR,85016,46.6872087211,-1.62355064963,INSEE
85190,LA GENETOUZE,FR,85098,46.7244524541,-1.50410719693,INSEE
85200,PISSOTTE,FR,85176,46.5010870694,-0.808352236192,INSEE
85200,AUCHAY SUR VENDEE,FR,85009,46.4474386161,-0.876574265149,INSEE
85200,FONTENAY LE COMTE,FR,85092,46.4563186117,-0.793449510859,INSEE
85200,MERVENT,FR,85143,46.5325327351,-0.748519927998,INSEE
85200,DOIX LES FONTAINES,FR,85080,46.3849492327,-0.806840287485,INSEE
85200,LONGEVES,FR,85126,46.4722105292,-0.858917690239,INSEE
85200,ST MARTIN DE FRAIGNEAU,FR,85244,46.4289052087,-0.758948963227,INSEE
85200,SERIGNE,FR,85281,46.5054321828,-0.848819460581,INSEE
85200,BOURNEAU,FR,85033,46.5476882922,-0.813838020265,INSEE
85200,ST MICHEL LE CLOUCQ,FR,85256,46.4861591475,-0.743056336646,INSEE
85200,MONTREUIL,FR,85148,46.3973419593,-0.840846860992,INSEE
85200,L ORBRIE,FR,85167,46.4997145725,-0.77427886573,INSEE
85210,ST JEAN DE BEUGNE,FR,85233,46.5196817523,-1.10826075013,INSEE
85210,ST MARTIN LARS EN STE HERMINE,FR,85248,46.5970244335,-0.976384286709,INSEE
85210,LA REORTHE,FR,85188,46.6113748938,-1.04881036553,INSEE
85210,ST AUBIN LA PLAINE,FR,85199,46.5040293195,-1.06506577005,INSEE
85210,ST JUIRE CHAMPGILLON,FR,85235,46.5882648491,-1.00959676911,INSEE
85210,LA CHAPELLE THEMER,FR,85056,46.5639307793,-0.960376685588,INSEE
85210,ST ETIENNE DE BRILLOUET,FR,85209,46.5138850327,-1.01157660374,INSEE
85210,STE HERMINE,FR,85223,46.5572659953,-1.07210861039,INSEE
85210,THIRE,FR,85290,46.5433098199,-1.00699777534,INSEE
85220,ST MAIXENT SUR VIE,FR,85239,46.7329496925,-1.82595152879,INSEE
85220,LA CHAIZE GIRAUD,FR,85045,46.6476375058,-1.81865076161,INSEE
85220,LANDEVIEILLE,FR,85120,46.6444349925,-1.7854367847,INSEE
85220,L AIGUILLON SUR VIE,FR,85002,46.6706426618,-1.82599992318,INSEE
85220,COEX,FR,85070,46.7078707764,-1.75788339462,INSEE
85220,ST REVEREND,FR,85268,46.7057741864,-1.83155480996,INSEE
85220,APREMONT,FR,85006,46.7572682339,-1.74841313647,INSEE
85220,LA CHAPELLE HERMIER,FR,85054,46.6826679204,-1.72083372442,INSEE
85220,COMMEQUIERS,FR,85071,46.7674752232,-1.82534079642,INSEE
85230,BEAUVOIR SUR MER,FR,85018,46.9086155426,-2.06349351302,INSEE
85230,BOUIN,FR,85029,46.9815930867,-2.00423808381,INSEE
85230,ST URBAIN,FR,85273,46.8818371328,-2.01607828912,INSEE
85230,ST GERVAIS,FR,85221,46.9285711589,-1.98059327519,INSEE
85240,MARILLET,FR,85136,46.5667525381,-0.634287713939,INSEE
85240,ST HILAIRE DES LOGES,FR,85227,46.4747117878,-0.650611151998,INSEE
85240,FAYMOREAU,FR,85087,46.5427361252,-0.624271378946,INSEE
85240,XANTON CHASSENON,FR,85306,46.4519408659,-0.706316598666,INSEE
85240,FOUSSAIS PAYRE,FR,85094,46.5230750581,-0.687135962627,INSEE
85240,RIVES D AUTISE,FR,85162,46.424726987,-0.665995249042,INSEE
85240,PUY DE SERRE,FR,85184,46.5650384637,-0.680144631346,INSEE
85250,ST ANDRE GOULE D OIE,FR,85196,46.8410224478,-1.19644211396,INSEE
85250,LA RABATELIERE,FR,85186,46.8584147661,-1.2569733759,INSEE
85250,CHAVAGNES EN PAILLERS,FR,85065,46.8951394423,-1.24054768713,INSEE
85250,ST FULGENT,FR,85215,46.8705618525,-1.16246465678,INSEE
85250,VENDRENNES,FR,85301,46.8226741756,-1.11650982164,INSEE
85260,LA COPECHAGNIERE,FR,85072,46.8523980181,-1.34349746898,INSEE
85260,L HERBERGEMENT,FR,85108,46.9166207979,-1.37033557148,INSEE
85260,MONTREVERD,FR,85197,46.9277672307,-1.4126154924,INSEE
85260,LES BROUZILS,FR,85038,46.8854235235,-1.33186892233,INSEE
85270,NOTRE DAME DE RIEZ,FR,85189,46.7532179022,-1.8935292542,INSEE
85270,ST HILAIRE DE RIEZ,FR,85226,46.7432732188,-1.96439228965,INSEE
85280,LA FERRIERE,FR,85089,46.7215872927,-1.33469332327,INSEE
85290,MORTAGNE SUR SEVRE,FR,85151,46.9910941319,-0.946500033344,INSEE
85290,ST LAURENT SUR SEVRE,FR,85238,46.9506837971,-0.901123752328,INSEE
85300,CHALLANS,FR,85047,46.8354416653,-1.84036683139,INSEE
85300,FROIDFOND,FR,85095,46.8789464367,-1.75511438567,INSEE
85300,SOULLANS,FR,85284,46.7951288466,-1.91392699457,INSEE
85300,LE PERRIER,FR,85172,46.8196487652,-1.97926629071,INSEE
85300,SALLERTAINE,FR,85280,46.8659054157,-1.94894081389,INSEE
85310,LA CHAIZE LE VICOMTE,FR,85046,46.6729533879,-1.29188591019,INSEE
85310,NESMY,FR,85160,46.5921936479,-1.40947698594,INSEE
85310,RIVES DE L YON,FR,85213,46.605637391,-1.3354497172,INSEE
85310,LE TABLIER,FR,85285,46.5596307281,-1.32788759657,INSEE
85320,CHATEAU GUIBERT,FR,85061,46.5741109302,-1.25524886228,INSEE
85320,LES PINEAUX,FR,85175,46.599225902,-1.17865799724,INSEE
85320,ROSNAY,FR,85193,46.5324344973,-1.3007139449,INSEE
85320,BESSAY,FR,85023,46.5397253861,-1.17028433093,INSEE
85320,LA BRETONNIERE LA CLAYE,FR,85036,46.4879459421,-1.26773426545,INSEE
85320,CORPE,FR,85073,46.5050234767,-1.17034425311,INSEE
85320,MAREUIL SUR LAY DISSAIS,FR,85135,46.5335825488,-1.22688907859,INSEE
85320,PEAULT,FR,85171,46.502029199,-1.22708559855,INSEE
85320,LA COUTURE,FR,85074,46.523938732,-1.26493227292,INSEE
85320,MOUTIERS SUR LE LAY,FR,85157,46.5651677306,-1.16826489836,INSEE
85320,STE PEXINE,FR,85261,46.5596018797,-1.12406235901,INSEE
85330,NOIRMOUTIER EN L ILE,FR,85163,47.0086655085,-2.26243620205,INSEE
85340,L ILE D OLONNE,FR,85112,46.570163703,-1.7737502368,INSEE
85340,LES SABLES D OLONNE,FR,85194,46.5007612799,-1.79255128677,INSEE
85350,L ILE D YEU,FR,85113,46.7093514816,-2.34712702345,INSEE
85360,LA TRANCHE SUR MER,FR,85294,46.3564601605,-1.43136322126,INSEE
85370,MOUZEUIL ST MARTIN,FR,85158,46.4591118412,-0.984449849889,INSEE
85370,NALLIERS,FR,85159,46.4658962703,-1.03958611312,INSEE
85370,LE LANGON,FR,85121,46.4393119039,-0.947017086151,INSEE
85390,BAZOGES EN PAREDS,FR,85014,46.6602005512,-0.914053446792,INSEE
85390,ST MAURICE LE GIRARD,FR,85252,46.6398624578,-0.810875649028,INSEE
85390,TALLUD STE GEMME,FR,85287,46.6949386862,-0.886169517112,INSEE
85390,CHAVAGNES LES REDOUX,FR,85066,46.7101499475,-0.915900131393,INSEE
85390,CHEFFOIS,FR,85067,46.6786935635,-0.782949851125,INSEE
85390,MOUILLERON ST GERMAIN,FR,85154,46.6612700667,-0.846784201071,INSEE
85400,STE GEMME LA PLAINE,FR,85216,46.4732196212,-1.11103084694,INSEE
85400,LAIROUX,FR,85117,46.4496842668,-1.27114022202,INSEE
85400,LUCON,FR,85128,46.4510564854,-1.16449285012,INSEE
85400,LES MAGNILS REIGNIERS,FR,85131,46.4635045649,-1.210635375,INSEE
85400,CHASNAIS,FR,85058,46.4459908481,-1.2385924923,INSEE
85410,ST LAURENT DE LA SALLE,FR,85237,46.5854041653,-0.922177315485,INSEE
85410,LA CAILLERE ST HILAIRE,FR,85040,46.6293907412,-0.933153931505,INSEE
85410,ST CYR DES GATS,FR,85205,46.572397925,-0.86344873853,INSEE
85410,THOUARSAIS BOUILDROUX,FR,85292,46.6062740621,-0.873461023865,INSEE
85410,CEZAIS,FR,85041,46.5917363748,-0.802618133558,INSEE
85410,ST SULPICE EN PAREDS,FR,85271,46.6130038733,-0.8310839288,INSEE
85420,LE MAZEAU,FR,85139,46.3298580373,-0.672957405035,INSEE
85420,LIEZ,FR,85123,46.3698532376,-0.70502476758,INSEE
85420,BOUILLE COURDAULT,FR,85028,46.3847932448,-0.684917815779,INSEE
85420,DAMVIX,FR,85078,46.32063079,-0.743504259797,INSEE
85420,MAILLE,FR,85132,46.3417503082,-0.787487297301,INSEE
85420,ST PIERRE LE VIEUX,FR,85265,46.4009643491,-0.742816267425,INSEE
85420,ST SIGISMOND,FR,85269,46.3368577973,-0.707293731101,INSEE
85420,MAILLEZAIS,FR,85133,46.3642178261,-0.750260780443,INSEE
85420,RIVES D AUTISE,FR,85162,46.424726987,-0.665995249042,INSEE
85430,AUBIGNY LES CLOUZEAUX,FR,85008,46.6028241769,-1.46743549114,INSEE
85430,NIEUL LE DOLENT,FR,85161,46.5676509922,-1.51560194548,INSEE
85430,LA BOISSIERE DES LANDES,FR,85026,46.5581861734,-1.44371985689,INSEE
85440,ST HILAIRE LA FORET,FR,85231,46.4551155186,-1.53048160541,INSEE
85440,TALMONT ST HILAIRE,FR,85288,46.475786445,-1.62751498166,INSEE
85440,POIROUX,FR,85179,46.5107890457,-1.53929317556,INSEE
85440,GROSBREUIL,FR,85103,46.5390090882,-1.6072005484,INSEE
85440,AVRILLE,FR,85010,46.4744272125,-1.49524360118,INSEE
85450,CHAMPAGNE LES MARAIS,FR,85049,46.3735020647,-1.13380723653,INSEE
85450,LA TAILLEE,FR,85286,46.3852513569,-0.941017792066,INSEE
85450,CHAILLE LES MARAIS,FR,85042,46.3853555319,-1.01044079362,INSEE
85450,VOUILLE LES MARAIS,FR,85304,46.3891941167,-0.968106001439,INSEE
85450,MOREILLES,FR,85149,46.4218721314,-1.09404530407,INSEE
85450,PUYRAVAULT,FR,85185,46.3653834101,-1.09115660367,INSEE
85450,STE RADEGONDE DES NOYERS,FR,85267,46.3694246909,-1.06671995264,INSEE
85460,LA FAUTE SUR MER,FR,85307,46.3199919131,-1.31487049579,INSEE
85460,L AIGUILLON SUR MER,FR,85001,46.304138479,-1.2623239198,INSEE
85470,BRETIGNOLLES SUR MER,FR,85035,46.6374826705,-1.86324200464,INSEE
85470,BREM SUR MER,FR,85243,46.6118566989,-1.81003917923,INSEE
85480,BOURNEZEAU,FR,85034,46.6296975315,-1.14101742229,INSEE
85480,FOUGERE,FR,85093,46.6617881911,-1.23612691916,INSEE
85480,ST HILAIRE LE VOUHIS,FR,85232,46.6859198669,-1.15222590884,INSEE
85480,THORIGNY,FR,85291,46.6179795025,-1.24888057642,INSEE
85490,BENET,FR,85020,46.368873213,-0.613959918706,INSEE
85500,BEAUREPAIRE,FR,85017,46.9050210355,-1.10144867013,INSEE
85500,ST PAUL EN PAREDS,FR,85259,46.8303789022,-0.964515191283,INSEE
85500,LES HERBIERS,FR,85109,46.8666125813,-1.02216086186,INSEE
85500,MESNARD LA BAROTIERE,FR,85144,46.851716793,-1.10954466033,INSEE
85500,CHANVERRIE,FR,85302,46.9634774521,-0.985340006089,INSEE
85510,ROCHETREJOUX,FR,85192,46.7852546732,-0.996743019108,INSEE
85510,LE BOUPERE,FR,85031,46.7877960262,-0.930897406714,INSEE
85520,JARD SUR MER,FR,85114,46.4246376808,-1.60014921643,INSEE
85520,ST VINCENT SUR JARD,FR,85278,46.4297504489,-1.54956205778,INSEE
85530,LA BRUFFIERE,FR,85039,47.0148006973,-1.18329758318,INSEE
85540,LE CHAMP ST PERE,FR,85050,46.5157210212,-1.33946630196,INSEE
85540,LE GIVRE,FR,85101,46.4729146043,-1.40256149118,INSEE
85540,MOUTIERS LES MAUXFAITS,FR,85156,46.489279204,-1.43622387207,INSEE
85540,ST VINCENT SUR GRAON,FR,85277,46.5034756656,-1.382954206,INSEE
85540,LA JONCHERE,FR,85116,46.4358647401,-1.38517843312,INSEE
85540,ST BENOIST SUR MER,FR,85201,46.4266286403,-1.3399129604,INSEE
85540,CURZON,FR,85077,46.4512376923,-1.30138059216,INSEE
85540,ST AVAUGOURD DES LANDES,FR,85200,46.5136722903,-1.47528120789,INSEE
85540,ST CYR EN TALMONDAIS,FR,85206,46.4597334032,-1.33722144355,INSEE
85550,LA BARRE DE MONTS,FR,85012,46.8722784154,-2.09984018879,INSEE
85560,LE BERNARD,FR,85022,46.44832528,-1.43979865314,INSEE
85560,LONGEVILLE SUR MER,FR,85127,46.4091029013,-1.47711855345,INSEE
85570,POUILLE,FR,85181,46.5022256779,-0.955223380119,INSEE
85570,ST VALERIEN,FR,85274,46.5348508899,-0.944470507825,INSEE
85570,L HERMENAULT,FR,85110,46.5156262822,-0.898430664265,INSEE
85570,PETOSSE,FR,85174,46.4796848965,-0.911734176662,INSEE
85570,ST MARTIN DES FONTAINES,FR,85245,46.5464637508,-0.907394581139,INSEE
85570,MARSAIS STE RADEGONDE,FR,85137,46.5380790745,-0.868868309437,INSEE
85580,ST DENIS DU PAYRE,FR,85207,46.4118936776,-1.27222282402,INSEE
85580,ST MICHEL EN L HERM,FR,85255,46.3366903175,-1.2483968538,INSEE
85580,TRIAIZE,FR,85297,46.3792685111,-1.19928351422,INSEE
85580,GRUES,FR,85104,46.3813091348,-1.32364519268,INSEE
85590,TREIZE VENTS,FR,85296,46.9168130123,-0.845959158017,INSEE
85590,LES EPESSES,FR,85082,46.8917166066,-0.903422756546,INSEE
85590,MALLIEVRE,FR,85134,46.9112847287,-0.864977836096,INSEE
85590,ST MALO DU BOIS,FR,85240,46.9248120291,-0.914182961099,INSEE
85590,ST MARS LA REORTHE,FR,85242,46.8597253005,-0.925777900202,INSEE
85600,LA BOISSIERE DE MONTAIGU,FR,85025,46.9451858636,-1.1916392484,INSEE
85600,MONTAIGU VENDEE,FR,85146,46.9759800852,-1.31364530268,INSEE
85600,TREIZE SEPTIERS,FR,85295,46.9975586143,-1.23193361154,INSEE
85610,CUGAND,FR,85076,47.0602388146,-1.25289811103,INSEE
85610,LA BERNARDIERE,FR,85021,47.0361828072,-1.27390355206,INSEE
85620,ROCHESERVIERE,FR,85190,46.9274273036,-1.50132208111,INSEE
85630,BARBATRE,FR,85011,46.9335754783,-2.16743559847,INSEE
85640,MOUCHAMPS,FR,85153,46.7870550926,-1.05454102867,INSEE
85660,ST PHILBERT DE BOUAINE,FR,85262,46.9927907526,-1.5073882242,INSEE
85670,LA CHAPELLE PALLUAU,FR,85055,46.7873638997,-1.62492863273,INSEE
85670,FALLERON,FR,85086,46.8623928354,-1.70108938038,INSEE
85670,ST ETIENNE DU BOIS,FR,85210,46.8418481774,-1.59617737479,INSEE
85670,ST PAUL MONT PENIT,FR,85260,46.8070059547,-1.66964833149,INSEE
85670,ST CHRISTOPHE DU LIGNERON,FR,85204,46.8151386519,-1.74035413493,INSEE
85670,GRAND LANDES,FR,85102,46.8483283063,-1.64453002578,INSEE
85670,PALLUAU,FR,85169,46.8063002019,-1.60225256402,INSEE
85680,LA GUERINIERE,FR,85106,46.9669962053,-2.2302799245,INSEE
85690,NOTRE DAME DE MONTS,FR,85164,46.8424284611,-2.10928732775,INSEE
85700,SEVREMONT,FR,85090,46.8211105864,-0.854584153953,INSEE
85700,LA MEILLERAIE TILLAY,FR,85140,46.742582825,-0.85478763606,INSEE
85700,MONTOURNAIS,FR,85147,46.7502937556,-0.770013941158,INSEE
85700,POUZAUGES,FR,85182,46.7812581702,-0.828778359084,INSEE
85700,REAUMUR,FR,85187,46.7145137269,-0.816742537248,INSEE
85700,MENOMBLET,FR,85141,46.7301338667,-0.728654955878,INSEE
85700,ST MESMIN,FR,85254,46.8005779435,-0.748892533741,INSEE
85710,BOIS DE CENE,FR,85024,46.9479643351,-1.89668693466,INSEE
85710,CHATEAUNEUF,FR,85062,46.916944435,-1.9261131832,INSEE
85710,LA GARNACHE,FR,85096,46.8977541296,-1.82443040539,INSEE
85740,L EPINE,FR,85083,46.9843405667,-2.26449527608,INSEE
85750,ANGLES,FR,85004,46.3870511077,-1.40049386944,INSEE
85770,LES VELLUIRE SUR VENDEE,FR,85177,46.4190919441,-0.910475769222,INSEE
85770,VIX,FR,85303,46.3543018169,-0.856628326667,INSEE
85770,LE GUE DE VELLUIRE,FR,85105,46.3675950645,-0.905432724485,INSEE
85770,L ILE D ELLE,FR,85111,46.3334258655,-0.919100677098,INSEE
85800,ST GILLES CROIX DE VIE,FR,85222,46.6904708814,-1.91946363327,INSEE
85800,LE FENOUILLER,FR,85088,46.7161264566,-1.89206667498,INSEE
85800,GIVRAND,FR,85100,46.6822701061,-1.8787272243,INSEE
EOF;
}

View File

@@ -1,86 +1,67 @@
<?php
/*
* Chill is a suite of a modules, Chill is a software for social workers
* Copyright (C) 2014, Champs Libres Cooperative SCRLFS, <http://www.champs-libres.coop>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
/**
* Chill is a software for social workers
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/
namespace Chill\MainBundle\DataFixtures\ORM;
use Chill\MainBundle\Entity\RoleScope;
use Doctrine\Common\DataFixtures\AbstractFixture;
use Doctrine\Common\DataFixtures\OrderedFixtureInterface;
use Doctrine\Persistence\ObjectManager;
use Chill\MainBundle\Entity\RoleScope;
use Chill\MainBundle\DataFixtures\ORM\LoadScopes;
/**
*
*
* @author Julien Fastré <julien.fastre@champs-libres.coop>
*/
class LoadRoleScopes extends AbstractFixture implements OrderedFixtureInterface
{
public static $permissions = [
'CHILL_FOO_SEE' => [
'names' => [
'fr' => 'voir foo',
'en' => 'see foo',
'nl' => 'zie foo',
],
],
'CHILL_FOO_SEE_DETAILS' => [
'names' => [
'fr' => 'voir foo avec détails',
'en' => 'see foo with details',
'nl' => 'zie foo in details',
],
],
'CHILL_FOO_EDIT' => [
'names' => [
'fr' => 'modifier foo',
'en' => 'edit foo',
'nl' => 'editie foo',
],
],
];
public static $references = [];
public function getOrder()
{
return 300;
}
public static $permissions = array(
'CHILL_FOO_SEE' => array(
'names' => array(
'fr' => 'voir foo',
'en' => 'see foo',
'nl' => 'zie foo'
)
),
'CHILL_FOO_SEE_DETAILS' => array(
'names' => array(
'fr' => 'voir foo avec détails',
'en' => 'see foo with details',
'nl' => 'zie foo in details'
)
),
'CHILL_FOO_EDIT' => array(
'names' => array(
'fr' => 'modifier foo',
'en' => 'edit foo',
'nl' => 'editie foo'
)
)
);
public static $references = array();
public function load(ObjectManager $manager)
{
foreach (static::$permissions as $key => $permission) {
foreach(LoadScopes::$references as $scopeReference) {
foreach (LoadScopes::$references as $scopeReference) {
$roleScope = new RoleScope();
$roleScope->setRole($key)
->setScope($this->getReference($scopeReference))
;
$reference = 'role_scope_'.$key.'_'.$this->getReference($scopeReference)->getName()['en'];
echo "Creating $reference \n";
->setScope($this->getReference($scopeReference));
$reference = 'role_scope_' . $key . '_' . $this->getReference($scopeReference)->getName()['en'];
echo "Creating {$reference} \n";
$this->addReference($reference, $roleScope);
$manager->persist($roleScope);
static::$references[] = $reference;
}
}
$manager->flush();
}
}

View File

@@ -1,21 +1,10 @@
<?php
/*
* Chill is a suite of a modules, Chill is a software for social workers
* Copyright (C) 2014, Champs Libres Cooperative SCRLFS, <http://www.champs-libres.coop>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
/**
* Chill is a software for social workers
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/
namespace Chill\MainBundle\DataFixtures\ORM;
@@ -25,55 +14,53 @@ use Doctrine\Common\DataFixtures\OrderedFixtureInterface;
use Doctrine\Persistence\ObjectManager;
/**
* Create scopes
*
* @author Julien Fastré <julien.fastre@champs-libres.coop>
* Create scopes.
*/
class LoadScopes extends AbstractFixture implements OrderedFixtureInterface
{
public static $references = [];
public $scopes = [
[
'names' => [
'fr' => 'tous',
'en' => 'all',
'nl' => 'algemeen',
],
],
[
'names' => [
'fr' => 'social',
'en' => 'social',
'nl' => 'sociaal',
],
],
[
'names' => [
'fr' => 'administratif',
'en' => 'administrative',
'nl' => 'administratief',
],
],
];
public function getOrder()
{
return 200;
}
public $scopes = array(
array(
'names' => array(
'fr' => 'tous',
'en' => 'all',
'nl' => 'algemeen'
),
),
array(
'names' => array(
'fr' => 'social',
'en' => 'social',
'nl' => 'sociaal'
)
),
array(
'names' => array(
'fr' => 'administratif',
'en' => 'administrative',
'nl' => 'administratief'
)
)
);
public static $references = array();
public function load(ObjectManager $manager)
{
{
foreach ($this->scopes as $new) {
$scope = new \Chill\MainBundle\Entity\Scope();
$scope->setName($new['names']);
$manager->persist($scope);
$reference = 'scope_'.$new['names']['en'];
$reference = 'scope_' . $new['names']['en'];
$this->addReference($reference, $scope);
static::$references[] = $reference;
}
$manager->flush();
}
}

View File

@@ -1,30 +1,59 @@
<?php
/**
* Chill is a software for social workers
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/
namespace Chill\MainBundle\DataFixtures\ORM;
use Chill\MainBundle\Entity\User;
use Doctrine\Common\DataFixtures\AbstractFixture;
use Doctrine\Common\DataFixtures\OrderedFixtureInterface;
use Doctrine\Persistence\ObjectManager;
use Symfony\Component\DependencyInjection\ContainerInterface;
use LogicException;
use Symfony\Component\DependencyInjection\ContainerAwareInterface;
use Chill\MainBundle\DataFixtures\ORM\LoadCenters;
use Chill\MainBundle\DataFixtures\ORM\LoadPermissionsGroup;
use Chill\MainBundle\Entity\User;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Symfony\Component\Security\Core\Encoder\EncoderFactory;
use Symfony\Component\Security\Core\Encoder\MessageDigestPasswordEncoder;
use function str_replace;
/**
* Load fixtures users into database
* Load fixtures users into database.
*
* create a user for each permission_group and center.
* username and password are identicals.
*
* @author Julien Fastré <julien.fastre@champs-libres.coop>
*/
class LoadUsers extends AbstractFixture implements OrderedFixtureInterface, ContainerAwareInterface
{
public static $refs = [
'center a_social' => [
'groupCenterRefs' => ['centerA_permission_group_social'],
],
'center a_administrative' => [
'groupCenterRefs' => ['centerA_permission_group_administrative'],
],
'center a_direction' => [
'groupCenterRefs' => ['centerA_permission_group_direction'],
],
'center b_social' => [
'groupCenterRefs' => ['centerB_permission_group_social'],
],
'center b_administrative' => [
'groupCenterRefs' => ['centerB_permission_group_administrative'],
],
'center b_direction' => [
'groupCenterRefs' => ['centerB_permission_group_direction'],
],
'multi_center' => [
'groupCenterRefs' => ['centerA_permission_group_social',
'centerB_permission_group_social', ],
],
];
/**
*
* @var ContainerInterface
*/
private $container;
@@ -34,58 +63,31 @@ class LoadUsers extends AbstractFixture implements OrderedFixtureInterface, Cont
return 1000;
}
public static $refs = array(
'center a_social' => array(
'groupCenterRefs' => ['centerA_permission_group_social']
),
'center a_administrative' => array(
'groupCenterRefs' => ['centerA_permission_group_administrative']
),
'center a_direction' => array(
'groupCenterRefs' => ['centerA_permission_group_direction']
),
'center b_social' => array(
'groupCenterRefs' => ['centerB_permission_group_social']
),
'center b_administrative' => array(
'groupCenterRefs' => ['centerB_permission_group_administrative']
),
'center b_direction' => array(
'groupCenterRefs' => ['centerB_permission_group_direction']
),
'multi_center' => array(
'groupCenterRefs' => ['centerA_permission_group_social',
'centerB_permission_group_social']
)
);
public function load(ObjectManager $manager)
{
foreach (self::$refs as $username => $params) {
$user = new User();
$defaultEncoder = new MessageDigestPasswordEncoder('sha512', true, 5000);
$encoderFactory = new EncoderFactory([
User::class => $defaultEncoder
User::class => $defaultEncoder,
]);
$user
->setUsername($username)
->setPassword($encoderFactory
->getEncoder($user)
->encodePassword('password', $user->getSalt())
)
->setEmail(sprintf("%s@chill.social", \str_replace(' ', '', $username)))
;
->setPassword(
$encoderFactory
->getEncoder($user)
->encodePassword('password', $user->getSalt())
)
->setEmail(sprintf('%s@chill.social', str_replace(' ', '', $username)));
foreach ($params['groupCenterRefs'] as $groupCenterRef) {
$user->addGroupCenter($this->getReference($groupCenterRef));
}
echo 'Creating user ' . $username ."... \n";
echo 'Creating user ' . $username . "... \n";
$manager->persist($user);
$this->addReference($username, $user);
}
@@ -93,13 +95,12 @@ class LoadUsers extends AbstractFixture implements OrderedFixtureInterface, Cont
$manager->flush();
}
public function setContainer(ContainerInterface $container = null)
public function setContainer(?ContainerInterface $container = null)
{
if (NULL === $container) {
throw new \LogicException('$container should not be null');
if (null === $container) {
throw new LogicException('$container should not be null');
}
$this->container = $container;
}
}

View File

@@ -1,20 +1,10 @@
<?php
/*
* Copyright (C) 2014-2018 Julien Fastré <julien.fastre@champs-libres.coop>
/**
* Chill is a software for social workers
*
* This program is free software: you can redistribute it and/or modify
* 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/>.
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/
namespace Chill\MainBundle\DependencyInjection;
@@ -23,60 +13,64 @@ use Chill\MainBundle\Controller\AddressApiController;
use Chill\MainBundle\Controller\LocationController;
use Chill\MainBundle\Controller\LocationTypeController;
use Chill\MainBundle\Controller\UserController;
use Chill\MainBundle\Doctrine\DQL\JsonbArrayLength;
use Chill\MainBundle\Doctrine\DQL\STContains;
use Chill\MainBundle\Doctrine\DQL\StrictWordSimilarityOPS;
use Chill\MainBundle\Entity\User;
use Chill\MainBundle\Entity\UserJob;
use Chill\MainBundle\Form\UserJobType;
use Chill\MainBundle\Form\UserType;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\Config\FileLocator;
use Symfony\Component\HttpKernel\DependencyInjection\Extension;
use Symfony\Component\DependencyInjection\Loader;
use Symfony\Component\DependencyInjection\Extension\PrependExtensionInterface;
use Chill\MainBundle\DependencyInjection\Widget\Factory\WidgetFactoryInterface;
use Chill\MainBundle\DependencyInjection\Configuration;
use Chill\MainBundle\Doctrine\DQL\GetJsonFieldByKey;
use Chill\MainBundle\Doctrine\DQL\Unaccent;
use Chill\MainBundle\Doctrine\DQL\JsonAggregate;
use Chill\MainBundle\Doctrine\DQL\JsonbArrayLength;
use Chill\MainBundle\Doctrine\DQL\JsonbExistsInArray;
use Chill\MainBundle\Doctrine\DQL\Similarity;
use Chill\MainBundle\Doctrine\DQL\OverlapsI;
use Chill\MainBundle\Doctrine\DQL\Replace;
use Chill\MainBundle\Doctrine\DQL\Similarity;
use Chill\MainBundle\Doctrine\DQL\STContains;
use Chill\MainBundle\Doctrine\DQL\StrictWordSimilarityOPS;
use Chill\MainBundle\Doctrine\DQL\Unaccent;
use Chill\MainBundle\Doctrine\ORM\Hydration\FlatHierarchyEntityHydrator;
use Chill\MainBundle\Doctrine\Type\NativeDateIntervalType;
use Chill\MainBundle\Doctrine\Type\PointType;
use Chill\MainBundle\Entity\Location;
use Chill\MainBundle\Entity\LocationType;
use Chill\MainBundle\Form\LocationTypeType;
use Chill\MainBundle\Entity\User;
use Chill\MainBundle\Entity\UserJob;
use Chill\MainBundle\Form\LocationFormType;
use Chill\MainBundle\Form\LocationTypeType;
use Chill\MainBundle\Form\UserJobType;
use Chill\MainBundle\Form\UserType;
use Exception;
use Symfony\Component\Config\FileLocator;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Extension\PrependExtensionInterface;
use Symfony\Component\DependencyInjection\Loader;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpKernel\DependencyInjection\Extension;
/**
* Class ChillMainExtension
* This class load config for chillMainExtension.
*
* @package Chill\MainBundle\DependencyInjection
*/
class ChillMainExtension extends Extension implements PrependExtensionInterface,
class ChillMainExtension extends Extension implements
PrependExtensionInterface,
Widget\HasWidgetFactoriesExtensionInterface
{
/**
* widget factory
* widget factory.
*
* @var WidgetFactoryInterface[]
*/
protected $widgetFactories = array();
protected $widgetFactories = [];
/**
* @param WidgetFactoryInterface $factory
*/
public function addWidgetFactory(WidgetFactoryInterface $factory)
{
$this->widgetFactories[] = $factory;
}
/**
* @return \Chill\MainBundle\DependencyInjection\Configuration|object|\Symfony\Component\Config\Definition\ConfigurationInterface|null
*/
public function getConfiguration(array $config, ContainerBuilder $container)
{
return new Configuration($this->widgetFactories, $container);
}
/**
* @return WidgetFactoryInterface[]
*/
@@ -86,10 +80,7 @@ class ChillMainExtension extends Extension implements PrependExtensionInterface,
}
/**
* {@inheritDoc}
* @param array $configs
* @param ContainerBuilder $container
* @throws \Exception
* @throws Exception
*/
public function load(array $configs, ContainerBuilder $container)
{
@@ -101,38 +92,55 @@ class ChillMainExtension extends Extension implements PrependExtensionInterface,
$container->setParameter('chill_main', $config);
// legacy config
$container->setParameter('chill_main.installation_name',
$config['installation_name']);
$container->setParameter(
'chill_main.installation_name',
$config['installation_name']
);
$container->setParameter('chill_main.available_languages',
$config['available_languages']);
$container->setParameter(
'chill_main.available_languages',
$config['available_languages']
);
$container->setParameter('chill_main.available_countries',
$config['available_countries']);
$container->setParameter(
'chill_main.available_countries',
$config['available_countries']
);
$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.pagination.item_per_page',
$config['pagination']['item_per_page']
);
$container->setParameter('chill_main.notifications',
$config['notifications']);
$container->setParameter(
'chill_main.notifications',
$config['notifications']
);
$container->setParameter('chill_main.redis',
$config['redis']);
$container->setParameter(
'chill_main.redis',
$config['redis']
);
$container->setParameter('chill_main.phone_helper',
$config['phone_helper'] ?? []);
$container->setParameter(
'chill_main.phone_helper',
$config['phone_helper'] ?? []
);
// add the key 'widget' without the key 'enable'
$container->setParameter('chill_main.widgets',
$container->setParameter(
'chill_main.widgets',
isset($config['widgets']['homepage']) ?
array('homepage' => $config['widgets']['homepage']):
array()
);
['homepage' => $config['widgets']['homepage']] :
[]
);
$loader = new Loader\YamlFileLoader($container, new FileLocator(__DIR__.'/../config'));
$loader = new Loader\YamlFileLoader($container, new FileLocator(__DIR__ . '/../config'));
$loader->load('services.yaml');
$loader->load('services/doctrine.yaml');
$loader->load('services/logger.yaml');
@@ -159,33 +167,20 @@ class ChillMainExtension extends Extension implements PrependExtensionInterface,
$this->configureCruds($container, $config['cruds'], $config['apis'], $loader);
}
/**
* @param array $config
* @param ContainerBuilder $container
* @return \Chill\MainBundle\DependencyInjection\Configuration|null|object|\Symfony\Component\Config\Definition\ConfigurationInterface
*/
public function getConfiguration(array $config, ContainerBuilder $container)
{
return new Configuration($this->widgetFactories, $container);
}
/**
* @param ContainerBuilder $container
*/
public function prepend(ContainerBuilder $container)
{
//add installation_name and date_format to globals
$chillMainConfig = $container->getExtensionConfig($this->getAlias());
$config = $this->processConfiguration($this
->getConfiguration($chillMainConfig, $container), $chillMainConfig);
$twigConfig = array(
'globals' => array(
'installation' => array(
'name' => $config['installation_name']),
'available_languages' => $config['available_languages']
),
'form_themes' => array('@ChillMain/Form/fields.html.twig')
);
->getConfiguration($chillMainConfig, $container), $chillMainConfig);
$twigConfig = [
'globals' => [
'installation' => [
'name' => $config['installation_name'], ],
'available_languages' => $config['available_languages'],
],
'form_themes' => ['@ChillMain/Form/fields.html.twig'],
];
$container->prependExtensionConfig('twig', $twigConfig);
//add DQL function to ORM (default entity_manager)
@@ -215,7 +210,7 @@ class ChillMainExtension extends Extension implements PrependExtensionInterface,
],
],
],
);
);
//add dbal types (default entity_manager)
$container
@@ -231,45 +226,43 @@ class ChillMainExtension extends Extension implements PrependExtensionInterface,
],
'types' => [
'dateinterval' => [
'class' => NativeDateIntervalType::class
'class' => NativeDateIntervalType::class,
],
'point' => [
'class' => PointType::class
]
]
]
'class' => PointType::class,
],
],
],
]
);
);
//add current route to chill main
$container->prependExtensionConfig('chill_main', array(
'routing' => array(
'resources' => array(
'@ChillMainBundle/config/routes.yaml'
)
)
));
$container->prependExtensionConfig('chill_main', [
'routing' => [
'resources' => [
'@ChillMainBundle/config/routes.yaml',
],
],
]);
//add a channel to log app events
$container->prependExtensionConfig('monolog', array(
'channels' => array('chill')
));
$container->prependExtensionConfig('monolog', [
'channels' => ['chill'],
]);
//add crud api
$this->prependCruds($container);
}
/**
* Load parameter for configuration and set parameters for api
* Load parameter for configuration and set parameters for api.
*/
protected function configureCruds(
ContainerBuilder $container,
array $crudConfig,
array $apiConfig,
Loader\YamlFileLoader $loader
): void
{
): void {
if (count($crudConfig) === 0) {
return;
}
@@ -282,10 +275,6 @@ class ChillMainExtension extends Extension implements PrependExtensionInterface,
// Note: the controller are loaded inside compiler pass
}
/**
* @param ContainerBuilder $container
*/
protected function prependCruds(ContainerBuilder $container)
{
$container->prependExtensionConfig('chill_main', [
@@ -302,11 +291,11 @@ class ChillMainExtension extends Extension implements PrependExtensionInterface,
'template' => '@ChillMain/UserJob/index.html.twig',
],
'new' => [
'role' => 'ROLE_ADMIN'
'role' => 'ROLE_ADMIN',
],
'edit' => [
'role' => 'ROLE_ADMIN'
]
'role' => 'ROLE_ADMIN',
],
],
],
[
@@ -319,17 +308,17 @@ class ChillMainExtension extends Extension implements PrependExtensionInterface,
'actions' => [
'index' => [
'role' => 'ROLE_ADMIN',
'template' => '@ChillMain/User/index.html.twig'
'template' => '@ChillMain/User/index.html.twig',
],
'new' => [
'role' => 'ROLE_ADMIN',
'template' => '@ChillMain/User/new.html.twig'
'template' => '@ChillMain/User/new.html.twig',
],
'edit' => [
'role' => 'ROLE_ADMIN',
'template' => '@ChillMain/User/edit.html.twig'
]
]
'template' => '@ChillMain/User/edit.html.twig',
],
],
],
[
'class' => Location::class,
@@ -343,15 +332,15 @@ class ChillMainExtension extends Extension implements PrependExtensionInterface,
'role' => 'ROLE_ADMIN',
'template' => '@ChillMain/Location/index.html.twig',
],
'new' => [
'new' => [
'role' => 'ROLE_ADMIN',
'template' => '@ChillMain/Location/new.html.twig',
],
'edit' => [
'edit' => [
'role' => 'ROLE_ADMIN',
'template' => '@ChillMain/Location/edit.html.twig',
]
]
],
],
],
[
'class' => LocationType::class,
@@ -365,15 +354,15 @@ class ChillMainExtension extends Extension implements PrependExtensionInterface,
'role' => 'ROLE_ADMIN',
'template' => '@ChillMain/LocationType/index.html.twig',
],
'new' => [
'new' => [
'role' => 'ROLE_ADMIN',
'template' => '@ChillMain/LocationType/new.html.twig',
],
'edit' => [
'edit' => [
'role' => 'ROLE_ADMIN',
'template' => '@ChillMain/LocationType/edit.html.twig',
]
]
],
],
],
],
'apis' => [
@@ -387,7 +376,7 @@ class ChillMainExtension extends Extension implements PrependExtensionInterface,
'_index' => [
'methods' => [
Request::METHOD_GET => true,
Request::METHOD_HEAD => true
Request::METHOD_HEAD => true,
],
],
'_entity' => [
@@ -395,10 +384,10 @@ class ChillMainExtension extends Extension implements PrependExtensionInterface,
Request::METHOD_GET => true,
Request::METHOD_POST => true,
Request::METHOD_HEAD => true,
Request::METHOD_PATCH => true
]
Request::METHOD_PATCH => true,
],
],
]
],
],
[
'controller' => \Chill\MainBundle\Controller\AddressReferenceAPIController::class,
@@ -410,16 +399,16 @@ class ChillMainExtension extends Extension implements PrependExtensionInterface,
'_index' => [
'methods' => [
Request::METHOD_GET => true,
Request::METHOD_HEAD => true
Request::METHOD_HEAD => true,
],
],
'_entity' => [
'methods' => [
Request::METHOD_GET => true,
Request::METHOD_HEAD => true
]
Request::METHOD_HEAD => true,
],
],
]
],
],
[
'controller' => \Chill\MainBundle\Controller\PostalCodeAPIController::class,
@@ -431,7 +420,7 @@ class ChillMainExtension extends Extension implements PrependExtensionInterface,
'_index' => [
'methods' => [
Request::METHOD_GET => true,
Request::METHOD_HEAD => true
Request::METHOD_HEAD => true,
],
],
'_entity' => [
@@ -439,9 +428,9 @@ class ChillMainExtension extends Extension implements PrependExtensionInterface,
Request::METHOD_GET => true,
Request::METHOD_HEAD => true,
Request::METHOD_POST => true,
]
],
],
]
],
],
[
'class' => \Chill\MainBundle\Entity\Country::class,
@@ -452,16 +441,16 @@ class ChillMainExtension extends Extension implements PrependExtensionInterface,
'_index' => [
'methods' => [
Request::METHOD_GET => true,
Request::METHOD_HEAD => true
Request::METHOD_HEAD => true,
],
],
'_entity' => [
'methods' => [
Request::METHOD_GET => true,
Request::METHOD_HEAD => true
]
Request::METHOD_HEAD => true,
],
],
]
],
],
[
'class' => \Chill\MainBundle\Entity\User::class,
@@ -473,16 +462,16 @@ class ChillMainExtension extends Extension implements PrependExtensionInterface,
'_index' => [
'methods' => [
Request::METHOD_GET => true,
Request::METHOD_HEAD => true
Request::METHOD_HEAD => true,
],
],
'_entity' => [
'methods' => [
Request::METHOD_GET => true,
Request::METHOD_HEAD => true,
]
],
],
]
],
],
[
'class' => \Chill\MainBundle\Entity\Scope::class,
@@ -493,16 +482,16 @@ class ChillMainExtension extends Extension implements PrependExtensionInterface,
'_index' => [
'methods' => [
Request::METHOD_GET => true,
Request::METHOD_HEAD => true
Request::METHOD_HEAD => true,
],
],
'_entity' => [
'methods' => [
Request::METHOD_GET => true,
Request::METHOD_HEAD => true,
]
],
],
]
],
],
[
'class' => \Chill\MainBundle\Entity\Location::class,
@@ -514,7 +503,7 @@ class ChillMainExtension extends Extension implements PrependExtensionInterface,
'_index' => [
'methods' => [
Request::METHOD_GET => true,
Request::METHOD_HEAD => true
Request::METHOD_HEAD => true,
],
],
'_entity' => [
@@ -522,10 +511,9 @@ class ChillMainExtension extends Extension implements PrependExtensionInterface,
Request::METHOD_GET => true,
Request::METHOD_HEAD => true,
Request::METHOD_POST => true,
]
],
],
]
],
],
[
'class' => \Chill\MainBundle\Entity\LocationType::class,
@@ -537,19 +525,18 @@ class ChillMainExtension extends Extension implements PrependExtensionInterface,
'_index' => [
'methods' => [
Request::METHOD_GET => true,
Request::METHOD_HEAD => true
Request::METHOD_HEAD => true,
],
],
'_entity' => [
'methods' => [
Request::METHOD_GET => true,
Request::METHOD_HEAD => true,
]
],
],
]
]
]
],
],
],
]);
}
}

View File

@@ -1,14 +1,21 @@
<?php
/**
* Chill is a software for social workers
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/
declare(strict_types=1);
namespace Chill\MainBundle\DependencyInjection\CompilerPass;
use Chill\MainBundle\Form\PermissionsGroupType;
use LogicException;
use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Chill\MainBundle\Form\PermissionsGroupType;
use Symfony\Component\DependencyInjection\Reference;
use LogicException;
class ACLFlagsCompilerPass implements CompilerPassInterface
{
@@ -16,19 +23,24 @@ class ACLFlagsCompilerPass implements CompilerPassInterface
{
$permissionGroupType = $container->getDefinition(PermissionsGroupType::class);
foreach($container->findTaggedServiceIds('chill_main.flags') as $id => $tags) {
foreach ($container->findTaggedServiceIds('chill_main.flags') as $id => $tags) {
$reference = new Reference($id);
foreach ($tags as $tag) {
switch($tag['scope']) {
switch ($tag['scope']) {
case PermissionsGroupType::FLAG_SCOPE:
$permissionGroupType->addMethodCall('addFlagProvider', [$reference]);
$permissionGroupType->addMethodCall('addFlagProvider', [ $reference ]);
break;
default:
throw new LogicException(sprintf(
"This tag 'scope' is not implemented: %s, on service with id %s", $tag['scope'], $id)
);
throw new LogicException(
sprintf(
"This tag 'scope' is not implemented: %s, on service with id %s",
$tag['scope'],
$id
)
);
}
}
}

View File

@@ -1,51 +1,38 @@
<?php
/*
* Copyright (C) 2015 Champs-Libres <info@champs-libres.coop>
/**
* Chill is a software for social workers
*
* This program is free software: you can redistribute it and/or modify
* 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/>.
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/
namespace Chill\MainBundle\DependencyInjection\CompilerPass;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use LogicException;
use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
use Symfony\Component\DependencyInjection\Reference;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Definition;
use Symfony\Component\DependencyInjection\Reference;
/**
* Compiles the services tagged with :
*
* Compiles the services tagged with :.
*
* - chill.export
* - chill.export_formatter
* - chill.export_aggregator
* - chill.export_filter
* - chill.export_elements_provider
*
*
* @author Julien Fastré <julien.fastre@champs-libres.coop>
*/
class ExportsCompilerPass implements CompilerPassInterface
{
public function process(ContainerBuilder $container)
{
if (!$container->has('Chill\MainBundle\Export\ExportManager')) {
throw new \LogicException('service Chill\MainBundle\Export\ExportManager '
throw new LogicException('service Chill\MainBundle\Export\ExportManager '
. 'is not defined. It is required by ExportsCompilerPass');
}
$chillManagerDefinition = $container->findDefinition(
'Chill\MainBundle\Export\ExportManager'
);
@@ -56,155 +43,164 @@ class ExportsCompilerPass implements CompilerPassInterface
$this->compileFormatters($chillManagerDefinition, $container);
$this->compileExportElementsProvider($chillManagerDefinition, $container);
}
private function compileExports(Definition $chillManagerDefinition,
ContainerBuilder $container)
{
$taggedServices = $container->findTaggedServiceIds(
'chill.export'
);
$knownAliases = array();
foreach ($taggedServices as $id => $tagAttributes) {
foreach ($tagAttributes as $attributes) {
if (!isset($attributes["alias"])) {
throw new \LogicException("the 'alias' attribute is missing in your ".
"service '$id' definition");
}
if (array_search($attributes["alias"], $knownAliases)) {
throw new \LogicException("There is already a chill.export service with alias "
.$attributes["alias"].". Choose another alias.");
}
$knownAliases[] = $attributes["alias"];
$chillManagerDefinition->addMethodCall(
'addExport',
array(new Reference($id), $attributes["alias"])
);
}
}
}
private function compileFilters(Definition $chillManagerDefinition,
ContainerBuilder $container)
{
$taggedServices = $container->findTaggedServiceIds(
'chill.export_filter'
);
$knownAliases = array();
foreach ($taggedServices as $id => $tagAttributes) {
foreach ($tagAttributes as $attributes) {
if (!isset($attributes["alias"])) {
throw new \LogicException("the 'alias' attribute is missing in your ".
"service '$id' definition");
}
if (array_search($attributes["alias"], $knownAliases)) {
throw new \LogicException("There is already a chill.export_filter service with alias "
.$attributes["alias"].". Choose another alias.");
}
$knownAliases[] = $attributes["alias"];
$chillManagerDefinition->addMethodCall(
'addFilter',
array(new Reference($id), $attributes["alias"])
);
}
}
}
private function compileAggregators(Definition $chillManagerDefinition,
ContainerBuilder $container)
private function compileAggregators(
Definition $chillManagerDefinition,
ContainerBuilder $container
)
{
$taggedServices = $container->findTaggedServiceIds(
'chill.export_aggregator'
);
$knownAliases = array();
$knownAliases = [];
foreach ($taggedServices as $id => $tagAttributes) {
foreach ($tagAttributes as $attributes) {
if (!isset($attributes["alias"])) {
throw new \LogicException("the 'alias' attribute is missing in your ".
"service '$id' definition");
if (!isset($attributes['alias'])) {
throw new LogicException("the 'alias' attribute is missing in your " .
"service '{$id}' definition");
}
if (array_search($attributes["alias"], $knownAliases)) {
throw new \LogicException("There is already a chill.export_aggregator service with alias "
.$attributes["alias"].". Choose another alias.");
if (array_search($attributes['alias'], $knownAliases)) {
throw new LogicException('There is already a chill.export_aggregator service with alias '
. $attributes['alias'] . '. Choose another alias.');
}
$knownAliases[] = $attributes["alias"];
$knownAliases[] = $attributes['alias'];
$chillManagerDefinition->addMethodCall(
'addAggregator',
array(new Reference($id), $attributes["alias"])
);
}
}
}
private function compileFormatters(Definition $chillManagerDefinition,
ContainerBuilder $container)
{
$taggedServices = $container->findTaggedServiceIds(
'chill.export_formatter'
);
$knownAliases = array();
foreach ($taggedServices as $id => $tagAttributes) {
foreach ($tagAttributes as $attributes) {
if (!isset($attributes["alias"])) {
throw new \LogicException("the 'alias' attribute is missing in your ".
"service '$id' definition");
}
if (array_search($attributes["alias"], $knownAliases)) {
throw new \LogicException("There is already a chill.export_formatter service with alias "
.$attributes["alias"].". Choose another alias.");
}
$knownAliases[] = $attributes["alias"];
$chillManagerDefinition->addMethodCall(
'addFormatter',
array(new Reference($id), $attributes["alias"])
);
}
}
}
private function compileExportElementsProvider(Definition $chillManagerDefinition,
ContainerBuilder $container)
{
$taggedServices = $container->findTaggedServiceIds(
'chill.export_elements_provider'
);
$knownAliases = array();
foreach ($taggedServices as $id => $tagAttributes) {
foreach ($tagAttributes as $attributes) {
if (!isset($attributes["prefix"])) {
throw new \LogicException("the 'prefix' attribute is missing in your ".
"service '$id' definition");
}
if (array_search($attributes["prefix"], $knownAliases)) {
throw new \LogicException("There is already a chill.export_elements_provider service with prefix "
.$attributes["prefix"].". Choose another prefix.");
}
$knownAliases[] = $attributes["prefix"];
$chillManagerDefinition->addMethodCall(
'addExportElementsProvider',
array(new Reference($id), $attributes["prefix"])
[new Reference($id), $attributes['alias']]
);
}
}
}
private function compileExportElementsProvider(
Definition $chillManagerDefinition,
ContainerBuilder $container
)
{
$taggedServices = $container->findTaggedServiceIds(
'chill.export_elements_provider'
);
$knownAliases = [];
foreach ($taggedServices as $id => $tagAttributes) {
foreach ($tagAttributes as $attributes) {
if (!isset($attributes['prefix'])) {
throw new LogicException("the 'prefix' attribute is missing in your " .
"service '{$id}' definition");
}
if (array_search($attributes['prefix'], $knownAliases)) {
throw new LogicException('There is already a chill.export_elements_provider service with prefix '
. $attributes['prefix'] . '. Choose another prefix.');
}
$knownAliases[] = $attributes['prefix'];
$chillManagerDefinition->addMethodCall(
'addExportElementsProvider',
[new Reference($id), $attributes['prefix']]
);
}
}
}
private function compileExports(
Definition $chillManagerDefinition,
ContainerBuilder $container
)
{
$taggedServices = $container->findTaggedServiceIds(
'chill.export'
);
$knownAliases = [];
foreach ($taggedServices as $id => $tagAttributes) {
foreach ($tagAttributes as $attributes) {
if (!isset($attributes['alias'])) {
throw new LogicException("the 'alias' attribute is missing in your " .
"service '{$id}' definition");
}
if (array_search($attributes['alias'], $knownAliases)) {
throw new LogicException('There is already a chill.export service with alias '
. $attributes['alias'] . '. Choose another alias.');
}
$knownAliases[] = $attributes['alias'];
$chillManagerDefinition->addMethodCall(
'addExport',
[new Reference($id), $attributes['alias']]
);
}
}
}
private function compileFilters(
Definition $chillManagerDefinition,
ContainerBuilder $container
)
{
$taggedServices = $container->findTaggedServiceIds(
'chill.export_filter'
);
$knownAliases = [];
foreach ($taggedServices as $id => $tagAttributes) {
foreach ($tagAttributes as $attributes) {
if (!isset($attributes['alias'])) {
throw new LogicException("the 'alias' attribute is missing in your " .
"service '{$id}' definition");
}
if (array_search($attributes['alias'], $knownAliases)) {
throw new LogicException('There is already a chill.export_filter service with alias '
. $attributes['alias'] . '. Choose another alias.');
}
$knownAliases[] = $attributes['alias'];
$chillManagerDefinition->addMethodCall(
'addFilter',
[new Reference($id), $attributes['alias']]
);
}
}
}
private function compileFormatters(
Definition $chillManagerDefinition,
ContainerBuilder $container
)
{
$taggedServices = $container->findTaggedServiceIds(
'chill.export_formatter'
);
$knownAliases = [];
foreach ($taggedServices as $id => $tagAttributes) {
foreach ($tagAttributes as $attributes) {
if (!isset($attributes['alias'])) {
throw new LogicException("the 'alias' attribute is missing in your " .
"service '{$id}' definition");
}
if (array_search($attributes['alias'], $knownAliases)) {
throw new LogicException('There is already a chill.export_formatter service with alias '
. $attributes['alias'] . '. Choose another alias.');
}
$knownAliases[] = $attributes['alias'];
$chillManagerDefinition->addMethodCall(
'addFormatter',
[new Reference($id), $attributes['alias']]
);
}
}
}
}

View File

@@ -1,46 +1,35 @@
<?php
/*
* Copyright (C) 2019 Champs-Libres <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\DependencyInjection\CompilerPass;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
use Symfony\Component\DependencyInjection\Reference;
use Chill\MainBundle\Form\Type\Export\PickCenterType;
/**
*
* Chill is a software for social workers
*
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/
namespace Chill\MainBundle\DependencyInjection\CompilerPass;
use LogicException;
use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Reference;
class GroupingCenterCompilerPass implements CompilerPassInterface
{
public function process(ContainerBuilder $container)
{
if (FALSE === $container->hasDefinition('chill.main.form.pick_centers_type')) {
throw new \LogicException("The service chill.main.form.pick_centers_type does "
. "not exists in container");
if (false === $container->hasDefinition('chill.main.form.pick_centers_type')) {
throw new LogicException('The service chill.main.form.pick_centers_type does '
. 'not exists in container');
}
$pickCenterType = $container->getDefinition('chill.main.form.pick_centers_type');
foreach ($container->findTaggedServiceIds('chill.grouping_center') as $serviceId => $tagged) {
$pickCenterType->addMethodCall('addGroupingCenter',
[ new Reference($serviceId) ]);
$pickCenterType->addMethodCall(
'addGroupingCenter',
[new Reference($serviceId)]
);
}
}
}

View File

@@ -1,44 +1,33 @@
<?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\DependencyInjection\CompilerPass;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
use Symfony\Component\DependencyInjection\Reference;
use Chill\MainBundle\Routing\MenuComposer;
/**
*
* Chill is a software for social workers
*
* @author Julien Fastré <julien.fastre@champs-libres.coop>
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/
namespace Chill\MainBundle\DependencyInjection\CompilerPass;
use Chill\MainBundle\Routing\MenuComposer;
use LogicException;
use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Reference;
class MenuCompilerPass implements CompilerPassInterface
{
public function process(ContainerBuilder $container)
{
if (!$container->hasDefinition('chill.main.menu_composer')) {
throw new \LogicException(sprintf("The service %s does not exists in "
. "container.", MenuComposer::class));
if (!$container->hasDefinition('chill.main.menu_composer')) {
throw new LogicException(sprintf('The service %s does not exists in '
. 'container.', MenuComposer::class));
}
$menuComposerDefinition = $container->getDefinition('chill.main.menu_composer');
$services = [];
foreach ($container->findTaggedServiceIds('chill.menu_builder') as $id => $tags) {
$services[] = [
'id' => $id,
@@ -50,11 +39,13 @@ class MenuCompilerPass implements CompilerPassInterface
if ($a['priority'] == $b['priority']) {
return 0;
}
return ($a['priority'] < $b['priority']) ? -1 : 1;
});
foreach ($services as $service) {
$class = $container->getDefinition($service['id'])->getClass();
foreach ($class::getMenuIds() as $menuId) {
$menuComposerDefinition
->addMethodCall('addLocalMenuBuilder', [new Reference($service['id']), $menuId]);

View File

@@ -1,43 +1,31 @@
<?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\DependencyInjection\CompilerPass;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
use Chill\MainBundle\Templating\UI\CountNotificationUser;
use Symfony\Component\DependencyInjection\Reference;
/**
*
* Chill is a software for social workers
*
* @author Julien Fastré <julien.fastre@champs-libres.coop>
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/
namespace Chill\MainBundle\DependencyInjection\CompilerPass;
use Chill\MainBundle\Templating\UI\CountNotificationUser;
use LogicException;
use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Reference;
class NotificationCounterCompilerPass implements CompilerPassInterface
{
public function process(ContainerBuilder $container)
{
if (!$container->hasDefinition(CountNotificationUser::class)) {
throw new \LogicException("The service ".CountNotificationUser::class." "
. "should be defined");
throw new LogicException('The service ' . CountNotificationUser::class . ' '
. 'should be defined');
}
$notificationCounterDefinition = $container->getDefinition(CountNotificationUser::class);
foreach ($container->findTaggedServiceIds('chill.count_notification.user') as $id => $tags) {
$notificationCounterDefinition
->addMethodCall('addNotificationCounter', [new Reference($id)]);

View File

@@ -1,32 +1,21 @@
<?php
/*
/**
* Chill is a software for social workers
*
* Copyright (C) 2014, Champs Libres Cooperative SCRLFS, <http://www.champs-libres.coop>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/
namespace Chill\MainBundle\DependencyInjection\CompilerPass;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use LogicException;
use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Reference;
class SearchableServicesCompilerPass implements CompilerPassInterface
{
/*
* (non-PHPdoc)
* @see \Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface::process()
@@ -34,10 +23,10 @@ class SearchableServicesCompilerPass implements CompilerPassInterface
public function process(ContainerBuilder $container)
{
if (!$container->hasDefinition('chill_main.search_provider')) {
throw new \LogicException('service chill_main.search_provider '
throw new LogicException('service chill_main.search_provider '
. 'is not defined.');
}
$definition = $container->getDefinition(
'chill_main.search_provider'
);
@@ -45,29 +34,27 @@ class SearchableServicesCompilerPass implements CompilerPassInterface
$taggedServices = $container->findTaggedServiceIds(
'chill.search'
);
$knownAliases = array();
$knownAliases = [];
foreach ($taggedServices as $id => $tagAttributes) {
foreach ($tagAttributes as $attributes) {
if (!isset($attributes["alias"])) {
throw new \LogicException("the 'name' attribute is missing in your ".
"service '$id' definition");
if (!isset($attributes['alias'])) {
throw new LogicException("the 'name' attribute is missing in your " .
"service '{$id}' definition");
}
if (array_search($attributes["alias"], $knownAliases)) {
throw new \LogicException("There is already a chill.search service with alias "
.$attributes["alias"].". Choose another alias.");
if (array_search($attributes['alias'], $knownAliases)) {
throw new LogicException('There is already a chill.search service with alias '
. $attributes['alias'] . '. Choose another alias.');
}
$knownAliases[] = $attributes["alias"];
$knownAliases[] = $attributes['alias'];
$definition->addMethodCall(
'addSearchService',
array(new Reference($id), $attributes["alias"])
[new Reference($id), $attributes['alias']]
);
}
}
}
}
}

View File

@@ -1,42 +1,32 @@
<?php
/*
* Copyright (C) 2015 Champs-Libres Coopérative <info@champs-libres.coop>
/**
* Chill is a software for social workers
*
* 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/>.
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/
namespace Chill\MainBundle\DependencyInjection\CompilerPass;
use LogicException;
use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Reference;
/**
* Add services taggued with `name: chill.timeline` to
* timeline_builder service definition
*
* Add services taggued with `name: chill.timeline` to
* timeline_builder service definition.
*/
class TimelineCompilerClass implements CompilerPassInterface
{
public function process(ContainerBuilder $container)
{
if (!$container->hasDefinition('chill_main.timeline_builder')) {
throw new \LogicException('service chill_main.timeline_builder '
throw new LogicException('service chill_main.timeline_builder '
. 'is not defined.');
}
$definition = $container->getDefinition(
'chill_main.timeline_builder'
);
@@ -44,22 +34,19 @@ class TimelineCompilerClass implements CompilerPassInterface
$taggedServices = $container->findTaggedServiceIds(
'chill.timeline'
);
foreach ($taggedServices as $id => $tagAttributes) {
foreach ($tagAttributes as $attributes) {
if (!isset($attributes["context"])) {
throw new \LogicException("the 'context' attribute is missing in your ".
"service '$id' definition");
if (!isset($attributes['context'])) {
throw new LogicException("the 'context' attribute is missing in your " .
"service '{$id}' definition");
}
$definition->addMethodCall(
'addProvider',
array($attributes["context"], $id, new Reference($id))
[$attributes['context'], $id, new Reference($id)]
);
}
}
}
}

View File

@@ -1,34 +1,24 @@
<?php
/*
* Copyright (C) 2016 Julien Fastré <julien.fastre@champs-libres.coop>
/**
* Chill is a software for social workers
*
* This program is free software: you can redistribute it and/or modify
* 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/>.
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/
namespace Chill\MainBundle\DependencyInjection\CompilerPass;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Chill\MainBundle\DependencyInjection\Widget\AbstractWidgetsCompilerPass;
use Symfony\Component\DependencyInjection\ContainerBuilder;
/**
* Compile the service definition to register widgets.
*
*/
class WidgetsCompilerPass extends AbstractWidgetsCompilerPass {
public function process(ContainerBuilder $container)
{
$this->doProcess($container, 'chill_main', 'chill_main.widgets');
}
class WidgetsCompilerPass extends AbstractWidgetsCompilerPass
{
public function process(ContainerBuilder $container)
{
$this->doProcess($container, 'chill_main', 'chill_main.widgets');
}
}

View File

@@ -1,59 +1,52 @@
<?php
/*
/**
* Chill is a software for social workers
* Copyright (C) 2015 Champs-Libres Coopérative <info@champs-libres.coop>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/
namespace Chill\MainBundle\DependencyInjection;
use LogicException;
use RuntimeException;
use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
use Symfony\Component\DependencyInjection\ContainerBuilder;
/**
* Description of ConfigConsistencyCompilerPass
*
* @author Julien Fastré <julien.fastre@champs-libres.coop>
* Description of ConfigConsistencyCompilerPass.
*/
class ConfigConsistencyCompilerPass implements CompilerPassInterface
{
public function process(ContainerBuilder $container)
{
$availableLanguages = $container
->getParameter('chill_main.available_languages');
->getParameter('chill_main.available_languages');
$methodCallsTranslator = $container
->findDefinition('translator.default')
->getMethodCalls();
$fallbackLocales = array();
foreach($methodCallsTranslator as $call) {
if ($call[0] === 'setFallbackLocales') {
$fallbackLocales = array_merge($fallbackLocales,
$call[1][0]);
}
->findDefinition('translator.default')
->getMethodCalls();
$fallbackLocales = [];
foreach ($methodCallsTranslator as $call) {
if ('setFallbackLocales' === $call[0]) {
$fallbackLocales = array_merge(
$fallbackLocales,
$call[1][0]
);
}
}
if (count($fallbackLocales) === 0) {
throw new \LogicException('the fallback locale are not defined. '
throw new LogicException('the fallback locale are not defined. '
. 'The framework config should not allow this.');
}
$diff = array_diff($fallbackLocales, $availableLanguages);
if (count($diff) > 0) {
throw new \RuntimeException(sprintf('The chill_main.available_languages'
throw new RuntimeException(sprintf('The chill_main.available_languages'
. ' parameter does not contains fallback locales. The languages %s'
. ' are missing.', implode(', ', $diff)));
}

View File

@@ -1,38 +1,38 @@
<?php
/**
* Chill is a software for social workers
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/
namespace Chill\MainBundle\DependencyInjection;
use Chill\MainBundle\DependencyInjection\Widget\AddWidgetConfigurationTrait;
use Symfony\Component\Config\Definition\Builder\TreeBuilder;
use Symfony\Component\Config\Definition\ConfigurationInterface;
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;
/**
* Configure the main bundle
* Configure the main bundle.
*/
class Configuration implements ConfigurationInterface
{
use AddWidgetConfigurationTrait;
private ContainerBuilder $containerBuilder;
public function __construct(
array $widgetFactories,
ContainerBuilder $containerBuilder)
array $widgetFactories,
ContainerBuilder $containerBuilder
)
{
$this->setWidgetFactories($widgetFactories);
$this->containerBuilder = $containerBuilder;
}
/**
* {@inheritDoc}
*/
public function getConfigTreeBuilder()
{
$treeBuilder = new TreeBuilder('chill_main');
@@ -40,225 +40,220 @@ class Configuration implements ConfigurationInterface
$rootNode
->children()
->scalarNode('installation_name')
->cannotBeEmpty()
->defaultValue('Chill')
->end() // end of scalar 'installation_name'
->arrayNode('available_languages')
->defaultValue(array('fr'))
->prototype('scalar')->end()
->end() // end of array 'available_languages'
->arrayNode('available_countries')
->defaultValue(array('FR'))
->prototype('scalar')->end()
->end() // end of array 'available_countries'
->arrayNode('routing')
->children()
->arrayNode('resources')
->prototype('scalar')->end()
->end() // end of array 'resources'
->end() // end of children
->end() // end of array node 'routing'
->arrayNode('pagination')
->canBeDisabled()
->children()
->integerNode('item_per_page')
->info('The number of item to show in the page result, by default')
->min(1)
->defaultValue(50)
->end() // end of integer 'item_per_page'
->end() // end of children
->end() // end of pagination
->arrayNode('notifications')
->children()
->scalarNode('from_email')
->cannotBeEmpty()
->end()
->scalarNode('from_name')
->cannotBeEmpty()
->end()
->enumNode('scheme')
->cannotBeEmpty()
->values(['http', 'https'])
->defaultValue('https')
->end()
->scalarNode('host')
->cannotBeEmpty()
->end()
->end()
->end() // end of notifications
->arrayNode('phone_helper')
->canBeUnset()
->children()
->scalarNode('twilio_sid')
->defaultNull()
->end()
->scalarNode('twilio_secret')
->defaultNull()
->end()
->end()
->end()
->arrayNode('acl')
->addDefaultsIfNotSet()
->children()
->booleanNode('form_show_scopes')
->defaultTrue()
->end()
->booleanNode('form_show_centers')
->defaultTrue()
->end()
->end()
->end()
->arrayNode('redis')
->children()
->scalarNode('host')
->cannotBeEmpty()
->end()
->scalarNode('port')
->defaultValue(6379)
->end()
->scalarNode('timeout')
->defaultValue(1)
->end()
->end()
->end()
->arrayNode('widgets')
->canBeEnabled()
->canBeUnset()
->children()
->append($this->addWidgetsConfiguration('homepage', $this->containerBuilder))
->end() // end of widgets/children
->end() // end of widgets
->arrayNode('cruds')
->defaultValue([])
->arrayPrototype()
->children()
->scalarNode('class')->cannotBeEmpty()->isRequired()->end()
->scalarNode('controller')
->cannotBeEmpty()
->defaultValue(\Chill\MainBundle\CRUD\Controller\CRUDController::class)
->end()
->scalarNode('name')->cannotBeEmpty()->isRequired()->end()
->scalarNode('base_path')->cannotBeEmpty()->isRequired()->end()
->scalarNode('base_role')->defaultNull()->end()
->scalarNode('form_class')->defaultNull()->end()
->arrayNode('actions')
->defaultValue([
'edit' => [],
'new' => []
])
->useAttributeAsKey('name')
->arrayPrototype()
->children()
->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")
->end()
->scalarNode('path')
->defaultNull()
->info('the path that will be **appended** after the base path. Do not forget to add '
->scalarNode('installation_name')
->cannotBeEmpty()
->defaultValue('Chill')
->end() // end of scalar 'installation_name'
->arrayNode('available_languages')
->defaultValue(['fr'])
->prototype('scalar')->end()
->end() // end of array 'available_languages'
->arrayNode('available_countries')
->defaultValue(['FR'])
->prototype('scalar')->end()
->end() // end of array 'available_countries'
->arrayNode('routing')
->children()
->arrayNode('resources')
->prototype('scalar')->end()
->end() // end of array 'resources'
->end() // end of children
->end() // end of array node 'routing'
->arrayNode('pagination')
->canBeDisabled()
->children()
->integerNode('item_per_page')
->info('The number of item to show in the page result, by default')
->min(1)
->defaultValue(50)
->end() // end of integer 'item_per_page'
->end() // end of children
->end() // end of pagination
->arrayNode('notifications')
->children()
->scalarNode('from_email')
->cannotBeEmpty()
->end()
->scalarNode('from_name')
->cannotBeEmpty()
->end()
->enumNode('scheme')
->cannotBeEmpty()
->values(['http', 'https'])
->defaultValue('https')
->end()
->scalarNode('host')
->cannotBeEmpty()
->end()
->end()
->end() // end of notifications
->arrayNode('phone_helper')
->canBeUnset()
->children()
->scalarNode('twilio_sid')
->defaultNull()
->end()
->scalarNode('twilio_secret')
->defaultNull()
->end()
->end()
->end()
->arrayNode('acl')
->addDefaultsIfNotSet()
->children()
->booleanNode('form_show_scopes')
->defaultTrue()
->end()
->booleanNode('form_show_centers')
->defaultTrue()
->end()
->end()
->end()
->arrayNode('redis')
->children()
->scalarNode('host')
->cannotBeEmpty()
->end()
->scalarNode('port')
->defaultValue(6379)
->end()
->scalarNode('timeout')
->defaultValue(1)
->end()
->end()
->end()
->arrayNode('widgets')
->canBeEnabled()
->canBeUnset()
->children()
->append($this->addWidgetsConfiguration('homepage', $this->containerBuilder))
->end() // end of widgets/children
->end() // end of widgets
->arrayNode('cruds')
->defaultValue([])
->arrayPrototype()
->children()
->scalarNode('class')->cannotBeEmpty()->isRequired()->end()
->scalarNode('controller')
->cannotBeEmpty()
->defaultValue(\Chill\MainBundle\CRUD\Controller\CRUDController::class)
->end()
->scalarNode('name')->cannotBeEmpty()->isRequired()->end()
->scalarNode('base_path')->cannotBeEmpty()->isRequired()->end()
->scalarNode('base_role')->defaultNull()->end()
->scalarNode('form_class')->defaultNull()->end()
->arrayNode('actions')
->defaultValue([
'edit' => [],
'new' => [],
])
->useAttributeAsKey('name')
->arrayPrototype()
->children()
->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')
->end()
->scalarNode('path')
->defaultNull()
->info('the path that will be **appended** after the base path. Do not forget to add '
. 'arguments for the method. Will be set to the action name, including an `{id}` '
. 'parameter if left empty.')
->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()
->scalarNode('role')
->defaultNull()
->info('the role that will be required for this action. Override option `base_role`')
->end()
->scalarNode('template')
->defaultNull()
->info('the template to render the view')
->end()
->end()
->end()
->end()
->end()
->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 '.
->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()
->scalarNode('role')
->defaultNull()
->info('the role that will be required for this action. Override option `base_role`')
->end()
->scalarNode('template')
->defaultNull()
->info('the template to render the view')
->end()
->end()
->end()
->end()
->end()
->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 '.
->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 '.
->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()
->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
;
;
return $treeBuilder;
}

View File

@@ -1,20 +1,25 @@
<?php
/**
* Chill is a software for social workers
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/
namespace Chill\MainBundle\DependencyInjection;
use Exception;
/**
* Description of MissingBundleException
*
* @author julien
* Description of MissingBundleException.
*/
class MissingBundleException extends Exception {
public function __construct($missingBundleName) {
$message = "The bundle $missingBundleName is missing.";
class MissingBundleException extends Exception
{
public function __construct($missingBundleName)
{
$message = "The bundle {$missingBundleName} is missing.";
parent::__construct($message, 500);
}
}

View File

@@ -1,42 +1,28 @@
<?php
/*
* Copyright (C) 2015 Julien Fastré <julien.fastre@champs-libres.coop>
/**
* Chill is a software for social workers
*
* This program is free software: you can redistribute it and/or modify
* 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/>.
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/
namespace Chill\MainBundle\DependencyInjection;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use LogicException;
use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Reference;
/**
*
*
* @author Julien Fastré <julien.fastre@champs-libres.coop>
*/
class RoleProvidersCompilerPass implements CompilerPassInterface
{
public function process(ContainerBuilder $container)
{
if (!$container->hasDefinition('chill.main.role_provider')) {
throw new \LogicException('service chill.main.role_provider '
throw new LogicException('service chill.main.role_provider '
. 'is not defined. It is required by RoleProviderCompilerPass');
}
$definition = $container->getDefinition(
'chill.main.role_provider'
);
@@ -44,14 +30,12 @@ class RoleProvidersCompilerPass implements CompilerPassInterface
$taggedServices = $container->findTaggedServiceIds(
'chill.role'
);
foreach ($taggedServices as $id => $tagAttributes) {
$definition->addMethodCall(
'addProvider',
array(new Reference($id))
[new Reference($id)]
);
}
}
}

View File

@@ -1,32 +1,24 @@
<?php
/*
* Copyright (C) 2016 Julien Fastré <julien.fastre@champs-libres.coop>
/**
* Chill is a software for social workers
*
* This program is free software: you can redistribute it and/or modify
* 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/>.
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/
namespace Chill\MainBundle\DependencyInjection\Widget;
use Chill\MainBundle\DependencyInjection\Widget\Factory\WidgetFactoryInterface;
use Doctrine\Common\Proxy\Exception\InvalidArgumentException;
use LengthException;
use LogicException;
use Symfony\Component\Config\Definition\Exception\InvalidConfigurationException;
use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\Config\Definition\Exception\InvalidConfigurationException;
use Doctrine\Common\Proxy\Exception\InvalidArgumentException;
use Symfony\Component\DependencyInjection\Reference;
use Symfony\Component\DependencyInjection\Definition;
use Chill\MainBundle\DependencyInjection\Widget\Factory\WidgetFactoryInterface;
use Chill\MainBundle\DependencyInjection\Widget\HasWidgetFactoriesExtensionInterface;
use Symfony\Component\DependencyInjection\Reference;
use UnexpectedValueException;
/**
* Compile the configurations and inject required service into container.
@@ -57,37 +49,30 @@ use Chill\MainBundle\DependencyInjection\Widget\HasWidgetFactoriesExtensionInter
* }
* }
* ```
*
*
*/
abstract class AbstractWidgetsCompilerPass implements CompilerPassInterface
{
private $widgetServices = array();
/**
*
* @var WidgetFactoryInterface[]
* the key to use to identify widget for a given place.
*/
private $widgetFactories;
public const WIDGET_CONFIG_ALIAS = 'widget_alias';
/**
* The service which will manage the widgets
* the key to use to order widget for a given place.
*/
public const WIDGET_CONFIG_ORDER = 'order';
/**
* The service which will manage the widgets.
*
* @var string
*/
const WIDGET_MANAGER = 'chill.main.twig.widget';
public const WIDGET_MANAGER = 'chill.main.twig.widget';
/**
* the method wich register the widget into give service.
*/
const WIDGET_MANAGER_METHOD_REGISTER = 'addWidget';
/**
* the value of the `name` key in service definitions's tag
*
* @var string
*/
const WIDGET_SERVICE_TAG_NAME = 'chill_widget';
public const WIDGET_MANAGER_METHOD_REGISTER = 'addWidget';
/**
* the key used to collect the alias in the service definition's tag.
@@ -96,34 +81,46 @@ abstract class AbstractWidgetsCompilerPass implements CompilerPassInterface
*
* @var string
*/
const WIDGET_SERVICE_TAG_ALIAS = 'alias';
public const WIDGET_SERVICE_TAG_ALIAS = 'alias';
/**
* the key used to collect the authorized place in the service definition's tag
* the value of the `name` key in service definitions's tag.
*
* @var string
*/
const WIDGET_SERVICE_TAG_PLACES = 'place';
public const WIDGET_SERVICE_TAG_NAME = 'chill_widget';
/**
* the key to use to order widget for a given place
*/
const WIDGET_CONFIG_ORDER = 'order';
/**
* the key to use to identify widget for a given place
*/
const WIDGET_CONFIG_ALIAS = 'widget_alias';
/**
* process the configuration and the container to add the widget available
* the key used to collect the authorized place in the service definition's tag.
*
* @var string
*/
public const WIDGET_SERVICE_TAG_PLACES = 'place';
/**
* cache of ordering by place.
*
* @internal used by function cacheAndGetOrdering
*
* @var array
*/
private $cacheOrdering = [];
/**
* @var WidgetFactoryInterface[]
*/
private $widgetFactories;
private $widgetServices = [];
/**
* process the configuration and the container to add the widget available.
*
* @param ContainerBuilder $container
* @param string $extension the extension of your bundle
* @param string $containerWidgetConfigParameterName the key under which we can use the widget configuration
* @throws \LogicException
* @throws \UnexpectedValueException if the given extension does not implement HasWidgetExtensionInterface
*
* @throws LogicException
* @throws UnexpectedValueException if the given extension does not implement HasWidgetExtensionInterface
*/
public function doProcess(
ContainerBuilder $container,
@@ -131,8 +128,8 @@ abstract class AbstractWidgetsCompilerPass implements CompilerPassInterface
$containerWidgetConfigParameterName
) {
if (!$container->hasDefinition(self::WIDGET_MANAGER)) {
throw new \LogicException("the service ".self::WIDGET_MANAGER." should".
" be present. It is required by ".self::class);
throw new LogicException('the service ' . self::WIDGET_MANAGER . ' should' .
' be present. It is required by ' . self::class);
}
$managerDefinition = $container->getDefinition(self::WIDGET_MANAGER);
@@ -142,15 +139,16 @@ abstract class AbstractWidgetsCompilerPass implements CompilerPassInterface
$extensionClass = $container->getExtension($extension);
// throw an error if extension does not implement HasWidgetFactoriesExtensionInterface
if (!$extensionClass instanceof HasWidgetFactoriesExtensionInterface) {
throw new \UnexpectedValueException(sprintf("The extension for %s "
. "do not implements %s. You should implement %s on %s",
$extension,
HasWidgetFactoriesExtensionInterface::class,
HasWidgetFactoriesExtensionInterface::class,
get_class($extensionClass)));
throw new UnexpectedValueException(sprintf(
'The extension for %s '
. 'do not implements %s. You should implement %s on %s',
$extension,
HasWidgetFactoriesExtensionInterface::class,
HasWidgetFactoriesExtensionInterface::class,
get_class($extensionClass)
));
}
$this->widgetFactories = $extensionClass->getWidgetFactories();
// collect the availabled tagged services
@@ -160,23 +158,22 @@ abstract class AbstractWidgetsCompilerPass implements CompilerPassInterface
$widgetParameters = $container->getParameter($containerWidgetConfigParameterName);
// and add them to the delegated_block
foreach($widgetParameters as $place => $widgets) {
foreach ($widgetParameters as $place => $widgets) {
foreach ($widgets as $param) {
$alias = $param[self::WIDGET_CONFIG_ALIAS];
// check that the service exists
if (!array_key_exists($alias, $this->widgetServices)) {
throw new InvalidConfigurationException(sprintf("The alias %s".
" is not defined.", $alias));
throw new InvalidConfigurationException(sprintf('The alias %s' .
' is not defined.', $alias));
}
// check that the widget is allowed at this place
if (!$this->isPlaceAllowedForWidget($place, $alias, $container)) {
throw new InvalidConfigurationException(sprintf(
"The widget with alias %s is not allowed at place %s",
'The widget with alias %s is not allowed at place %s',
$alias,
$place
));
));
}
// get the order, eventually corrected
@@ -189,64 +186,145 @@ abstract class AbstractWidgetsCompilerPass implements CompilerPassInterface
$factory = $this->widgetServices[$alias];
// get the config (under the key which equals to widget_alias
$config = isset($param[$factory->getWidgetAlias()]) ?
$param[$factory->getWidgetAlias()] : array();
$param[$factory->getWidgetAlias()] : [];
// register the service into the container
$serviceId =$this->registerServiceIntoContainer($container,
$factory, $place, $order, $config);
$serviceId = $this->registerServiceIntoContainer(
$container,
$factory,
$place,
$order,
$config
);
$managerDefinition->addMethodCall(self::WIDGET_MANAGER_METHOD_REGISTER,
array(
$place,
$order,
new Reference($serviceId),
$config
));
$managerDefinition->addMethodCall(
self::WIDGET_MANAGER_METHOD_REGISTER,
[
$place,
$order,
new Reference($serviceId),
$config,
]
);
} else {
$managerDefinition->addMethodCall(self::WIDGET_MANAGER_METHOD_REGISTER,
array(
$place,
$order,
new Reference($this->widgetServices[$alias]),
array() // the config is alway an empty array
));
$managerDefinition->addMethodCall(
self::WIDGET_MANAGER_METHOD_REGISTER,
[
$place,
$order,
new Reference($this->widgetServices[$alias]),
[], // the config is alway an empty array
]
);
}
}
}
}
/**
* This method collect all service tagged with `self::WIDGET_SERVICE_TAG`, and
* add also the widget defined by factories.
*
* This method also check that the service is correctly tagged with `alias` and
* `places`, or the factory give a correct alias and more than one place.
*
* @throws InvalidConfigurationException
* @throws InvalidArgumentException
*/
protected function collectTaggedServices(ContainerBuilder $container)
{
// first, check the service tagged in service definition
foreach ($container->findTaggedServiceIds(self::WIDGET_SERVICE_TAG_NAME) as $id => $attrs) {
foreach ($attrs as $attr) {
// check the alias is set
if (!isset($attr[self::WIDGET_SERVICE_TAG_ALIAS])) {
throw new InvalidConfigurationException('you should add an ' . self::WIDGET_SERVICE_TAG_ALIAS .
' key on the service ' . $id);
}
// check the place is set
if (!isset($attr[self::WIDGET_SERVICE_TAG_PLACES])) {
throw new InvalidConfigurationException(sprintf(
'You should add a %s key on the service %s',
self::WIDGET_SERVICE_TAG_PLACES,
$id
));
}
// check the alias does not exists yet
if (array_key_exists($attr[self::WIDGET_SERVICE_TAG_ALIAS], $this->widgetServices)) {
throw new InvalidArgumentException('a service has already be defined with the ' .
self::WIDGET_SERVICE_TAG_ALIAS . ' ' . $attr[self::WIDGET_SERVICE_TAG_ALIAS]);
}
// register the service as available
$this->widgetServices[$attr[self::WIDGET_SERVICE_TAG_ALIAS]] = $id;
}
}
// add the services defined by factories
foreach ($this->widgetFactories as $factory) {
/* @var $factory WidgetFactoryInterface */
$alias = $factory->getWidgetAlias();
// check the alias is not empty
if (empty($alias)) {
throw new LogicException(sprintf(
'the widget factory %s returns an empty alias',
get_class($factory)
));
}
// check the places are not empty
if (!is_array($factory->getAllowedPlaces())) {
throw new UnexpectedValueException("the method 'getAllowedPlaces' "
. 'should return a non-empty array. Unexpected value on ' .
get_class($factory));
}
if (count($factory->getAllowedPlaces()) == 0) {
throw new LengthException("The method 'getAllowedPlaces' should "
. 'return a non-empty array, but returned 0 elements on ' .
get_class($factory) . '::getAllowedPlaces()');
}
// check the alias does not exists yet
if (array_key_exists($alias, $this->widgetServices)) {
throw new InvalidArgumentException('a service has already be defined with the ' .
self::WIDGET_SERVICE_TAG_ALIAS . ' ' . $alias);
}
// register the factory as available
$this->widgetServices[$factory->getWidgetAlias()] = $factory;
}
}
/**
* register the service into container.
*
* @param ContainerBuilder $container
* @param WidgetFactoryInterface $factory
* @param string $place
* @param float $order
* @param array $config
*
* @return string the id of the new service
*/
protected function registerServiceIntoContainer(
ContainerBuilder $container,
WidgetFactoryInterface $factory,
ContainerBuilder $container,
WidgetFactoryInterface $factory,
$place,
$order,
array $config
) {
$serviceId = $factory->getServiceId($container, $place, $order, $config);
$definition = $factory->createDefinition(
$container,
$place,
$order,
array $config
) {
$serviceId = $factory->getServiceId($container, $place, $order, $config);
$definition = $factory->createDefinition($container, $place,
$order, $config);
$config
);
$container->setDefinition($serviceId, $definition);
return $serviceId;
}
/**
* cache of ordering by place.
*
* @internal used by function cacheAndGetOrdering
* @var array
*/
private $cacheOrdering = array();
/**
* check if the ordering has already be used for the given $place and,
* if yes, correct the ordering by incrementation of 1 until the ordering
@@ -256,44 +334,46 @@ abstract class AbstractWidgetsCompilerPass implements CompilerPassInterface
*
* @param string $place
* @param float $ordering
*
* @return float
*/
private function cacheAndGetOrdering($place, $ordering) {
private function cacheAndGetOrdering($place, $ordering)
{
// create a key in the cache array if not exists
if (!array_key_exists($place, $this->cacheOrdering)) {
$this->cacheOrdering[$place] = array();
$this->cacheOrdering[$place] = [];
}
// check if the order exists
if (array_search($ordering, $this->cacheOrdering[$place])) {
// if the order exists, increment of 1 and try again
return $this->cacheAndGetOrdering($place, $ordering + 1);
} else {
// cache the ordering
$this->cacheOrdering[$place][] = $ordering;
return $ordering;
}
// cache the ordering
$this->cacheOrdering[$place][] = $ordering;
return $ordering;
}
/**
* get the places where the service is allowed
* get the places where the service is allowed.
*
* @param mixed $place
* @param mixed $widgetAlias
*
* @param Definition $definition
* @return unknown
*/
private function isPlaceAllowedForWidget($place, $widgetAlias, ContainerBuilder $container)
{
if ($this->widgetServices[$widgetAlias] instanceof WidgetFactoryInterface) {
if (in_array($place, $this->widgetServices[$widgetAlias]
->getAllowedPlaces())) {
->getAllowedPlaces())) {
return true;
}
} else {
$definition = $container->findDefinition($this->widgetServices[$widgetAlias]);
foreach($definition->getTag(self::WIDGET_SERVICE_TAG_NAME) as $attrs) {
foreach ($definition->getTag(self::WIDGET_SERVICE_TAG_NAME) as $attrs) {
$placeValue = $attrs[self::WIDGET_SERVICE_TAG_PLACES];
if ($placeValue === $place) {
@@ -304,86 +384,4 @@ abstract class AbstractWidgetsCompilerPass implements CompilerPassInterface
return false;
}
/**
* This method collect all service tagged with `self::WIDGET_SERVICE_TAG`, and
* add also the widget defined by factories
*
* This method also check that the service is correctly tagged with `alias` and
* `places`, or the factory give a correct alias and more than one place.
*
* @param ContainerBuilder $container
* @throws InvalidConfigurationException
* @throws InvalidArgumentException
*/
protected function collectTaggedServices(ContainerBuilder $container)
{
// first, check the service tagged in service definition
foreach ($container->findTaggedServiceIds(self::WIDGET_SERVICE_TAG_NAME) as $id => $attrs) {
foreach ($attrs as $attr) {
// check the alias is set
if (!isset($attr[self::WIDGET_SERVICE_TAG_ALIAS])) {
throw new InvalidConfigurationException("you should add an ".self::WIDGET_SERVICE_TAG_ALIAS.
" key on the service ".$id);
}
// check the place is set
if (!isset($attr[self::WIDGET_SERVICE_TAG_PLACES])) {
throw new InvalidConfigurationException(sprintf(
"You should add a %s key on the service %s",
self::WIDGET_SERVICE_TAG_PLACES,
$id
));
}
// check the alias does not exists yet
if (array_key_exists($attr[self::WIDGET_SERVICE_TAG_ALIAS], $this->widgetServices)) {
throw new InvalidArgumentException("a service has already be defined with the ".
self::WIDGET_SERVICE_TAG_ALIAS." ".$attr[self::WIDGET_SERVICE_TAG_ALIAS]);
}
// register the service as available
$this->widgetServices[$attr[self::WIDGET_SERVICE_TAG_ALIAS]] = $id;
}
}
// add the services defined by factories
foreach($this->widgetFactories as $factory) {
/* @var $factory WidgetFactoryInterface */
$alias = $factory->getWidgetAlias();
// check the alias is not empty
if (empty($alias)) {
throw new \LogicException(sprintf(
"the widget factory %s returns an empty alias",
get_class($factory)));
}
// check the places are not empty
if (!is_array($factory->getAllowedPlaces())) {
throw new \UnexpectedValueException("the method 'getAllowedPlaces' "
. "should return a non-empty array. Unexpected value on ".
get_class($factory));
}
if (count($factory->getAllowedPlaces()) == 0) {
throw new \LengthException("The method 'getAllowedPlaces' should "
. "return a non-empty array, but returned 0 elements on ".
get_class($factory).'::getAllowedPlaces()');
}
// check the alias does not exists yet
if (array_key_exists($alias, $this->widgetServices)) {
throw new InvalidArgumentException("a service has already be defined with the ".
self::WIDGET_SERVICE_TAG_ALIAS." ".$alias);
}
// register the factory as available
$this->widgetServices[$factory->getWidgetAlias()] = $factory;
}
}
}

View File

@@ -1,90 +1,81 @@
<?php
/*
* Copyright (C) 2016 Julien Fastré <julien.fastre@champs-libres.coop>
/**
* Chill is a software for social workers
*
* This program is free software: you can redistribute it and/or modify
* 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/>.
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/
namespace Chill\MainBundle\DependencyInjection\Widget;
use Symfony\Component\Config\Definition\Builder\TreeBuilder;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Chill\MainBundle\DependencyInjection\Widget\AbstractWidgetsCompilerPass as WidgetsCompilerPass;
use Generator;
use Symfony\Component\Config\Definition\Builder\TreeBuilder;
use Symfony\Component\Config\Definition\Exception\InvalidConfigurationException;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use function implode;
/**
* This trait allow to add automatic configuration for widget inside your config.
*
* Usage
*
* Usage
* ======
*
*
* 1. Register widget factories
* ----------------------------
*
*
* Add widget factories, using `setWidgetFactories`
*
* Example :
*
*
* Example :
*
* ```
* use Symfony\Component\DependencyInjection\ContainerBuilder;
* use Chill\MainBundle\DependencyInjection\Widget\AddWidgetConfigurationTrait;
*
* class MyConfig
*
* class MyConfig
* {
*
*
* use addWidgetConfigurationTrait;
*
*
* public function __construct(array $widgetFactories = array(), ContainerBuilder $container)
* {
* $this->setWidgetFactories($widgetFactories);
* // will be used on next step
* $this->container = $container;
* }
*
*
* }
* ```
*
*
*
*
*
*
* 2. add widget config to your config
* -----------------------------------
*
*
* ```
* use Symfony\Component\DependencyInjection\ContainerBuilder;
* use Chill\MainBundle\DependencyInjection\Widget\AddWidgetConfigurationTrait;
* use Symfony\Component\Config\Definition\Builder\TreeBuilder;
*
* class MyConfig
*
* class MyConfig
* {
*
*
* use addWidgetConfigurationTrait;
*
*
* private $container;
*
*
* public function __construct(array $widgetFactories = array(), ContainerBuilder $container)
* {
* $this->setWidgetFactories($widgetFactories);
* $this->container;
* }
*
*
* public function getConfigTreeBuilder()
* {
* $treeBuilder = new TreeBuilder();
* $root = $treeBuilder->root('my_root');
*
*
* $root->children()
* ->arrayNode('widgets')
* ->canBeDisabled()
@@ -93,15 +84,15 @@ use Symfony\Component\Config\Definition\Exception\InvalidConfigurationException;
* ->end()
* ->end()
* ;
*
*
* return $treeBuilder;
* }
*
*
* }
* ```
*
* the above code will add to the config :
*
*
* the above code will add to the config :
*
* ```
* widgets:
* enabled: true
@@ -113,8 +104,6 @@ use Symfony\Component\Config\Definition\Exception\InvalidConfigurationException;
* person_list:
* # options for the person_list
* ```
*
*
*/
trait AddWidgetConfigurationTrait
{
@@ -122,16 +111,7 @@ trait AddWidgetConfigurationTrait
* @param WidgetFactoryInterface[]
*/
private $widgetFactories;
/**
*
* @param WidgetFactoryInterface[] $widgetFactories
*/
public function setWidgetFactories(array $widgetFactories)
{
$this->widgetFactories = $widgetFactories;
}
/**
* @return WidgetFactoryInterface[]
*/
@@ -139,12 +119,20 @@ trait AddWidgetConfigurationTrait
{
return $this->widgetFactories;
}
/**
* @param WidgetFactoryInterface[] $widgetFactories
*/
public function setWidgetFactories(array $widgetFactories)
{
$this->widgetFactories = $widgetFactories;
}
/**
* add configuration nodes for the widget at the given place.
*
*
* @param type $place
* @param ContainerBuilder $containerBuilder
*
* @return type
*/
protected function addWidgetsConfiguration($place, ContainerBuilder $containerBuilder)
@@ -152,101 +140,104 @@ trait AddWidgetConfigurationTrait
$treeBuilder = new TreeBuilder($place);
$root = $treeBuilder->getRootNode($place)
->canBeUnset()
->info('register widgets on place "'.$place.'"');
->info('register widgets on place "' . $place . '"');
// if no childen, return the root
if (count(iterator_to_array($this->filterWidgetByPlace($place))) === 0) {
return $root;
}
$prototypeChildren = $root->prototype('array')->children();
$prototypeChildren
->floatNode(WidgetsCompilerPass::WIDGET_CONFIG_ORDER)
->isRequired()
->info("the ordering of the widget. May be a number with decimal")
->example("10.58")
->end()
->isRequired()
->info('the ordering of the widget. May be a number with decimal')
->example('10.58')
->end()
->scalarNode(WidgetsCompilerPass::WIDGET_CONFIG_ALIAS)
// this node is scalar: when the configuration is build, the
// tagged services are not available. But when the config reference
// is build, the services are avaialble => we add the possible aliases
// in the info.
->info("the widget alias (see your installed bundles config). "
. "Possible values are (maybe incomplete) : ".
\implode(", ", $this->getWidgetAliasesbyPlace($place, $containerBuilder)))
->isRequired()
->end()
;
->info('the widget alias (see your installed bundles config). '
. 'Possible values are (maybe incomplete) : ' .
implode(', ', $this->getWidgetAliasesbyPlace($place, $containerBuilder)))
->isRequired()
->end();
// adding the possible config on each widget under the widget_alias
foreach ($this->filterWidgetByPlace($place) as $factory) {
$builder = new TreeBuilder($factory->getWidgetAlias());
$widgetOptionsRoot = $builder->getRootNode($factory->getWidgetAlias());
$widgetOptionsRoot->canBeUnset()
->info(sprintf('the configuration for the widget "%s" (only required if this widget is set in widget_alias)',
$factory->getWidgetAlias()));
->info(sprintf(
'the configuration for the widget "%s" (only required if this widget is set in widget_alias)',
$factory->getWidgetAlias()
));
$factory->configureOptions($place, $widgetOptionsRoot->children());
$prototypeChildren->append($widgetOptionsRoot);
}
return $root;
}
/**
* get all widget factories for the given place.
*
* @param string $place
* @return \Generator a generator containing a widget factory
*
* @return Generator a generator containing a widget factory
*/
protected function filterWidgetByPlace($place)
{
foreach($this->widgetFactories as $factory) {
foreach ($this->widgetFactories as $factory) {
if (in_array($place, $factory->getAllowedPlaces())) {
yield $factory;
}
}
}
/**
* get the all possible aliases for the given place. This method
* search within service tags and widget factories
*
* **Note** that services are not available when the config is build: the whole
* search within service tags and widget factories.
*
* **Note** that services are not available when the config is build: the whole
* aliases will be checked in compiler pass, or when the command
* `config:dump-reference` is runned.
*
*
* @param type $place
* @param ContainerBuilder $containerBuilder
* @return type
*
* @throws InvalidConfigurationException if a service's tag does not have the "alias" key
*
* @return type
*/
protected function getWidgetAliasesbyPlace($place, ContainerBuilder $containerBuilder)
{
$result = array();
$result = [];
foreach ($this->filterWidgetByPlace($place) as $factory) {
$result[] = $factory->getWidgetAlias();
}
// append the aliases added without factory
foreach ($containerBuilder
->findTaggedServiceIds(WidgetsCompilerPass::WIDGET_SERVICE_TAG_NAME)
->findTaggedServiceIds(WidgetsCompilerPass::WIDGET_SERVICE_TAG_NAME)
as $serviceId => $tags) {
foreach ($tags as $tag) {
// throw an error if no alias in definition
if (!array_key_exists(WidgetsCompilerPass::WIDGET_SERVICE_TAG_ALIAS, $tag)) {
throw new InvalidConfigurationException(sprintf(
"The service with id %s does not have any %d key",
$serviceId,
WidgetsCompilerPass::WIDGET_SERVICE_TAG_ALIAS
));
}
// add the key to the possible results
$result[] = $tag[WidgetsCompilerPass::WIDGET_SERVICE_TAG_ALIAS];
foreach ($tags as $tag) {
// throw an error if no alias in definition
if (!array_key_exists(WidgetsCompilerPass::WIDGET_SERVICE_TAG_ALIAS, $tag)) {
throw new InvalidConfigurationException(sprintf(
'The service with id %s does not have any %d key',
$serviceId,
WidgetsCompilerPass::WIDGET_SERVICE_TAG_ALIAS
));
}
// add the key to the possible results
$result[] = $tag[WidgetsCompilerPass::WIDGET_SERVICE_TAG_ALIAS];
}
}
return $result;
}
}
}

View File

@@ -1,47 +1,32 @@
<?php
/*
* Copyright (C) 2016 Julien Fastré <julien.fastre@champs-libres.coop>
/**
* Chill is a software for social workers
*
* This program is free software: you can redistribute it and/or modify
* 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/>.
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/
namespace Chill\MainBundle\DependencyInjection\Widget\Factory;
use Chill\MainBundle\DependencyInjection\Widget\Factory\WidgetFactoryInterface;
use Symfony\Component\DependencyInjection\ContainerBuilder;
/**
* Allow to easily create WidgetFactory.
*
* Allow to easily create WidgetFactory.
*
* Extending this factory, the widget will be created using the already defined
* service created "as other services" in your configuration (the most frequent
* way is using `services.yml` file.
*
* If you need to create different service based upon place, position or
*
* If you need to create different service based upon place, position or
* definition, you should implements directly
* `Chill\MainBundle\DependencyInjection\Widget\Factory\WidgetFactoryInterface`
*
*
*/
abstract class AbstractWidgetFactory implements WidgetFactoryInterface
{
/**
*
* {@inheritdoc}
*
*
* Will create the definition by returning the definition from the `services.yml`
* file (or `services.xml` or `what-you-want.yml`).
*
@@ -49,9 +34,9 @@ abstract class AbstractWidgetFactory implements WidgetFactoryInterface
*/
public function createDefinition(ContainerBuilder $containerBuilder, $place, $order, array $config)
{
return $containerBuilder->getDefinition($this
->getServiceId($containerBuilder, $place, $order, $config)
);
return $containerBuilder->getDefinition(
$this
->getServiceId($containerBuilder, $place, $order, $config)
);
}
}
}

View File

@@ -1,52 +1,41 @@
<?php
/*
* Copyright (C) 2016 Julien Fastré <julien.fastre@champs-libres.coop>
/**
* Chill is a software for social workers
*
* This program is free software: you can redistribute it and/or modify
* 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/>.
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/
namespace Chill\MainBundle\DependencyInjection\Widget\Factory;
use Symfony\Component\Config\Definition\Builder\NodeBuilder;
use Symfony\Component\DependencyInjection\ContainerBuilder;
/**
* Factory for creating configuration of widgets.
*
*
* When you need a widget with some configuration, you should implements this
* interface on a factory. The factory will add configuration to the bundle
* interface on a factory. The factory will add configuration to the bundle
* giving the places for your widget.
*
* Using this interface, **you do not need** to define the service in your
* container configuration (`services.yml` files).
*
*
* Using this interface, **you do not need** to define the service in your
* container configuration (`services.yml` files).
*
* Once the class is created, you should inject the factory inside the container
* at compile time, in your `Bundle` class :
*
*
*
*
* ```
* namespace Chill\PersonBundle;
*
* use Symfony\Component\HttpKernel\Bundle\Bundle;
* use Symfony\Component\DependencyInjection\ContainerBuilder;
* use Chill\PersonBundle\Widget\PersonListWidgetFactory;
*
*
* class ChillPersonBundle extends Bundle
* {
* public function build(ContainerBuilder $container)
* public function build(ContainerBuilder $container)
* {
* parent::build($container);
* // register a widget factory into chill_main :
@@ -55,49 +44,40 @@ use Symfony\Component\DependencyInjection\ContainerBuilder;
* }
* }
* ```
*
*
*
*/
interface WidgetFactoryInterface
{
/**
* configure options for the widget. Those options will be added in
* configure options for the widget. Those options will be added in
* configuration in the bundle where the widget will be used.
*
*
* @param type $place
* @param NodeBuilder $node
*/
public function configureOptions($place, NodeBuilder $node);
/**
* get the widget alias. This alias will be used in configuration (`config.yml`)
*/
public function getWidgetAlias();
/**
* Create a definition for the service which will render the widget.
*
* (Note: you can define the service by yourself, as other services,
*
* (Note: you can define the service by yourself, as other services,
* using the `AbstractWidgetFactory`)
*
* @param ContainerBuilder $containerBuilder
*
* @param type $place
* @param type $order
* @param array $config
*/
public function createDefinition(ContainerBuilder $containerBuilder, $place, $order, array $config);
/**
* return the service id to build the widget.
*
* @param ContainerBuilder $containerBuilder
*
* @param string $place
* @param float $order
* @param array $config
*
*
* @return string the service definition
*
*/
public function getServiceId(ContainerBuilder $containerBuilder, $place, $order, array $config);
/**
* get the widget alias. This alias will be used in configuration (`config.yml`).
*/
public function getWidgetAlias();
}

View File

@@ -1,20 +1,10 @@
<?php
/*
* Copyright (C) 2016 Julien Fastré <julien.fastre@champs-libres.coop>
/**
* Chill is a software for social workers
*
* This program is free software: you can redistribute it and/or modify
* 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/>.
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/
namespace Chill\MainBundle\DependencyInjection\Widget;
@@ -23,20 +13,19 @@ use Chill\MainBundle\DependencyInjection\Widget\Factory\WidgetFactoryInterface;
/**
* Register widget factories to an extension.
*
*/
interface HasWidgetFactoriesExtensionInterface {
interface HasWidgetFactoriesExtensionInterface
{
/**
* register a widget factory
*
* register a widget factory.
*
* @param \Chill\MainBundle\DependencyInjection\Widget\WidgetFactoryInterface $factory
*/
public function addWidgetFactory(WidgetFactoryInterface $factory);
/**
* get all the widget factories registered for this extension
*
* get all the widget factories registered for this extension.
*
* @return WidgetFactoryInterface[]
*/
public function getWidgetFactories();

View File

@@ -1,20 +1,12 @@
<?php
/*
* Copyright (C) 2017 Champs Libres Cooperative <info@champs-libres.coop>
/**
* Chill is a software for social workers
*
* This program is free software: you can redistribute it and/or modify
* 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/>.
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/
namespace Chill\MainBundle\Doctrine\DQL;
use Doctrine\ORM\Query\AST\Functions\FunctionNode;
@@ -22,16 +14,21 @@ use Doctrine\ORM\Query\Lexer;
use Doctrine\ORM\Query\Parser;
use Doctrine\ORM\Query\SqlWalker;
/**
*
*
* @author Julien Fastré <julien.fastre@champs-libres.coop>
*/
class GetJsonFieldByKey extends FunctionNode
{
private $expr1;
private $expr2;
public function getSql(SqlWalker $sqlWalker)
{
return sprintf(
'(%s->%s)',
$this->expr1->dispatch($sqlWalker),
$this->expr2->dispatch($sqlWalker)
);
}
public function parse(Parser $parser)
{
$parser->match(Lexer::T_IDENTIFIER);
@@ -41,13 +38,4 @@ class GetJsonFieldByKey extends FunctionNode
$this->expr2 = $parser->StringPrimary();
$parser->match(Lexer::T_CLOSE_PARENTHESIS);
}
public function getSql(SqlWalker $sqlWalker)
{
return sprintf(
'(%s->%s)',
$this->expr1->dispatch($sqlWalker),
$this->expr2->dispatch($sqlWalker)
);
}
}

View File

@@ -1,20 +1,12 @@
<?php
/*
* Copyright (C) 2017 Champs Libres Cooperative <info@champs-libres.coop>
/**
* Chill is a software for social workers
*
* This program is free software: you can redistribute it and/or modify
* 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/>.
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/
namespace Chill\MainBundle\Doctrine\DQL;
use Doctrine\ORM\Query\AST\Functions\FunctionNode;
@@ -24,16 +16,14 @@ use Doctrine\ORM\Query\SqlWalker;
/**
* Return an aggregation of values in a json representation, as a string.
*
*
* Internally, this function use the postgresql `jsonb_agg` function. Using
* json allow to aggregate data from different types without have to cast them.
*
* @author Julien Fastré <julien.fastre@champs-libres.coop>
*/
class JsonAggregate extends FunctionNode
{
private $expr;
public function getSql(SqlWalker $sqlWalker)
{
return sprintf('jsonb_agg(%s)', $this->expr->dispatch($sqlWalker));

View File

@@ -1,8 +1,12 @@
<?php
/*
*
/**
* Chill is a software for social workers
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/
namespace Chill\MainBundle\Doctrine\DQL;
use Doctrine\ORM\Query\AST\Functions\FunctionNode;
@@ -11,7 +15,7 @@ use Doctrine\ORM\Query\Parser;
use Doctrine\ORM\Query\SqlWalker;
/**
* Return the length of an array
* Return the length of an array.
*/
class JsonbArrayLength extends FunctionNode
{

View File

@@ -1,8 +1,12 @@
<?php
/*
*
/**
* Chill is a software for social workers
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/
namespace Chill\MainBundle\Doctrine\DQL;
use Doctrine\ORM\Query\AST\Functions\FunctionNode;
@@ -10,13 +14,10 @@ use Doctrine\ORM\Query\Lexer;
use Doctrine\ORM\Query\Parser;
use Doctrine\ORM\Query\SqlWalker;
/**
*
@author Julien Fastré <julien.fastre@champs-libres.coop>
*/
class JsonbExistsInArray extends FunctionNode
{
private $expr1;
private $expr2;
public function getSql(SqlWalker $sqlWalker): string

View File

@@ -1,5 +1,12 @@
<?php
/**
* Chill is a software for social workers
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/
declare(strict_types=1);
namespace Chill\MainBundle\Doctrine\DQL;
@@ -8,23 +15,24 @@ use Doctrine\ORM\Query\AST\Functions\FunctionNode;
use Doctrine\ORM\Query\AST\PathExpression;
use Doctrine\ORM\Query\Lexer;
use Doctrine\ORM\Query\Parser;
use Exception;
/**
* DQL function for OVERLAPS function in postgresql
* DQL function for OVERLAPS function in postgresql.
*
* If a value is null in period start, it will be replaced by -infinity.
* If a value is null in period end, it will be replaced by infinity
*/
class OverlapsI extends FunctionNode
{
private $firstPeriodStart;
private $firstPeriodEnd;
private $secondPeriodStart;
private $firstPeriodStart;
private $secondPeriodEnd;
private $secondPeriodStart;
public function getSql(\Doctrine\ORM\Query\SqlWalker $sqlWalker)
{
return sprintf(
@@ -36,36 +44,6 @@ class OverlapsI extends FunctionNode
);
}
protected function makeCase($sqlWalker, $part, string $position): string
{
switch ($position) {
case 'start' :
$p = '-infinity';
break;
case 'end':
$p = 'infinity';
break;
default:
throw new \Exception('Unexpected position value.');
}
if ($part instanceof PathExpression) {
return sprintf(
"CASE WHEN %s IS NOT NULL THEN %s ELSE '%s'::date END",
$part->dispatch($sqlWalker),
$part->dispatch($sqlWalker),
$p
);
}
return sprintf(
"CASE WHEN %s::date IS NOT NULL THEN %s::date ELSE '%s'::date END",
$part->dispatch($sqlWalker),
$part->dispatch($sqlWalker),
$p
);
}
public function parse(Parser $parser): void
{
$parser->match(Lexer::T_IDENTIFIER);
@@ -92,4 +70,38 @@ class OverlapsI extends FunctionNode
$parser->match(Lexer::T_CLOSE_PARENTHESIS);
}
protected function makeCase($sqlWalker, $part, string $position): string
{
switch ($position) {
case 'start':
$p = '-infinity';
break;
case 'end':
$p = 'infinity';
break;
default:
throw new Exception('Unexpected position value.');
}
if ($part instanceof PathExpression) {
return sprintf(
"CASE WHEN %s IS NOT NULL THEN %s ELSE '%s'::date END",
$part->dispatch($sqlWalker),
$part->dispatch($sqlWalker),
$p
);
}
return sprintf(
"CASE WHEN %s::date IS NOT NULL THEN %s::date ELSE '%s'::date END",
$part->dispatch($sqlWalker),
$part->dispatch($sqlWalker),
$p
);
}
}

View File

@@ -1,46 +1,33 @@
<?php
/*
/**
* Chill is a software for social workers
* Copyright (C) 2019 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/>.
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/
namespace Chill\MainBundle\Doctrine\DQL;
use Doctrine\ORM\Query\AST\Functions\FunctionNode;
use Doctrine\ORM\Query\Lexer;
/**
*
*
*/
class Replace extends FunctionNode
{
protected $string;
protected $from;
protected $string;
protected $to;
public function getSql(\Doctrine\ORM\Query\SqlWalker $sqlWalker): string
{
return 'REPLACE('.
$this->string->dispatch($sqlWalker).
', '.
$this->from->dispatch($sqlWalker).
', '.
$this->to->dispatch($sqlWalker).
return 'REPLACE(' .
$this->string->dispatch($sqlWalker) .
', ' .
$this->from->dispatch($sqlWalker) .
', ' .
$this->to->dispatch($sqlWalker) .
')';
}
@@ -48,17 +35,17 @@ class Replace extends FunctionNode
{
$parser->match(Lexer::T_IDENTIFIER);
$parser->match(Lexer::T_OPEN_PARENTHESIS);
$this->string = $parser->StringPrimary();
$parser->match(Lexer::T_COMMA);
$this->from = $parser->StringPrimary();
$parser->match(Lexer::T_COMMA);
$this->to = $parser->StringPrimary();
$parser->match(Lexer::T_CLOSE_PARENTHESIS);
}
}

View File

@@ -1,28 +1,19 @@
<?php
/*
/**
* Chill is a software for social workers
* Copyright (C) 2018 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/>.
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/
namespace Chill\MainBundle\Doctrine\DQL;
use Doctrine\ORM\Query\AST\Functions\FunctionNode;
use Doctrine\ORM\Query\Lexer;
/**
* Geometry function 'ST_CONTAINS', added by postgis
* Geometry function 'ST_CONTAINS', added by postgis.
*/
class STContains extends FunctionNode
{
@@ -32,8 +23,8 @@ class STContains extends FunctionNode
public function getSql(\Doctrine\ORM\Query\SqlWalker $sqlWalker)
{
return 'ST_CONTAINS('.$this->firstPart->dispatch($sqlWalker).
', ' . $this->secondPart->dispatch($sqlWalker) .")";
return 'ST_CONTAINS(' . $this->firstPart->dispatch($sqlWalker) .
', ' . $this->secondPart->dispatch($sqlWalker) . ')';
}
public function parse(\Doctrine\ORM\Query\Parser $parser)

View File

@@ -1,21 +1,12 @@
<?php
/*
/**
* Chill is a software for social workers
* Copyright (C) 2018 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/>.
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/
namespace Chill\MainBundle\Doctrine\DQL;
use Doctrine\ORM\Query\AST\Functions\FunctionNode;
@@ -29,8 +20,8 @@ class Similarity extends FunctionNode
public function getSql(\Doctrine\ORM\Query\SqlWalker $sqlWalker)
{
return 'SIMILARITY('.$this->firstPart->dispatch($sqlWalker).
', ' . $this->secondPart->dispatch($sqlWalker) .")";
return 'SIMILARITY(' . $this->firstPart->dispatch($sqlWalker) .
', ' . $this->secondPart->dispatch($sqlWalker) . ')';
}
public function parse(\Doctrine\ORM\Query\Parser $parser)

View File

@@ -1,5 +1,12 @@
<?php
/**
* Chill is a software for social workers
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/
namespace Chill\MainBundle\Doctrine\DQL;
use Doctrine\ORM\Query\Lexer;
@@ -12,13 +19,13 @@ class StrictWordSimilarityOPS extends \Doctrine\ORM\Query\AST\Functions\Function
private $secondPart;
public function getSql(\Doctrine\ORM\Query\SqlWalker $sqlWalker)
public function getSql(SqlWalker $sqlWalker)
{
return $this->firstPart->dispatch($sqlWalker).
return $this->firstPart->dispatch($sqlWalker) .
' <<% ' . $this->secondPart->dispatch($sqlWalker);
}
public function parse(\Doctrine\ORM\Query\Parser $parser)
public function parse(Parser $parser)
{
$parser->match(Lexer::T_IDENTIFIER);
$parser->match(Lexer::T_OPEN_PARENTHESIS);

View File

@@ -1,21 +1,10 @@
<?php
/*
/**
* Chill is a software for social workers
* Copyright (C) 2015 Champs-Libres Coopérative <info@champs-libres.coop>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/
namespace Chill\MainBundle\Doctrine\DQL;
@@ -24,30 +13,27 @@ use Doctrine\ORM\Query\AST\Functions\FunctionNode;
use Doctrine\ORM\Query\Lexer;
/**
* Unaccent string using postgresql extension unaccent :
* http://www.postgresql.org/docs/current/static/unaccent.html
*
* Usage : StringFunction UNACCENT(string)
* Unaccent string using postgresql extension unaccent :
* http://www.postgresql.org/docs/current/static/unaccent.html.
*
* @author Julien Fastré <julien.fastre@champs-libres.coop>
* Usage : StringFunction UNACCENT(string)
*/
class Unaccent extends FunctionNode
{
private $string;
public function getSql(\Doctrine\ORM\Query\SqlWalker $sqlWalker)
{
return 'UNACCENT(' . $this->string->dispatch($sqlWalker) .")";
return 'UNACCENT(' . $this->string->dispatch($sqlWalker) . ')';
}
public function parse(\Doctrine\ORM\Query\Parser $parser)
{
$parser->match(Lexer::T_IDENTIFIER);
$parser->match(Lexer::T_OPEN_PARENTHESIS);
$this->string = $parser->StringPrimary();
$parser->match(Lexer::T_CLOSE_PARENTHESIS);
}
}

View File

@@ -1,36 +1,37 @@
<?php
/**
* Chill is a software for social workers
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/
namespace Chill\MainBundle\Doctrine\Event;
use Chill\MainBundle\Doctrine\Model\TrackCreationInterface;
use Chill\MainBundle\Doctrine\Model\TrackUpdateInterface;
use Chill\MainBundle\Entity\User;
use DateTimeImmutable;
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
Events::preUpdate,
];
}
@@ -41,7 +42,7 @@ class TrackCreateUpdateSubscriber implements EventSubscriber
if ($object instanceof TrackCreationInterface
&& $this->security->getUser() instanceof User) {
$object->setCreatedBy($this->security->getUser());
$object->setCreatedAt(new \DateTimeImmutable('now'));
$object->setCreatedAt(new DateTimeImmutable('now'));
}
$this->onUpdate($object);
@@ -56,10 +57,10 @@ class TrackCreateUpdateSubscriber implements EventSubscriber
protected function onUpdate(object $object): void
{
if ($object instanceof TrackUpdateInterface
if ($object instanceof TrackUpdateInterface
&& $this->security->getUser() instanceof User) {
$object->setUpdatedBy($this->security->getUser());
$object->setUpdatedAt(new \DateTimeImmutable('now'));
$object->setUpdatedAt(new DateTimeImmutable('now'));
}
}
}

View File

@@ -1,12 +1,19 @@
<?php
/**
* Chill is a software for social workers
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/
namespace Chill\MainBundle\Doctrine\Migrations;
use Doctrine\Migrations\Version\Comparator;
use Doctrine\Migrations\Version\Version;
use function strcmp;
use function explode;
use function strcmp;
/**
* Compare Version classes names from different namespaces and order them.
@@ -15,18 +22,15 @@ use function explode;
*/
final class VersionComparator implements Comparator
{
public function compare(Version $a, Version $b): int
{
return strcmp($this->getNumber($a), $this->getNumber($b));
}
private function getNumber(Version $version): string
{
$names = explode("\\", (string) $version);
$names = explode('\\', (string) $version);
return end($names);
}
public function compare(Version $a, Version $b): int
{
$q = strcmp($this->getNumber($a), $this->getNumber($b));
return $q;
}
}

View File

@@ -1,25 +1,79 @@
<?php
/**
* Chill is a software for social workers
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/
namespace Chill\MainBundle\Doctrine\Model;
use \JsonSerializable;
use Exception;
use JsonSerializable;
use function json_encode;
class Point implements JsonSerializable {
private ?float $lat;
private ?float $lon;
class Point implements JsonSerializable
{
public static string $SRID = '4326';
private ?float $lat;
private ?float $lon;
private function __construct(?float $lon, ?float $lat)
{
$this->lat = $lat;
$this->lon = $lon;
}
public function toGeoJson(): string
public static function fromArrayGeoJson(array $array): self
{
$array = $this->toArrayGeoJson();
if ('Point' === $array['type'] && isset($array['coordinates'])) {
return self::fromLonLat($array['coordinates'][0], $array['coordinates'][1]);
}
return \json_encode($array);
throw new Exception('Unable to build a point from input data.');
}
public static function fromGeoJson(string $geojson): self
{
$a = json_decode($geojson);
if (null === $a) {
throw PointException::badJsonString($geojson);
}
if (null === $a->type || null === $a->coordinates) {
throw PointException::badJsonString($geojson);
}
if ('Point' !== $a->type) {
throw PointException::badGeoType();
}
[$lon, $lat] = $a->coordinates;
return Point::fromLonLat($lon, $lat);
}
public static function fromLonLat(float $lon, float $lat): self
{
if ((-180 < $lon && 180 > $lon) && (-90 < $lat && 90 > $lat)) {
return new Point($lon, $lat);
}
throw PointException::badCoordinates($lon, $lat);
}
public function getLat(): float
{
return $this->lat;
}
public function getLon(): float
{
return $this->lon;
}
public function jsonSerialize(): array
@@ -35,59 +89,15 @@ class Point implements JsonSerializable {
];
}
public function toGeoJson(): string
{
$array = $this->toArrayGeoJson();
return json_encode($array);
}
public function toWKT(): string
{
return sprintf("SRID=%s;POINT(%s %s)", self::$SRID, $this->lon, $this->lat);
}
public static function fromGeoJson(string $geojson): self
{
$a = json_decode($geojson);
if (null === $a) {
throw PointException::badJsonString($geojson);
}
if (null === $a->type || null === $a->coordinates) {
throw PointException::badJsonString($geojson);
}
if ($a->type !== 'Point'){
throw PointException::badGeoType();
}
[$lon, $lat] = $a->coordinates;
return Point::fromLonLat($lon, $lat);
}
public static function fromLonLat(float $lon, float $lat): self
{
if (($lon > -180 && $lon < 180) && ($lat > -90 && $lat < 90)) {
return new Point($lon, $lat);
}
throw PointException::badCoordinates($lon, $lat);
}
public static function fromArrayGeoJson(array $array): self
{
if ($array['type'] === 'Point' && isset($array['coordinates'])) {
return self::fromLonLat($array['coordinates'][0], $array['coordinates'][1]);
}
throw new \Exception('Unable to build a point from input data.');
}
public function getLat(): float
{
return $this->lat;
}
public function getLon(): float
{
return $this->lon;
return sprintf('SRID=%s;POINT(%s %s)', self::$SRID, $this->lon, $this->lat);
}
}

View File

@@ -1,27 +1,33 @@
<?php
/**
* Chill is a software for social workers
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/
namespace Chill\MainBundle\Doctrine\Model;
use \Exception;
use Exception;
/**
* Description of PointException
*
* Description of PointException.
*/
class PointException extends Exception {
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");
return new self("Input coordinates are not valid in the used coordinate system (longitude = {$lon} , latitude = {$lat})");
}
public static function badGeoType(): self
{
return new self("The geoJSON object type is not valid");
return new self('The geoJSON object type is not valid');
}
public static function badJsonString($str): self
{
return new self("The JSON string is not valid: {$str}");
}
}

View File

@@ -1,12 +1,20 @@
<?php
/**
* Chill is a software for social workers
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/
namespace Chill\MainBundle\Doctrine\Model;
use Chill\MainBundle\Entity\User;
use DateTimeInterface;
interface TrackCreationInterface
{
public function setCreatedBy(User $user): self;
public function setCreatedAt(DateTimeInterface $datetime): self;
public function setCreatedAt(\DateTimeInterface $datetime): self;
public function setCreatedBy(User $user): self;
}

View File

@@ -1,12 +1,20 @@
<?php
/**
* Chill is a software for social workers
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/
namespace Chill\MainBundle\Doctrine\Model;
use Chill\MainBundle\Entity\User;
use DateTimeInterface;
interface TrackUpdateInterface
{
public function setUpdatedBy(User $user): self;
public function setUpdatedAt(DateTimeInterface $datetime): self;
public function setUpdatedAt(\DateTimeInterface $datetime): self;
public function setUpdatedBy(User $user): self;
}

View File

@@ -1,5 +1,12 @@
<?php
/**
* Chill is a software for social workers
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/
declare(strict_types=1);
namespace Chill\MainBundle\Doctrine\ORM\Hydration;
@@ -16,17 +23,6 @@ final class FlatHierarchyEntityHydrator extends ObjectHydrator
return array_values(iterator_to_array($this->flatListGenerator($this->buildChildrenHashmap(parent::hydrateAllData()))));
}
private function flatListGenerator(array $hashMap, ?object $parent = null): Generator
{
$parent = null === $parent ? null : spl_object_id($parent);
$hashMap += [$parent => []];
foreach ($hashMap[$parent] as $node) {
yield spl_object_id($node) => $node;
yield from $this->flatListGenerator($hashMap, $node);
}
}
private function buildChildrenHashmap(array $nodes): array
{
return array_reduce(
@@ -44,4 +40,15 @@ final class FlatHierarchyEntityHydrator extends ObjectHydrator
);
}
private function flatListGenerator(array $hashMap, ?object $parent = null): Generator
{
$parent = null === $parent ? null : spl_object_id($parent);
$hashMap += [$parent => []];
foreach ($hashMap[$parent] as $node) {
yield spl_object_id($node) => $node;
yield from $this->flatListGenerator($hashMap, $node);
}
}
}

View File

@@ -1,20 +1,68 @@
<?php
/**
* Chill is a software for social workers
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/
namespace Chill\MainBundle\Doctrine\Type;
use Doctrine\DBAL\Types\DateIntervalType;
use DateInterval;
use Doctrine\DBAL\Platforms\AbstractPlatform;
use Doctrine\DBAL\Types\ConversionException;
use Doctrine\DBAL\Types\DateIntervalType;
use Exception;
use function current;
use function preg_match;
use function reset;
/**
* Re-declare the date interval to use the implementation of date interval in
* postgreql
*
* @author Julien Fastré <julien.fastre@champs-libres.coop>
* postgreql.
*/
class NativeDateIntervalType extends DateIntervalType
{
const FORMAT = '%rP%YY%MM%DDT%HH%IM%SS';
public const FORMAT = '%rP%YY%MM%DDT%HH%IM%SS';
public function convertToDatabaseValue($value, AbstractPlatform $platform)
{
if (null === $value) {
return null;
}
if ($value instanceof DateInterval) {
return $value->format(self::FORMAT);
}
throw ConversionException::conversionFailedInvalidType($value, $this->getName(), ['null', 'DateInterval']);
}
public function convertToPHPValue($value, AbstractPlatform $platform)
{
if (null === $value || $value instanceof DateInterval) {
return $value;
}
try {
$strings = explode(' ', $value);
if (count($strings) === 0) {
return null;
}
$intervalSpec = 'P';
reset($strings);
do {
$intervalSpec .= $this->convertEntry($strings);
} while (next($strings) !== false);
return new DateInterval($intervalSpec);
} catch (Exception $exception) {
throw $this->createConversionException($value, $exception);
}
}
public function getName(): string
{
@@ -26,86 +74,52 @@ class NativeDateIntervalType extends DateIntervalType
return 'INTERVAL';
}
/**
* {@inheritdoc}
*/
public function convertToDatabaseValue($value, AbstractPlatform $platform)
{
if (null === $value) {
return null;
}
if ($value instanceof \DateInterval) {
return $value->format(self::FORMAT);
}
throw ConversionException::conversionFailedInvalidType($value, $this->getName(), ['null', 'DateInterval']);
}
public function convertToPHPValue($value, AbstractPlatform $platform)
{
if ($value === null || $value instanceof \DateInterval) {
return $value;
}
try {
$strings = explode(' ', $value);
if (count($strings) === 0) {
return null;
}
$intervalSpec = 'P';
\reset($strings);
do {
$intervalSpec .= $this->convertEntry($strings);
} while (next($strings) !== FALSE);
return new \DateInterval($intervalSpec);
} catch (\Exception $exception) {
throw $this->createConversionException($value, $exception);
}
}
private function convertEntry(&$strings)
{
$current = \current($strings);
if (is_numeric($current)) {
$next = \next($strings);
switch($next) {
case 'year':
case 'years':
$unit = 'Y';
break;
case 'mon':
case 'mons':
$unit = 'M';
break;
case 'day':
case 'days':
$unit = 'D';
break;
default:
throw $this->createConversionException(implode('', $strings));
}
return $current.$unit;
} elseif (\preg_match('/([0-9]{2}\:[0-9]{2}:[0-9]{2})/', $current) === 1) {
$tExploded = explode(':', $current);
$intervalSpec = 'T';
$intervalSpec.= $tExploded[0].'H';
$intervalSpec.= $tExploded[1].'M';
$intervalSpec.= $tExploded[2].'S';
return $intervalSpec;
}
}
protected function createConversionException($value, $exception = null)
{
return ConversionException::conversionFailedFormat($value, $this->getName(), 'xx year xx mons xx days 01:02:03', $exception);
}
private function convertEntry(&$strings)
{
$current = current($strings);
if (is_numeric($current)) {
$next = \next($strings);
switch ($next) {
case 'year':
case 'years':
$unit = 'Y';
break;
case 'mon':
case 'mons':
$unit = 'M';
break;
case 'day':
case 'days':
$unit = 'D';
break;
default:
throw $this->createConversionException(implode('', $strings));
}
return $current . $unit;
}
if (preg_match('/([0-9]{2}\:[0-9]{2}:[0-9]{2})/', $current) === 1) {
$tExploded = explode(':', $current);
$intervalSpec = 'T';
$intervalSpec .= $tExploded[0] . 'H';
$intervalSpec .= $tExploded[1] . 'M';
$intervalSpec .= $tExploded[2] . 'S';
return $intervalSpec;
}
}
}

View File

@@ -1,69 +1,76 @@
<?php
/**
* Chill is a software for social workers
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/
declare(strict_types=1);
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;
use Doctrine\DBAL\Types\Type;
/**
* A Type for Doctrine to implement the Geography Point type
* implemented by Postgis on postgis+postgresql databases
* implemented by Postgis on postgis+postgresql databases.
*/
class PointType extends Type
{
public const POINT = 'point';
/**
* @return string
*/
public function getSQLDeclaration(array $column, AbstractPlatform $platform)
public function canRequireSQLConversion()
{
return 'geometry(POINT,'.Point::$SRID.')';
return true;
}
public function convertToDatabaseValue($value, AbstractPlatform $platform)
{
if (null === $value) {
return null;
}
return $value->toWKT();
}
public function convertToDatabaseValueSQL($sqlExpr, AbstractPlatform $platform)
{
return $sqlExpr;
}
/**
* @param mixed $value
*
* @return ?Point
*/
public function convertToPHPValue($value, AbstractPlatform $platform)
{
if ($value === NULL){
return NULL;
if (null === $value) {
return null;
}
return Point::fromGeoJson($value);
}
public function convertToPHPValueSQL($sqlExpr, $platform)
{
return 'ST_AsGeoJSON(' . $sqlExpr . ') ';
}
public function getName()
{
return self::POINT;
}
public function convertToDatabaseValue($value, AbstractPlatform $platform)
/**
* @return string
*/
public function getSQLDeclaration(array $column, AbstractPlatform $platform)
{
if ($value === NULL){
return NULL;
}
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;
return 'geometry(POINT,' . Point::$SRID . ')';
}
}

View File

@@ -1,79 +1,36 @@
<?php
/**
* Chill is a software for social workers
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/
namespace Chill\MainBundle\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;
use DateTime;
use DateTimeInterface;
use Doctrine\ORM\Mapping as ORM;
use Symfony\Component\Serializer\Annotation\Groups;
use Symfony\Component\Validator\Context\ExecutionContextInterface;
/**
* Address
* Address.
*
* @ORM\Entity
* @ORM\Table(name="chill_main_address")
* @ORM\HasLifecycleCallbacks()
* @ORM\HasLifecycleCallbacks
*/
class Address
{
/**
* @var integer
*
* @ORM\Id
* @ORM\Column(name="id", type="integer")
* @ORM\GeneratedValue(strategy="AUTO")
* @ORM\ManyToOne(targetEntity=AddressReference::class)
* @Groups({"write"})
*/
private $id;
/**
* @var string
*
* @ORM\Column(type="string", length=255)
* @Groups({"write"})
*/
private $street = '';
/**
* @var string
*
* @ORM\Column(type="string", length=255)
* @Groups({"write"})
*/
private $streetNumber = '';
/**
* @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;
private ?AddressReference $addressReference = null;
/**
* @var string|null
@@ -89,7 +46,14 @@ class Address
* @ORM\Column(type="string", length=16, nullable=true)
* @Groups({"write"})
*/
private $flat;
private $corridor;
/**
* A list of metadata, added by customizable fields.
*
* @var array
*/
private $customs = [];
/**
* @var string|null
@@ -108,29 +72,34 @@ class Address
private $extra;
/**
* Indicates when the address starts validation. Used to build an history
* of address. By default, the current date.
* @var string|null
*
* @var \DateTime
*
* @ORM\Column(type="date")
* @ORM\Column(type="string", length=16, nullable=true)
* @Groups({"write"})
*/
private \DateTime $validFrom;
private $flat;
/**
* Indicates when the address ends. Used to build an history
* of address.
* @var string|null
*
* @var \DateTime|null
*
* @ORM\Column(type="date", nullable=true)
* @ORM\Column(type="string", length=16, nullable=true)
* @Groups({"write"})
*/
private ?\DateTime $validTo = null;
private $floor;
/**
* @var int
*
* @ORM\Id
* @ORM\Column(name="id", type="integer")
* @ORM\GeneratedValue(strategy="AUTO")
* @Groups({"write"})
*/
private $id;
/**
* True if the address is a "no address", aka homeless person, ...
*
* @Groups({"write"})
* @ORM\Column(type="boolean")
*
@@ -139,17 +108,7 @@ class Address
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
* A ThirdParty reference for person's addresses that are linked to a third party.
*
* @var ThirdParty|null
*
@@ -160,226 +119,71 @@ class Address
private $linkedToThirdParty;
/**
* A list of metadata, added by customizable fields
* A geospatial field storing the coordinates of the Address.
*
* @var array
*/
private $customs = [];
/**
* @ORM\ManyToOne(targetEntity=AddressReference::class)
* @var Point|null
*
* @ORM\Column(type="point", nullable=true)
* @Groups({"write"})
*/
private ?AddressReference $addressReference = null;
private $point;
/**
* @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 $steps;
/**
* @var string
*
* @ORM\Column(type="string", length=255)
* @Groups({"write"})
*/
private $street = '';
/**
* @var string
*
* @ORM\Column(type="string", length=255)
* @Groups({"write"})
*/
private $streetNumber = '';
/**
* Indicates when the address starts validation. Used to build an history
* of address. By default, the current date.
*
* @ORM\Column(type="date")
* @Groups({"write"})
*/
private DateTime $validFrom;
/**
* Indicates when the address ends. Used to build an history
* of address.
*
* @ORM\Column(type="date", nullable=true)
* @Groups({"write"})
*/
private ?DateTime $validTo = null;
public function __construct()
{
$this->validFrom = new \DateTime();
$this->validFrom = new DateTime();
}
/**
* Get id
*
* @return integer
*/
public function getId()
{
return $this->id;
}
/**
* Set streetAddress1 (legacy function)
*
* @param string $streetAddress1
*
* @return Address
*/
public function setStreetAddress1($streetAddress1)
{
$this->street = $streetAddress1 === NULL ? '' : $streetAddress1;
return $this;
}
/**
* Get streetAddress1 (legacy function)
*
* @return string
*/
public function getStreetAddress1()
{
return $this->street;
}
/**
* Set streetAddress2 (legacy function)
*
* @param string $streetAddress2
*
* @return Address
*/
public function setStreetAddress2($streetAddress2)
{
$this->streetNumber = $streetAddress2 === NULL ? '' : $streetAddress2;
return $this;
}
/**
* Get streetAddress2 (legacy function)
*
* @return string
*/
public function getStreetAddress2()
{
return $this->streetNumber;
}
/**
* 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;
}
/**
* @return \DateTime
*/
public function getValidFrom()
{
return $this->validFrom;
}
/**
* @param \DateTime $validFrom
* @return Address
*/
public function setValidFrom(\DateTime $validFrom)
{
$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
*/
public function isNoAddress(): bool
{
return $this->getIsNoAddress();
}
/**
* Set IsNoAddress
*
* Indicate true if the address is a fake address (homeless, ...)
*
* @param bool $isNoAddress
* @return $this
*/
public function setIsNoAddress(bool $isNoAddress): self
{
$this->isNoAddress = $isNoAddress;
return $this;
}
/**
* Get customs informations in the address
*
* @return array
*/
public function getCustoms(): array
{
return $this->customs;
}
/**
* 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
*/
public function validate(ExecutionContextInterface $context, $payload)
{
if (!$this->getValidFrom() instanceof \DateTime) {
$context
->buildViolation("address.date-should-be-set")
->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")
->atPath('postCode')
->addViolation();
}
}
/**
* @param Address $original
* @return Address
*/
public static function createFromAddress(Address $original) : Address
public static function createFromAddress(Address $original): Address
{
return (new Address())
->setAddressReference($original->getAddressReference())
@@ -398,8 +202,7 @@ class Address
->setStreet($original->getStreet())
->setStreetNumber($original->getStreetNumber())
->setValidFrom($original->getValidFrom())
->setValidTo($original->getValidTo())
;
->setValidTo($original->getValidTo());
}
public static function createFromAddressReference(AddressReference $original): Address
@@ -409,44 +212,17 @@ class Address
->setPostcode($original->getPostcode())
->setStreet($original->getStreet())
->setStreetNumber($original->getStreetNumber())
->setAddressReference($original)
;
->setAddressReference($original);
}
public function getStreet(): ?string
public function getAddressReference(): ?AddressReference
{
return $this->street;
return $this->addressReference;
}
public function setStreet(string $street): self
public function getBuildingName(): ?string
{
$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;
return $this->buildingName;
}
public function getCorridor(): ?string
@@ -454,11 +230,72 @@ class Address
return $this->corridor;
}
public function setCorridor(?string $corridor): self
/**
* Get customs informations in the address.
*/
public function getCustoms(): array
{
$this->corridor = $corridor;
return $this->customs;
}
return $this;
public function getDistribution(): ?string
{
return $this->distribution;
}
public function getExtra(): ?string
{
return $this->extra;
}
public function getFlat(): ?string
{
return $this->flat;
}
public function getFloor(): ?string
{
return $this->floor;
}
/**
* Get id.
*
* @return int
*/
public function getId()
{
return $this->id;
}
/**
* Get IsNoAddress.
*
* Indicate true if the address is a fake address (homeless, ...)
*/
public function getIsNoAddress(): bool
{
return $this->isNoAddress;
}
public function getLinkedToThirdParty()
{
return $this->linkedToThirdParty;
}
public function getPoint(): ?Point
{
return $this->point;
}
/**
* Get postcode.
*
* @return PostalCode
*/
public function getPostcode()
{
return $this->postcode;
}
public function getSteps(): ?string
@@ -466,16 +303,59 @@ class Address
return $this->steps;
}
public function setSteps(?string $steps): self
public function getStreet(): ?string
{
$this->steps = $steps;
return $this;
return $this->street;
}
public function getBuildingName(): ?string
/**
* Get streetAddress1 (legacy function).
*
* @return string
*/
public function getStreetAddress1()
{
return $this->buildingName;
return $this->street;
}
/**
* Get streetAddress2 (legacy function).
*
* @return string
*/
public function getStreetAddress2()
{
return $this->streetNumber;
}
public function getStreetNumber(): ?string
{
return $this->streetNumber;
}
/**
* @return DateTime
*/
public function getValidFrom()
{
return $this->validFrom;
}
public function getValidTo(): ?DateTimeInterface
{
return $this->validTo;
}
public function isNoAddress(): bool
{
return $this->getIsNoAddress();
}
public function setAddressReference(?AddressReference $addressReference = null): Address
{
$this->addressReference = $addressReference;
return $this;
}
public function setBuildingName(?string $buildingName): self
@@ -485,21 +365,23 @@ class Address
return $this;
}
public function getFlat(): ?string
public function setCorridor(?string $corridor): self
{
return $this->flat;
}
public function setFlat(?string $flat): self
{
$this->flat = $flat;
$this->corridor = $corridor;
return $this;
}
public function getDistribution(): ?string
/**
* Store custom informations in the address.
*
* @return $this
*/
public function setCustoms(array $customs): self
{
return $this->distribution;
$this->customs = $customs;
return $this;
}
public function setDistribution(?string $distribution): self
@@ -509,11 +391,6 @@ class Address
return $this;
}
public function getExtra(): ?string
{
return $this->extra;
}
public function setExtra(?string $extra): self
{
$this->extra = $extra;
@@ -521,33 +398,32 @@ class Address
return $this;
}
public function getValidTo(): ?\DateTimeInterface
public function setFlat(?string $flat): self
{
return $this->validTo;
}
public function setValidTo(?\DateTimeInterface $validTo = null): self
{
$this->validTo = $validTo;
$this->flat = $flat;
return $this;
}
public function getPoint(): ?Point
public function setFloor(?string $floor): self
{
return $this->point;
}
public function setPoint(?Point $point): self
{
$this->point = $point;
$this->floor = $floor;
return $this;
}
public function getLinkedToThirdParty()
/**
* Set IsNoAddress.
*
* Indicate true if the address is a fake address (homeless, ...)
*
* @return $this
*/
public function setIsNoAddress(bool $isNoAddress): self
{
return $this->linkedToThirdParty;
$this->isNoAddress = $isNoAddress;
return $this;
}
public function setLinkedToThirdParty($linkedToThirdParty): self
@@ -557,22 +433,130 @@ class Address
return $this;
}
/**
* @return AddressReference|null
*/
public function getAddressReference(): ?AddressReference
public function setPoint(?Point $point): self
{
return $this->addressReference;
}
$this->point = $point;
/**
* @param AddressReference|null $addressReference
* @return Address
*/
public function setAddressReference(?AddressReference $addressReference = null): Address
{
$this->addressReference = $addressReference;
return $this;
}
}
/**
* Set postcode.
*
* @param PostalCode $postcode
*
* @return Address
*/
public function setPostcode(?PostalCode $postcode = null)
{
$this->postcode = $postcode;
return $this;
}
public function setSteps(?string $steps): self
{
$this->steps = $steps;
return $this;
}
public function setStreet(string $street): self
{
$this->street = $street;
return $this;
}
/**
* Set streetAddress1 (legacy function).
*
* @param string $streetAddress1
*
* @return Address
*/
public function setStreetAddress1($streetAddress1)
{
$this->street = null === $streetAddress1 ? '' : $streetAddress1;
return $this;
}
/**
* Set streetAddress2 (legacy function).
*
* @param string $streetAddress2
*
* @return Address
*/
public function setStreetAddress2($streetAddress2)
{
$this->streetNumber = null === $streetAddress2 ? '' : $streetAddress2;
return $this;
}
public function setStreetNumber(string $streetNumber): self
{
$this->streetNumber = $streetNumber;
return $this;
}
/**
* @return Address
*/
public function setValidFrom(DateTime $validFrom)
{
$this->validFrom = $validFrom;
return $this;
}
public function setValidTo(?DateTimeInterface $validTo = null): self
{
$this->validTo = $validTo;
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 array $payload
*/
public function validate(ExecutionContextInterface $context, $payload)
{
if (!$this->getValidFrom() instanceof DateTime) {
$context
->buildViolation('address.date-should-be-set')
->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')
->atPath('postCode')
->addViolation();
}
}
}

View File

@@ -1,15 +1,22 @@
<?php
/**
* Chill is a software for social workers
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/
namespace Chill\MainBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
use Chill\MainBundle\Doctrine\Model\Point;
use Doctrine\ORM\Mapping as ORM;
use Symfony\Component\Serializer\Annotation\Groups;
/**
* @ORM\Entity
* @ORM\Table(name="chill_main_address_reference")
* @ORM\HasLifecycleCallbacks()
* @ORM\HasLifecycleCallbacks
*/
class AddressReference
{
@@ -21,12 +28,42 @@ class AddressReference
*/
private $id;
/**
* @ORM\Column(type="string", length=255, nullable=true)
* @groups({"read"})
*/
private $municipalityCode;
/**
* A geospatial field storing the coordinates of the Address.
*
* @var Point
*
* @ORM\Column(type="point")
* @groups({"read"})
*/
private $point;
/**
* @var PostalCode
*
* @ORM\ManyToOne(targetEntity="Chill\MainBundle\Entity\PostalCode")
* @groups({"read"})
*/
private $postcode;
/**
* @ORM\Column(type="string", length=255)
* @groups({"read"})
*/
private $refId;
/**
* @ORM\Column(type="string", length=255, nullable=true)
* @groups({"read"})
*/
private $source;
/**
* @ORM\Column(type="string", length=255, nullable=true)
* @groups({"read"})
@@ -39,94 +76,23 @@ class AddressReference
*/
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
public function getMunicipalityCode(): ?string
{
return $this->refId;
return $this->municipalityCode;
}
public function setRefId(string $refId): self
public function getPoint(): ?Point
{
$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;
return $this->point;
}
/**
* Set postcode
*
* @param PostalCode $postcode
*
* @return Address
*/
public function setPostcode(PostalCode $postcode = null)
{
$this->postcode = $postcode;
return $this;
}
/**
* Get postcode
* Get postcode.
*
* @return PostalCode
*/
@@ -135,9 +101,24 @@ class AddressReference
return $this->postcode;
}
public function getMunicipalityCode(): ?string
public function getRefId(): ?string
{
return $this->municipalityCode;
return $this->refId;
}
public function getSource(): ?string
{
return $this->source;
}
public function getStreet(): ?string
{
return $this->street;
}
public function getStreetNumber(): ?string
{
return $this->streetNumber;
}
public function setMunicipalityCode(?string $municipalityCode): self
@@ -147,9 +128,32 @@ class AddressReference
return $this;
}
public function getSource(): ?string
public function setPoint(?Point $point): self
{
return $this->source;
$this->point = $point;
return $this;
}
/**
* Set postcode.
*
* @param PostalCode $postcode
*
* @return Address
*/
public function setPostcode(?PostalCode $postcode = null)
{
$this->postcode = $postcode;
return $this;
}
public function setRefId(string $refId): self
{
$this->refId = $refId;
return $this;
}
public function setSource(?string $source): self
@@ -159,14 +163,16 @@ class AddressReference
return $this;
}
public function getPoint(): ?Point
public function setStreet(?string $street): self
{
return $this->point;
$this->street = $street;
return $this;
}
public function setPoint(?Point $point): self
public function setStreetNumber(?string $streetNumber): self
{
$this->point = $point;
$this->streetNumber = $streetNumber;
return $this;
}

View File

@@ -1,28 +1,17 @@
<?php
/*
/**
* Chill is a software for social workers
*
* Copyright (C) 2014, Champs Libres Cooperative SCRLFS, <http://www.champs-libres.coop>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/
namespace Chill\MainBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\Common\Collections\Collection;
use Doctrine\ORM\Mapping as ORM;
use Symfony\Component\Serializer\Annotation as Serializer;
/**
@@ -31,24 +20,6 @@ use Symfony\Component\Serializer\Annotation as Serializer;
*/
class Center implements HasCenterInterface
{
/**
* @var integer
*
* @ORM\Id
* @ORM\Column(name="id", type="integer")
* @ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* @var string
*
* @ORM\Column(type="string", length=255)
* @Serializer\Groups({"docgen:read"})
*/
private string $name = '';
/**
* @var Collection
*
@@ -59,6 +30,20 @@ class Center implements HasCenterInterface
*/
private $groupCenters;
/**
* @var int
*
* @ORM\Id
* @ORM\Column(name="id", type="integer")
* @ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* @ORM\Column(type="string", length=255)
* @Serializer\Groups({"docgen:read"})
*/
private string $name = '';
/**
* Center constructor.
@@ -71,27 +56,27 @@ class Center implements HasCenterInterface
/**
* @return string
*/
public function getName()
public function __toString()
{
return $this->name;
return $this->getName();
}
/**
* @param $name
* @return $this
*/
public function setName($name)
public function addGroupCenter(GroupCenter $groupCenter)
{
$this->name = $name;
$this->groupCenters->add($groupCenter);
return $this;
}
/**
* @return int
* @return $this|Center
*/
public function getId()
public function getCenter()
{
return $this->id;
return $this;
}
/**
@@ -103,29 +88,30 @@ class Center implements HasCenterInterface
}
/**
* @param GroupCenter $groupCenter
* @return $this
* @return int
*/
public function addGroupCenter(GroupCenter $groupCenter)
public function getId()
{
$this->groupCenters->add($groupCenter);
return $this;
return $this->id;
}
/**
* @return string
*/
public function __toString()
public function getName()
{
return $this->getName();
return $this->name;
}
/**
* @return $this|Center
* @param $name
*
* @return $this
*/
public function getCenter()
public function setName($name)
{
$this->name = $name;
return $this;
}
}

View File

@@ -1,23 +1,10 @@
<?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/>.
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/
namespace Chill\MainBundle\Entity;
@@ -31,6 +18,17 @@ use Symfony\Component\Serializer\Annotation as Serializer;
*/
class Civility
{
/**
* @ORM\Column(type="json")
* @Serializer\Groups({"read"})
*/
private array $abbreviation = [];
/**
* @ORM\Column(type="boolean")
*/
private bool $active = true;
/**
* @ORM\Id
* @ORM\GeneratedValue
@@ -45,16 +43,15 @@ class Civility
*/
private array $name = [];
/**
* @ORM\Column(type="json")
* @Serializer\Groups({"read"})
*/
private array $abbreviation = [];
public function getAbbreviation(): array
{
return $this->abbreviation;
}
/**
* @ORM\Column(type="boolean")
*/
private bool $active = true;
public function getActive(): ?bool
{
return $this->active;
}
public function getId(): ?int
{
@@ -66,18 +63,16 @@ class Civility
return $this->name;
}
public function setName(array $name): self
/**
* @return Civility
*/
public function setAbbreviation(array $abbreviation): self
{
$this->name = $name;
$this->abbreviation = $abbreviation;
return $this;
}
public function getActive(): ?bool
{
return $this->active;
}
public function setActive(bool $active): self
{
$this->active = $active;
@@ -85,21 +80,10 @@ class Civility
return $this;
}
/**
* @return array
*/
public function getAbbreviation(): array
public function setName(array $name): self
{
return $this->abbreviation;
}
$this->name = $name;
/**
* @param array $abbreviation
* @return Civility
*/
public function setAbbreviation(array $abbreviation): self
{
$this->abbreviation = $abbreviation;
return $this;
}
}

View File

@@ -1,22 +1,37 @@
<?php
/**
* Chill is a software for social workers
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/
namespace Chill\MainBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
use Symfony\Component\Serializer\Annotation\Groups;
/**
* Country
* Country.
*
* @ORM\Entity
* @ORM\Table(name="country")
* @ORM\Cache(usage="READ_ONLY", region="country_cache_region")
* @ORM\HasLifecycleCallbacks()
* @ORM\HasLifecycleCallbacks
*/
class Country
{
/**
* @var integer
* @var string
*
* @ORM\Column(type="string", length=3)
* @groups({"read"})
*/
private $countryCode;
/**
* @var int
*
* @ORM\Id
* @ORM\Column(name="id", type="integer")
@@ -30,52 +45,9 @@ class Country
*
* @ORM\Column(type="json")
* @groups({"read"})
*
*/
private $name;
/**
* @var string
*
* @ORM\Column(type="string", length=3)
* @groups({"read"})
*/
private $countryCode;
/**
* Get id
*
* @return integer
*/
public function getId()
{
return $this->id;
}
/**
* Set name
*
* @param string $name
* @return Country
*/
public function setName($name)
{
$this->name = $name;
return $this;
}
/**
* Get name
*
* @return string
*/
public function getName()
{
return $this->name;
}
/**
* @return string
*/
@@ -85,7 +57,6 @@ class Country
}
/**
*
* @return the string
*/
public function getCountryCode()
@@ -94,13 +65,46 @@ class Country
}
/**
* Get id.
*
* @return int
*/
public function getId()
{
return $this->id;
}
/**
* Get name.
*
* @return string
*/
public function getName()
{
return $this->name;
}
/**
* @param string $countryCode
*/
public function setCountryCode($countryCode)
{
$this->countryCode = $countryCode;
return $this;
}
/**
* Set name.
*
* @param string $name
*
* @return Country
*/
public function setName($name)
{
$this->name = $name;
return $this;
}
}

View File

@@ -1,12 +1,19 @@
<?php
/**
* Chill is a software for social workers
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/
namespace Chill\MainBundle\Entity\Embeddable;
use Chill\MainBundle\Entity\User;
use DateTime;
use Doctrine\ORM\Mapping as ORM;
/**
* @ORM\Embeddable()
* @ORM\Embeddable
*/
class CommentEmbeddable
{
@@ -17,18 +24,19 @@ class CommentEmbeddable
private $comment;
/**
* Embeddable does not support associations
* @var integer
* @ORM\Column(type="integer", nullable=true)
*/
private $userId;
/**
* @var \DateTime
* @var DateTime
* @ORM\Column(type="datetime", nullable=true)
*/
private $date;
/**
* Embeddable does not support associations.
*
* @var int
* @ORM\Column(type="integer", nullable=true)
*/
private $userId;
/**
* @return string
*/
@@ -37,6 +45,22 @@ class CommentEmbeddable
return $this->comment;
}
/**
* @return DateTime
*/
public function getDate()
{
return $this->date;
}
/**
* @return interger $userId
*/
public function getUserId()
{
return $this->userId;
}
public function isEmpty()
{
return empty($this->getComment());
@@ -51,34 +75,18 @@ class CommentEmbeddable
}
/**
* @return interger $userId
* @param DateTime $date
*/
public function getUserId()
public function setDate(?DateTime $date)
{
return $this->userId;
$this->date = $date;
}
/**
* @param integer $userId
* @param int $userId
*/
public function setUserId($userId)
{
$this->userId = $userId;
}
/**
* @return \DateTime
*/
public function getDate()
{
return $this->date;
}
/**
* @param \DateTime $date
*/
public function setDate(?\DateTime $date)
{
$this->date = $date;
}
}

View File

@@ -1,49 +1,25 @@
<?php
/*
* Chill is a suite of a modules, Chill is a software for social workers
* Copyright (C) 2014, Champs Libres Cooperative SCRLFS, <http://www.champs-libres.coop>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
/**
* Chill is a software for social workers
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/
namespace Chill\MainBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
use Chill\MainBundle\Entity\Center;
use Chill\MainBundle\Entity\PermissionsGroup;
use Doctrine\Common\Collections\Collection;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\Common\Collections\Collection;
use Doctrine\ORM\Mapping as ORM;
/**
* @ORM\Entity
* @ORM\Table(name="group_centers")
* @ORM\Cache(usage="NONSTRICT_READ_WRITE", region="acl_cache_region")
*
* @author Julien Fastré <julien.fastre@champs-libres.coop>
*/
class GroupCenter
{
/**
* @var int
*
* @ORM\Id
* @ORM\Column(name="id", type="integer")
* @ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* @var Center
*
@@ -54,7 +30,26 @@ class GroupCenter
* @ORM\Cache(usage="NONSTRICT_READ_WRITE")
*/
private $center;
/**
* @var int
*
* @ORM\Id
* @ORM\Column(name="id", type="integer")
* @ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* @var PermissionsGroup
*
* @ORM\ManyToOne(
* targetEntity="Chill\MainBundle\Entity\PermissionsGroup",
* inversedBy="groupCenters")
* @ORM\Cache(usage="NONSTRICT_READ_WRITE")
*/
private $permissionsGroup;
/**
* @var Collection
*
@@ -64,18 +59,7 @@ class GroupCenter
* )
*/
private $users;
/**
* @var PermissionsGroup
*
* @ORM\ManyToOne(
* targetEntity="Chill\MainBundle\Entity\PermissionsGroup",
* inversedBy="groupCenters")
* @ORM\Cache(usage="NONSTRICT_READ_WRITE")
*/
private $permissionsGroup;
/**
* GroupCenter constructor.
*/
@@ -84,14 +68,6 @@ class GroupCenter
$this->permissionsGroup = new ArrayCollection();
$this->users = new ArrayCollection();
}
/**
* @return int
*/
public function getId()
{
return $this->id;
}
/**
* @return Center
@@ -102,23 +78,13 @@ class GroupCenter
}
/**
* @param Center $center
* @return \Chill\MainBundle\Entity\GroupCenter
* @return int
*/
public function setCenter(Center $center)
public function getId()
{
$this->center = $center;
return $this;
return $this->id;
}
/**
* @return ArrayCollection|Collection
*/
public function getUsers()
{
return $this->users;
}
/**
* @return PermissionGroup
*/
@@ -128,17 +94,30 @@ class GroupCenter
}
/**
* @param \Chill\MainBundle\Entity\PermissionsGroup $permissionGroup
* @return ArrayCollection|Collection
*/
public function getUsers()
{
return $this->users;
}
/**
* @return \Chill\MainBundle\Entity\GroupCenter
*/
public function setCenter(Center $center)
{
$this->center = $center;
return $this;
}
/**
* @return \Chill\MainBundle\Entity\GroupCenter
*/
public function setPermissionsGroup(PermissionsGroup $permissionsGroup)
{
$this->permissionsGroup = $permissionsGroup;
return $this;
}
}

View File

@@ -1,35 +1,22 @@
<?php
/*
* Copyright (C) 2015 Julien Fastré <julien.fastre@champs-libres.coop>
/**
* Chill is a software for social workers
*
* This program is free software: you can redistribute it and/or modify
* 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/>.
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/
namespace Chill\MainBundle\Entity;
/**
* Interface for entities which may be linked to a center
*
*
* @author Julien Fastré <julien.fastre@champs-libres.coop>
* Interface for entities which may be linked to a center.
*/
interface HasCenterInterface
{
/**
* the linked center
*
* the linked center.
*
* @return Center
*/
public function getCenter();

View File

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

View File

@@ -1,34 +1,22 @@
<?php
/*
* Copyright (C) 2015 Julien Fastré <julien.fastre@champs-libres.coop>
/**
* Chill is a software for social workers
*
* This program is free software: you can redistribute it and/or modify
* 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/>.
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/
namespace Chill\MainBundle\Entity;
/**
* Interface for entities which have a scop
*
* @author Julien Fastré <julien.fastre@champs-libres.coop>
* Interface for entities which have a scop.
*/
interface HasScopeInterface
{
/**
* Return the linked scope
*
* Return the linked scope.
*
* @return Scope
*/
public function getScope();

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