Merge remote-tracking branch 'origin/master' into 616_rapid-action

This commit is contained in:
2024-06-12 16:45:43 +02:00
2249 changed files with 42970 additions and 30730 deletions

View File

@@ -38,10 +38,10 @@ class CRUDControllerCompilerPass implements CompilerPassInterface
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)) {
@@ -51,7 +51,7 @@ class CRUDControllerCompilerPass implements CompilerPassInterface
// add the "addMethodCall"
$container->getDefinition($controllerClass)
->addMethodCall('setCrudConfig', ['%' . $param . '%']);
->addMethodCall('setCrudConfig', ['%'.$param.'%']);
} else {
$controller = new Definition($controllerClass);
@@ -59,7 +59,7 @@ class CRUDControllerCompilerPass implements CompilerPassInterface
$controller->setAutoconfigured(true);
$controller->setPublic(true);
$controller->addMethodCall('setCrudConfig', ['%' . $param . '%']);
$controller->addMethodCall('setCrudConfig', ['%'.$param.'%']);
$container->setDefinition($controllerServiceName, $controller);
}

View File

@@ -15,16 +15,18 @@ use Chill\MainBundle\CRUD\Resolver\Resolver;
use Chill\MainBundle\Pagination\PaginatorFactory;
use Chill\MainBundle\Pagination\PaginatorInterface;
use Chill\MainBundle\Security\Authorization\AuthorizationHelper;
use Doctrine\DBAL\LockMode;
use Doctrine\ORM\EntityManagerInterface;
use Doctrine\ORM\OptimisticLockException;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpKernel\Exception\ConflictHttpException;
use Symfony\Component\Serializer\SerializerInterface;
use Symfony\Component\Validator\Validator\ValidatorInterface;
use Symfony\Contracts\Translation\TranslatorInterface;
use function array_merge;
abstract class AbstractCRUDController extends AbstractController
{
/**
@@ -36,11 +38,8 @@ abstract class AbstractCRUDController extends AbstractController
/**
* get the role given from the config.
*
* @param mixed $entity
* @param mixed $_format
*/
protected function getRoleFor(string $action, Request $request, $entity, $_format): string
protected function getRoleFor(string $action, Request $request, mixed $entity, mixed $_format): string
{
$actionConfig = $this->getActionConfig($action);
@@ -52,14 +51,12 @@ abstract class AbstractCRUDController extends AbstractController
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()));
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()));
}
public static function getSubscribedServices(): array
{
return array_merge(
return \array_merge(
parent::getSubscribedServices(),
[
'chill_main.paginator_factory' => PaginatorFactory::class,
@@ -132,10 +129,8 @@ abstract class AbstractCRUDController extends AbstractController
*
* 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
protected function countEntities(string $action, Request $request, mixed $_format): int
{
return $this->buildQueryEntities($action, $request)
->select('COUNT(e)')
@@ -160,7 +155,7 @@ abstract class AbstractCRUDController extends AbstractController
}
/**
* @return string The crud name.
* @return string the crud name
*/
protected function getCrudName(): string
{
@@ -171,10 +166,8 @@ abstract class AbstractCRUDController extends AbstractController
* 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
protected function getEntity(mixed $action, string $id, Request $request): object
{
$e = $this
->getDoctrine()
@@ -184,6 +177,21 @@ abstract class AbstractCRUDController extends AbstractController
if (null === $e) {
throw $this->createNotFoundException(sprintf('The object %s for id %s is not found', $this->getEntityClass(), $id));
}
if ($request->query->has('entity_version')) {
$expectedVersion = $request->query->getInt('entity_version');
try {
$manager = $this->getDoctrine()->getManagerForClass($this->getEntityClass());
if ($manager instanceof EntityManagerInterface) {
$manager->lock($e, LockMode::OPTIMISTIC, $expectedVersion);
} else {
throw new \LogicException('This manager does not allow locking.');
}
} catch (OptimisticLockException $e) {
throw new ConflictHttpException('Sorry, but someone else has already changed this entity. Please refresh the page and apply the changes again', $e);
}
}
return $e;
}
@@ -205,10 +213,8 @@ abstract class AbstractCRUDController extends AbstractController
/**
* Get the result of the query.
*
* @param mixed $query
*/
protected function getQueryResult(string $action, Request $request, string $_format, int $totalItems, PaginatorInterface $paginator, $query)
protected function getQueryResult(string $action, Request $request, string $_format, int $totalItems, PaginatorInterface $paginator, mixed $query)
{
return $query->getQuery()->getResult();
}
@@ -220,41 +226,32 @@ abstract class AbstractCRUDController extends AbstractController
/**
* Called on post check ACL.
*
* @param mixed $entity
*/
protected function onPostCheckACL(string $action, Request $request, string $_format, $entity): ?Response
protected function onPostCheckACL(string $action, Request $request, string $_format, mixed $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
protected function onPostFetchEntity(string $action, Request $request, mixed $entity, mixed $_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
protected function onPostIndexBuildQuery(string $action, Request $request, string $_format, int $totalItems, PaginatorInterface $paginator, mixed $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
protected function onPostIndexFetchQuery(string $action, Request $request, string $_format, int $totalItems, PaginatorInterface $paginator, mixed $entities): ?Response
{
return null;
}
@@ -274,11 +271,8 @@ abstract class AbstractCRUDController extends AbstractController
/**
* Add ordering fields in the query build by self::queryEntities.
*
* @param mixed $query
* @param mixed $_format
*/
protected function orderQuery(string $action, $query, Request $request, PaginatorInterface $paginator, $_format)
protected function orderQuery(string $action, mixed $query, Request $request, PaginatorInterface $paginator, mixed $_format)
{
return $query;
}

View File

@@ -13,9 +13,6 @@ 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\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpKernel\Exception\BadRequestHttpException;
@@ -24,39 +21,22 @@ 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
{
/**
* Base method for handling api action.
*
* @param mixed $id
* @param string $_format
*
* @return void
*/
public function entityApi(Request $request, $id, ?string $_format = 'json'): Response
public function entityApi(Request $request, mixed $id, ?string $_format = 'json'): Response
{
switch ($request->getMethod()) {
case Request::METHOD_GET:
case Request::METHOD_HEAD:
return $this->entityGet('_entity', $request, $id, $_format);
case Request::METHOD_PUT:
case Request::METHOD_PATCH:
return $this->entityPut('_entity', $request, $id, $_format);
case Request::METHOD_POST:
return $this->entityPostAction('_entity', $request, $id);
case Request::METHOD_DELETE:
return $this->entityDelete('_entity', $request, $id, $_format);
default:
throw new BadRequestHttpException('This method is not implemented');
}
return match ($request->getMethod()) {
Request::METHOD_GET, Request::METHOD_HEAD => $this->entityGet('_entity', $request, $id, $_format),
Request::METHOD_PUT, Request::METHOD_PATCH => $this->entityPut('_entity', $request, $id, $_format),
Request::METHOD_POST => $this->entityPostAction('_entity', $request, $id),
Request::METHOD_DELETE => $this->entityDelete('_entity', $request, $id, $_format),
default => throw new BadRequestHttpException('This method is not implemented'),
};
}
public function entityDelete($action, Request $request, $id, string $_format): Response
@@ -64,8 +44,7 @@ class ApiController extends AbstractCRUDController
$entity = $this->getEntity($action, $id, $request);
if (null === $entity) {
throw $this->createNotFoundException(sprintf('The %s with id %s '
. 'is not found', $this->getCrudName(), $id));
throw $this->createNotFoundException(sprintf('The %s with id %s is not found', $this->getCrudName(), $id));
}
$response = $this->checkACL($action, $request, $_format, $entity);
@@ -115,13 +94,10 @@ class ApiController extends AbstractCRUDController
public function entityPost(Request $request, $_format): Response
{
switch ($request->getMethod()) {
case Request::METHOD_POST:
return $this->entityPostAction('_entity', $request, $_format);
default:
throw new BadRequestHttpException('This method is not implemented');
}
return match ($request->getMethod()) {
Request::METHOD_POST => $this->entityPostAction('_entity', $request, $_format),
default => throw new BadRequestHttpException('This method is not implemented'),
};
}
public function entityPut($action, Request $request, $id, string $_format): Response
@@ -135,8 +111,7 @@ class ApiController extends AbstractCRUDController
}
if (null === $entity) {
throw $this->createNotFoundException(sprintf('The %s with id %s '
. 'is not found', $this->getCrudName(), $id));
throw $this->createNotFoundException(sprintf('The %s with id %s is not found', $this->getCrudName(), $id));
}
$response = $this->checkACL($action, $request, $_format, $entity);
@@ -160,7 +135,7 @@ class ApiController extends AbstractCRUDController
try {
$entity = $this->deserialize($action, $request, $_format, $entity);
} catch (NotEncodableValueException $e) {
throw new BadRequestHttpException('invalid json', 400, $e);
throw new BadRequestHttpException('invalid json', $e, 400);
}
$errors = $this->validate($action, $request, $_format, $entity);
@@ -178,7 +153,7 @@ class ApiController extends AbstractCRUDController
return $response;
}
$this->getDoctrine()->getManager()->flush();
$this->getDoctrine()->getManagerForClass($this->getEntityClass())->flush();
$response = $this->onAfterFlush($action, $request, $_format, $entity, $errors);
@@ -199,14 +174,10 @@ class ApiController extends AbstractCRUDController
*/
public function indexApi(Request $request, string $_format)
{
switch ($request->getMethod()) {
case Request::METHOD_GET:
case REQUEST::METHOD_HEAD:
return $this->indexApiAction('_index', $request, $_format);
default:
throw $this->createNotFoundException('This method is not supported');
}
return match ($request->getMethod()) {
Request::METHOD_GET, Request::METHOD_HEAD => $this->indexApiAction('_index', $request, $_format),
default => throw $this->createNotFoundException('This method is not supported'),
};
}
public function onBeforeSerialize(string $action, Request $request, $_format, $entity): ?Response
@@ -234,15 +205,15 @@ class ApiController extends AbstractCRUDController
*
* @param string action
* @param mixed id
* @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 $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
* @param bool $forcePersist force to persist the created element (only for POST request)
*
* @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
protected function addRemoveSomething(string $action, mixed $id, Request $request, string $_format, string $property, string $postedDataType, array $postedDataContext = [], bool $forcePersist = false): Response
{
$entity = $this->getEntity($action, $id, $request);
@@ -273,27 +244,16 @@ class ApiController extends AbstractCRUDController
try {
$postedData = $this->getSerializer()->deserialize($request->getContent(), $postedDataType, $_format, $postedDataContext);
} catch (\Symfony\Component\Serializer\Exception\UnexpectedValueException $e) {
throw new BadRequestHttpException(sprintf('Unable to deserialize posted ' .
'data: %s', $e->getMessage()), $e, 0);
throw new BadRequestHttpException(sprintf('Unable to deserialize posted data: %s', $e->getMessage()), $e, 0);
}
switch ($request->getMethod()) {
case Request::METHOD_DELETE:
// oups... how to use property accessor to remove element ?
/* @phpstan-ignore-next-line as we do not find a simpler way to do this */
$entity->{'remove' . ucfirst($property)}($postedData);
break;
case Request::METHOD_POST:
/* @phpstan-ignore-next-line as we do not find a simpler way to do this */
$entity->{'add' . ucfirst($property)}($postedData);
break;
default:
throw new BadRequestHttpException('this method is not supported');
}
match ($request->getMethod()) {
/* @phpstan-ignore-next-line */
Request::METHOD_DELETE => $entity->{'remove'.\ucfirst($property)}($postedData),
/* @phpstan-ignore-next-line */
Request::METHOD_POST => $entity->{'add'.\ucfirst($property)}($postedData),
default => throw new BadRequestHttpException('this method is not supported'),
};
$errors = $this->validate($action, $request, $_format, $entity, [$postedData]);
@@ -308,7 +268,7 @@ class ApiController extends AbstractCRUDController
return $this->json($errors, 422);
}
if ($forcePersist && $request->getMethod() === Request::METHOD_POST) {
if ($forcePersist && Request::METHOD_POST === $request->getMethod()) {
$this->getDoctrine()->getManager()->persist($postedData);
}
@@ -320,20 +280,16 @@ class ApiController extends AbstractCRUDController
return $response;
}
switch ($request->getMethod()) {
case Request::METHOD_DELETE:
return $this->json('', Response::HTTP_OK);
case Request::METHOD_POST:
return $this->json(
$postedData,
Response::HTTP_OK,
[],
$this->getContextForSerializationPostAlter($action, $request, $_format, $entity, [$postedData])
);
}
throw new Exception('Unable to handle such request method.');
return match ($request->getMethod()) {
Request::METHOD_DELETE => $this->json('', Response::HTTP_OK),
Request::METHOD_POST => $this->json(
$postedData,
Response::HTTP_OK,
[],
$this->getContextForSerializationPostAlter($action, $request, $_format, $entity, [$postedData])
),
default => throw new \Exception('Unable to handle such request method.'),
};
}
/**
@@ -349,7 +305,7 @@ class ApiController extends AbstractCRUDController
$default[AbstractNormalizer::OBJECT_TO_POPULATE] = $entity;
}
$context = array_merge(
$context = \array_merge(
$default,
$this->getContextForSerialization($action, $request, $_format, $entity)
);
@@ -372,11 +328,8 @@ class ApiController extends AbstractCRUDController
* 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
protected function entityGet(string $action, Request $request, mixed $id, mixed $_format = 'html'): Response
{
$entity = $this->getEntity($action, $id, $request);
@@ -474,18 +427,11 @@ class ApiController extends AbstractCRUDController
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');
}
return match ($request->getMethod()) {
Request::METHOD_GET => ['groups' => ['read']],
Request::METHOD_PUT, Request::METHOD_PATCH, Request::METHOD_POST => ['groups' => ['write']],
default => throw new \LogicException('get context for serialization is not implemented for this method'),
};
}
/**
@@ -493,15 +439,12 @@ class ApiController extends AbstractCRUDController
* 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
protected function getContextForSerializationPostAlter(string $action, Request $request, string $_format, mixed $entity, array $more = []): array
{
return ['groups' => ['read']];
}
protected function getSerializer(): SerializerInterface
{
return $this->get('serializer');
@@ -531,9 +474,8 @@ class ApiController extends AbstractCRUDController
* 4. Serialize the entities in a Collection, using `SerializeCollection`
*
* @param string $action
* @param mixed $_format
*/
protected function indexApiAction($action, Request $request, $_format)
protected function indexApiAction($action, Request $request, mixed $_format)
{
$this->onPreIndex($action, $request, $_format);
@@ -611,10 +553,8 @@ class ApiController extends AbstractCRUDController
/**
* Serialize collections.
*
* @param mixed $entities
*/
protected function serializeCollection(string $action, Request $request, string $_format, PaginatorInterface $paginator, $entities): Response
protected function serializeCollection(string $action, Request $request, string $_format, PaginatorInterface $paginator, mixed $entities): Response
{
$model = new Collection($entities, $paginator);

View File

@@ -19,7 +19,6 @@ use Chill\MainBundle\Security\Authorization\AuthorizationHelper;
use Chill\MainBundle\Templating\Listing\FilterOrderHelper;
use Chill\MainBundle\Templating\Listing\FilterOrderHelperFactoryInterface;
use Doctrine\ORM\QueryBuilder;
use LogicException;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
use Symfony\Component\Form\FormInterface;
@@ -30,9 +29,6 @@ use Symfony\Component\Security\Core\Role\Role;
use Symfony\Component\Serializer\SerializerInterface;
use Symfony\Contracts\Translation\TranslatorInterface;
use function array_key_exists;
use function array_merge;
class CRUDController extends AbstractController
{
/**
@@ -47,9 +43,6 @@ class CRUDController extends AbstractController
return new Response($parameter);
}
/**
* @param $id
*/
public function delete(Request $request, $id): Response
{
return $this->deleteAction('delete', $request, $id);
@@ -59,27 +52,23 @@ class CRUDController extends AbstractController
* BAse method for edit action.
*
* IMplemented by the method formEditAction, with action as 'edit'
*
* @param mixed $id
*/
public function edit(Request $request, $id): Response
public function edit(Request $request, mixed $id): Response
{
return $this->formEditAction('edit', $request, $id);
}
/**
* Get the context for the serialization.
*
* @param mixed $entity
*/
public function getContextForSerialization(string $action, Request $request, $entity, string $_format): array
public function getContextForSerialization(string $action, Request $request, mixed $entity, string $_format): array
{
return [];
}
public static function getSubscribedServices(): array
{
return array_merge(
return \array_merge(
parent::getSubscribedServices(),
[
'chill_main.paginator_factory' => PaginatorFactory::class,
@@ -122,10 +111,8 @@ class CRUDController extends AbstractController
* Base method for the view action.
*
* Implemented by the method viewAction, with action as 'view'
*
* @param mixed $id
*/
public function view(Request $request, $id): Response
public function view(Request $request, mixed $id): Response
{
return $this->viewAction('view', $request, $id);
}
@@ -184,11 +171,9 @@ class CRUDController extends AbstractController
* Throw an \Symfony\Component\Security\Core\Exception\AccessDeniedHttpException
* if not accessible.
*
* @param mixed $entity
*
* @throws \Symfony\Component\Security\Core\Exception\AccessDeniedHttpException
*/
protected function checkACL(string $action, $entity)
protected function checkACL(string $action, mixed $entity)
{
$this->denyAccessUnlessGranted($this->getRoleFor($action), $entity);
}
@@ -224,11 +209,8 @@ class CRUDController extends AbstractController
*
* It is preferable to override customizeForm instead of overriding
* this method.
*
* @param mixed $entity
* @param string $formClass
*/
protected function createFormFor(string $action, $entity, ?string $formClass = null, array $formOptions = []): FormInterface
protected function createFormFor(string $action, mixed $entity, ?string $formClass = null, array $formOptions = []): FormInterface
{
$formClass ??= $this->getFormClassFor($action);
@@ -251,7 +233,6 @@ class CRUDController extends AbstractController
}
/**
* @param $id
* @param null $formClass
*/
protected function deleteAction(string $action, Request $request, $id, $formClass = null): Response
@@ -267,13 +248,7 @@ class CRUDController extends AbstractController
}
if (null === $entity) {
throw $this->createNotFoundException(
sprintf(
'The %s with id %s is not found',
$this->getCrudName(),
$id
)
);
throw $this->createNotFoundException(sprintf('The %s with id %s is not found', $this->getCrudName(), $id));
}
$response = $this->checkACL($action, $entity);
@@ -312,7 +287,7 @@ class CRUDController extends AbstractController
return $result;
}
return $this->redirectToRoute('chill_crud_' . $this->getCrudName() . '_view', ['id' => $entity->getId()]);
return $this->redirectToRoute('chill_crud_'.$this->getCrudName().'_view', ['id' => $entity->getId()]);
}
if ($form->isSubmitted()) {
@@ -333,8 +308,6 @@ class CRUDController extends AbstractController
/**
* Duplicate an entity.
*
* @return mixed
*/
protected function duplicateEntity(string $action, Request $request)
{
@@ -431,7 +404,7 @@ class CRUDController extends AbstractController
return $result;
}
return $this->redirectToRoute('chill_crud_' . $this->getCrudName() . '_view', ['id' => $entity->getId()]);
return $this->redirectToRoute('chill_crud_'.$this->getCrudName().'_view', ['id' => $entity->getId()]);
}
if ($form->isSubmitted()) {
@@ -486,23 +459,16 @@ class CRUDController extends AbstractController
* 6. Launch rendering, the parameter is fetch using `getTemplateFor`
* The parameters may be personnalized using `generateTemplateParameter`.
*
* @param mixed $id
* @param string $formClass
* @param class-string $formClass
*
* @throws \Symfony\Component\HttpKernel\Exception\NotFoundHttpException
*/
protected function formEditAction(string $action, Request $request, $id, ?string $formClass = null, array $formOptions = []): Response
protected function formEditAction(string $action, Request $request, mixed $id, ?string $formClass = null, array $formOptions = []): 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
)
);
throw $this->createNotFoundException(sprintf('The %s with id %s is not found', $this->getCrudName(), $id));
}
$response = $this->checkACL($action, $entity);
@@ -537,7 +503,7 @@ class CRUDController extends AbstractController
return $result;
}
return $this->redirectToRoute('chill_crud_' . $this->getCrudName() . '_index');
return $this->redirectToRoute('chill_crud_'.$this->getCrudName().'_index');
}
if ($form->isSubmitted()) {
@@ -572,29 +538,15 @@ class CRUDController extends AbstractController
* Generate a success message when a form could be flushed successfully.
*
* @param string $action
* @param mixed $entity
*/
protected function generateFormSuccessMessage($action, $entity): string
protected function generateFormSuccessMessage($action, mixed $entity): string
{
switch ($action) {
case 'edit':
$msg = 'crud.edit.success';
break;
case 'new':
$msg = 'crud.new.success';
break;
case 'delete':
$msg = 'crud.delete.success';
break;
default:
$msg = 'crud.default.success';
}
$msg = match ($action) {
'edit' => 'crud.edit.success',
'new' => 'crud.new.success',
'delete' => 'crud.delete.success',
default => 'crud.default.success',
};
return $this->getTranslator()->trans($msg);
}
@@ -602,13 +554,11 @@ class CRUDController extends AbstractController
/**
* Customize template parameters.
*
* @param mixed $entity
*
* @return array
*/
protected function generateTemplateParameter(
string $action,
$entity,
mixed $entity,
Request $request,
array $defaultTemplateParameters = []
) {
@@ -617,8 +567,6 @@ class CRUDController extends AbstractController
/**
* Include services.
*
* @return mixed
*/
protected function getActionConfig(string $action)
{
@@ -652,11 +600,8 @@ class CRUDController extends AbstractController
* get the instance of the entity with the given id.
*
* @param string $id
* @param mixed $action
*
* @return object
*/
protected function getEntity($action, $id, Request $request): ?object
protected function getEntity(mixed $action, $id, Request $request): ?object
{
return $this->getDoctrine()
->getRepository($this->getEntityClass())
@@ -709,8 +654,6 @@ class CRUDController extends AbstractController
/**
* Get the result of the query.
*
* @return mixed
*/
protected function getQueryResult(
string $action,
@@ -727,7 +670,7 @@ class CRUDController extends AbstractController
/**
* @return \Chill\MainBundle\Entity\Center[]
*/
protected function getReachableCenters(Role $role, ?Scope $scope = null)
protected function getReachableCenters(string $role, ?Scope $scope = null)
{
return $this->getAuthorizationHelper()
->getReachableCenters($this->getUser(), $role, $scope);
@@ -742,7 +685,7 @@ class CRUDController extends AbstractController
*/
protected function getRoleFor($action)
{
if (array_key_exists('role', $this->getActionConfig($action))) {
if (\array_key_exists('role', $this->getActionConfig($action))) {
return $this->getActionConfig($action)['role'];
}
@@ -757,39 +700,25 @@ class CRUDController extends AbstractController
* and view.
*
* @param string $action
* @param mixed $entity the entity for the current request, or an array of entities
*
* @throws LogicException if no template are available
*
* @return string the path to the template
*
* @throws \LogicException if no template are available
*/
protected function getTemplateFor($action, $entity, Request $request)
protected function getTemplateFor($action, mixed $entity, Request $request)
{
if ($this->hasCustomTemplate($action, $entity, $request)) {
return $this->getActionConfig($action)['template'];
}
switch ($action) {
case 'new':
return '@ChillMain/CRUD/new.html.twig';
case 'edit':
return '@ChillMain/CRUD/edit.html.twig';
case 'index':
return '@ChillMain/CRUD/index.html.twig';
case 'view':
return '@ChillMain/CRUD/view.html.twig';
case 'delete':
return '@ChillMain/CRUD/delete.html.twig';
default:
throw new LogicException("the view for action {$action} is not "
. 'defined. You should override ' . __METHOD__ . ' to add this '
. 'action');
}
return match ($action) {
'new' => '@ChillMain/CRUD/new.html.twig',
'edit' => '@ChillMain/CRUD/edit.html.twig',
'index' => '@ChillMain/CRUD/index.html.twig',
'view' => '@ChillMain/CRUD/view.html.twig',
'delete' => '@ChillMain/CRUD/delete.html.twig',
default => throw new \LogicException("the view for action {$action} is not ".'defined. You should override '.__METHOD__.' to add this action'),
};
}
protected function getTranslator(): TranslatorInterface
@@ -797,10 +726,6 @@ class CRUDController extends AbstractController
return $this->container->get('translator');
}
/**
* @param $action
* @param $entity
*/
protected function hasCustomTemplate($action, $entity, Request $request): bool
{
return !empty($this->getActionConfig($action)['template']);
@@ -904,86 +829,56 @@ class CRUDController extends AbstractController
* * save-and-close: return to index of current crud ;
* * save-and-new: return to new page of current crud ;
* * save-and-view: return to view page of current crud ;
*
* @param mixed $entity
*
* @return \Symfony\Component\HttpFoundation\RedirectResponse
*/
protected function onBeforeRedirectAfterSubmission(string $action, $entity, FormInterface $form, Request $request)
protected function onBeforeRedirectAfterSubmission(string $action, mixed $entity, FormInterface $form, Request $request): ?Response
{
$next = $request->request->get('submit', 'save-and-close');
switch ($next) {
case 'save-and-close':
return $this->redirectToRoute('chill_crud_' . $this->getCrudName() . '_index');
case 'save-and-new':
return $this->redirectToRoute('chill_crud_' . $this->getCrudName() . '_new', $request->query->all());
default:
return $this->redirectToRoute('chill_crud_' . $this->getCrudName() . '_view', [
'id' => $entity->getId(),
]);
}
return match ($next) {
'save-and-close' => $this->redirectToRoute('chill_crud_'.$this->getCrudName().'_index'),
'save-and-new' => $this->redirectToRoute('chill_crud_'.$this->getCrudName().'_new', $request->query->all()),
default => $this->redirectToRoute('chill_crud_'.$this->getCrudName().'_view', [
'id' => $entity->getId(),
]),
};
}
protected function onFormValid(string $action, object $entity, FormInterface $form, Request $request)
{
}
/**
* @param $action
* @param $entity
*/
protected function onPostCheckACL($action, Request $request, $entity): ?Response
{
return null;
}
/**
* @param $action
* @param $entity
*/
protected function onPostFetchEntity($action, Request $request, $entity): ?Response
{
return null;
}
/**
* @param $entity
*/
protected function onPostFlush(string $action, $entity, FormInterface $form, Request $request)
{
}
/**
* method used by indexAction.
*
* @param mixed $query
*/
protected function onPostIndexBuildQuery(string $action, Request $request, int $totalItems, PaginatorInterface $paginator, $query)
protected function onPostIndexBuildQuery(string $action, Request $request, int $totalItems, PaginatorInterface $paginator, mixed $query)
{
}
/**
* method used by indexAction.
*
* @param mixed $entities
*/
protected function onPostIndexFetchQuery(string $action, Request $request, int $totalItems, PaginatorInterface $paginator, $entities)
protected function onPostIndexFetchQuery(string $action, Request $request, int $totalItems, PaginatorInterface $paginator, mixed $entities)
{
}
/**
* @param $entity
*/
protected function onPostPersist(string $action, $entity, FormInterface $form, Request $request)
{
}
/**
* @param $entity
*/
protected function onPostRemove(string $action, $entity, FormInterface $form, Request $request)
{
}
@@ -992,9 +887,6 @@ class CRUDController extends AbstractController
{
}
/**
* @param $entity
*/
protected function onPreFlush(string $action, $entity, FormInterface $form, Request $request)
{
}
@@ -1010,16 +902,10 @@ class CRUDController extends AbstractController
{
}
/**
* @param $entity
*/
protected function onPrePersist(string $action, $entity, FormInterface $form, Request $request)
{
}
/**
* @param $entity
*/
protected function onPreRemove(string $action, $entity, FormInterface $form, Request $request)
{
}
@@ -1057,9 +943,6 @@ class CRUDController extends AbstractController
return $this->orderQuery($action, $query, $request, $paginator);
}
/**
* @param $entity
*/
protected function removeEntity(string $action, $entity, FormInterface $form, Request $request)
{
$this->getDoctrine()
@@ -1087,11 +970,8 @@ class CRUDController extends AbstractController
* * `crud_name`: the crud name
* 6. Launch rendering, the parameter is fetch using `getTemplateFor`
* The parameters may be personnalized using `generateTemplateParameter`.
*
* @param mixed $id
* @param mixed $_format
*/
protected function viewAction(string $action, Request $request, $id, $_format = 'html'): Response
protected function viewAction(string $action, Request $request, mixed $id, mixed $_format = 'html'): Response
{
$entity = $this->getEntity($action, $id, $request);
@@ -1102,13 +982,7 @@ class CRUDController extends AbstractController
}
if (null === $entity) {
throw $this->createNotFoundException(
sprintf(
'The %s with id %s is not found',
$this->getCrudName(),
$id
)
);
throw $this->createNotFoundException(sprintf('The %s with id %s is not found', $this->getCrudName(), $id));
}
$response = $this->checkACL($action, $entity);

View File

@@ -12,10 +12,6 @@ declare(strict_types=1);
namespace Chill\MainBundle\CRUD\Resolver;
use Doctrine\ORM\EntityManagerInterface;
use LogicException;
use function array_key_exists;
use function strtoupper;
/**
* Class Resolver.
@@ -25,17 +21,17 @@ class Resolver
/**
* The key to get the role necessary for the action.
*/
public const ROLE = 'role';
final public const ROLE = 'role';
/**
* @deprecated
*/
public const ROLE_EDIT = 'role.edit';
final public const ROLE_EDIT = 'role.edit';
/**
* @deprecated
*/
public const ROLE_VIEW = 'role.view';
final public const ROLE_VIEW = 'role.view';
/**
* @var array
@@ -65,28 +61,22 @@ class Resolver
}
/**
* @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'] .
'_' .
return \strtoupper(
$this->crudConfig[$crudName]['base_role'].
'_'.
$action
);
}
/**
* @param $key
* @param $crudName
* @param null $action
*
* @return string
@@ -102,14 +92,11 @@ class Resolver
}
/**
* @param $crudName
* @param $action
*
* @return bool
*/
public function hasAction($crudName, $action)
{
return array_key_exists(
return \array_key_exists(
$action,
$this->crudConfig[$crudName]['actions']
);

View File

@@ -11,20 +11,11 @@ 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 function array_filter;
use function array_keys;
use function array_search;
use function count;
use function in_array;
use const ARRAY_FILTER_USE_BOTH;
class CRUDRoutesLoader extends Loader
{
private const ALL_INDEX_METHODS = [Request::METHOD_GET, Request::METHOD_HEAD];
@@ -36,30 +27,22 @@ class CRUDRoutesLoader extends Loader
Request::METHOD_DELETE,
];
protected array $apiCrudConfig = [];
protected array $crudConfig = [];
private bool $isLoaded = false;
public function __construct(array $crudConfig, array $apiCrudConfig)
public function __construct(protected array $crudConfig, protected array $apiCrudConfig)
{
$this->crudConfig = $crudConfig;
$this->apiCrudConfig = $apiCrudConfig;
parent::__construct();
}
/**
* Load routes for CRUD and CRUD Api.
*
* @param mixed $resource
* @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();
@@ -76,7 +59,6 @@ class CRUDRoutesLoader extends Loader
}
/**
* @param mixed $resource
* @param null $type
*
* @return bool
@@ -88,13 +70,11 @@ class CRUDRoutesLoader extends Loader
/**
* Load routes for api single.
*
* @param $crudConfig
*/
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
@@ -104,55 +84,41 @@ class CRUDRoutesLoader extends Loader
// continue;
}
// compute default action
switch ($name) {
case '_entity':
$controllerAction = 'entityApi';
break;
case '_index':
$controllerAction = 'indexApi';
break;
default:
$controllerAction = $name . 'Api';
break;
}
$controllerAction = match ($name) {
'_entity' => 'entityApi',
'_index' => 'indexApi',
default => $name.'Api',
};
$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'], true) ? '' : '/' . $name;
$localName = \in_array($name, ['_entity', '_index'], true) ? '' : '/'.$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+'];
$methods = array_keys(array_filter(
$methods = \array_keys(\array_filter(
$action['methods'],
static fn ($value, $key) => $value,
ARRAY_FILTER_USE_BOTH
\ARRAY_FILTER_USE_BOTH
));
if (count($methods) === 0) {
throw new RuntimeException("The api configuration named \"{$crudConfig['name']}\", action \"{$name}\", " .
'does not have any allowed methods. You should remove this action from the config ' .
'or allow, at least, one method');
if (0 === \count($methods)) {
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, true)) {
unset($methods[array_search(Request::METHOD_POST, $methods, true)]);
if ('_entity' === $name && \in_array(Request::METHOD_POST, $methods, true)) {
unset($methods[\array_search(Request::METHOD_POST, $methods, true)]);
$entityPostRoute = $this->createEntityPostRoute(
$name,
$crudConfig,
@@ -165,7 +131,7 @@ class CRUDRoutesLoader extends Loader
);
}
if (count($methods) === 0) {
if (0 === \count($methods)) {
// the only method was POST,
// continue to next
continue;
@@ -174,7 +140,7 @@ 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;
@@ -182,35 +148,33 @@ class CRUDRoutesLoader extends Loader
/**
* Load routes for CRUD (without api).
*
* @param $crudConfig
*/
protected function loadCrudConfig($crudConfig): RouteCollection
{
$collection = new RouteCollection();
$controller = 'cscrud_' . $crudConfig['name'] . '_controller';
$controller = 'cscrud_'.$crudConfig['name'].'_controller';
foreach ($crudConfig['actions'] as $name => $action) {
// defaults (controller name)
$defaults = [
'_controller' => $controller . ':' . ($action['controller_action'] ?? $name),
'_controller' => $controller.':'.($action['controller_action'] ?? $name),
];
if ('index' === $name) {
$path = '{_locale}' . $crudConfig['base_path'];
$path = '{_locale}'.$crudConfig['base_path'];
$route = new Route($path, $defaults);
} elseif ('new' === $name) {
$path = '{_locale}' . $crudConfig['base_path'] . '/' . $name;
$path = '{_locale}'.$crudConfig['base_path'].'/'.$name;
$route = new Route($path, $defaults);
} else {
$path = '{_locale}' . $crudConfig['base_path'] . ($action['path'] ?? '/{id}/' . $name);
$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);
$collection->add('chill_crud_'.$crudConfig['name'].'_'.$name, $route);
}
return $collection;
@@ -218,11 +182,11 @@ 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]);

View File

@@ -35,8 +35,6 @@ class TwigCRUDResolver extends AbstractExtension
}
/**
* @param $configKey
* @param $crudName
* @param null $action
*
* @return string
@@ -54,21 +52,18 @@ class TwigCRUDResolver extends AbstractExtension
return [
new TwigFunction(
'chill_crud_config',
[$this, 'getConfig'],
$this->getConfig(...),
['is_safe' => 'html']
),
new TwigFunction(
'chill_crud_action_exists',
[$this, 'hasAction'],
$this->hasAction(...),
[]
),
];
}
/**
* @param $crudName
* @param $action
*
* @return bool
*/
public function hasAction($crudName, $action)

View File

@@ -15,7 +15,6 @@ use Chill\MainBundle\Cron\CronJobInterface;
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;
@@ -66,16 +65,16 @@ class ChillMainBundle extends Bundle
$container->registerForAutoconfiguration(ViewEntityInfoProviderInterface::class)
->addTag('chill_main.entity_info_provider');
$container->addCompilerPass(new SearchableServicesCompilerPass());
$container->addCompilerPass(new ConfigConsistencyCompilerPass());
$container->addCompilerPass(new TimelineCompilerClass());
$container->addCompilerPass(new RoleProvidersCompilerPass());
$container->addCompilerPass(new ExportsCompilerPass());
$container->addCompilerPass(new WidgetsCompilerPass());
$container->addCompilerPass(new NotificationCounterCompilerPass());
$container->addCompilerPass(new MenuCompilerPass());
$container->addCompilerPass(new ACLFlagsCompilerPass());
$container->addCompilerPass(new CRUDControllerCompilerPass());
$container->addCompilerPass(new ShortMessageCompilerPass());
$container->addCompilerPass(new SearchableServicesCompilerPass(), \Symfony\Component\DependencyInjection\Compiler\PassConfig::TYPE_BEFORE_OPTIMIZATION, 0);
$container->addCompilerPass(new ConfigConsistencyCompilerPass(), \Symfony\Component\DependencyInjection\Compiler\PassConfig::TYPE_BEFORE_OPTIMIZATION, 0);
$container->addCompilerPass(new TimelineCompilerClass(), \Symfony\Component\DependencyInjection\Compiler\PassConfig::TYPE_BEFORE_OPTIMIZATION, 0);
$container->addCompilerPass(new RoleProvidersCompilerPass(), \Symfony\Component\DependencyInjection\Compiler\PassConfig::TYPE_BEFORE_OPTIMIZATION, 0);
$container->addCompilerPass(new ExportsCompilerPass(), \Symfony\Component\DependencyInjection\Compiler\PassConfig::TYPE_BEFORE_OPTIMIZATION, 0);
$container->addCompilerPass(new WidgetsCompilerPass(), \Symfony\Component\DependencyInjection\Compiler\PassConfig::TYPE_BEFORE_OPTIMIZATION, 0);
$container->addCompilerPass(new NotificationCounterCompilerPass(), \Symfony\Component\DependencyInjection\Compiler\PassConfig::TYPE_BEFORE_OPTIMIZATION, 0);
$container->addCompilerPass(new MenuCompilerPass(), \Symfony\Component\DependencyInjection\Compiler\PassConfig::TYPE_BEFORE_OPTIMIZATION, 0);
$container->addCompilerPass(new ACLFlagsCompilerPass(), \Symfony\Component\DependencyInjection\Compiler\PassConfig::TYPE_BEFORE_OPTIMIZATION, 0);
$container->addCompilerPass(new CRUDControllerCompilerPass(), \Symfony\Component\DependencyInjection\Compiler\PassConfig::TYPE_BEFORE_OPTIMIZATION, 0);
$container->addCompilerPass(new ShortMessageCompilerPass(), \Symfony\Component\DependencyInjection\Compiler\PassConfig::TYPE_BEFORE_OPTIMIZATION, 0);
}
}

View File

@@ -17,11 +17,9 @@ 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;
@@ -33,15 +31,6 @@ 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 count;
use function implode;
use function random_bytes;
use function trim;
class ChillImportUsersCommand extends Command
{
/**
@@ -53,39 +42,23 @@ class ChillImportUsersCommand extends Command
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,
UserPasswordEncoderInterface $passwordEncoder,
ValidatorInterface $validator,
UserRepository $userRepository
protected EntityManagerInterface $em,
protected LoggerInterface $logger,
protected UserPasswordEncoderInterface $passwordEncoder,
protected ValidatorInterface $validator,
protected UserRepository $userRepository
) {
$this->em = $em;
$this->passwordEncoder = $passwordEncoder;
$this->validator = $validator;
$this->logger = $logger;
$this->userRepository = $userRepository;
parent::__construct('chill:main:import-users');
}
@@ -107,7 +80,7 @@ class ChillImportUsersCommand extends Command
$str[] = $e->getMessage();
}
return implode(';', $str);
return \implode(';', $str);
}
protected function configure()
@@ -123,8 +96,8 @@ class ChillImportUsersCommand extends Command
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()])) {
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()];
}
}
@@ -154,12 +127,12 @@ class ChillImportUsersCommand extends Command
{
$user = new User();
$user
->setEmail(trim($data['email']))
->setUsername(trim($data['username']))
->setEmail(\trim((string) $data['email']))
->setUsername(\trim((string) $data['username']))
->setEnabled(true)
->setPassword($this->passwordEncoder->encodePassword(
$user,
bin2hex(random_bytes(32))
\bin2hex(\random_bytes(32))
));
$errors = $this->validator->validate($user);
@@ -170,8 +143,7 @@ class ChillImportUsersCommand extends Command
$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');
throw new \RuntimeException('Found errors while creating an user. Watch messages in command output');
}
$pgs = $this->getPermissionGroup($data['permission group']);
@@ -214,7 +186,7 @@ class ChillImportUsersCommand extends Command
return false;
}
protected function execute(InputInterface $input, OutputInterface $output)
protected function execute(InputInterface $input, OutputInterface $output): int
{
$this->tempOutput = $output;
$this->tempInput = $input;
@@ -231,9 +203,11 @@ class ChillImportUsersCommand extends Command
try {
$this->loadUsers();
} catch (Exception $e) {
} catch (\Exception $e) {
throw $e;
}
return 0;
}
/**
@@ -254,9 +228,9 @@ class ChillImportUsersCommand extends Command
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];
}
@@ -289,8 +263,7 @@ class ChillImportUsersCommand extends Command
$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);
@@ -303,7 +276,7 @@ class ChillImportUsersCommand extends Command
protected function getPermissionGroup($alias)
{
if (array_key_exists($alias, $this->permissionGroups)) {
if (\array_key_exists($alias, $this->permissionGroups)) {
return $this->permissionGroups[$alias];
}
@@ -316,30 +289,29 @@ class ChillImportUsersCommand extends Command
$permissionGroupsByName[$permissionGroup->getName()] = $permissionGroup;
}
if (count($permissionGroupsByName) === 0) {
throw new RuntimeException('no permission groups found. Create them '
. 'before importing users');
if (0 === \count($permissionGroupsByName)) {
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)
\array_keys($permissionGroupsByName)
);
$question
->setMultiselect(true)
->setAutocompleterValues(array_keys($permissionGroupsByName))
->setAutocompleterValues(\array_keys($permissionGroupsByName))
->setNormalizer(static function ($value) {
if (null === $value) {
return '';
}
return trim($value);
return \trim((string) $value);
});
$helper = $this->getHelper('question');
$keys = $helper->ask($this->tempInput, $this->tempOutput, $question);
$this->tempOutput->writeln('You have chosen ' . implode(', ', $keys));
$this->tempOutput->writeln('You have chosen '.\implode(', ', $keys));
if (
$helper->ask(
@@ -358,7 +330,7 @@ class ChillImportUsersCommand extends Command
$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');
throw new \RuntimeException('Error while responding to a question');
}
protected function loadUsers()
@@ -373,7 +345,7 @@ class ChillImportUsersCommand extends Command
if ($this->doesUserExists($r)) {
$this->tempOutput->writeln(sprintf("User with username '%s' already "
. 'exists, skipping', $r['username']));
.'exists, skipping', $r['username']));
$this->logger->info('One user already exists, skipping creation', [
'username_in_file' => $r['username'],
@@ -396,7 +368,7 @@ class ChillImportUsersCommand extends Command
foreach ($reader->getRecords() as $r) {
$this->centers[$r['alias']] =
array_merge(
\array_merge(
$this->centers[$r['alias']] ?? [],
$this->getCenters(
$r['center']

View File

@@ -14,10 +14,7 @@ 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;
@@ -27,11 +24,6 @@ use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
use function array_key_exists;
use function array_merge;
use function in_array;
use function trim;
/**
* Class ChillUserSendRenewPasswordCodeCommand.
*/
@@ -64,17 +56,13 @@ class ChillUserSendRenewPasswordCodeCommand extends Command
/**
* The current input interface.
*
* @var InputInterface
*/
private $input;
private ?InputInterface $input = null;
/**
* The current output interface.
*
* @var OutputInterface
*/
private $output;
private ?OutputInterface $output = null;
public function __construct(
LoggerInterface $logger,
@@ -101,7 +89,7 @@ class ChillUserSendRenewPasswordCodeCommand extends Command
->addOption('subject', null, InputOption::VALUE_REQUIRED, 'Subject of the email', 'Recover your password');
}
protected function execute(InputInterface $input, OutputInterface $output)
protected function execute(InputInterface $input, OutputInterface $output): int
{
$this->input = $input;
$this->output = $output;
@@ -119,18 +107,20 @@ class ChillUserSendRenewPasswordCodeCommand extends Command
$this->sendRecoverCode($user);
}
return 0;
}
/**
* @throws Exception
*
* @return Reader
*
* @throws \Exception
*/
protected function getReader()
{
try {
$reader = Reader::createFromPath($this->input->getArgument('csvfile'));
} catch (Exception $e) {
} catch (\Exception $e) {
$this->logger->error('The csv file could not be read', [
'path' => $this->input->getArgument('csvfile'),
]);
@@ -143,11 +133,10 @@ class ChillUserSendRenewPasswordCodeCommand extends Command
$headers = $reader->getHeader();
if (
false === in_array('username', $headers, true)
&& false === in_array('email', $headers, true)
false === \in_array('username', $headers, true)
&& false === \in_array('email', $headers, true)
) {
throw new InvalidArgumentException('The csv file does not have an '
. 'username or email header');
throw new \InvalidArgumentException('The csv file does not have an username or email header');
}
return $reader;
@@ -159,25 +148,25 @@ class ChillUserSendRenewPasswordCodeCommand extends Command
$userRepository = $this->em->getRepository(User::class);
try {
if (array_key_exists('email', $row)) {
return $userRepository->findOneByUsernameOrEmail(trim($row['email']));
if (\array_key_exists('email', $row)) {
return $userRepository->findOneByUsernameOrEmail(\trim((string) $row['email']));
}
} catch (\Doctrine\ORM\NoResultException $e) {
} catch (\Doctrine\ORM\NoResultException) {
// continue, we will try username
}
try {
if (array_key_exists('username', $row)) {
return $userRepository->findOneByUsernameOrEmail(trim($row['username']));
if (\array_key_exists('username', $row)) {
return $userRepository->findOneByUsernameOrEmail(\trim((string) $row['username']));
}
} catch (\Doctrine\ORM\NoResultException $e) {
} catch (\Doctrine\ORM\NoResultException) {
return null;
}
}
protected function onUserNotFound($row, $offset)
{
$this->logger->alert('User not found', array_merge([
$this->logger->alert('User not found', \array_merge([
'offset' => $offset,
], $row));
}
@@ -194,7 +183,7 @@ class ChillUserSendRenewPasswordCodeCommand extends Command
}
$template = $this->input->getOption('template');
$expiration = DateTime::createFromFormat(
$expiration = \DateTime::createFromFormat(
'U',
$this->input->getOption('expiration')
);

View File

@@ -19,14 +19,10 @@ use Symfony\Component\Console\Output\OutputInterface;
class ExecuteCronJobCommand extends Command
{
private CronManagerInterface $cronManager;
public function __construct(
CronManagerInterface $cronManager
private readonly CronManagerInterface $cronManager
) {
parent::__construct('chill:cron-job:execute');
$this->cronManager = $cronManager;
}
protected function configure()
@@ -38,7 +34,7 @@ class ExecuteCronJobCommand extends Command
->addUsage('');
}
protected function execute(InputInterface $input, OutputInterface $output)
protected function execute(InputInterface $input, OutputInterface $output): int
{
if ([] === $input->getArgument('job')) {
$this->cronManager->run();

View File

@@ -20,17 +20,11 @@ use Symfony\Component\Console\Output\OutputInterface;
class LoadAddressesBEFromBestAddressCommand extends Command
{
private AddressReferenceBEFromBestAddress $addressImporter;
private PostalCodeBEFromBestAddress $postalCodeBEFromBestAddressImporter;
public function __construct(
AddressReferenceBEFromBestAddress $addressImporter,
PostalCodeBEFromBestAddress $postalCodeBEFromBestAddressImporter
private readonly AddressReferenceBEFromBestAddress $addressImporter,
private readonly PostalCodeBEFromBestAddress $postalCodeBEFromBestAddressImporter
) {
parent::__construct();
$this->addressImporter = $addressImporter;
$this->postalCodeBEFromBestAddressImporter = $postalCodeBEFromBestAddressImporter;
}
protected function configure()

View File

@@ -19,12 +19,9 @@ use Symfony\Component\Console\Output\OutputInterface;
class LoadAddressesFRFromBANOCommand extends Command
{
private AddressReferenceFromBano $addressReferenceFromBano;
public function __construct(AddressReferenceFromBano $addressReferenceFromBano)
public function __construct(private readonly AddressReferenceFromBano $addressReferenceFromBano)
{
parent::__construct();
$this->addressReferenceFromBano = $addressReferenceFromBano;
}
protected function configure()
@@ -37,7 +34,7 @@ class LoadAddressesFRFromBANOCommand extends Command
protected function execute(InputInterface $input, OutputInterface $output): int
{
foreach ($input->getArgument('departementNo') as $departementNo) {
$output->writeln('Import addresses for ' . $departementNo);
$output->writeln('Import addresses for '.$departementNo);
$this->addressReferenceFromBano->import($departementNo);
}

View File

@@ -12,48 +12,36 @@ declare(strict_types=1);
namespace Chill\MainBundle\Command;
use Chill\MainBundle\Entity\Language;
use Doctrine\ORM\EntityManager;
use Doctrine\ORM\EntityManagerInterface;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Intl\Intl;
use function in_array;
use Symfony\Component\DependencyInjection\ParameterBag\ParameterBagInterface;
use Symfony\Component\Intl\Languages;
/*
* Load or update the languages entities command
*/
class LoadAndUpdateLanguagesCommand extends Command
{
public const INCLUDE_ANCIENT = 'include_ancient';
final public const INCLUDE_ANCIENT = 'include_ancient';
public const INCLUDE_REGIONAL_VERSION = 'include_regional';
final 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',
private array $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;
// The regional version of language are language with _ in the code
// This array contains regional code to not exclude
private $regionalVersionToInclude = ['ro_MD'];
private array $regionalVersionToInclude = ['ro_MD'];
/**
* LoadCountriesCommand constructor.
*
* @param $availableLanguages
*/
public function __construct(EntityManager $entityManager, $availableLanguages)
public function __construct(private readonly EntityManagerInterface $entityManager, private readonly ParameterBagInterface $parameterBag)
{
$this->entityManager = $entityManager;
$this->availableLanguages = $availableLanguages;
parent::__construct();
}
@@ -66,21 +54,21 @@ 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) . '.'
.implode(',', $this->regionalVersionToInclude).'.'
)
->addOption(
self::INCLUDE_ANCIENT,
null,
InputOption::VALUE_NONE,
'Include the ancient languages that are languages with code '
. implode(', ', $this->ancientToExclude) . '.'
.implode(', ', $this->ancientToExclude).'.'
);
}
@@ -89,55 +77,51 @@ class LoadAndUpdateLanguagesCommand extends Command
*
* @see \Symfony\Component\Console\Command\Command::execute()
*/
protected function execute(InputInterface $input, OutputInterface $output)
protected function execute(InputInterface $input, OutputInterface $output): int
{
$em = $this->entityManager;
$chillAvailableLanguages = $this->availableLanguages;
$languageBundle = Intl::getLanguageBundle();
$chillAvailableLanguages = $this->parameterBag->get('chill_main.available_languages');
$languages = [];
foreach ($chillAvailableLanguages as $avLang) {
$languages[$avLang] = $languageBundle->getLanguageNames($avLang);
$languages[$avLang] = Languages::getNames();
}
$languageCodes = array_keys($languages[$chillAvailableLanguages[0]]);
foreach ($languageCodes as $code) {
foreach (Languages::getNames() as $code => $lang) {
$excludeCode = (
(
!$input->getOption(self::INCLUDE_REGIONAL_VERSION)
&& strpos($code, '_')
&& !in_array($code, $this->regionalVersionToInclude, true)
&& !\in_array($code, $this->regionalVersionToInclude, true)
) || (
!$input->getOption(self::INCLUDE_ANCIENT)
&& in_array($code, $this->ancientToExclude, true)
&& \in_array($code, $this->ancientToExclude, true)
)
);
$langageDB = $em->getRepository(Language::class)->find($code);
if (!$excludeCode) {
if (!$langageDB) {
$langageDB = new \Chill\MainBundle\Entity\Language();
$langageDB->setId($code);
$em->persist($langageDB);
}
$avLangNames = [];
foreach ($chillAvailableLanguages as $avLang) {
$avLangNames[$avLang] = $languages[$avLang][$code];
}
$langageDB->setName($avLangNames);
} else {
if ($langageDB) {
$em->remove($langageDB);
}
echo 'Code excluded : ' . $code . ' - ' . $languageBundle->getLanguageName($code) . "\n";
if (true === $excludeCode) {
continue;
}
$languageDB = $em->getRepository(Language::class)->find($code);
if (null === $languageDB) {
$languageDB = new Language();
$languageDB->setId($code);
$em->persist($languageDB);
}
$avLangNames = [];
foreach ($chillAvailableLanguages as $avLang) {
$avLangNames[$avLang] = ucfirst(Languages::getName($code, $avLang));
}
$languageDB->setName($avLangNames);
}
$em->flush();
return 0;
}
}

View File

@@ -16,49 +16,32 @@ use Doctrine\ORM\EntityManager;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Intl\Intl;
use Symfony\Component\Intl\Countries;
class LoadCountriesCommand extends Command
{
private $availableLanguages;
/**
* @var EntityManager
*/
private $entityManager;
/**
* LoadCountriesCommand constructor.
*
* @param $availableLanguages
*/
public function __construct(EntityManager $entityManager, $availableLanguages)
public function __construct(private readonly EntityManager $entityManager, private $availableLanguages)
{
$this->entityManager = $entityManager;
$this->availableLanguages = $availableLanguages;
parent::__construct();
}
public static function prepareCountryList($languages)
{
$regionBundle = Intl::getRegionBundle();
$countries = [];
foreach ($languages as $language) {
$countries[$language] = $regionBundle->getCountryNames($language);
}
$countryCodes = Countries::getCountryCodes();
$countryEntities = [];
foreach ($countries[$languages[0]] as $countryCode => $name) {
foreach ($countryCodes as $code) {
$names = [];
foreach ($languages as $language) {
$names[$language] = $countries[$language][$countryCode];
$names[$language] = Countries::getName($code, $language);
}
$country = new \Chill\MainBundle\Entity\Country();
$country->setName($names)->setCountryCode($countryCode);
$country = new Country();
$country->setName($names)->setCountryCode($code);
$countryEntities[] = $country;
}
@@ -73,7 +56,7 @@ class LoadCountriesCommand extends Command
protected function configure()
{
$this->setName('chill:main:countries:populate')
->setDescription('Load or update countries in db. This command does not delete existing countries, ' .
->setDescription('Load or update countries in db. This command does not delete existing countries, '.
'but will update names according to available languages');
}
@@ -82,7 +65,7 @@ class LoadCountriesCommand extends Command
*
* @see \Symfony\Component\Console\Command\Command::execute()
*/
protected function execute(InputInterface $input, OutputInterface $output)
protected function execute(InputInterface $input, OutputInterface $output): int
{
$countries = static::prepareCountryList($this->availableLanguages);
$em = $this->entityManager;
@@ -99,5 +82,7 @@ class LoadCountriesCommand extends Command
}
$em->flush();
return 0;
}
}

View File

@@ -18,12 +18,8 @@ use Symfony\Component\Console\Output\OutputInterface;
class LoadPostalCodeFR extends Command
{
private PostalCodeFRFromOpenData $loader;
public function __construct(PostalCodeFRFromOpenData $loader)
public function __construct(private readonly PostalCodeFRFromOpenData $loader)
{
$this->loader = $loader;
parent::__construct();
}

View File

@@ -15,8 +15,6 @@ use Chill\MainBundle\Doctrine\Model\Point;
use Chill\MainBundle\Entity\Country;
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;
@@ -25,19 +23,10 @@ use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Filesystem\Filesystem;
use Symfony\Component\Validator\Validator\ValidatorInterface;
use function count;
use function strlen;
class LoadPostalCodesCommand extends Command
{
private EntityManagerInterface $entityManager;
private ValidatorInterface $validator;
public function __construct(EntityManagerInterface $entityManager, ValidatorInterface $validator)
public function __construct(private readonly EntityManagerInterface $entityManager, private readonly ValidatorInterface $validator)
{
$this->entityManager = $entityManager;
$this->validator = $validator;
parent::__construct();
}
@@ -46,15 +35,15 @@ class LoadPostalCodesCommand extends Command
$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 '
. "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.')
."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.')
.'the csv file. See the help for specifications.')
->addOption(
'delimiter',
'd',
@@ -78,11 +67,11 @@ class LoadPostalCodesCommand extends Command
);
}
protected function execute(InputInterface $input, OutputInterface $output)
protected function execute(InputInterface $input, OutputInterface $output): int
{
$csv = $this->getCSVResource($input);
if ($output->getVerbosity() === OutputInterface::VERBOSITY_VERY_VERBOSE) {
if (OutputInterface::VERBOSITY_VERY_VERBOSE === $output->getVerbosity()) {
$output->writeln('The content of the file is ...');
$output->write(file_get_contents($input->getArgument('csv_file')));
}
@@ -96,34 +85,36 @@ class LoadPostalCodesCommand extends Command
0,
$input->getOption('delimiter'),
$input->getOption('enclosure'),
$input->getOption('escape')
(string) $input->getOption('escape')
))
) {
try {
$this->addPostalCode($row, $output);
++$num;
} catch (ExistingPostalCodeException|CountryCodeNotFoundException|PostalCodeNotValidException $ex) {
$output->writeln('<warning> on line ' . $line . ' : ' . $ex->getMessage() . '</warning>');
} catch (CountryCodeNotFoundException|ExistingPostalCodeException|PostalCodeNotValidException $ex) {
$output->writeln('<warning> on line '.$line.' : '.$ex->getMessage().'</warning>');
}
++$line;
}
$this->entityManager->flush();
$output->writeln('<info>' . $num . ' were added !</info>');
$output->writeln('<info>'.$num.' were added !</info>');
return 0;
}
private function addPostalCode($row, OutputInterface $output)
{
if ('FR' === $row[2] && strlen($row[0]) === 4) {
if ('FR' === $row[2] && 4 === \strlen((string) $row[0])) {
// CP in FRANCE are on 5 digit
// For CP starting with a zero, the starting zero can be remove if stored as number in a csv
// add a zero if CP from FR and on 4 digit
$row[0] = '0' . $row[0];
$row[0] = '0'.$row[0];
}
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
@@ -131,12 +122,7 @@ class LoadPostalCodesCommand extends Command
->findOneBy(['countryCode' => $row[2]]);
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]
));
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
@@ -144,12 +130,8 @@ class LoadPostalCodesCommand extends Command
->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]
));
if (\count($existingPC) > 0) {
throw new ExistingPostalCodeException(sprintf('A postal code with code : %s and name : %s already exists, skipping', $row[0], $row[1]));
}
$postalCode = (new PostalCode())
@@ -171,13 +153,13 @@ class LoadPostalCodesCommand extends Command
$errors = $this->validator->validate($postalCode);
if ($errors->count() === 0) {
if (0 === $errors->count()) {
$em->persist($postalCode);
} else {
$msg = '';
foreach ($errors as $error) {
$msg .= ' ' . $error->getMessage();
$msg .= ' '.$error->getMessage();
}
throw new PostalCodeNotValidException($msg);
@@ -199,28 +181,27 @@ class LoadPostalCodesCommand extends Command
$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.');
throw new \RuntimeException('The file does not exists or you do not have the right to read it.');
}
$resource = fopen($filename, 'rb');
if (false === $resource) {
throw new RuntimeException("The file '{$filename}' could not be opened.");
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

@@ -13,7 +13,6 @@ 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;
@@ -26,24 +25,18 @@ use Symfony\Component\Security\Core\Encoder\MessageDigestPasswordEncoder;
*/
class SetPasswordCommand extends Command
{
/**
* @var EntityManager
*/
private $entityManager;
/**
* SetPasswordCommand constructor.
*/
public function __construct(EntityManager $entityManager)
public function __construct(private readonly EntityManager $entityManager)
{
$this->entityManager = $entityManager;
parent::__construct();
}
public function _getUser($username)
{
return $this->entityManager
->getRepository(\Chill\MainBundle\Entity\User::class)
->getRepository(User::class)
->findOneBy(['username' => $username]);
}
@@ -65,17 +58,16 @@ class SetPasswordCommand extends Command
$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')
.'username you want to change password')
->addArgument('password', InputArgument::OPTIONAL, 'the new password');
}
public function execute(InputInterface $input, OutputInterface $output)
public function execute(InputInterface $input, OutputInterface $output): int
{
$user = $this->_getUser($input->getArgument('username'));
if (null === $user) {
throw new LogicException("The user with username '" .
$input->getArgument('username') . "' is not found");
throw new \LogicException("The user with username '".$input->getArgument('username')."' is not found");
}
$password = $input->getArgument('password');
@@ -83,9 +75,11 @@ class SetPasswordCommand extends Command
if (null === $password) {
$dialog = $this->getHelperSet()->get('dialog');
$password = $dialog->askHiddenResponse($output, '<question>the new password :'
. '</question>');
.'</question>');
}
$this->_setPassword($user, $password);
return 0;
}
}

View File

@@ -19,7 +19,7 @@ use Symfony\Component\Console\Output\OutputInterface;
class SynchronizeEntityInfoViewsCommand extends Command
{
public function __construct(
private ViewEntityInfoManager $viewEntityInfoManager,
private readonly ViewEntityInfoManager $viewEntityInfoManager,
) {
parent::__construct('chill:db:sync-views');
}

View File

@@ -36,7 +36,7 @@ class AbsenceController extends AbstractController
$em = $this->getDoctrine()->getManager();
$em->flush();
return $this->redirect($this->generateUrl('chill_main_user_absence_index'));
return $this->redirectToRoute('chill_main_user_absence_index');
}
return $this->render('@ChillMain/Menu/absence.html.twig', [
@@ -60,6 +60,6 @@ class AbsenceController extends AbstractController
$em = $this->getDoctrine()->getManager();
$em->flush();
return $this->redirect($this->generateUrl('chill_main_user_absence_index'));
return $this->redirectToRoute('chill_main_user_absence_index');
}
}

View File

@@ -24,18 +24,10 @@ use Symfony\Component\HttpKernel\Exception\BadRequestHttpException;
use Symfony\Component\Routing\Annotation\Route;
use Symfony\Component\Serializer\Normalizer\AbstractNormalizer;
use function trim;
final class AddressReferenceAPIController extends ApiController
{
private AddressReferenceRepository $addressReferenceRepository;
private PaginatorFactory $paginatorFactory;
public function __construct(AddressReferenceRepository $addressReferenceRepository, PaginatorFactory $paginatorFactory)
public function __construct(private readonly AddressReferenceRepository $addressReferenceRepository, private readonly PaginatorFactory $paginatorFactory)
{
$this->addressReferenceRepository = $addressReferenceRepository;
$this->paginatorFactory = $paginatorFactory;
}
/**
@@ -51,7 +43,7 @@ final class AddressReferenceAPIController extends ApiController
$pattern = $request->query->get('q');
if ('' === trim($pattern)) {
if ('' === \trim((string) $pattern)) {
throw new BadRequestHttpException('the search pattern is empty');
}

View File

@@ -23,20 +23,8 @@ use Symfony\Component\Serializer\SerializerInterface;
class AddressToReferenceMatcherController
{
private Security $security;
private EntityManagerInterface $entityManager;
private SerializerInterface $serializer;
public function __construct(
Security $security,
EntityManagerInterface $entityManager,
SerializerInterface $serializer
) {
$this->security = $security;
$this->entityManager = $entityManager;
$this->serializer = $serializer;
public function __construct(private readonly Security $security, private readonly EntityManagerInterface $entityManager, private readonly SerializerInterface $serializer)
{
}
/**

View File

@@ -47,4 +47,12 @@ class AdminController extends AbstractController
{
return $this->render('@ChillMain/Admin/indexUser.html.twig');
}
/**
* @Route("/{_locale}/admin/dashboard", name="chill_main_dashboard_admin")
*/
public function indexDashboardAction()
{
return $this->render('@ChillMain/Admin/indexDashboard.html.twig');
}
}

View File

@@ -11,176 +11,19 @@ declare(strict_types=1);
namespace Chill\MainBundle\Controller;
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 Chill\MainBundle\CRUD\Controller\CRUDController;
use Chill\MainBundle\Pagination\PaginatorInterface;
use Symfony\Component\HttpFoundation\Request;
/**
* Class CenterController.
*/
class CenterController extends AbstractController
class CenterController extends CRUDController
{
/**
* Creates a new Center entity.
*/
public function createAction(Request $request)
protected function orderQuery(string $action, $query, Request $request, PaginatorInterface $paginator)
{
$center = new Center();
$form = $this->createCreateForm($center);
$form->handleRequest($request);
$query->addOrderBy('e.name', 'ASC');
if ($form->isValid()) {
$em = $this->getDoctrine()->getManager();
$em->persist($center);
$em->flush();
return $this->redirect($this->generateUrl('admin_center'));
}
return $this->render('@ChillMain/Center/new.html.twig', [
'entity' => $center,
'form' => $form->createView(),
]);
}
/**
* Displays a form to edit an existing Center entity.
*
* @param mixed $id
*/
public function editAction($id)
{
$em = $this->getDoctrine()->getManager();
$center = $em->getRepository(\Chill\MainBundle\Entity\Center::class)->find($id);
if (!$center) {
throw $this->createNotFoundException('Unable to find Center entity.');
}
$editForm = $this->createEditForm($center);
return $this->render('@ChillMain/Center/edit.html.twig', [
'entity' => $center,
'edit_form' => $editForm->createView(),
]);
}
/**
* Lists all Center entities.
*/
public function indexAction()
{
$em = $this->getDoctrine()->getManager();
$entities = $em->getRepository(\Chill\MainBundle\Entity\Center::class)->findAll();
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(\Chill\MainBundle\Entity\Center::class)->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)
{
$em = $this->getDoctrine()->getManager();
$center = $em->getRepository(\Chill\MainBundle\Entity\Center::class)->find($id);
if (!$center) {
throw $this->createNotFoundException('Unable to find Center entity.');
}
$editForm = $this->createEditForm($center);
$editForm->handleRequest($request);
if ($editForm->isValid()) {
$em->flush();
return $this->redirect($this->generateUrl('admin_center_edit', ['id' => $id]));
}
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;
return parent::orderQuery($action, $query, $request, $paginator);
}
}

View File

@@ -0,0 +1,52 @@
<?php
declare(strict_types=1);
/*
* 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\User;
use Chill\MainBundle\Repository\NewsItemRepository;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\Routing\Annotation\Route;
final readonly class DashboardApiController
{
public function __construct(
private NewsItemRepository $newsItemRepository,
) {
}
/**
* Get user dashboard config (not yet based on user id and still hardcoded for now).
*
* @Route("/api/1.0/main/dashboard-config-item.json", methods={"get"})
*/
public function getDashboardConfiguration(): JsonResponse
{
$data = [];
if (0 < $this->newsItemRepository->countCurrentNews()) {
// show news only if we have news
// NOTE: maybe this should be done in the frontend...
$data[] =
[
'position' => 'top-left',
'id' => 1,
'type' => 'news',
'metadata' => [
// arbitrary data that will be store "some time"
'only_unread' => false,
],
];
}
return new JsonResponse($data, JsonResponse::HTTP_OK, []);
}
}

View File

@@ -18,6 +18,9 @@ use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
*/
class DefaultController extends AbstractController
{
/**
* @\Symfony\Component\Routing\Annotation\Route(path="/{_locale}/homepage", name="chill_main_homepage")
*/
public function indexAction()
{
if ($this->isGranted('ROLE_ADMIN')) {
@@ -27,9 +30,12 @@ class DefaultController extends AbstractController
return $this->render('@ChillMain/layout.html.twig');
}
/**
* @\Symfony\Component\Routing\Annotation\Route(path="/homepage", name="chill_main_homepage_without_locale")
*/
public function indexWithoutLocaleAction()
{
return $this->redirect($this->generateUrl('chill_main_homepage'));
return $this->redirectToRoute('chill_main_homepage');
}
public function testAction()
@@ -66,22 +72,22 @@ class DefaultController extends AbstractController
],
[
'name' => 'Link 2',
//'link' => "http://localhost",
// '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.',
],
[
'name' => 'Link 3',
//'link' => "http://localhost",
// '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.',
],
[
'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.",
// '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',
//'link' => "http://localhost",
// '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.',
],
],

View File

@@ -25,10 +25,9 @@ use Chill\MainBundle\Redis\ChillRedis;
use Chill\MainBundle\Repository\SavedExportRepositoryInterface;
use Chill\MainBundle\Security\Authorization\SavedExportVoter;
use Doctrine\ORM\EntityManagerInterface;
use LogicException;
use Psr\Log\LoggerInterface;
use RedisException;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\DependencyInjection\ParameterBag\ParameterBagInterface;
use Symfony\Component\Form\Extension\Core\Type\FormType;
use Symfony\Component\Form\Extension\Core\Type\SubmitType;
use Symfony\Component\Form\FormFactoryInterface;
@@ -39,12 +38,8 @@ use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpFoundation\Session\SessionInterface;
use Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException;
use Symfony\Component\Routing\Annotation\Route;
use Symfony\Component\Security\Core\Security;
use Symfony\Contracts\Translation\TranslatorInterface;
use function count;
use function serialize;
use function unserialize;
/**
* Class ExportController
@@ -52,62 +47,30 @@ use function unserialize;
*/
class ExportController extends AbstractController
{
private EntityManagerInterface $entityManager;
/**
* @var ExportManager
*/
private $exportManager;
/**
* @var FormFactoryInterface
*/
private $formFactory;
/**
* @var LoggerInterface
*/
private $logger;
/**
* @var ChillRedis
*/
private $redis;
/**
* @var SessionInterface
*/
private $session;
/**
* @var TranslatorInterface
*/
private $translator;
private readonly bool $filterStatsByCenters;
public function __construct(
ChillRedis $chillRedis,
ExportManager $exportManager,
FormFactoryInterface $formFactory,
LoggerInterface $logger,
SessionInterface $session,
TranslatorInterface $translator,
EntityManagerInterface $entityManager,
private readonly ChillRedis $redis,
private readonly ExportManager $exportManager,
private readonly FormFactoryInterface $formFactory,
private readonly LoggerInterface $logger,
private readonly SessionInterface $session,
private readonly TranslatorInterface $translator,
private readonly EntityManagerInterface $entityManager,
private readonly ExportFormHelper $exportFormHelper,
private readonly SavedExportRepositoryInterface $savedExportRepository,
private readonly Security $security,
ParameterBagInterface $parameterBag,
) {
$this->entityManager = $entityManager;
$this->redis = $chillRedis;
$this->exportManager = $exportManager;
$this->formFactory = $formFactory;
$this->logger = $logger;
$this->session = $session;
$this->translator = $translator;
$this->filterStatsByCenters = $parameterBag->get('chill_main')['acl']['filter_stats_by_center'];
}
public function downloadResultAction(Request $request, $alias)
/**
* @\Symfony\Component\Routing\Annotation\Route(path="/{_locale}/exports/download/{alias}", name="chill_main_export_download", methods={"GET"})
*/
public function downloadResultAction(Request $request, mixed $alias)
{
/** @var \Chill\MainBundle\Export\ExportManager $exportManager */
/** @var ExportManager $exportManager */
$exportManager = $this->exportManager;
$export = $exportManager->getExport($alias);
$key = $request->query->get('key', null);
@@ -145,11 +108,13 @@ class ExportController extends AbstractController
*
* @param string $alias
*
* @return \Symfony\Component\HttpFoundation\Response
* @return Response
*
* @\Symfony\Component\Routing\Annotation\Route(path="/{_locale}/exports/generate/{alias}", name="chill_main_export_generate", methods={"GET"})
*/
public function generateAction(Request $request, $alias)
{
/** @var \Chill\MainBundle\Export\ExportManager $exportManager */
/** @var ExportManager $exportManager */
$exportManager = $this->exportManager;
$key = $request->query->get('key', null);
$savedExport = $this->getSavedExportFromRequest($request);
@@ -167,7 +132,7 @@ class ExportController extends AbstractController
/**
* @Route("/{_locale}/exports/generate-from-saved/{id}", name="chill_main_export_generate_from_saved")
*
* @throws RedisException
* @throws \RedisException
*/
public function generateFromSavedExport(SavedExport $savedExport): RedirectResponse
{
@@ -175,7 +140,7 @@ class ExportController extends AbstractController
$key = md5(uniqid((string) random_int(0, mt_getrandmax()), false));
$this->redis->setEx($key, 3600, serialize($savedExport->getOptions()));
$this->redis->setEx($key, 3600, \serialize($savedExport->getOptions()));
return $this->redirectToRoute(
'chill_main_export_download',
@@ -189,6 +154,8 @@ class ExportController extends AbstractController
/**
* Render the list of available exports.
*
* @\Symfony\Component\Routing\Annotation\Route(path="/{_locale}/exports/", name="chill_main_export_index")
*/
public function indexAction(): Response
{
@@ -213,6 +180,7 @@ class ExportController extends AbstractController
* 3. 'generate': gather data from session from the previous steps, and
* make a redirection to the "generate" action with data in query (HTTP GET)
*
* @\Symfony\Component\Routing\Annotation\Route(path="/{_locale}/exports/new/{alias}", name="chill_main_export_new")
*/
public function newAction(Request $request, string $alias): Response
{
@@ -220,7 +188,7 @@ class ExportController extends AbstractController
$exportManager = $this->exportManager;
$export = $exportManager->getExport($alias);
if ($exportManager->isGrantedForElement($export) === false) {
if (false === $exportManager->isGrantedForElement($export)) {
throw $this->createAccessDeniedException('The user does not have access to this export');
}
@@ -228,22 +196,13 @@ class ExportController extends AbstractController
$step = $request->query->getAlpha('step', 'centers');
switch ($step) {
case 'centers':
return $this->selectCentersStep($request, $export, $alias, $savedExport);
case 'export':
return $this->exportFormStep($request, $export, $alias, $savedExport);
case 'formatter':
return $this->formatterFormStep($request, $export, $alias, $savedExport);
case 'generate':
return $this->forwardToGenerate($request, $export, $alias, $savedExport);
default:
throw $this->createNotFoundException("The given step '{$step}' is invalid");
}
return match ($step) {
'centers' => $this->selectCentersStep($request, $export, $alias, $savedExport),
'export' => $this->exportFormStep($request, $export, $alias, $savedExport),
'formatter' => $this->formatterFormStep($request, $export, $alias, $savedExport),
'generate' => $this->forwardToGenerate($request, $export, $alias, $savedExport),
default => throw $this->createNotFoundException("The given step '{$step}' is invalid"),
};
}
/**
@@ -315,14 +274,14 @@ class ExportController extends AbstractController
*/
protected function createCreateFormExport(string $alias, string $step, array $data, ?SavedExport $savedExport): FormInterface
{
/** @var \Chill\MainBundle\Export\ExportManager $exportManager */
/** @var ExportManager $exportManager */
$exportManager = $this->exportManager;
$isGenerate = strpos($step, 'generate_') === 0;
$isGenerate = str_starts_with($step, 'generate_');
$options = match ($step) {
'export', 'generate_export' => [
'export_alias' => $alias,
'picked_centers' => $exportManager->getPickedCenters($data['centers'])
'picked_centers' => $exportManager->getPickedCenters($data['centers'] ?? []),
],
'formatter', 'generate_formatter' => [
'export_alias' => $alias,
@@ -345,7 +304,7 @@ class ExportController extends AbstractController
FormType::class,
$defaultFormData,
[
'method' => $isGenerate ? 'GET' : 'POST',
'method' => $isGenerate ? Request::METHOD_GET : Request::METHOD_POST,
'csrf_protection' => !$isGenerate,
]
);
@@ -380,9 +339,9 @@ class ExportController extends AbstractController
$exportManager = $this->exportManager;
// check we have data from the previous step (export step)
$data = $this->session->get('centers_step', null);
$data = $this->session->get('centers_step', []);
if (null === $data) {
if (null === $data && true === $this->filterStatsByCenters) {
return $this->redirectToRoute('chill_main_export_new', [
'step' => $this->getNextStep('export', $export, true),
'alias' => $alias,
@@ -393,7 +352,7 @@ class ExportController extends AbstractController
$form = $this->createCreateFormExport($alias, 'export', $data, $savedExport);
if ($request->getMethod() === 'POST') {
if (Request::METHOD_POST === $request->getMethod()) {
$form->handleRequest($request);
if ($form->isValid()) {
@@ -408,14 +367,12 @@ class ExportController extends AbstractController
);
$this->session->set('export_step', $data);
//redirect to next step
return $this->redirect(
$this->generateUrl('chill_main_export_new', [
'step' => $this->getNextStep('export', $export),
'alias' => $alias,
'from_saved' => $request->get('from_saved', '')
])
);
// redirect to next step
return $this->redirectToRoute('chill_main_export_new', [
'step' => $this->getNextStep('export', $export),
'alias' => $alias,
'from_saved' => $request->get('from_saved', ''),
]);
}
$this->logger->debug('form export is invalid', [
'location' => __METHOD__, ]);
@@ -449,7 +406,7 @@ class ExportController extends AbstractController
$form = $this->createCreateFormExport($alias, 'formatter', $data, $savedExport);
if ($request->getMethod() === 'POST') {
if (Request::METHOD_POST === $request->getMethod()) {
$form->handleRequest($request);
if ($form->isValid()) {
@@ -460,15 +417,12 @@ class ExportController extends AbstractController
$request->request->all()
);
//redirect to next step
return $this->redirect($this->generateUrl(
'chill_main_export_new',
[
'alias' => $alias,
'step' => $this->getNextStep('formatter', $export),
'from_saved' => $request->get('from_saved', ''),
]
));
// redirect to next step
return $this->redirectToRoute('chill_main_export_new', [
'alias' => $alias,
'step' => $this->getNextStep('formatter', $export),
'from_saved' => $request->get('from_saved', ''),
]);
}
}
@@ -488,18 +442,17 @@ class ExportController extends AbstractController
*
* The data from previous steps is removed from session.
*
* @param \Chill\MainBundle\Export\DirectExportInterface|\Chill\MainBundle\Export\ExportInterface $export
* @param string $alias
*
* @return \Symfony\Component\HttpFoundation\RedirectResponse
* @return RedirectResponse
*/
private function forwardToGenerate(Request $request, $export, $alias, ?SavedExport $savedExport)
private function forwardToGenerate(Request $request, DirectExportInterface|ExportInterface $export, $alias, ?SavedExport $savedExport)
{
$dataCenters = $this->session->get('centers_step_raw', null);
$dataFormatter = $this->session->get('formatter_step_raw', null);
$dataExport = $this->session->get('export_step_raw', null);
if (null === $dataFormatter && $export instanceof \Chill\MainBundle\Export\ExportInterface) {
if (null === $dataFormatter && $export instanceof ExportInterface) {
return $this->redirectToRoute('chill_main_export_new', [
'alias' => $alias,
'step' => $this->getNextStep('generate', $export, true),
@@ -516,7 +469,7 @@ class ExportController extends AbstractController
unset($parameters['_token']);
$key = md5(uniqid((string) random_int(0, mt_getrandmax()), 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');
@@ -537,15 +490,19 @@ class ExportController extends AbstractController
$alias = $rawData['alias'];
$formCenters = $this->createCreateFormExport($alias, 'generate_centers', [], $savedExport);
$formCenters->submit($rawData['centers']);
$dataCenters = $formCenters->getData();
if ($this->filterStatsByCenters) {
$formCenters = $this->createCreateFormExport($alias, 'generate_centers', [], $savedExport);
$formCenters->submit($rawData['centers']);
$dataCenters = $formCenters->getData();
} else {
$dataCenters = ['centers' => []];
}
$formExport = $this->createCreateFormExport($alias, 'generate_export', $dataCenters, $savedExport);
$formExport->submit($rawData['export']);
$dataExport = $formExport->getData();
if (count($rawData['formatter']) > 0) {
if (\count($rawData['formatter']) > 0) {
$formFormatter = $this->createCreateFormExport(
$alias,
'generate_formatter',
@@ -560,19 +517,26 @@ class ExportController extends AbstractController
}
/**
* @param \Chill\MainBundle\Export\DirectExportInterface|\Chill\MainBundle\Export\ExportInterface $export
* @param string $alias
*
* @return Response
*/
private function selectCentersStep(Request $request, $export, $alias, ?SavedExport $savedExport = null)
private function selectCentersStep(Request $request, DirectExportInterface|ExportInterface $export, $alias, ?SavedExport $savedExport = null)
{
/** @var \Chill\MainBundle\Export\ExportManager $exportManager */
if (!$this->filterStatsByCenters) {
return $this->redirectToRoute('chill_main_export_new', [
'step' => $this->getNextStep('centers', $export),
'alias' => $alias,
'from_saved' => $request->get('from_saved', ''),
]);
}
/** @var ExportManager $exportManager */
$exportManager = $this->exportManager;
$form = $this->createCreateFormExport($alias, 'centers', [], $savedExport);
if ($request->getMethod() === 'POST') {
if (Request::METHOD_POST === $request->getMethod()) {
$form->handleRequest($request);
if ($form->isValid()) {
@@ -583,14 +547,13 @@ class ExportController extends AbstractController
// check ACL
if (
$exportManager->isGrantedForElement(
false === $exportManager->isGrantedForElement(
$export,
null,
$exportManager->getPickedCenters($data['centers'])
) === false
)
) {
throw $this->createAccessDeniedException('you do not have '
. 'access to this export for those centers');
throw $this->createAccessDeniedException('you do not have access to this export for those centers');
}
$this->session->set(
@@ -639,30 +602,29 @@ class ExportController extends AbstractController
*
* 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
* @param string $step the current step
* @param bool $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)
private function getNextStep($step, DirectExportInterface|ExportInterface $export, $reverse = false)
{
switch ($step) {
case 'centers':
if (false !== $reverse) {
throw new LogicException("there is no step before 'export'");
throw new \LogicException("there is no step before 'export'");
}
return 'export';
case 'export':
if ($export instanceof \Chill\MainBundle\Export\ExportInterface) {
if ($export instanceof ExportInterface) {
return $reverse ? 'centers' : 'formatter';
}
if ($export instanceof \Chill\MainBundle\Export\DirectExportInterface) {
if ($export instanceof DirectExportInterface) {
return $reverse ? 'centers' : 'generate';
}
@@ -672,13 +634,13 @@ class ExportController extends AbstractController
case 'generate':
if (false === $reverse) {
throw new LogicException("there is no step after 'generate'");
throw new \LogicException("there is no step after 'generate'");
}
return 'formatter';
default:
throw new LogicException("the step {$step} is not defined.");
throw new \LogicException("the step {$step} is not defined.");
}
}
@@ -688,7 +650,7 @@ class ExportController extends AbstractController
throw $this->createNotFoundException('key does not exists');
}
if ($this->redis->exists($key) !== 1) {
if (1 !== $this->redis->exists($key)) {
$this->addFlash('error', $this->translator->trans('This report is not available any more'));
throw $this->createNotFoundException('key does not exists');
@@ -697,10 +659,10 @@ class ExportController extends AbstractController
$serialized = $this->redis->get($key);
if (false === $serialized) {
throw new LogicException('the key could not be reached from redis');
throw new \LogicException('the key could not be reached from redis');
}
$rawData = unserialize($serialized);
$rawData = \unserialize($serialized);
$this->logger->notice('[export] choices for an export unserialized', [
'key' => $key,
@@ -718,7 +680,7 @@ class ExportController extends AbstractController
};
if (null !== $savedExport && !$this->security->isGranted(SavedExportVoter::EDIT, $savedExport)) {
throw new AccessDeniedHttpException("saved export edition not allowed");
throw new AccessDeniedHttpException('saved export edition not allowed');
}
return $savedExport;

View File

@@ -24,30 +24,8 @@ use Symfony\Component\Serializer\SerializerInterface;
class GeographicalUnitByAddressApiController
{
private PaginatorFactory $paginatorFactory;
private GeographicalUnitRepositoryInterface $geographicalUnitRepository;
private Security $security;
private SerializerInterface $serializer;
/**
* @param PaginatorFactory $paginatorFactory
* @param GeographicalUnitRepositoryInterface $geographicalUnitRepository
* @param Security $security
* @param SerializerInterface $serializer
*/
public function __construct(
PaginatorFactory $paginatorFactory,
GeographicalUnitRepositoryInterface $geographicalUnitRepository,
Security $security,
SerializerInterface $serializer
) {
$this->paginatorFactory = $paginatorFactory;
$this->geographicalUnitRepository = $geographicalUnitRepository;
$this->security = $security;
$this->serializer = $serializer;
public function __construct(private readonly PaginatorFactory $paginatorFactory, private readonly GeographicalUnitRepositoryInterface $geographicalUnitRepository, private readonly Security $security, private readonly SerializerInterface $serializer)
{
}
/**

View File

@@ -36,7 +36,6 @@ class LocationApiController extends ApiController
/**
* @param QueryBuilder $query
* @param mixed $_format
*/
protected function orderQuery(string $action, $query, Request $request, PaginatorInterface $paginator, $_format)
{

View File

@@ -35,6 +35,8 @@ class LoginController extends AbstractController
* Show a login form.
*
* @return Response
*
* @\Symfony\Component\Routing\Annotation\Route(path="/login", name="login")
*/
public function loginAction(Request $request)
{

View File

@@ -0,0 +1,53 @@
<?php
declare(strict_types=1);
/*
* 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\Pagination\PaginatorFactory;
use Chill\MainBundle\Repository\NewsItemRepository;
use Chill\MainBundle\Serializer\Model\Collection;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\Routing\Annotation\Route;
use Symfony\Component\Serializer\Normalizer\AbstractNormalizer;
use Symfony\Component\Serializer\SerializerInterface;
class NewsItemApiController
{
public function __construct(
private readonly NewsItemRepository $newsItemRepository,
private readonly SerializerInterface $serializer,
private readonly PaginatorFactory $paginatorFactory
) {
}
/**
* Get list of news items filtered on start and end date.
*
* @Route("/api/1.0/main/news/current.json", methods={"get"})
*/
public function listCurrentNewsItems(): JsonResponse
{
$total = $this->newsItemRepository->countCurrentNews();
$paginator = $this->paginatorFactory->create($total);
$newsItems = $this->newsItemRepository->findCurrentNews(
$paginator->getItemsPerPage(),
$paginator->getCurrentPage()->getFirstItemNumber()
);
return new JsonResponse($this->serializer->serialize(
new Collection(array_values($newsItems), $paginator),
'json',
[
AbstractNormalizer::GROUPS => ['read'],
]
), JsonResponse::HTTP_OK, [], true);
}
}

View File

@@ -0,0 +1,27 @@
<?php
declare(strict_types=1);
/*
* 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;
use Chill\MainBundle\Pagination\PaginatorInterface;
use Symfony\Component\HttpFoundation\Request;
class NewsItemController extends CRUDController
{
protected function orderQuery(string $action, $query, Request $request, PaginatorInterface $paginator)
{
$query->addOrderBy('e.startDate', 'DESC');
$query->addOrderBy('e.id', 'DESC');
return parent::orderQuery($action, $query, $request, $paginator);
}
}

View File

@@ -0,0 +1,73 @@
<?php
declare(strict_types=1);
/*
* 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\NewsItem;
use Chill\MainBundle\Pagination\PaginatorFactory;
use Chill\MainBundle\Repository\NewsItemRepository;
use Chill\MainBundle\Templating\Listing\FilterOrderHelper;
use Chill\MainBundle\Templating\Listing\FilterOrderHelperFactoryInterface;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Annotation\Route;
use Twig\Environment;
final readonly class NewsItemHistoryController
{
public function __construct(
private readonly NewsItemRepository $newsItemRepository,
private readonly PaginatorFactory $paginatorFactory,
private readonly FilterOrderHelperFactoryInterface $filterOrderHelperFactory,
private readonly Environment $environment,
) {
}
/**
* @Route("/{_locale}/news-items/history", name="chill_main_news_items_history")
*/
public function list(): Response
{
$filter = $this->buildFilterOrder();
$total = $this->newsItemRepository->countAllFilteredBySearchTerm($filter->getQueryString());
$newsItems = $this->newsItemRepository->findAllFilteredBySearchTerm($filter->getQueryString());
$pagination = $this->paginatorFactory->create($total);
return new Response($this->environment->render('@ChillMain/NewsItem/news_items_history.html.twig', [
'entities' => $newsItems,
'paginator' => $pagination,
'filter_order' => $filter,
]));
}
/**
* @Route("/{_locale}/news-items/{id}", name="chill_main_single_news_item")
*/
public function showSingleItem(NewsItem $newsItem, Request $request): Response
{
return new Response($this->environment->render(
'@ChillMain/NewsItem/show.html.twig',
[
'entity' => $newsItem,
]
));
}
private function buildFilterOrder(): FilterOrderHelper
{
$filterBuilder = $this->filterOrderHelperFactory
->create(self::class)
->addSearchBox();
return $filterBuilder->build();
}
}

View File

@@ -19,42 +19,20 @@ use Chill\MainBundle\Security\Authorization\NotificationVoter;
use Chill\MainBundle\Serializer\Model\Collection;
use Chill\MainBundle\Serializer\Model\Counter;
use Doctrine\ORM\EntityManagerInterface;
use RuntimeException;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\Routing\Annotation\Route;
use Symfony\Component\Security\Core\Exception\AccessDeniedException;
use Symfony\Component\Security\Core\Security;
use Symfony\Component\Serializer\SerializerInterface;
use UnexpectedValueException;
/**
* @Route("/api/1.0/main/notification")
*/
class NotificationApiController
{
private EntityManagerInterface $entityManager;
private NotificationRepository $notificationRepository;
private PaginatorFactory $paginatorFactory;
private Security $security;
private SerializerInterface $serializer;
public function __construct(
EntityManagerInterface $entityManager,
NotificationRepository $notificationRepository,
PaginatorFactory $paginatorFactory,
Security $security,
SerializerInterface $serializer
) {
$this->entityManager = $entityManager;
$this->notificationRepository = $notificationRepository;
$this->paginatorFactory = $paginatorFactory;
$this->security = $security;
$this->serializer = $serializer;
public function __construct(private readonly EntityManagerInterface $entityManager, private readonly NotificationRepository $notificationRepository, private readonly PaginatorFactory $paginatorFactory, private readonly Security $security, private readonly SerializerInterface $serializer)
{
}
/**
@@ -113,23 +91,14 @@ class NotificationApiController
$user = $this->security->getUser();
if (!$user instanceof User) {
throw new RuntimeException('not possible to mark as read by this user');
throw new \RuntimeException('not possible to mark as read by this user');
}
switch ($target) {
case 'read':
$notification->markAsReadBy($user);
break;
case 'unread':
$notification->markAsUnreadBy($user);
break;
default:
throw new UnexpectedValueException("target not supported: {$target}");
}
match ($target) {
'read' => $notification->markAsReadBy($user),
'unread' => $notification->markAsUnreadBy($user),
default => throw new \UnexpectedValueException("target not supported: {$target}"),
};
$this->entityManager->flush();

View File

@@ -41,44 +41,8 @@ use function in_array;
*/
class NotificationController extends AbstractController
{
private LoggerInterface $chillLogger;
private EntityManagerInterface $em;
private LoggerInterface $logger;
private NotificationHandlerManager $notificationHandlerManager;
private NotificationRepository $notificationRepository;
private PaginatorFactory $paginatorFactory;
private Security $security;
private TranslatorInterface $translator;
private UserRepository $userRepository;
public function __construct(
EntityManagerInterface $em,
LoggerInterface $chillLogger,
LoggerInterface $logger,
Security $security,
NotificationRepository $notificationRepository,
NotificationHandlerManager $notificationHandlerManager,
PaginatorFactory $paginatorFactory,
TranslatorInterface $translator,
UserRepository $userRepository
) {
$this->em = $em;
$this->logger = $logger;
$this->chillLogger = $chillLogger;
$this->security = $security;
$this->notificationRepository = $notificationRepository;
$this->notificationHandlerManager = $notificationHandlerManager;
$this->paginatorFactory = $paginatorFactory;
$this->translator = $translator;
$this->userRepository = $userRepository;
public function __construct(private readonly EntityManagerInterface $em, private readonly LoggerInterface $chillLogger, private readonly LoggerInterface $logger, private readonly Security $security, private readonly NotificationRepository $notificationRepository, private readonly NotificationHandlerManager $notificationHandlerManager, private readonly PaginatorFactory $paginatorFactory, private readonly TranslatorInterface $translator, private readonly UserRepository $userRepository)
{
}
/**
@@ -117,7 +81,7 @@ class NotificationController extends AbstractController
try {
$handler = $this->notificationHandlerManager->getHandler($notification);
} catch (NotificationHandlerNotFound $e) {
} catch (NotificationHandlerNotFound) {
throw new BadRequestHttpException('no handler for this notification');
}
@@ -186,7 +150,7 @@ class NotificationController extends AbstractController
throw new AccessDeniedHttpException('You must be authenticated and a user to create a notification');
}
foreach (['accessKey'/*, 'email'*/] as $param) {
foreach (['accessKey'/* , 'email' */] as $param) {
if (!$request->query->has($param)) {
throw new BadRequestHttpException("Missing {$param} parameter");
}
@@ -229,7 +193,7 @@ class NotificationController extends AbstractController
$this->denyAccessUnlessGranted('IS_AUTHENTICATED_REMEMBERED');
$currentUser = $this->security->getUser();
$notificationsNbr = $this->notificationRepository->countAllForAttendee(($currentUser));
$notificationsNbr = $this->notificationRepository->countAllForAttendee($currentUser);
$paginator = $this->paginatorFactory->create($notificationsNbr);
$notifications = $this->notificationRepository->findAllForAttendee(
@@ -302,7 +266,7 @@ class NotificationController extends AbstractController
return $this->redirectToRoute('chill_main_notification_show', [
'id' => $notification->getId(),
'_fragment' => 'comment-' . $commentId,
'_fragment' => 'comment-'.$commentId,
]);
}

View File

@@ -17,8 +17,6 @@ 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;
@@ -26,6 +24,7 @@ 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\Routing\Annotation\Route;
use Symfony\Component\Security\Core\Encoder\UserPasswordEncoderInterface;
use Symfony\Component\Validator\Constraints\Callback;
use Symfony\Component\Validator\Context\ExecutionContextInterface;
@@ -87,6 +86,8 @@ class PasswordController extends AbstractController
/**
* @return Response
*
* @\Symfony\Component\Routing\Annotation\Route(path="/public/{_locale}/password/request-changed", name="password_request_recover_changed")
*/
public function changeConfirmedAction()
{
@@ -94,14 +95,14 @@ class PasswordController extends AbstractController
}
/**
* @return Response|\Symfony\Component\HttpFoundation\RedirectResponse
* @\Symfony\Component\Routing\Annotation\Route(path="/public/{_locale}/password/recover", name="password_recover")
*/
public function recoverAction(Request $request)
public function recoverAction(Request $request): Response|\Symfony\Component\HttpFoundation\RedirectResponse
{
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);
.'to try to recover password, due to mitigating possible '
.'attack. Try to contact your system administrator'), Response::HTTP_FORBIDDEN);
}
$query = $request->query;
@@ -114,8 +115,8 @@ class PasswordController extends AbstractController
if (null === $user) {
$this->eventDispatcher->dispatch(
PasswordRecoverEvent::INVALID_TOKEN,
new PasswordRecoverEvent($token, null, $request->getClientIp())
new PasswordRecoverEvent($token, null, $request->getClientIp()),
PasswordRecoverEvent::INVALID_TOKEN
);
throw $this->createNotFoundException(sprintf('User %s not found', $username));
@@ -123,8 +124,8 @@ class PasswordController extends AbstractController
if (true !== $this->tokenManager->verify($hash, $token, $user, $timestamp)) {
$this->eventDispatcher->dispatch(
PasswordRecoverEvent::INVALID_TOKEN,
new PasswordRecoverEvent($token, $user, $request->getClientIp())
new PasswordRecoverEvent($token, $user, $request->getClientIp()),
PasswordRecoverEvent::INVALID_TOKEN
);
return new Response('Invalid token', Response::HTTP_FORBIDDEN);
@@ -162,14 +163,14 @@ class PasswordController extends AbstractController
* @throws \Doctrine\ORM\NoResultException
* @throws \Doctrine\ORM\NonUniqueResultException
*
* @return Response|\Symfony\Component\HttpFoundation\RedirectResponse
* @\Symfony\Component\Routing\Annotation\Route(path="/public/{_locale}/password/request-recover", name="password_request_recover")
*/
public function requestRecoverAction(Request $request)
public function requestRecoverAction(Request $request): Response|\Symfony\Component\HttpFoundation\RedirectResponse
{
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);
.'to try to recover password, due to mitigating possible '
.'attack. Try to contact your system administrator'), Response::HTTP_FORBIDDEN);
}
$form = $this->requestRecoverForm();
@@ -190,17 +191,17 @@ class PasswordController extends AbstractController
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.'));
.'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);
.'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'))
(new \DateTimeImmutable('now'))->add(new \DateInterval('PT30M'))
);
// logging for prod
@@ -214,16 +215,16 @@ class PasswordController extends AbstractController
);
$this->eventDispatcher->dispatch(
PasswordRecoverEvent::ASK_TOKEN_SUCCESS,
new PasswordRecoverEvent(null, $user, $request->getClientIp())
new PasswordRecoverEvent(null, $user, $request->getClientIp()),
PasswordRecoverEvent::ASK_TOKEN_SUCCESS
);
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())
new PasswordRecoverEvent(null, null, $request->getClientIp()),
PasswordRecoverEvent::ASK_TOKEN_INVALID_FORM
);
}
@@ -234,6 +235,8 @@ class PasswordController extends AbstractController
/**
* @return Response
*
* @\Symfony\Component\Routing\Annotation\Route(path="/public/{_locale}/password/request-confirm", name="password_request_recover_confirm")
*/
public function requestRecoverConfirmAction()
{
@@ -242,6 +245,8 @@ class PasswordController extends AbstractController
/**
* @return Response
*
* @Route("/{_locale}/my/password", name="change_my_password")
*/
public function UserPasswordAction(Request $request)
{
@@ -304,7 +309,7 @@ class PasswordController extends AbstractController
->orWhere($qb->expr()->eq('u.emailCanonical', 'UNACCENT(LOWER(:pattern))'))
->setParameter('pattern', $pattern);
if ((int) $qb->getQuery()->getSingleScalarResult() !== 1) {
if (1 !== (int) $qb->getQuery()->getSingleScalarResult()) {
$context->addViolation('This username or email does not exists');
}
},

View File

@@ -19,21 +19,10 @@ use Symfony\Component\Routing\Annotation\Route;
use Symfony\Component\Security\Core\Security;
use Symfony\Component\Serializer\Normalizer\DenormalizerInterface;
use function array_key_exists;
use function json_decode;
class PermissionApiController extends AbstractController
{
private DenormalizerInterface $denormalizer;
private Security $security;
public function __construct(
DenormalizerInterface $denormalizer,
Security $security
) {
$this->denormalizer = $denormalizer;
$this->security = $security;
public function __construct(private readonly DenormalizerInterface $denormalizer, private readonly Security $security)
{
}
/**
@@ -45,21 +34,17 @@ class PermissionApiController extends AbstractController
{
$this->denyAccessUnlessGranted('ROLE_USER');
$data = json_decode($request->getContent(), true);
$data = \json_decode($request->getContent(), true);
if (null === $data) {
throw new BadRequestHttpException(sprintf(
'Could not decode json received, or data invalid: %s, %s',
json_last_error(),
json_last_error_msg()
));
throw new BadRequestHttpException(sprintf('Could not decode json received, or data invalid: %s, %s', json_last_error(), json_last_error_msg()));
}
if (!array_key_exists('object', $data)) {
if (!\array_key_exists('object', $data)) {
throw new BadRequestHttpException('the object key is not present');
}
if (!array_key_exists('class', $data)) {
if (!\array_key_exists('class', $data)) {
throw new BadRequestHttpException('the class key is not present');
}

View File

@@ -21,7 +21,6 @@ use Chill\MainBundle\Repository\RoleScopeRepository;
use Chill\MainBundle\Security\RoleProvider;
use Chill\MainBundle\Templating\TranslatableStringHelper;
use Doctrine\ORM\EntityManagerInterface;
use RuntimeException;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\Form\Extension\Core\Type\SubmitType;
use Symfony\Component\Form\FormInterface;
@@ -31,8 +30,6 @@ use Symfony\Component\Security\Core\Role\RoleHierarchyInterface;
use Symfony\Component\Validator\Validator\ValidatorInterface;
use Symfony\Contracts\Translation\TranslatorInterface;
use function array_key_exists;
/**
* Class PermissionsGroupController.
*/
@@ -54,6 +51,7 @@ final class PermissionsGroupController extends AbstractController
}
/**
* @\Symfony\Component\Routing\Annotation\Route(path="/{_locale}/admin/permissionsgroup/{id}/add_link_role_scope", name="admin_permissionsgroup_add_role_scope", methods={"PUT"})
*/
public function addLinkRoleScopeAction(Request $request, int $id): Response
{
@@ -75,7 +73,7 @@ final class PermissionsGroupController extends AbstractController
$permissionsGroup->addRoleScope($roleScope);
$violations = $this->validator->validate($permissionsGroup);
if ($violations->count() === 0) {
if (0 === $violations->count()) {
$this->em->flush();
$this->addFlash(
@@ -83,10 +81,7 @@ final class PermissionsGroupController extends AbstractController
$this->translator->trans('The permissions have been added')
);
return $this->redirect($this->generateUrl(
'admin_permissionsgroup_edit',
['id' => $id]
));
return $this->redirectToRoute('admin_permissionsgroup_edit', ['id' => $id]);
}
foreach ($violations as $error) {
@@ -135,6 +130,8 @@ final class PermissionsGroupController extends AbstractController
/**
* Creates a new PermissionsGroup entity.
*
* @\Symfony\Component\Routing\Annotation\Route(path="/{_locale}/admin/permissionsgroup/create", name="admin_permissionsgroup_create", methods={"POST"})
*/
public function createAction(Request $request): Response
{
@@ -146,10 +143,7 @@ final class PermissionsGroupController extends AbstractController
$this->em->persist($permissionsGroup);
$this->em->flush();
return $this->redirect($this->generateUrl(
'admin_permissionsgroup_edit',
['id' => $permissionsGroup->getId()]
));
return $this->redirectToRoute('admin_permissionsgroup_edit', ['id' => $permissionsGroup->getId()]);
}
return $this->render('@ChillMain/PermissionsGroup/new.html.twig', [
@@ -160,6 +154,8 @@ final class PermissionsGroupController extends AbstractController
/**
* remove an association between permissionsGroup and roleScope.
*
* @\Symfony\Component\Routing\Annotation\Route(path="/{_locale}/admin/permissionsgroup/{pgid}/delete_link_role_scope/{rsid}", name="admin_permissionsgroup_delete_role_scope", methods={"DELETE"})
*/
public function deleteLinkRoleScopeAction(int $pgid, int $rsid): Response
{
@@ -176,30 +172,27 @@ final class PermissionsGroupController extends AbstractController
try {
$permissionsGroup->removeRoleScope($roleScope);
} catch (RuntimeException) {
} catch (\RuntimeException) {
$this->addFlash(
'notice',
$this->translator->trans("The role '%role%' and circle "
. "'%scope%' is not associated with this permission group", [
."'%scope%' is not associated with this permission group", [
'%role%' => $this->translator->trans($roleScope->getRole()),
'%scope%' => $this->translatableStringHelper
->localize($roleScope->getScope()->getName()),
])
);
return $this->redirect($this->generateUrl(
'admin_permissionsgroup_edit',
['id' => $pgid]
));
return $this->redirectToRoute('admin_permissionsgroup_edit', ['id' => $pgid]);
}
$this->em->flush();
if ($roleScope->getScope() !== null) {
if (null !== $roleScope->getScope()) {
$this->addFlash(
'notice',
$this->translator->trans("The role '%role%' on circle "
. "'%scope%' has been removed", [
."'%scope%' has been removed", [
'%role%' => $this->translator->trans($roleScope->getRole()),
'%scope%' => $this->translatableStringHelper
->localize($roleScope->getScope()->getName()),
@@ -214,14 +207,13 @@ final class PermissionsGroupController extends AbstractController
);
}
return $this->redirect($this->generateUrl(
'admin_permissionsgroup_edit',
['id' => $pgid]
));
return $this->redirectToRoute('admin_permissionsgroup_edit', ['id' => $pgid]);
}
/**
* Displays a form to edit an existing PermissionsGroup entity.
*
* @\Symfony\Component\Routing\Annotation\Route(path="/{_locale}/admin/permissionsgroup/{id}/edit", name="admin_permissionsgroup_edit")
*/
public function editAction(int $id): Response
{
@@ -268,6 +260,8 @@ final class PermissionsGroupController extends AbstractController
/**
* Lists all PermissionsGroup entities.
*
* @\Symfony\Component\Routing\Annotation\Route(path="/{_locale}/admin/permissionsgroup/", name="admin_permissionsgroup")
*/
public function indexAction(): Response
{
@@ -280,6 +274,8 @@ final class PermissionsGroupController extends AbstractController
/**
* Displays a form to create a new PermissionsGroup entity.
*
* @\Symfony\Component\Routing\Annotation\Route(path="/{_locale}/admin/permissionsgroup/new", name="admin_permissionsgroup_new")
*/
public function newAction(): Response
{
@@ -294,6 +290,8 @@ final class PermissionsGroupController extends AbstractController
/**
* Finds and displays a PermissionsGroup entity.
*
* @\Symfony\Component\Routing\Annotation\Route(path="/{_locale}/admin/permissionsgroup/{id}/show", name="admin_permissionsgroup_show")
*/
public function showAction(int $id): Response
{
@@ -310,17 +308,17 @@ final class PermissionsGroupController extends AbstractController
usort(
$roleScopes,
static function (RoleScope $a, RoleScope $b) use ($translatableStringHelper) {
if ($a->getScope() === null) {
if (null === $a->getScope()) {
return 1;
}
if ($b->getScope() === null) {
if (null === $b->getScope()) {
return +1;
}
return strcmp(
$translatableStringHelper->localize($a->getScope()->getName()),
$translatableStringHelper->localize($b->getScope()->getName())
(string) $translatableStringHelper->localize($a->getScope()->getName()),
(string) $translatableStringHelper->localize($b->getScope()->getName())
);
}
);
@@ -345,6 +343,8 @@ final class PermissionsGroupController extends AbstractController
/**
* Edits an existing PermissionsGroup entity.
*
* @\Symfony\Component\Routing\Annotation\Route(path="/{_locale}/admin/permissionsgroup/{id}/update", name="admin_permissionsgroup_update", methods={"POST", "PUT"})
*/
public function updateAction(Request $request, int $id): Response
{
@@ -352,8 +352,7 @@ final class PermissionsGroupController extends AbstractController
->find($id);
if (!$permissionsGroup) {
throw $this->createNotFoundException('Unable to find Permissions'
. 'Group entity.');
throw $this->createNotFoundException('Unable to find PermissionsGroup entity.');
}
$editForm = $this->createEditForm($permissionsGroup);
@@ -362,7 +361,7 @@ final class PermissionsGroupController extends AbstractController
if ($editForm->isValid()) {
$this->em->flush();
return $this->redirect($this->generateUrl('admin_permissionsgroup_edit', ['id' => $id]));
return $this->redirectToRoute('admin_permissionsgroup_edit', ['id' => $id]);
}
$deleteRoleScopesForm = [];
@@ -452,8 +451,6 @@ final class PermissionsGroupController extends AbstractController
/**
* Creates a form to delete a link to roleScope.
*
* @param mixed $permissionsGroup The entity id
*/
private function createDeleteRoleScopeForm(
PermissionsGroup $permissionsGroup,
@@ -492,7 +489,7 @@ final class PermissionsGroupController extends AbstractController
$expandedRoles = [];
foreach ($roleScopes as $roleScope) {
if (!array_key_exists($roleScope->getRole(), $expandedRoles)) {
if (!\array_key_exists($roleScope->getRole(), $expandedRoles)) {
$expandedRoles[$roleScope->getRole()] =
array_map(
static fn ($role) => $role,

View File

@@ -26,20 +26,8 @@ use Symfony\Component\Serializer\Normalizer\AbstractNormalizer;
final class PostalCodeAPIController extends ApiController
{
private CountryRepository $countryRepository;
private PaginatorFactory $paginatorFactory;
private PostalCodeRepositoryInterface $postalCodeRepository;
public function __construct(
CountryRepository $countryRepository,
PostalCodeRepositoryInterface $postalCodeRepository,
PaginatorFactory $paginatorFactory
) {
$this->countryRepository = $countryRepository;
$this->postalCodeRepository = $postalCodeRepository;
$this->paginatorFactory = $paginatorFactory;
public function __construct(private readonly CountryRepository $countryRepository, private readonly PostalCodeRepositoryInterface $postalCodeRepository, private readonly PaginatorFactory $paginatorFactory)
{
}
/**
@@ -55,7 +43,7 @@ final class PostalCodeAPIController extends ApiController
$pattern = $request->query->get('q');
if ('' === trim($pattern)) {
if ('' === trim((string) $pattern)) {
throw new BadRequestHttpException('the search pattern is empty');
}

View File

@@ -19,8 +19,6 @@ use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\Routing\Annotation\Route;
use function array_map;
/**
* Class PostalCodeController.
*/
@@ -55,21 +53,21 @@ class PostalCodeController extends AbstractController
->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',
.'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 . '%')
->setParameter('pattern', '%'.$pattern.'%')
->setMaxResults(30);
$results = array_map(function ($row) {
$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));

View File

@@ -30,50 +30,12 @@ use Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException;
use Symfony\Component\Routing\Annotation\Route;
use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
use Symfony\Component\Security\Core\Security;
use Symfony\Component\Templating\EngineInterface;
use Symfony\Contracts\Translation\TranslatorInterface;
use function count;
class SavedExportController
{
private EntityManagerInterface $entityManager;
private ExportManager $exportManager;
private FormFactoryInterface $formFactory;
private SavedExportRepositoryInterface $savedExportRepository;
private Security $security;
private SessionInterface $session;
private EngineInterface $templating;
private TranslatorInterface $translator;
private UrlGeneratorInterface $urlGenerator;
public function __construct(
EngineInterface $templating,
EntityManagerInterface $entityManager,
ExportManager $exportManager,
FormFactoryInterface $formBuilder,
SavedExportRepositoryInterface $savedExportRepository,
Security $security,
SessionInterface $session,
TranslatorInterface $translator,
UrlGeneratorInterface $urlGenerator
) {
$this->exportManager = $exportManager;
$this->entityManager = $entityManager;
$this->formFactory = $formBuilder;
$this->savedExportRepository = $savedExportRepository;
$this->security = $security;
$this->session = $session;
$this->templating = $templating;
$this->translator = $translator;
$this->urlGenerator = $urlGenerator;
public function __construct(private readonly \Twig\Environment $templating, private readonly EntityManagerInterface $entityManager, private readonly ExportManager $exportManager, private readonly FormFactoryInterface $formFactory, private readonly SavedExportRepositoryInterface $savedExportRepository, private readonly Security $security, private readonly SessionInterface $session, private readonly TranslatorInterface $translator, private readonly UrlGeneratorInterface $urlGenerator)
{
}
/**
@@ -177,7 +139,7 @@ class SavedExportController
'@ChillMain/SavedExport/index.html.twig',
[
'grouped_exports' => $exportsGrouped,
'total' => count($exports),
'total' => \count($exports),
]
)
);

View File

@@ -24,6 +24,8 @@ class ScopeController extends AbstractController
{
/**
* Creates a new Scope entity.
*
* @\Symfony\Component\Routing\Annotation\Route(path="/{_locale}/admin/scope/create", name="admin_scope_create", methods={"POST"})
*/
public function createAction(Request $request)
{
@@ -31,12 +33,12 @@ class ScopeController extends AbstractController
$form = $this->createCreateForm($scope);
$form->handleRequest($request);
if ($form->isValid()) {
if ($form->isSubmitted() && $form->isValid()) {
$em = $this->getDoctrine()->getManager();
$em->persist($scope);
$em->flush();
return $this->redirect($this->generateUrl('admin_scope'));
return $this->redirectToRoute('admin_scope');
}
return $this->render('@ChillMain/Scope/new.html.twig', [
@@ -48,13 +50,13 @@ class ScopeController extends AbstractController
/**
* Displays a form to edit an existing Scope entity.
*
* @param mixed $id
* @\Symfony\Component\Routing\Annotation\Route(path="/{_locale}/admin/scope/{id}/edit", name="admin_scope_edit")
*/
public function editAction($id)
public function editAction(mixed $id)
{
$em = $this->getDoctrine()->getManager();
$scope = $em->getRepository(\Chill\MainBundle\Entity\Scope::class)->find($id);
$scope = $em->getRepository(Scope::class)->find($id);
if (!$scope) {
throw $this->createNotFoundException('Unable to find Scope entity.');
@@ -70,12 +72,14 @@ class ScopeController extends AbstractController
/**
* Lists all Scope entities.
*
* @\Symfony\Component\Routing\Annotation\Route(path="/{_locale}/admin/scope/", name="admin_scope")
*/
public function indexAction()
{
$em = $this->getDoctrine()->getManager();
$entities = $em->getRepository(\Chill\MainBundle\Entity\Scope::class)->findAll();
$entities = $em->getRepository(Scope::class)->findAll();
return $this->render('@ChillMain/Scope/index.html.twig', [
'entities' => $entities,
@@ -84,6 +88,8 @@ class ScopeController extends AbstractController
/**
* Displays a form to create a new Scope entity.
*
* @\Symfony\Component\Routing\Annotation\Route(path="/{_locale}/admin/scope/new", name="admin_scope_new")
*/
public function newAction()
{
@@ -98,14 +104,12 @@ class ScopeController extends AbstractController
/**
* Finds and displays a Scope entity.
*
* @param mixed $id
*/
public function showAction($id)
public function showAction(mixed $id)
{
$em = $this->getDoctrine()->getManager();
$scope = $em->getRepository(\Chill\MainBundle\Entity\Scope::class)->find($id);
$scope = $em->getRepository(Scope::class)->find($id);
if (!$scope) {
throw $this->createNotFoundException('Unable to find Scope entity.');
@@ -119,13 +123,13 @@ class ScopeController extends AbstractController
/**
* Edits an existing Scope entity.
*
* @param mixed $id
* @\Symfony\Component\Routing\Annotation\Route(path="/{_locale}/admin/scope/{id}/update", name="admin_scope_update", methods={"POST", "PUT"})
*/
public function updateAction(Request $request, $id)
public function updateAction(Request $request, mixed $id)
{
$em = $this->getDoctrine()->getManager();
$scope = $em->getRepository(\Chill\MainBundle\Entity\Scope::class)->find($id);
$scope = $em->getRepository(Scope::class)->find($id);
if (!$scope) {
throw $this->createNotFoundException('Unable to find Scope entity.');
@@ -134,10 +138,10 @@ class ScopeController extends AbstractController
$editForm = $this->createEditForm($scope);
$editForm->handleRequest($request);
if ($editForm->isValid()) {
if ($editForm->isSubmitted() && $editForm->isValid()) {
$em->flush();
return $this->redirect($this->generateUrl('admin_scope_edit', ['id' => $id]));
return $this->redirectToRoute('admin_scope_edit', ['id' => $id]);
}
return $this->render('@ChillMain/Scope/edit.html.twig', [

View File

@@ -27,36 +27,19 @@ use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpKernel\Exception\BadRequestHttpException;
use Symfony\Contracts\Translation\TranslatorInterface;
use function count;
use function key;
use function reset;
/**
* Class SearchController.
*/
class SearchController extends AbstractController
{
protected PaginatorFactory $paginatorFactory;
protected SearchApi $searchApi;
protected SearchProvider $searchProvider;
protected TranslatorInterface $translator;
public function __construct(
SearchProvider $searchProvider,
TranslatorInterface $translator,
PaginatorFactory $paginatorFactory,
SearchApi $searchApi
) {
$this->searchProvider = $searchProvider;
$this->translator = $translator;
$this->paginatorFactory = $paginatorFactory;
$this->searchApi = $searchApi;
public function __construct(protected SearchProvider $searchProvider, protected TranslatorInterface $translator, protected PaginatorFactory $paginatorFactory, protected SearchApi $searchApi)
{
}
public function advancedSearchAction($name, Request $request)
/**
* @\Symfony\Component\Routing\Annotation\Route(path="/{_locale}/search/advanced/{name}", name="chill_main_advanced_search")
*/
public function advancedSearchAction(mixed $name, Request $request)
{
try {
/** @var Chill\MainBundle\Search\SearchProvider $variable */
@@ -64,9 +47,8 @@ class SearchController extends AbstractController
/** @var Chill\MainBundle\Search\HasAdvancedSearchFormInterface $variable */
$search = $this->searchProvider
->getHasAdvancedFormByName($name);
} catch (\Chill\MainBundle\Search\UnknowSearchNameException $e) {
throw $this->createNotFoundException('no advanced search for '
. "{$name}");
} catch (UnknowSearchNameException) {
throw $this->createNotFoundException('no advanced search for '."{$name}");
}
if ($request->query->has('q')) {
@@ -101,6 +83,9 @@ class SearchController extends AbstractController
);
}
/**
* @\Symfony\Component\Routing\Annotation\Route(path="/{_locale}/search/advanced", name="chill_main_advanced_search_list")
*/
public function advancedSearchListAction(Request $request)
{
/** @var Chill\MainBundle\Search\SearchProvider $variable */
@@ -108,7 +93,7 @@ class SearchController extends AbstractController
$advancedSearchProviders = $searchProvider
->getHasAdvancedFormSearchServices();
if (count($advancedSearchProviders) === 1) {
if (1 === \count($advancedSearchProviders)) {
return $this->redirectToRoute('chill_main_advanced_search', [
'name' => array_key_first($advancedSearchProviders),
]);
@@ -117,9 +102,12 @@ class SearchController extends AbstractController
return $this->render('@ChillMain/Search/choose_list.html.twig');
}
public function searchAction(Request $request, $_format)
/**
* @\Symfony\Component\Routing\Annotation\Route(path="/{_locale}/search.{_format}", name="chill_main_search", requirements={"_format"="html|json"}, defaults={"_format"="html"})
*/
public function searchAction(Request $request, mixed $_format)
{
$pattern = trim($request->query->get('q', ''));
$pattern = trim((string) $request->query->get('q', ''));
if ('' === $pattern) {
switch ($_format) {
@@ -128,7 +116,7 @@ class SearchController extends AbstractController
'@ChillMain/Search/error.html.twig',
[
'message' => $this->translator->trans('Your search is empty. '
. 'Please provide search terms.'),
.'Please provide search terms.'),
'pattern' => $pattern,
]
);
@@ -147,7 +135,7 @@ class SearchController extends AbstractController
if (null === $name) {
if ('json' === $_format) {
return new JsonResponse('Currently, we still do not aggregate results '
. 'from different providers', JsonResponse::HTTP_BAD_REQUEST);
.'from different providers', JsonResponse::HTTP_BAD_REQUEST);
}
// no specific search selected. Rendering result in "preview" mode
@@ -175,7 +163,7 @@ class SearchController extends AbstractController
), ];
if ('json' === $_format) {
return new JsonResponse(reset($results));
return new JsonResponse(\reset($results));
}
}
} catch (UnknowSearchDomainException $ex) {
@@ -183,18 +171,18 @@ class SearchController extends AbstractController
'@ChillMain/Search/error.html.twig',
[
'message' => $this->translator->trans('The domain %domain% '
. 'is unknow. Please check your search.', ['%domain%' => $ex->getDomain()]),
.'is unknow. Please check your search.', ['%domain%' => $ex->getDomain()]),
'pattern' => $pattern,
]
);
} catch (UnknowSearchNameException $ex) {
throw $this->createNotFoundException('The name ' . $ex->getName() . ' is not found');
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()),
'message' => $this->translator->trans('Invalid terms').
': '.$this->translator->trans($ex->getMessage()),
'pattern' => $pattern,
]
);
@@ -206,15 +194,17 @@ class SearchController extends AbstractController
);
}
public function searchApi(Request $request, $_format): JsonResponse
/**
* @\Symfony\Component\Routing\Annotation\Route(path="/api/1.0/search.{_format}", name="chill_main_search_global", requirements={"_format"="json"}, defaults={"_format"="json"})
*/
public function searchApi(Request $request, mixed $_format): JsonResponse
{
//TODO this is an incomplete implementation
// TODO this is an incomplete implementation
$query = $request->query->get('q', '');
$types = $request->query->get('type', []);
if (count($types) === 0) {
throw new BadRequestHttpException('The request must contains at '
. ' one type');
if (0 === \count($types)) {
throw new BadRequestHttpException('The request must contains at one type');
}
try {

View File

@@ -18,24 +18,10 @@ use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\Routing\Annotation\Route;
use Symfony\Component\Security\Core\Security;
use function count;
class TimelineCenterController extends AbstractController
{
protected PaginatorFactory $paginatorFactory;
protected TimelineBuilder $timelineBuilder;
private Security $security;
public function __construct(
TimelineBuilder $timelineBuilder,
PaginatorFactory $paginatorFactory,
Security $security
) {
$this->timelineBuilder = $timelineBuilder;
$this->paginatorFactory = $paginatorFactory;
$this->security = $security;
public function __construct(protected TimelineBuilder $timelineBuilder, protected PaginatorFactory $paginatorFactory, private readonly Security $security)
{
}
/**
@@ -54,7 +40,7 @@ class TimelineCenterController extends AbstractController
$centers[] = $group->getCenter();
}
if (0 === count($centers)) {
if (0 === \count($centers)) {
throw $this->createNotFoundException();
}

View File

@@ -28,10 +28,8 @@ class UserApiController extends ApiController
* "_format": "json"
* }
* )
*
* @param mixed $_format
*/
public function currentLocation($_format): JsonResponse
public function currentLocation(mixed $_format): JsonResponse
{
return $this->json(
$this->getUser()->getCurrentLocation(),
@@ -49,10 +47,8 @@ class UserApiController extends ApiController
* "_format": "json"
* }
* )
*
* @param mixed $_format
*/
public function whoami($_format): JsonResponse
public function whoami(mixed $_format): JsonResponse
{
return $this->json(
$this->getUser(),
@@ -72,10 +68,6 @@ class UserApiController extends ApiController
}
}
/**
* @param mixed $query
* @param mixed $_format
*/
protected function orderQuery(string $action, $query, Request $request, PaginatorInterface $paginator, $_format)
{
return $query->orderBy('e.label', 'ASC');

View File

@@ -22,7 +22,6 @@ use Chill\MainBundle\Pagination\PaginatorInterface;
use Chill\MainBundle\Repository\UserRepository;
use Chill\MainBundle\Templating\Listing\FilterOrderHelper;
use Psr\Log\LoggerInterface;
use RuntimeException;
use Symfony\Component\DependencyInjection\ParameterBag\ParameterBagInterface;
use Symfony\Component\Form\Extension\Core\Type\SubmitType;
use Symfony\Component\Form\Form;
@@ -33,46 +32,25 @@ 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\Contracts\Translation\TranslatorInterface;
class UserController extends CRUDController
{
public const FORM_GROUP_CENTER_COMPOSED = 'composed_groupcenter';
final public const FORM_GROUP_CENTER_COMPOSED = 'composed_groupcenter';
protected ParameterBagInterface $parameterBag;
private LoggerInterface $logger;
private UserPasswordEncoderInterface $passwordEncoder;
private UserRepository $userRepository;
private ValidatorInterface $validator;
public function __construct(
LoggerInterface $chillLogger,
ValidatorInterface $validator,
UserPasswordEncoderInterface $passwordEncoder,
UserRepository $userRepository,
ParameterBagInterface $parameterBag
) {
$this->logger = $chillLogger;
$this->userRepository = $userRepository;
$this->validator = $validator;
$this->passwordEncoder = $passwordEncoder;
$this->parameterBag = $parameterBag;
public function __construct(private readonly LoggerInterface $logger, private readonly ValidatorInterface $validator, private readonly UserPasswordEncoderInterface $passwordEncoder, private readonly UserRepository $userRepository, protected ParameterBagInterface $parameterBag, private readonly TranslatorInterface $translator)
{
}
/**
* @Route("/{_locale}/admin/main/user/{uid}/add_link_groupcenter",
* name="admin_user_add_groupcenter")
*
* @param mixed $uid
*/
public function addLinkGroupCenterAction(Request $request, $uid): Response
public function addLinkGroupCenterAction(Request $request, mixed $uid): Response
{
$em = $this->getDoctrine()->getManager();
$user = $em->getRepository(\Chill\MainBundle\Entity\User::class)->find($uid);
$user = $em->getRepository(User::class)->find($uid);
if (!$user) {
throw $this->createNotFoundException('Unable to find User entity.');
@@ -87,19 +65,16 @@ class UserController extends CRUDController
);
$user->addGroupCenter($groupCenter);
if ($this->validator->validate($user)->count() === 0) {
if (0 === $this->validator->validate($user)->count()) {
$em->flush();
$this->addFlash('success', $this->get('translator')->trans('The '
. 'permissions have been successfully added to the user'));
$this->addFlash('success', $this->translator->trans('The '
.'permissions have been successfully added to the user'));
$returnPathParams = $request->query->has('returnPath') ?
['returnPath' => $request->query->get('returnPath')] : [];
return $this->redirect($this->generateUrl(
'chill_crud_admin_user_edit',
array_merge(['id' => $uid], $returnPathParams)
));
return $this->redirectToRoute('chill_crud_admin_user_edit', array_merge(['id' => $uid], $returnPathParams));
}
foreach ($this->validator->validate($user) as $error) {
@@ -122,21 +97,18 @@ class UserController extends CRUDController
/**
* @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
public function deleteLinkGroupCenterAction(mixed $uid, mixed $gcid, Request $request): RedirectResponse
{
$em = $this->getDoctrine()->getManager();
$user = $em->getRepository(\Chill\MainBundle\Entity\User::class)->find($uid);
$user = $em->getRepository(User::class)->find($uid);
if (!$user) {
throw $this->createNotFoundException('Unable to find User entity.');
}
$groupCenter = $em->getRepository(\Chill\MainBundle\Entity\GroupCenter::class)
$groupCenter = $em->getRepository(GroupCenter::class)
->find($gcid);
if (!$groupCenter) {
@@ -145,18 +117,18 @@ class UserController extends CRUDController
try {
$user->removeGroupCenter($groupCenter);
} catch (RuntimeException $ex) {
$this->addFlash('error', $this->get('translator')->trans($ex->getMessage()));
} catch (\RuntimeException $ex) {
$this->addFlash('error', $this->translator->trans($ex->getMessage()));
return $this->redirect($this->generateUrl('chill_crud_admin_user_edit', ['id' => $uid]));
return $this->redirectToRoute('chill_crud_admin_user_edit', ['id' => $uid]);
}
$em->flush();
$this->addFlash('success', $this->get('translator')
$this->addFlash('success', $this->translator
->trans('The permissions where removed.'));
return $this->redirect($this->generateUrl('chill_crud_admin_user_edit', ['id' => $uid]));
return $this->redirectToRoute('chill_crud_admin_user_edit', ['id' => $uid]);
}
public function edit(Request $request, $id): Response
@@ -165,13 +137,7 @@ class UserController extends CRUDController
$entity = $this->getEntity($action, $id, $request);
if (null === $entity) {
throw $this->createNotFoundException(
sprintf(
'The %s with id %s is not found',
$this->getCrudName(),
$id
)
);
throw $this->createNotFoundException(sprintf('The %s with id %s is not found', $this->getCrudName(), $id));
}
$response = $this->checkACL($action, $entity);
@@ -206,7 +172,7 @@ class UserController extends CRUDController
return $result;
}
return $this->redirectToRoute('chill_crud_' . $this->getCrudName() . '_index');
return $this->redirectToRoute('chill_crud_'.$this->getCrudName().'_index');
}
if ($form->isSubmitted()) {
@@ -244,7 +210,7 @@ class UserController extends CRUDController
$user->setCurrentLocation($currentLocation);
$this->getDoctrine()->getManager()->flush();
$this->addFlash('success', $this->get('translator')->trans('Current location successfully updated'));
$this->addFlash('success', $this->translator->trans('Current location successfully updated'));
return $this->redirect(
$request->query->has('returnPath') ? $request->query->get('returnPath') :
@@ -280,7 +246,7 @@ class UserController extends CRUDController
$user->setPassword($this->passwordEncoder->encodePassword($user, $password));
$this->getDoctrine()->getManager()->flush();
$this->addFlash('success', $this->get('translator')->trans('Password successfully updated!'));
$this->addFlash('success', $this->translator->trans('Password successfully updated!'));
return $this->redirect(
$request->query->has('returnPath') ? $request->query->get('returnPath') :
@@ -421,10 +387,8 @@ class UserController extends CRUDController
/**
* Creates a form to delete a link to a GroupCenter.
*
* @param mixed $request
*/
private function createDeleteLinkGroupCenterForm(User $user, GroupCenter $groupCenter, $request): FormInterface
private function createDeleteLinkGroupCenterForm(User $user, GroupCenter $groupCenter, mixed $request): FormInterface
{
$returnPathParams = $request->query->has('returnPath') ? ['returnPath' => $request->query->get('returnPath')] : [];
@@ -462,7 +426,7 @@ class UserController extends CRUDController
{
$em = $this->getDoctrine()->getManager();
$groupCenterManaged = $em->getRepository(\Chill\MainBundle\Entity\GroupCenter::class)
$groupCenterManaged = $em->getRepository(GroupCenter::class)
->findOneBy([
'center' => $groupCenter->getCenter(),
'permissionsGroup' => $groupCenter->getPermissionsGroup(),

View File

@@ -48,17 +48,17 @@ final readonly class UserExportController
$csv = Writer::createFromPath('php://temp', 'r+');
$csv->insertOne(
array_map(
fn (string $e) => $this->translator->trans('admin.users.export.' . $e),
fn (string $e) => $this->translator->trans('admin.users.export.'.$e),
[
'id',
'username',
// 'username',
'email',
'enabled',
'civility_id',
'civility_abbreviation',
'civility_name',
'label',
'mainCenter_id' ,
'mainCenter_id',
'mainCenter_name',
'mainScope_id',
'mainScope_name',
@@ -68,11 +68,12 @@ final readonly class UserExportController
'currentLocation_name',
'mainLocation_id',
'mainLocation_name',
'absenceStart'
'absenceStart',
]
)
);
$csv->addFormatter(fn (array $row) => null !== ($row['absenceStart'] ?? null) ? array_merge($row, ['absenceStart' => $row['absenceStart']->format('Y-m-d')]) : $row);
/* @phpstan-ignore-next-line as phpstan seem to ignore that we transform datetime into string */
$csv->insertAll($users);
return new StreamedResponse(
@@ -92,7 +93,6 @@ final readonly class UserExportController
}
/**
* @return StreamedResponse
* @throws \League\Csv\CannotInsertRecord
* @throws \League\Csv\Exception
* @throws \League\Csv\UnavailableStream
@@ -110,7 +110,7 @@ final readonly class UserExportController
$csv = Writer::createFromPath('php://temp', 'r+');
$csv->insertOne(
array_map(
fn (string $e) => $this->translator->trans('admin.users.export.' . $e),
fn (string $e) => $this->translator->trans('admin.users.export.'.$e),
[
'id',
'username',

View File

@@ -0,0 +1,46 @@
<?php
declare(strict_types=1);
/*
* 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\User;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Annotation\Route;
use Twig\Environment;
class UserJobScopeHistoriesController extends AbstractController
{
public function __construct(
private readonly Environment $engine,
) {
}
/**
* @Route("/{_locale}/admin/main/user/{id}/job-scope-history", name="admin_user_job_scope_history")
*/
public function indexAction(User $user): Response
{
$jobHistories = $user->getUserJobHistoriesOrdered();
$scopeHistories = $user->getMainScopeHistoriesOrdered();
return new Response(
$this->engine->render(
'@ChillMain/User/history.html.twig',
[
'user' => $user,
'jobHistories' => $jobHistories,
'scopeHistories' => $scopeHistories,
]
)
);
}
}

View File

@@ -0,0 +1,66 @@
<?php
declare(strict_types=1);
/*
* 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\Form\UserPhonenumberType;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\Form\Extension\Core\Type\SubmitType;
use Symfony\Component\Form\FormInterface;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\Security\Core\User\UserInterface;
use Symfony\Contracts\Translation\TranslatorInterface;
use Symfony\Component\Routing\Annotation\Route;
class UserProfileController extends AbstractController
{
public function __construct(
private readonly TranslatorInterface $translator,
) {
}
/**
* User profile that allows editing of phonenumber and visualization of certain data.
*
* @Route("/{_locale}/main/user/my-profile", name="chill_main_user_profile")
*/
public function __invoke(Request $request)
{
$user = $this->getUser();
$editForm = $this->createPhonenumberEditForm($user);
$editForm->handleRequest($request);
if ($editForm->isSubmitted() && $editForm->isValid()) {
$phonenumber = $editForm->get('phonenumber')->getData();
$user->setPhonenumber($phonenumber);
$this->getDoctrine()->getManager()->flush();
$this->addFlash('success', $this->translator->trans('user.profile.Phonenumber successfully updated!'));
return $this->redirectToRoute('chill_main_user_profile');
}
return $this->render('@ChillMain/User/profile.html.twig', [
'user' => $user,
'form' => $editForm->createView(),
]);
}
private function createPhonenumberEditForm(UserInterface $user): FormInterface
{
return $this->createForm(
UserPhonenumberType::class,
$user,
)
->add('submit', SubmitType::class, ['label' => $this->translator->trans('Save')]);
}
}

View File

@@ -18,7 +18,6 @@ use Chill\MainBundle\Repository\Workflow\EntityWorkflowRepository;
use Chill\MainBundle\Serializer\Model\Collection;
use Chill\MainBundle\Serializer\Model\Counter;
use Doctrine\ORM\EntityManagerInterface;
use LogicException;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
@@ -30,28 +29,8 @@ use Symfony\Component\Serializer\SerializerInterface;
class WorkflowApiController
{
private EntityManagerInterface $entityManager;
private EntityWorkflowRepository $entityWorkflowRepository;
private PaginatorFactory $paginatorFactory;
private Security $security;
private SerializerInterface $serializer;
public function __construct(
EntityManagerInterface $entityManager,
EntityWorkflowRepository $entityWorkflowRepository,
PaginatorFactory $paginatorFactory,
Security $security,
SerializerInterface $serializer
) {
$this->entityManager = $entityManager;
$this->entityWorkflowRepository = $entityWorkflowRepository;
$this->paginatorFactory = $paginatorFactory;
$this->security = $security;
$this->serializer = $serializer;
public function __construct(private readonly EntityManagerInterface $entityManager, private readonly EntityWorkflowRepository $entityWorkflowRepository, private readonly PaginatorFactory $paginatorFactory, private readonly Security $security, private readonly SerializerInterface $serializer)
{
}
/**
@@ -160,46 +139,19 @@ class WorkflowApiController
$user = $this->security->getUser();
switch ($request->query->get('subscribe')) {
case 'final':
switch ($action) {
case 'subscribe':
$entityWorkflow->addSubscriberToFinal($user);
break;
case 'unsubscribe':
$entityWorkflow->removeSubscriberToFinal($user);
break;
default:
throw new LogicException();
}
break;
case 'step':
switch ($action) {
case 'subscribe':
$entityWorkflow->addSubscriberToStep($user);
break;
case 'unsubscribe':
$entityWorkflow->removeSubscriberToStep($user);
break;
default:
throw new LogicException();
}
break;
default:
throw new BadRequestHttpException('subscribe parameter must be equal to "step" or "final"');
}
match ($request->query->get('subscribe')) {
'final' => match ($action) {
'subscribe' => $entityWorkflow->addSubscriberToFinal($user),
'unsubscribe' => $entityWorkflow->removeSubscriberToFinal($user),
default => throw new \LogicException(),
},
'step' => match ($action) {
'subscribe' => $entityWorkflow->addSubscriberToStep($user),
'unsubscribe' => $entityWorkflow->removeSubscriberToStep($user),
default => throw new \LogicException(),
},
default => throw new BadRequestHttpException('subscribe parameter must be equal to "step" or "final"'),
};
$this->entityManager->flush();

View File

@@ -35,36 +35,11 @@ use Symfony\Component\Validator\Validator\ValidatorInterface;
use Symfony\Component\Workflow\Registry;
use Symfony\Component\Workflow\TransitionBlocker;
use Symfony\Contracts\Translation\TranslatorInterface;
use function count;
class WorkflowController extends AbstractController
{
private EntityManagerInterface $entityManager;
private EntityWorkflowManager $entityWorkflowManager;
private EntityWorkflowRepository $entityWorkflowRepository;
private PaginatorFactory $paginatorFactory;
private Registry $registry;
private Security $security;
private TranslatorInterface $translator;
private ValidatorInterface $validator;
public function __construct(EntityWorkflowManager $entityWorkflowManager, EntityWorkflowRepository $entityWorkflowRepository, ValidatorInterface $validator, PaginatorFactory $paginatorFactory, Registry $registry, EntityManagerInterface $entityManager, TranslatorInterface $translator, Security $security)
public function __construct(private readonly EntityWorkflowManager $entityWorkflowManager, private readonly EntityWorkflowRepository $entityWorkflowRepository, private readonly ValidatorInterface $validator, private readonly PaginatorFactory $paginatorFactory, private readonly Registry $registry, private readonly EntityManagerInterface $entityManager, private readonly TranslatorInterface $translator, private readonly Security $security)
{
$this->entityWorkflowManager = $entityWorkflowManager;
$this->entityWorkflowRepository = $entityWorkflowRepository;
$this->validator = $validator;
$this->paginatorFactory = $paginatorFactory;
$this->registry = $registry;
$this->entityManager = $entityManager;
$this->translator = $translator;
$this->security = $security;
}
/**
@@ -93,11 +68,11 @@ class WorkflowController extends AbstractController
$errors = $this->validator->validate($entityWorkflow, null, ['creation']);
if (count($errors) > 0) {
if (\count($errors) > 0) {
$msg = [];
foreach ($errors as $error) {
/** @var \Symfony\Component\Validator\ConstraintViolationInterface $error */
/* @var \Symfony\Component\Validator\ConstraintViolationInterface $error */
$msg[] = $error->getMessage();
}
@@ -320,7 +295,7 @@ class WorkflowController extends AbstractController
$workflow = $this->registry->get($entityWorkflow, $entityWorkflow->getWorkflowName());
$errors = [];
if (count($workflow->getEnabledTransitions($entityWorkflow)) > 0) {
if (\count($workflow->getEnabledTransitions($entityWorkflow)) > 0) {
// possible transition
$usersInvolved = $entityWorkflow->getUsersInvolved();
@@ -336,7 +311,7 @@ class WorkflowController extends AbstractController
[
'transition' => true,
'entity_workflow' => $entityWorkflow,
'suggested_users' => $usersInvolved
'suggested_users' => $usersInvolved,
]
);
@@ -350,12 +325,7 @@ class WorkflowController extends AbstractController
$tb->getParameters()
), iterator_to_array($blockers));
throw $this->createAccessDeniedException(
sprintf(
"not allowed to apply transition {$transition}: %s",
implode(', ', $msgs)
)
);
throw $this->createAccessDeniedException(sprintf("not allowed to apply transition {$transition}: %s", implode(', ', $msgs)));
}
// TODO symfony 5: add those "future" on context ($workflow->apply($entityWorkflow, $transition, $context)
@@ -400,7 +370,7 @@ class WorkflowController extends AbstractController
'transition_form' => isset($transitionForm) ? $transitionForm->createView() : null,
'entity_workflow' => $entityWorkflow,
'transition_form_errors' => $errors,
//'comment_form' => $commentForm->createView(),
// 'comment_form' => $commentForm->createView(),
]
);
}

View File

@@ -19,5 +19,14 @@ interface CronJobInterface
public function getKey(): string;
public function run(): void;
/**
* Execute the cronjob.
*
* If data is returned, this data is passed as argument on the next execution
*
* @param array $lastExecutionData the data which was returned from the previous execution
*
* @return array|null optionally return an array with the same data than the previous execution
*/
public function run(array $lastExecutionData): ?array;
}

View File

@@ -13,11 +13,10 @@ namespace Chill\MainBundle\Cron;
use Chill\MainBundle\Entity\CronJobExecution;
use Chill\MainBundle\Repository\CronJobExecutionRepositoryInterface;
use DateTimeImmutable;
use Doctrine\DBAL\Types\Types;
use Doctrine\ORM\EntityManagerInterface;
use Exception;
use Psr\Log\LoggerInterface;
use function array_key_exists;
/**
* Manage cronjob and execute them.
@@ -38,38 +37,25 @@ use function array_key_exists;
* If a tasks is "forced", there is no test about eligibility of the task (the `canRun` method is not called),
* and the last task execution is not recorded.
*/
class CronManager implements CronManagerInterface
final readonly class CronManager implements CronManagerInterface
{
private const LOG_PREFIX = '[cron manager] ';
private const UPDATE_AFTER_EXEC = 'UPDATE ' . CronJobExecution::class . ' cr SET cr.lastEnd = :now, cr.lastStatus = :status WHERE cr.key = :key';
private const UPDATE_AFTER_EXEC = 'UPDATE '.CronJobExecution::class.' cr SET cr.lastEnd = :now, cr.lastStatus = :status WHERE cr.key = :key';
private const UPDATE_BEFORE_EXEC = 'UPDATE ' . CronJobExecution::class . ' cr SET cr.lastStart = :now WHERE cr.key = :key';
private const UPDATE_BEFORE_EXEC = 'UPDATE '.CronJobExecution::class.' cr SET cr.lastStart = :now WHERE cr.key = :key';
private CronJobExecutionRepositoryInterface $cronJobExecutionRepository;
private EntityManagerInterface $entityManager;
/**
* @var iterable<CronJobInterface>
*/
private iterable $jobs;
private LoggerInterface $logger;
private const UPDATE_LAST_EXECUTION_DATA = 'UPDATE '.CronJobExecution::class.' cr SET cr.lastExecutionData = :data WHERE cr.key = :key';
/**
* @param CronJobInterface[] $jobs
*/
public function __construct(
CronJobExecutionRepositoryInterface $cronJobExecutionRepository,
EntityManagerInterface $entityManager,
iterable $jobs,
LoggerInterface $logger
private CronJobExecutionRepositoryInterface $cronJobExecutionRepository,
private EntityManagerInterface $entityManager,
private iterable $jobs,
private LoggerInterface $logger
) {
$this->cronJobExecutionRepository = $cronJobExecutionRepository;
$this->entityManager = $entityManager;
$this->jobs = $jobs;
$this->logger = $logger;
}
public function run(?string $forceJob = null): void
@@ -84,11 +70,13 @@ class CronManager implements CronManagerInterface
foreach ($orderedJobs as $job) {
if ($job->canRun($lasts[$job->getKey()] ?? null)) {
if (array_key_exists($job->getKey(), $lasts)) {
if (\array_key_exists($job->getKey(), $lasts)) {
$executionData = $lasts[$job->getKey()]->getLastExecutionData();
$this->entityManager
->createQuery(self::UPDATE_BEFORE_EXEC)
->setParameters([
'now' => new DateTimeImmutable('now'),
'now' => new \DateTimeImmutable('now'),
'key' => $job->getKey(),
])
->execute();
@@ -96,31 +84,44 @@ class CronManager implements CronManagerInterface
$execution = new CronJobExecution($job->getKey());
$this->entityManager->persist($execution);
$this->entityManager->flush();
$executionData = $execution->getLastExecutionData();
}
$this->entityManager->clear();
// note: at this step, the entity manager does not have any entity CronJobExecution
// into his internal memory
try {
$this->logger->info(sprintf('%sWill run job', self::LOG_PREFIX), ['job' => $job->getKey()]);
$job->run();
$result = $job->run($executionData);
$this->entityManager
->createQuery(self::UPDATE_AFTER_EXEC)
->setParameters([
'now' => new DateTimeImmutable('now'),
'now' => new \DateTimeImmutable('now'),
'status' => CronJobExecution::SUCCESS,
'key' => $job->getKey(),
])
->execute();
if (null !== $result) {
$this->entityManager
->createQuery(self::UPDATE_LAST_EXECUTION_DATA)
->setParameter('data', $result, Types::JSON)
->setParameter('key', $job->getKey(), Types::STRING)
->execute();
}
$this->logger->info(sprintf('%sSuccessfully run job', self::LOG_PREFIX), ['job' => $job->getKey()]);
return;
} catch (Exception $e) {
} catch (\Exception) {
$this->logger->error(sprintf('%sRunning job failed', self::LOG_PREFIX), ['job' => $job->getKey()]);
$this->entityManager
->createQuery(self::UPDATE_AFTER_EXEC)
->setParameters([
'now' => new DateTimeImmutable('now'),
'now' => new \DateTimeImmutable('now'),
'status' => CronJobExecution::FAILURE,
'key' => $job->getKey(),
])
@@ -133,7 +134,7 @@ class CronManager implements CronManagerInterface
}
/**
* @return array<0: CronJobInterface[], 1: array<string, CronJobExecution>>
* @return array{0: array<CronJobInterface>, 1: array<string, CronJobExecution>}
*/
private function getOrderedJobs(): array
{
@@ -150,16 +151,16 @@ class CronManager implements CronManagerInterface
$orderedJobs,
static function (CronJobInterface $a, CronJobInterface $b) use ($lasts): int {
if (
(!array_key_exists($a->getKey(), $lasts) && !array_key_exists($b->getKey(), $lasts))
!\array_key_exists($a->getKey(), $lasts) && !\array_key_exists($b->getKey(), $lasts)
) {
return 0;
}
if (!array_key_exists($a->getKey(), $lasts) && array_key_exists($b->getKey(), $lasts)) {
if (!\array_key_exists($a->getKey(), $lasts) && \array_key_exists($b->getKey(), $lasts)) {
return -1;
}
if (!array_key_exists($b->getKey(), $lasts) && array_key_exists($a->getKey(), $lasts)) {
if (!\array_key_exists($b->getKey(), $lasts) && \array_key_exists($a->getKey(), $lasts)) {
return 1;
}
@@ -174,7 +175,7 @@ class CronManager implements CronManagerInterface
{
foreach ($this->jobs as $job) {
if ($job->getKey() === $forceJob) {
$job->run();
$job->run([]);
}
}
}

View File

@@ -12,7 +12,6 @@ declare(strict_types=1);
namespace Chill\MainBundle\DataFixtures\ORM;
use Chill\MainBundle\Entity\Notification;
use DateTimeImmutable;
use Doctrine\Persistence\ObjectManager;
/**
@@ -27,14 +26,14 @@ trait LoadAbstractNotificationsTrait
foreach ($this->notifs as $notif) {
$entityId = $this->getReference($notif['entityRef'])->getId();
echo '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'))
->setDate(new \DateTimeImmutable('now'))
->setRead([]);
foreach ($notif['addressees'] as $addressee) {

View File

@@ -26,10 +26,7 @@ class LoadAddressReferences extends AbstractFixture implements ContainerAwareInt
{
protected $faker;
/**
* @var ContainerInterface
*/
private $container;
private ?ContainerInterface $container = null;
public function __construct()
{

View File

@@ -23,10 +23,7 @@ use Symfony\Component\DependencyInjection\ContainerInterface;
*/
class LoadCountries extends AbstractFixture implements ContainerAwareInterface, OrderedFixtureInterface
{
/**
* @var ContainerInterface
*/
private $container;
private ?ContainerInterface $container = null;
public function getOrder()
{

View File

@@ -35,7 +35,7 @@ class LoadGroupCenters extends AbstractFixture implements OrderedFixtureInterfac
$manager->persist($GroupCenter);
$reference = $centerRef . '_' . $permissionGroupRef;
$reference = $centerRef.'_'.$permissionGroupRef;
$this->addReference($reference, $GroupCenter);
static::$refs[] = $reference;
echo "Creating {$reference}... \n";

View File

@@ -17,9 +17,6 @@ use Doctrine\Common\DataFixtures\OrderedFixtureInterface;
use Doctrine\Persistence\ObjectManager;
use Symfony\Component\DependencyInjection\ContainerAwareInterface;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Symfony\Component\Intl\Intl;
use function in_array;
/**
* Load languages into database.
@@ -27,17 +24,14 @@ use function in_array;
class LoadLanguages extends AbstractFixture implements ContainerAwareInterface, OrderedFixtureInterface
{
// Array of ancien languages (to exclude)
private $ancientToExclude = ['ang', 'egy', 'fro', 'goh', 'grc', 'la', 'non', 'peo', 'pro', 'sga',
private array $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;
private ?ContainerInterface $container = null;
// The regional version of language are language with _ in the code
// This array contains regional code to not exclude
private $regionalVersionToInclude = ['ro_MD'];
private array $regionalVersionToInclude = ['ro_MD'];
public function getOrder()
{
@@ -48,10 +42,10 @@ class LoadLanguages extends AbstractFixture implements ContainerAwareInterface,
{
echo "loading languages... \n";
foreach (Intl::getLanguageBundle()->getLanguageNames() as $code => $language) {
foreach (\Symfony\Component\Intl\Languages::getNames() as $code => $language) {
if (
!in_array($code, $this->regionalVersionToInclude, true)
&& !in_array($code, $this->ancientToExclude, true)
!\in_array($code, $this->regionalVersionToInclude, true)
&& !\in_array($code, $this->ancientToExclude, true)
) {
$lang = (new Language())
->setId($code)
@@ -78,7 +72,7 @@ class LoadLanguages extends AbstractFixture implements ContainerAwareInterface,
$names = [];
foreach ($this->container->getParameter('chill_main.available_languages') as $lang) {
$names[$lang] = Intl::getLanguageBundle()->getLanguageName($languageCode);
$names[$lang] = \Symfony\Component\Intl\Languages::getName($languageCode, $lang);
}
return $names;

View File

@@ -23,10 +23,7 @@ use Symfony\Component\DependencyInjection\ContainerInterface;
*/
class LoadLocationType extends AbstractFixture implements ContainerAwareInterface, OrderedFixtureInterface
{
/**
* @var ContainerInterface
*/
private $container;
private ?ContainerInterface $container = null;
public function getOrder()
{

View File

@@ -63,7 +63,7 @@ class LoadPermissionsGroup extends AbstractFixture implements OrderedFixtureInte
}
$manager->persist($permissionGroup);
$reference = 'permission_group_' . $new['name'];
$reference = 'permission_group_'.$new['name'];
echo "Creating {$reference} \n";
$this->setReference($reference, $permissionGroup);
static::$refs[] = $reference;

View File

@@ -18,9 +18,6 @@ use Doctrine\Common\DataFixtures\AbstractFixture;
use Doctrine\Common\DataFixtures\OrderedFixtureInterface;
use Doctrine\Persistence\ObjectManager;
use function strtolower;
use function ucwords;
/**
* Description of LoadPostalCodes.
*/
@@ -28,7 +25,7 @@ class LoadPostalCodes extends AbstractFixture implements OrderedFixtureInterface
{
public static $refs = [];
private static $postalCodeBelgium = <<<'EOF'
private static string $postalCodeBelgium = <<<'EOF'
1000,BRUXELLES,BE
1020,BRUXELLES,BE
1030,SCHAERBEEK,BE
@@ -63,7 +60,7 @@ class LoadPostalCodes extends AbstractFixture implements OrderedFixtureInterface
1320,BEAUVECHAIN,BE
EOF;
private static $postalCodeFrance = <<<'EOF'
private static string $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
@@ -347,26 +344,26 @@ class LoadPostalCodes extends AbstractFixture implements OrderedFixtureInterface
->findOneBy(['countryCode' => $countryCode]);
foreach ($lines as $line) {
$code = str_getcsv($line);
$code = str_getcsv((string) $line);
$c = new PostalCode();
$c->setCountry($country)
->setCode($code[0])
->setName(ucwords(strtolower($code[1])));
->setName(\ucwords(\strtolower((string) $code[1])));
if (null !== $code[3]) {
if (null !== ($code[3] ?? null)) {
$c->setRefPostalCodeId($code[3]);
}
if (null !== $code[4] & null !== $code[5]) {
if (null !== ($code[4] ?? null) & null !== ($code[5] ?? null)) {
$c->setCenter(Point::fromLonLat((float) $code[5], (float) $code[4]));
}
if (null !== $code[6]) {
if (null !== ($code[6] ?? null)) {
$c->setPostalCodeSource($code[6]);
}
$manager->persist($c);
$ref = 'postal_code_' . $code[0];
$ref = 'postal_code_'.$code[0];
if (!$this->hasReference($ref)) {
$this->addReference($ref, $c);

View File

@@ -56,7 +56,7 @@ class LoadRoleScopes extends AbstractFixture implements OrderedFixtureInterface
$roleScope = new RoleScope();
$roleScope->setRole($key)
->setScope($this->getReference($scopeReference));
$reference = 'role_scope_' . $key . '_' . $this->getReference($scopeReference)->getName()['en'];
$reference = 'role_scope_'.$key.'_'.$this->getReference($scopeReference)->getName()['en'];
echo "Creating {$reference} \n";
$this->addReference($reference, $roleScope);
$manager->persist($roleScope);

View File

@@ -58,7 +58,7 @@ class LoadScopes extends AbstractFixture implements OrderedFixtureInterface
$scope->setName($new['names']);
$manager->persist($scope);
$reference = 'scope_' . $new['names']['en'];
$reference = 'scope_'.$new['names']['en'];
$this->addReference($reference, $scope);
static::$references[] = $reference;
}

View File

@@ -15,14 +15,11 @@ use Chill\MainBundle\Entity\User;
use Doctrine\Common\DataFixtures\AbstractFixture;
use Doctrine\Common\DataFixtures\OrderedFixtureInterface;
use Doctrine\Persistence\ObjectManager;
use LogicException;
use Symfony\Component\DependencyInjection\ContainerAwareInterface;
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.
*
@@ -56,10 +53,7 @@ class LoadUsers extends AbstractFixture implements ContainerAwareInterface, Orde
],
];
/**
* @var ContainerInterface
*/
private $container;
private ?ContainerInterface $container = null;
public function getOrder()
{
@@ -84,13 +78,13 @@ class LoadUsers extends AbstractFixture implements ContainerAwareInterface, Orde
->getEncoder($user)
->encodePassword('password', $user->getSalt())
)
->setEmail(sprintf('%s@chill.social', str_replace(' ', '', $username)));
->setEmail(sprintf('%s@chill.social', \str_replace(' ', '', (string) $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);
}
@@ -101,7 +95,7 @@ class LoadUsers extends AbstractFixture implements ContainerAwareInterface, Orde
public function setContainer(?ContainerInterface $container = null)
{
if (null === $container) {
throw new LogicException('$container should not be null');
throw new \LogicException('$container should not be null');
}
$this->container = $container;

View File

@@ -12,12 +12,14 @@ declare(strict_types=1);
namespace Chill\MainBundle\DependencyInjection;
use Chill\MainBundle\Controller\AddressApiController;
use Chill\MainBundle\Controller\CenterController;
use Chill\MainBundle\Controller\CivilityApiController;
use Chill\MainBundle\Controller\CivilityController;
use Chill\MainBundle\Controller\CountryController;
use Chill\MainBundle\Controller\LanguageController;
use Chill\MainBundle\Controller\LocationController;
use Chill\MainBundle\Controller\LocationTypeController;
use Chill\MainBundle\Controller\NewsItemController;
use Chill\MainBundle\Controller\RegroupmentController;
use Chill\MainBundle\Controller\UserController;
use Chill\MainBundle\Controller\UserJobApiController;
@@ -30,6 +32,7 @@ use Chill\MainBundle\Doctrine\DQL\Greatest;
use Chill\MainBundle\Doctrine\DQL\JsonAggregate;
use Chill\MainBundle\Doctrine\DQL\JsonbArrayLength;
use Chill\MainBundle\Doctrine\DQL\JsonbExistsInArray;
use Chill\MainBundle\Doctrine\DQL\JsonBuildObject;
use Chill\MainBundle\Doctrine\DQL\JsonExtract;
use Chill\MainBundle\Doctrine\DQL\Least;
use Chill\MainBundle\Doctrine\DQL\OverlapsI;
@@ -44,24 +47,27 @@ 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\Center;
use Chill\MainBundle\Entity\Civility;
use Chill\MainBundle\Entity\Country;
use Chill\MainBundle\Entity\GeographicalUnitLayer;
use Chill\MainBundle\Entity\Language;
use Chill\MainBundle\Entity\Location;
use Chill\MainBundle\Entity\LocationType;
use Chill\MainBundle\Entity\NewsItem;
use Chill\MainBundle\Entity\Regroupment;
use Chill\MainBundle\Entity\User;
use Chill\MainBundle\Entity\UserJob;
use Chill\MainBundle\Form\CenterType;
use Chill\MainBundle\Form\CivilityType;
use Chill\MainBundle\Form\CountryType;
use Chill\MainBundle\Form\LanguageType;
use Chill\MainBundle\Form\LocationFormType;
use Chill\MainBundle\Form\LocationTypeType;
use Chill\MainBundle\Form\NewsItemType;
use Chill\MainBundle\Form\RegroupmentType;
use Chill\MainBundle\Form\UserJobType;
use Chill\MainBundle\Form\UserType;
use Exception;
use Misd\PhoneNumberBundle\Doctrine\DBAL\Types\PhoneNumberType;
use Ramsey\Uuid\Doctrine\UuidType;
use Symfony\Component\Config\FileLocator;
@@ -71,8 +77,6 @@ use Symfony\Component\DependencyInjection\Loader;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpKernel\DependencyInjection\Extension;
use function count;
/**
* Class ChillMainExtension
* This class load config for chillMainExtension.
@@ -93,10 +97,7 @@ class ChillMainExtension extends Extension implements
$this->widgetFactories[] = $factory;
}
/**
* @return \Chill\MainBundle\DependencyInjection\Configuration|object|\Symfony\Component\Config\Definition\ConfigurationInterface|null
*/
public function getConfiguration(array $config, ContainerBuilder $container)
public function getConfiguration(array $config, ContainerBuilder $container): Configuration
{
return new Configuration($this->widgetFactories, $container);
}
@@ -110,7 +111,7 @@ class ChillMainExtension extends Extension implements
}
/**
* @throws Exception
* @throws \Exception
*/
public function load(array $configs, ContainerBuilder $container)
{
@@ -190,7 +191,7 @@ class ChillMainExtension extends Extension implements
[]
);
$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');
@@ -218,12 +219,12 @@ class ChillMainExtension extends Extension implements
$this->configureCruds($container, $config['cruds'], $config['apis'], $loader);
$container->setParameter('chill_main.short_messages', $config['short_messages']);
//$this->configureSms($config['short_messages'], $container, $loader);
// $this->configureSms($config['short_messages'], $container, $loader);
}
public function prepend(ContainerBuilder $container)
{
//add installation_name and date_format to globals
// add installation_name and date_format to globals
$chillMainConfig = $container->getExtensionConfig($this->getAlias());
$config = $this->processConfiguration($this
->getConfiguration($chillMainConfig, $container), $chillMainConfig);
@@ -238,7 +239,7 @@ class ChillMainExtension extends Extension implements
];
$container->prependExtensionConfig('twig', $twigConfig);
//add DQL function to ORM (default entity_manager)
// add DQL function to ORM (default entity_manager)
$container
->prependExtensionConfig(
'doctrine',
@@ -251,6 +252,7 @@ class ChillMainExtension extends Extension implements
'AGGREGATE' => JsonAggregate::class,
'REPLACE' => Replace::class,
'JSON_EXTRACT' => JsonExtract::class,
'JSON_BUILD_OBJECT' => JsonBuildObject::class,
],
'numeric_functions' => [
'JSONB_EXISTS_IN_ARRAY' => JsonbExistsInArray::class,
@@ -262,7 +264,7 @@ class ChillMainExtension extends Extension implements
'ST_X' => STX::class,
'ST_Y' => STY::class,
'GREATEST' => Greatest::class,
'LEAST' => LEAST::class,
'LEAST' => Least::class,
],
'datetime_functions' => [
'EXTRACT' => Extract::class,
@@ -277,7 +279,7 @@ class ChillMainExtension extends Extension implements
],
);
//add dbal types (default entity_manager)
// add dbal types (default entity_manager)
$container
->prependExtensionConfig(
'doctrine',
@@ -299,7 +301,7 @@ class ChillMainExtension extends Extension implements
]
);
//add current route to chill main
// add current route to chill main
$container->prependExtensionConfig('chill_main', [
'routing' => [
'resources' => [
@@ -308,7 +310,7 @@ class ChillMainExtension extends Extension implements
],
]);
//add a channel to log app events
// add a channel to log app events
$container->prependExtensionConfig('monolog', [
'channels' => ['chill'],
]);
@@ -320,7 +322,7 @@ class ChillMainExtension extends Extension implements
],
]);
//add crud api
// add crud api
$this->prependCruds($container);
}
@@ -333,7 +335,7 @@ class ChillMainExtension extends Extension implements
array $apiConfig,
Loader\YamlFileLoader $loader
): void {
if (count($crudConfig) === 0) {
if (0 === \count($crudConfig)) {
return;
}
@@ -524,6 +526,56 @@ class ChillMainExtension extends Extension implements
],
],
],
[
'class' => Center::class,
'name' => 'center',
'base_path' => '/admin/center',
'form_class' => CenterType::class,
'controller' => CenterController::class,
'actions' => [
'index' => [
'role' => 'ROLE_ADMIN',
'template' => '@ChillMain/Admin/Center/index.html.twig',
],
'new' => [
'role' => 'ROLE_ADMIN',
'template' => '@ChillMain/Admin/Center/new.html.twig',
],
'edit' => [
'role' => 'ROLE_ADMIN',
'template' => '@ChillMain/Admin/Center/edit.html.twig',
],
],
],
[
'class' => NewsItem::class,
'name' => 'news_item',
'base_path' => '/admin/news_item',
'form_class' => NewsItemType::class,
'controller' => NewsItemController::class,
'actions' => [
'index' => [
'role' => 'ROLE_ADMIN',
'template' => '@ChillMain/NewsItem/index.html.twig',
],
'new' => [
'role' => 'ROLE_ADMIN',
'template' => '@ChillMain/NewsItem/new.html.twig',
],
'view' => [
'role' => 'ROLE_ADMIN',
'template' => '@ChillMain/NewsItem/view_admin.html.twig',
],
'edit' => [
'role' => 'ROLE_ADMIN',
'template' => '@ChillMain/NewsItem/edit.html.twig',
],
'delete' => [
'role' => 'ROLE_ADMIN',
'template' => '@ChillMain/NewsItem/delete.html.twig',
],
],
],
],
'apis' => [
[
@@ -550,7 +602,7 @@ class ChillMainExtension extends Extension implements
],
],
[
'class' => \Chill\MainBundle\Entity\UserJob::class,
'class' => UserJob::class,
'name' => 'user_job',
'base_path' => '/api/1.0/main/user-job',
'base_role' => 'ROLE_USER',
@@ -614,7 +666,7 @@ class ChillMainExtension extends Extension implements
],
],
[
'class' => \Chill\MainBundle\Entity\Country::class,
'class' => Country::class,
'name' => 'country',
'base_path' => '/api/1.0/main/country',
'base_role' => 'ROLE_USER',
@@ -634,7 +686,7 @@ class ChillMainExtension extends Extension implements
],
],
[
'class' => \Chill\MainBundle\Entity\User::class,
'class' => User::class,
'controller' => \Chill\MainBundle\Controller\UserApiController::class,
'name' => 'user',
'base_path' => '/api/1.0/main/user',
@@ -676,7 +728,7 @@ class ChillMainExtension extends Extension implements
],
],
[
'class' => \Chill\MainBundle\Entity\Location::class,
'class' => Location::class,
'controller' => \Chill\MainBundle\Controller\LocationApiController::class,
'name' => 'location',
'base_path' => '/api/1.0/main/location',
@@ -698,7 +750,7 @@ class ChillMainExtension extends Extension implements
],
],
[
'class' => \Chill\MainBundle\Entity\LocationType::class,
'class' => LocationType::class,
'controller' => \Chill\MainBundle\Controller\LocationTypeApiController::class,
'name' => 'location_type',
'base_path' => '/api/1.0/main/location-type',
@@ -719,7 +771,7 @@ class ChillMainExtension extends Extension implements
],
],
[
'class' => \Chill\MainBundle\Entity\Civility::class,
'class' => Civility::class,
'name' => 'civility',
'base_path' => '/api/1.0/main/civility',
'base_role' => 'ROLE_USER',
@@ -746,7 +798,7 @@ class ChillMainExtension extends Extension implements
],
],
],
]
],
],
]);
}

View File

@@ -12,7 +12,6 @@ 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 Symfony\Component\DependencyInjection\Reference;
@@ -27,21 +26,10 @@ class ACLFlagsCompilerPass implements CompilerPassInterface
$reference = new Reference($id);
foreach ($tags as $tag) {
switch ($tag['scope']) {
case PermissionsGroupType::FLAG_SCOPE:
$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
)
);
}
match ($tag['scope']) {
PermissionsGroupType::FLAG_SCOPE => $permissionGroupType->addMethodCall('addFlagProvider', [$reference]),
default => throw new \LogicException(sprintf("This tag 'scope' is not implemented: %s, on service with id %s", $tag['scope'], $id)),
};
}
}
}

View File

@@ -12,7 +12,6 @@ declare(strict_types=1);
namespace Chill\MainBundle\DependencyInjection\CompilerPass;
use Chill\MainBundle\Export\ExportManager;
use LogicException;
use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Definition;
@@ -32,8 +31,7 @@ class ExportsCompilerPass implements CompilerPassInterface
public function process(ContainerBuilder $container)
{
if (!$container->has(ExportManager::class)) {
throw new LogicException('service ' . ExportManager::class . ' '
. 'is not defined. It is required by ExportsCompilerPass');
throw new \LogicException('service '.ExportManager::class.' is not defined. It is required by ExportsCompilerPass');
}
$chillManagerDefinition = $container->findDefinition(
@@ -57,13 +55,11 @@ class ExportsCompilerPass implements CompilerPassInterface
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");
throw new \LogicException("the 'prefix' attribute is missing in your service '{$id}' definition");
}
if (array_search($attributes['prefix'], $knownAliases, true)) {
throw new LogicException('There is already a chill.export_elements_provider service with prefix '
. $attributes['prefix'] . '. Choose another prefix.');
throw new \LogicException('There is already a chill.export_elements_provider service with prefix '.$attributes['prefix'].'. Choose another prefix.');
}
$knownAliases[] = $attributes['prefix'];
@@ -88,13 +84,11 @@ class ExportsCompilerPass implements CompilerPassInterface
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");
throw new \LogicException("the 'alias' attribute is missing in your service '{$id}' definition");
}
if (array_search($attributes['alias'], $knownAliases, true)) {
throw new LogicException('There is already a chill.export_formatter service with alias '
. $attributes['alias'] . '. Choose another alias.');
throw new \LogicException('There is already a chill.export_formatter service with alias '.$attributes['alias'].'. Choose another alias.');
}
$knownAliases[] = $attributes['alias'];

View File

@@ -12,7 +12,6 @@ declare(strict_types=1);
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;
@@ -22,8 +21,7 @@ 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));
throw new \LogicException(sprintf('The service %s does not exists in container.', MenuComposer::class));
}
$menuComposerDefinition = $container->getDefinition('chill.main.menu_composer');

View File

@@ -12,7 +12,6 @@ declare(strict_types=1);
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;
@@ -22,8 +21,7 @@ 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);

View File

@@ -11,7 +11,6 @@ declare(strict_types=1);
namespace Chill\MainBundle\DependencyInjection\CompilerPass;
use LogicException;
use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Reference;
@@ -26,8 +25,7 @@ class SearchableServicesCompilerPass implements CompilerPassInterface
public function process(ContainerBuilder $container)
{
if (!$container->hasDefinition('chill_main.search_provider')) {
throw new LogicException('service chill_main.search_provider '
. 'is not defined.');
throw new \LogicException('service chill_main.search_provider is not defined.');
}
$definition = $container->getDefinition(
@@ -43,13 +41,11 @@ class SearchableServicesCompilerPass implements CompilerPassInterface
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");
throw new \LogicException("the 'name' attribute is missing in your service '{$id}' definition");
}
if (array_search($attributes['alias'], $knownAliases, true)) {
throw new LogicException('There is already a chill.search service with alias '
. $attributes['alias'] . '. Choose another alias.');
throw new \LogicException('There is already a chill.search service with alias '.$attributes['alias'].'. Choose another alias.');
}
$knownAliases[] = $attributes['alias'];

View File

@@ -28,7 +28,6 @@ use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Definition;
use Symfony\Component\DependencyInjection\Exception\RuntimeException;
use Symfony\Component\DependencyInjection\Reference;
use function array_key_exists;
class ShortMessageCompilerPass implements CompilerPassInterface
{
@@ -36,37 +35,35 @@ class ShortMessageCompilerPass implements CompilerPassInterface
{
$config = $container->resolveEnvPlaceholders($container->getParameter('chill_main.short_messages'), true);
// weird fix for special characters
$config['dsn'] = str_replace(['%%'], ['%'], $config['dsn']);
$config['dsn'] = str_replace(['%%'], ['%'], (string) $config['dsn']);
$dsn = parse_url($config['dsn']);
parse_str($dsn['query'] ?? '', $dsn['queries']);
if ('null' === $dsn['scheme'] || false === $config['enabled']) {
$defaultTransporter = new Reference(NullShortMessageSender::class);
} elseif ('ovh' === $dsn['scheme']) {
if (!class_exists('\\' . \Ovh\Api::class)) {
if (!class_exists('\\'.\Ovh\Api::class)) {
throw new RuntimeException('Class \\Ovh\\Api not found');
}
foreach (['user', 'host', 'pass'] as $component) {
if (!array_key_exists($component, $dsn)) {
throw new RuntimeException(sprintf('The component %s does not exist in dsn. Please provide a dsn ' .
'like ovh://applicationKey:applicationSecret@endpoint?consumerKey=xxxx&sender=yyyy&service_name=zzzz', $component));
if (!\array_key_exists($component, $dsn)) {
throw new RuntimeException(sprintf('The component %s does not exist in dsn. Please provide a dsn like ovh://applicationKey:applicationSecret@endpoint?consumerKey=xxxx&sender=yyyy&service_name=zzzz', $component));
}
$container->setParameter('chill_main.short_messages.ovh_config_' . $component, $dsn[$component]);
$container->setParameter('chill_main.short_messages.ovh_config_'.$component, $dsn[$component]);
}
foreach (['consumer_key', 'sender', 'service_name'] as $param) {
if (!array_key_exists($param, $dsn['queries'])) {
throw new RuntimeException(sprintf('The parameter %s does not exist in dsn. Please provide a dsn ' .
'like ovh://applicationKey:applicationSecret@endpoint?consumerKey=xxxx&sender=yyyy&service_name=zzzz', $param));
if (!\array_key_exists($param, $dsn['queries'])) {
throw new RuntimeException(sprintf('The parameter %s does not exist in dsn. Please provide a dsn like ovh://applicationKey:applicationSecret@endpoint?consumerKey=xxxx&sender=yyyy&service_name=zzzz', $param));
}
$container->setParameter('chill_main.short_messages.ovh_config_' . $param, $dsn['queries'][$param]);
$container->setParameter('chill_main.short_messages.ovh_config_'.$param, $dsn['queries'][$param]);
}
$ovh = new Definition();
$ovh
->setClass('\\' . \Ovh\Api::class)
->setClass('\\'.\Ovh\Api::class)
->setArgument(0, $dsn['user'])
->setArgument(1, $dsn['pass'])
->setArgument(2, $dsn['host'])

View File

@@ -11,7 +11,6 @@ declare(strict_types=1);
namespace Chill\MainBundle\DependencyInjection\CompilerPass;
use LogicException;
use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Reference;
@@ -25,8 +24,7 @@ class TimelineCompilerClass implements CompilerPassInterface
public function process(ContainerBuilder $container)
{
if (!$container->hasDefinition('chill_main.timeline_builder')) {
throw new LogicException('service chill_main.timeline_builder '
. 'is not defined.');
throw new \LogicException('service chill_main.timeline_builder is not defined.');
}
$definition = $container->getDefinition(
@@ -40,8 +38,7 @@ class TimelineCompilerClass implements CompilerPassInterface
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");
throw new \LogicException("the 'context' attribute is missing in your service '{$id}' definition");
}
$definition->addMethodCall(

View File

@@ -11,13 +11,9 @@ declare(strict_types=1);
namespace Chill\MainBundle\DependencyInjection;
use LogicException;
use RuntimeException;
use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use function count;
/**
* Description of ConfigConsistencyCompilerPass.
*/
@@ -42,17 +38,14 @@ class ConfigConsistencyCompilerPass implements CompilerPassInterface
}
}
if (count($fallbackLocales) === 0) {
throw new LogicException('the fallback locale are not defined. '
. 'The framework config should not allow this.');
if (0 === \count($fallbackLocales)) {
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'
. ' parameter does not contains fallback locales. The languages %s'
. ' are missing.', implode(', ', $diff)));
if (\count($diff) > 0) {
throw new \RuntimeException(sprintf('The chill_main.available_languages parameter does not contains fallback locales. The languages %s are missing.', implode(', ', $diff)));
}
}
}

View File

@@ -24,14 +24,11 @@ class Configuration implements ConfigurationInterface
{
use AddWidgetConfigurationTrait;
private ContainerBuilder $containerBuilder;
public function __construct(
array $widgetFactories,
ContainerBuilder $containerBuilder
private readonly ContainerBuilder $containerBuilder
) {
$this->setWidgetFactories($widgetFactories);
$this->containerBuilder = $containerBuilder;
}
public function getConfigTreeBuilder()
@@ -119,8 +116,12 @@ class Configuration implements ConfigurationInterface
->booleanNode('form_show_centers')
->defaultTrue()
->end()
->booleanNode('filter_stats_by_center')
->defaultTrue()
->info("if set to false, the exports won't take into account the center of the people")
->end()
->end()
->end() // end of 'acl'
->booleanNode('access_global_history')
->defaultTrue()
->end()
@@ -179,8 +180,8 @@ class Configuration implements ConfigurationInterface
->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.')
.'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')
@@ -219,15 +220,15 @@ class Configuration implements ConfigurationInterface
->children()
->scalarNode('controller_action')
->defaultNull()
->info('the method name to call in the controller. Will be set to the concatenation ' .
->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 ' .
->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()
@@ -238,8 +239,8 @@ class Configuration implements ConfigurationInterface
->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 ' .
->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')

View File

@@ -11,12 +11,10 @@ declare(strict_types=1);
namespace Chill\MainBundle\DependencyInjection;
use Exception;
/**
* Description of MissingBundleException.
*/
class MissingBundleException extends Exception
class MissingBundleException extends \Exception
{
public function __construct($missingBundleName)
{

View File

@@ -11,7 +11,6 @@ declare(strict_types=1);
namespace Chill\MainBundle\DependencyInjection;
use LogicException;
use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Reference;
@@ -21,8 +20,7 @@ class RoleProvidersCompilerPass implements CompilerPassInterface
public function process(ContainerBuilder $container)
{
if (!$container->hasDefinition('chill.main.role_provider')) {
throw new LogicException('service chill.main.role_provider '
. 'is not defined. It is required by RoleProviderCompilerPass');
throw new \LogicException('service chill.main.role_provider is not defined. It is required by RoleProviderCompilerPass');
}
$definition = $container->getDefinition(

View File

@@ -13,20 +13,11 @@ 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\DependencyInjection\Definition;
use Symfony\Component\DependencyInjection\Reference;
use UnexpectedValueException;
use function array_key_exists;
use function count;
use function get_class;
use function in_array;
use function is_array;
/**
* Compile the configurations and inject required service into container.
@@ -63,24 +54,24 @@ abstract class AbstractWidgetsCompilerPass implements CompilerPassInterface
/**
* the key to use to identify widget for a given place.
*/
public const WIDGET_CONFIG_ALIAS = 'widget_alias';
final public const WIDGET_CONFIG_ALIAS = 'widget_alias';
/**
* the key to use to order widget for a given place.
*/
public const WIDGET_CONFIG_ORDER = 'order';
final public const WIDGET_CONFIG_ORDER = 'order';
/**
* The service which will manage the widgets.
*
* @var string
*/
public const WIDGET_MANAGER = 'chill.main.twig.widget';
final public const WIDGET_MANAGER = 'chill.main.twig.widget';
/**
* the method wich register the widget into give service.
*/
public const WIDGET_MANAGER_METHOD_REGISTER = 'addWidget';
final public const WIDGET_MANAGER_METHOD_REGISTER = 'addWidget';
/**
* the key used to collect the alias in the service definition's tag.
@@ -89,46 +80,44 @@ abstract class AbstractWidgetsCompilerPass implements CompilerPassInterface
*
* @var string
*/
public const WIDGET_SERVICE_TAG_ALIAS = 'alias';
final public const WIDGET_SERVICE_TAG_ALIAS = 'alias';
/**
* the value of the `name` key in service definitions's tag.
*
* @var string
*/
public const WIDGET_SERVICE_TAG_NAME = 'chill_widget';
final public const WIDGET_SERVICE_TAG_NAME = 'chill_widget';
/**
* the key used to collect the authorized place in the service definition's tag.
*
* @var string
*/
public const WIDGET_SERVICE_TAG_PLACES = 'place';
final public const WIDGET_SERVICE_TAG_PLACES = 'place';
/**
* cache of ordering by place.
*
* @internal used by function cacheAndGetOrdering
*
* @var array
*/
private $cacheOrdering = [];
private array $cacheOrdering = [];
/**
* @var WidgetFactoryInterface[]
*/
private $widgetFactories;
private ?array $widgetFactories = null;
private $widgetServices = [];
private array $widgetServices = [];
/**
* process the configuration and the container to add the widget available.
*
* @param string $extension the extension of your bundle
* @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,
@@ -136,8 +125,7 @@ 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);
@@ -147,14 +135,7 @@ 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, $extensionClass::class));
}
$this->widgetFactories = $extensionClass->getWidgetFactories();
@@ -170,18 +151,13 @@ abstract class AbstractWidgetsCompilerPass implements CompilerPassInterface
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));
if (!\array_key_exists($alias, $this->widgetServices)) {
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',
$alias,
$place
));
throw new InvalidConfigurationException(sprintf('The widget with alias %s is not allowed at place %s', $alias, $place));
}
// get the order, eventually corrected
@@ -244,23 +220,17 @@ abstract class AbstractWidgetsCompilerPass implements CompilerPassInterface
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);
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
));
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]);
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
@@ -275,29 +245,21 @@ abstract class AbstractWidgetsCompilerPass implements CompilerPassInterface
// check the alias is not empty
if (empty($alias)) {
throw new LogicException(sprintf(
'the widget factory %s returns an empty alias',
get_class($factory)
));
throw new \LogicException(sprintf('the widget factory %s returns an empty alias', $factory::class));
}
// 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 (!\is_array($factory->getAllowedPlaces())) {
throw new \UnexpectedValueException("the method 'getAllowedPlaces' ".'should return a non-empty array. Unexpected value on '.$factory::class);
}
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()');
if (0 === \count($factory->getAllowedPlaces())) {
throw new \LengthException("The method 'getAllowedPlaces' should ".'return a non-empty array, but returned 0 elements on '.$factory::class.'::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);
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
@@ -309,7 +271,7 @@ abstract class AbstractWidgetsCompilerPass implements CompilerPassInterface
* register the service into container.
*
* @param string $place
* @param float $order
* @param float $order
*
* @return string the id of the new service
*/
@@ -340,14 +302,14 @@ abstract class AbstractWidgetsCompilerPass implements CompilerPassInterface
* recursive method.
*
* @param string $place
* @param float $ordering
* @param float $ordering
*
* @return float
*/
private function cacheAndGetOrdering($place, $ordering)
{
// create a key in the cache array if not exists
if (!array_key_exists($place, $this->cacheOrdering)) {
if (!\array_key_exists($place, $this->cacheOrdering)) {
$this->cacheOrdering[$place] = [];
}
@@ -365,16 +327,13 @@ abstract class AbstractWidgetsCompilerPass implements CompilerPassInterface
/**
* get the places where the service is allowed.
*
* @param mixed $place
* @param mixed $widgetAlias
*
* @return unknown
*/
private function isPlaceAllowedForWidget($place, $widgetAlias, ContainerBuilder $container)
private function isPlaceAllowedForWidget(mixed $place, mixed $widgetAlias, ContainerBuilder $container)
{
if ($this->widgetServices[$widgetAlias] instanceof WidgetFactoryInterface) {
if (
in_array($place, $this->widgetServices[$widgetAlias]
\in_array($place, $this->widgetServices[$widgetAlias]
->getAllowedPlaces(), true)
) {
return true;

View File

@@ -16,10 +16,6 @@ use Generator;
use Symfony\Component\Config\Definition\Builder\TreeBuilder;
use Symfony\Component\Config\Definition\Exception\InvalidConfigurationException;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use function array_key_exists;
use function count;
use function implode;
use function in_array;
/**
* This trait allow to add automatic configuration for widget inside your config.
@@ -141,10 +137,10 @@ trait AddWidgetConfigurationTrait
$treeBuilder = new TreeBuilder($place);
$root = $treeBuilder->getRootNode()
->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) {
if (0 === \count(iterator_to_array($this->filterWidgetByPlace($place)))) {
return $root;
}
@@ -162,8 +158,8 @@ trait AddWidgetConfigurationTrait
// 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)))
.'Possible values are (maybe incomplete) : '.
\implode(', ', $this->getWidgetAliasesbyPlace($place, $containerBuilder)))
->isRequired()
->end();
@@ -188,12 +184,12 @@ trait AddWidgetConfigurationTrait
*
* @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) {
if (in_array($place, $factory->getAllowedPlaces(), true)) {
if (\in_array($place, $factory->getAllowedPlaces(), true)) {
yield $factory;
}
}
@@ -209,9 +205,9 @@ trait AddWidgetConfigurationTrait
*
* @param type $place
*
* @throws InvalidConfigurationException if a service's tag does not have the "alias" key
*
* @return array
*
* @throws InvalidConfigurationException if a service's tag does not have the "alias" key
*/
protected function getWidgetAliasesbyPlace($place, ContainerBuilder $containerBuilder)
{
@@ -223,16 +219,11 @@ trait AddWidgetConfigurationTrait
// append the aliases added without factory
foreach ($containerBuilder
->findTaggedServiceIds(WidgetsCompilerPass::WIDGET_SERVICE_TAG_NAME)
as $serviceId => $tags) {
->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
));
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];

View File

@@ -72,7 +72,7 @@ interface WidgetFactoryInterface
* return the service id to build the widget.
*
* @param string $place
* @param float $order
* @param float $order
*
* @return string the service definition
*/

View File

@@ -12,15 +12,14 @@ declare(strict_types=1);
namespace Chill\MainBundle\Doctrine\DQL;
use Doctrine\ORM\Query\AST\Functions\FunctionNode;
use Doctrine\ORM\Query\Lexer;
use Doctrine\ORM\Query\Parser;
use Doctrine\ORM\Query\SqlWalker;
class Age extends FunctionNode
{
private $value1;
private mixed $value1 = null;
private $value2;
private mixed $value2 = null;
public function getSql(SqlWalker $sqlWalker)
{
@@ -40,15 +39,15 @@ class Age extends FunctionNode
public function parse(Parser $parser)
{
$parser->match(Lexer::T_IDENTIFIER);
$parser->match(Lexer::T_OPEN_PARENTHESIS);
$parser->match(\Doctrine\ORM\Query\TokenType::T_IDENTIFIER);
$parser->match(\Doctrine\ORM\Query\TokenType::T_OPEN_PARENTHESIS);
$this->value1 = $parser->SimpleArithmeticExpression();
$parser->match(Lexer::T_COMMA);
$parser->match(\Doctrine\ORM\Query\TokenType::T_COMMA);
$this->value2 = $parser->SimpleArithmeticExpression();
$parser->match(Lexer::T_CLOSE_PARENTHESIS);
$parser->match(\Doctrine\ORM\Query\TokenType::T_CLOSE_PARENTHESIS);
}
}

View File

@@ -14,7 +14,6 @@ namespace Chill\MainBundle\Doctrine\DQL;
use Doctrine\ORM\Query\AST\Functions\DateDiffFunction;
use Doctrine\ORM\Query\AST\Functions\FunctionNode;
use Doctrine\ORM\Query\AST\PathExpression;
use Doctrine\ORM\Query\Lexer;
use Doctrine\ORM\Query\Parser;
use Doctrine\ORM\Query\SqlWalker;
@@ -29,10 +28,10 @@ class Extract extends FunctionNode
{
private string $field;
private $value;
//private PathExpression $value;
//private FunctionNode $value;
//private DateDiffFunction $value;
private \Doctrine\ORM\Query\AST\Node|string|null $value = null;
// private PathExpression $value;
// private FunctionNode $value;
// private DateDiffFunction $value;
public function getSql(SqlWalker $sqlWalker)
{
@@ -45,17 +44,17 @@ class Extract extends FunctionNode
public function parse(Parser $parser)
{
$parser->match(Lexer::T_IDENTIFIER);
$parser->match(Lexer::T_OPEN_PARENTHESIS);
$parser->match(\Doctrine\ORM\Query\TokenType::T_IDENTIFIER);
$parser->match(\Doctrine\ORM\Query\TokenType::T_OPEN_PARENTHESIS);
$parser->match(Lexer::T_IDENTIFIER);
$parser->match(\Doctrine\ORM\Query\TokenType::T_IDENTIFIER);
$this->field = $parser->getLexer()->token['value'];
$parser->match(Lexer::T_FROM);
$parser->match(\Doctrine\ORM\Query\TokenType::T_FROM);
//$this->value = $parser->ScalarExpression();
// $this->value = $parser->ScalarExpression();
$this->value = $parser->ArithmeticPrimary();
$parser->match(Lexer::T_CLOSE_PARENTHESIS);
$parser->match(\Doctrine\ORM\Query\TokenType::T_CLOSE_PARENTHESIS);
}
}

View File

@@ -12,15 +12,14 @@ declare(strict_types=1);
namespace Chill\MainBundle\Doctrine\DQL;
use Doctrine\ORM\Query\AST\Functions\FunctionNode;
use Doctrine\ORM\Query\Lexer;
use Doctrine\ORM\Query\Parser;
use Doctrine\ORM\Query\SqlWalker;
class GetJsonFieldByKey extends FunctionNode
{
private $expr1;
private ?\Doctrine\ORM\Query\AST\Node $expr1 = null;
private $expr2;
private ?\Doctrine\ORM\Query\AST\Node $expr2 = null;
public function getSql(SqlWalker $sqlWalker)
{
@@ -33,11 +32,11 @@ class GetJsonFieldByKey extends FunctionNode
public function parse(Parser $parser)
{
$parser->match(Lexer::T_IDENTIFIER);
$parser->match(Lexer::T_OPEN_PARENTHESIS);
$parser->match(\Doctrine\ORM\Query\TokenType::T_IDENTIFIER);
$parser->match(\Doctrine\ORM\Query\TokenType::T_OPEN_PARENTHESIS);
$this->expr1 = $parser->StringPrimary();
$parser->match(Lexer::T_COMMA);
$parser->match(\Doctrine\ORM\Query\TokenType::T_COMMA);
$this->expr2 = $parser->StringPrimary();
$parser->match(Lexer::T_CLOSE_PARENTHESIS);
$parser->match(\Doctrine\ORM\Query\TokenType::T_CLOSE_PARENTHESIS);
}
}

View File

@@ -13,7 +13,6 @@ namespace Chill\MainBundle\Doctrine\DQL;
use Doctrine\ORM\Query\AST\Functions\FunctionNode;
use Doctrine\ORM\Query\AST\Node;
use Doctrine\ORM\Query\Lexer;
use Doctrine\ORM\Query\Parser;
use Doctrine\ORM\Query\SqlWalker;
@@ -33,7 +32,7 @@ class Greatest extends FunctionNode
public function getSql(SqlWalker $sqlWalker)
{
return 'GREATEST(' . implode(', ', array_map(static fn (Node $expr) => $expr->dispatch($sqlWalker), $this->exprs)) . ')';
return 'GREATEST('.implode(', ', array_map(static fn (Node $expr) => $expr->dispatch($sqlWalker), $this->exprs)).')';
}
public function parse(Parser $parser)
@@ -41,15 +40,15 @@ class Greatest extends FunctionNode
$this->exprs = [];
$lexer = $parser->getLexer();
$parser->match(Lexer::T_IDENTIFIER);
$parser->match(Lexer::T_OPEN_PARENTHESIS);
$parser->match(\Doctrine\ORM\Query\TokenType::T_IDENTIFIER);
$parser->match(\Doctrine\ORM\Query\TokenType::T_OPEN_PARENTHESIS);
$this->exprs[] = $parser->ArithmeticPrimary();
while (Lexer::T_COMMA === $lexer->lookahead['type']) {
$parser->match(Lexer::T_COMMA);
while (\Doctrine\ORM\Query\TokenType::T_COMMA === $lexer->lookahead['type']) {
$parser->match(\Doctrine\ORM\Query\TokenType::T_COMMA);
$this->exprs[] = $parser->ArithmeticPrimary();
}
$parser->match(Lexer::T_CLOSE_PARENTHESIS);
$parser->match(\Doctrine\ORM\Query\TokenType::T_CLOSE_PARENTHESIS);
}
}

View File

@@ -12,7 +12,6 @@ declare(strict_types=1);
namespace Chill\MainBundle\Doctrine\DQL;
use Doctrine\ORM\Query\AST\Functions\FunctionNode;
use Doctrine\ORM\Query\Lexer;
use Doctrine\ORM\Query\Parser;
use Doctrine\ORM\Query\SqlWalker;
@@ -24,7 +23,7 @@ use Doctrine\ORM\Query\SqlWalker;
*/
class JsonAggregate extends FunctionNode
{
private $expr;
private ?\Doctrine\ORM\Query\AST\Node $expr = null;
public function getSql(SqlWalker $sqlWalker)
{
@@ -33,9 +32,9 @@ class JsonAggregate extends FunctionNode
public function parse(Parser $parser)
{
$parser->match(Lexer::T_IDENTIFIER);
$parser->match(Lexer::T_OPEN_PARENTHESIS);
$parser->match(\Doctrine\ORM\Query\TokenType::T_IDENTIFIER);
$parser->match(\Doctrine\ORM\Query\TokenType::T_OPEN_PARENTHESIS);
$this->expr = $parser->StringPrimary();
$parser->match(Lexer::T_CLOSE_PARENTHESIS);
$parser->match(\Doctrine\ORM\Query\TokenType::T_CLOSE_PARENTHESIS);
}
}

View File

@@ -0,0 +1,52 @@
<?php
declare(strict_types=1);
/*
* 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;
use Doctrine\ORM\Query\AST\Node;
use Doctrine\ORM\Query\Parser;
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.
*/
class JsonBuildObject extends FunctionNode
{
/**
* @var array|Node[]
*/
private array $exprs = [];
public function getSql(SqlWalker $sqlWalker)
{
return 'JSONB_BUILD_OBJECT('.implode(', ', array_map(static fn (Node $expr) => $expr->dispatch($sqlWalker), $this->exprs)).')';
}
public function parse(Parser $parser)
{
$lexer = $parser->getLexer();
$parser->match(\Doctrine\ORM\Query\TokenType::T_IDENTIFIER);
$parser->match(\Doctrine\ORM\Query\TokenType::T_OPEN_PARENTHESIS);
$this->exprs[] = $parser->ArithmeticPrimary();
while (\Doctrine\ORM\Query\TokenType::T_COMMA === $lexer->lookahead['type']) {
$parser->match(\Doctrine\ORM\Query\TokenType::T_COMMA);
$this->exprs[] = $parser->ArithmeticPrimary();
}
$parser->match(\Doctrine\ORM\Query\TokenType::T_CLOSE_PARENTHESIS);
}
}

View File

@@ -12,15 +12,14 @@ declare(strict_types=1);
namespace Chill\MainBundle\Doctrine\DQL;
use Doctrine\ORM\Query\AST\Functions\FunctionNode;
use Doctrine\ORM\Query\Lexer;
use Doctrine\ORM\Query\Parser;
use Doctrine\ORM\Query\SqlWalker;
class JsonExtract extends FunctionNode
{
private $element;
private \Doctrine\ORM\Query\AST\Node|string|null $element = null;
private $keyToExtract;
private ?\Doctrine\ORM\Query\AST\ArithmeticExpression $keyToExtract = null;
public function getSql(SqlWalker $sqlWalker)
{
@@ -29,15 +28,15 @@ class JsonExtract extends FunctionNode
public function parse(Parser $parser)
{
$parser->match(Lexer::T_IDENTIFIER);
$parser->match(Lexer::T_OPEN_PARENTHESIS);
$parser->match(\Doctrine\ORM\Query\TokenType::T_IDENTIFIER);
$parser->match(\Doctrine\ORM\Query\TokenType::T_OPEN_PARENTHESIS);
$this->element = $parser->ArithmeticPrimary();
$parser->match(Lexer::T_COMMA);
$parser->match(\Doctrine\ORM\Query\TokenType::T_COMMA);
$this->keyToExtract = $parser->ArithmeticExpression();
$parser->match(Lexer::T_CLOSE_PARENTHESIS);
$parser->match(\Doctrine\ORM\Query\TokenType::T_CLOSE_PARENTHESIS);
}
}

View File

@@ -12,7 +12,6 @@ declare(strict_types=1);
namespace Chill\MainBundle\Doctrine\DQL;
use Doctrine\ORM\Query\AST\Functions\FunctionNode;
use Doctrine\ORM\Query\Lexer;
use Doctrine\ORM\Query\Parser;
use Doctrine\ORM\Query\SqlWalker;
@@ -21,7 +20,7 @@ use Doctrine\ORM\Query\SqlWalker;
*/
class JsonbArrayLength extends FunctionNode
{
private $expr1;
private ?\Doctrine\ORM\Query\AST\Node $expr1 = null;
public function getSql(SqlWalker $sqlWalker): string
{
@@ -33,9 +32,9 @@ class JsonbArrayLength extends FunctionNode
public function parse(Parser $parser): void
{
$parser->match(Lexer::T_IDENTIFIER);
$parser->match(Lexer::T_OPEN_PARENTHESIS);
$parser->match(\Doctrine\ORM\Query\TokenType::T_IDENTIFIER);
$parser->match(\Doctrine\ORM\Query\TokenType::T_OPEN_PARENTHESIS);
$this->expr1 = $parser->StringPrimary();
$parser->match(Lexer::T_CLOSE_PARENTHESIS);
$parser->match(\Doctrine\ORM\Query\TokenType::T_CLOSE_PARENTHESIS);
}
}

View File

@@ -12,15 +12,14 @@ declare(strict_types=1);
namespace Chill\MainBundle\Doctrine\DQL;
use Doctrine\ORM\Query\AST\Functions\FunctionNode;
use Doctrine\ORM\Query\Lexer;
use Doctrine\ORM\Query\Parser;
use Doctrine\ORM\Query\SqlWalker;
class JsonbExistsInArray extends FunctionNode
{
private $expr1;
private ?\Doctrine\ORM\Query\AST\Node $expr1 = null;
private $expr2;
private ?\Doctrine\ORM\Query\AST\InputParameter $expr2 = null;
public function getSql(SqlWalker $sqlWalker): string
{
@@ -33,11 +32,11 @@ class JsonbExistsInArray extends FunctionNode
public function parse(Parser $parser): void
{
$parser->match(Lexer::T_IDENTIFIER);
$parser->match(Lexer::T_OPEN_PARENTHESIS);
$parser->match(\Doctrine\ORM\Query\TokenType::T_IDENTIFIER);
$parser->match(\Doctrine\ORM\Query\TokenType::T_OPEN_PARENTHESIS);
$this->expr1 = $parser->StringPrimary();
$parser->match(Lexer::T_COMMA);
$parser->match(\Doctrine\ORM\Query\TokenType::T_COMMA);
$this->expr2 = $parser->InputParameter();
$parser->match(Lexer::T_CLOSE_PARENTHESIS);
$parser->match(\Doctrine\ORM\Query\TokenType::T_CLOSE_PARENTHESIS);
}
}

View File

@@ -13,7 +13,6 @@ namespace Chill\MainBundle\Doctrine\DQL;
use Doctrine\ORM\Query\AST\Functions\FunctionNode;
use Doctrine\ORM\Query\AST\Node;
use Doctrine\ORM\Query\Lexer;
use Doctrine\ORM\Query\Parser;
use Doctrine\ORM\Query\SqlWalker;
@@ -33,7 +32,7 @@ class Least extends FunctionNode
public function getSql(SqlWalker $sqlWalker)
{
return 'LEAST(' . implode(', ', array_map(static fn (Node $expr) => $expr->dispatch($sqlWalker), $this->exprs)) . ')';
return 'LEAST('.implode(', ', array_map(static fn (Node $expr) => $expr->dispatch($sqlWalker), $this->exprs)).')';
}
public function parse(Parser $parser)
@@ -41,15 +40,15 @@ class Least extends FunctionNode
$this->exprs = [];
$lexer = $parser->getLexer();
$parser->match(Lexer::T_IDENTIFIER);
$parser->match(Lexer::T_OPEN_PARENTHESIS);
$parser->match(\Doctrine\ORM\Query\TokenType::T_IDENTIFIER);
$parser->match(\Doctrine\ORM\Query\TokenType::T_OPEN_PARENTHESIS);
$this->exprs[] = $parser->ArithmeticPrimary();
while (Lexer::T_COMMA === $lexer->lookahead['type']) {
$parser->match(Lexer::T_COMMA);
while (\Doctrine\ORM\Query\TokenType::T_COMMA === $lexer->lookahead['type']) {
$parser->match(\Doctrine\ORM\Query\TokenType::T_COMMA);
$this->exprs[] = $parser->ArithmeticPrimary();
}
$parser->match(Lexer::T_CLOSE_PARENTHESIS);
$parser->match(\Doctrine\ORM\Query\TokenType::T_CLOSE_PARENTHESIS);
}
}

View File

@@ -13,9 +13,7 @@ namespace Chill\MainBundle\Doctrine\DQL;
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.
@@ -25,13 +23,13 @@ use Exception;
*/
class OverlapsI extends FunctionNode
{
private $firstPeriodEnd;
private ?\Doctrine\ORM\Query\AST\Node $firstPeriodEnd = null;
private $firstPeriodStart;
private ?\Doctrine\ORM\Query\AST\Node $firstPeriodStart = null;
private $secondPeriodEnd;
private ?\Doctrine\ORM\Query\AST\Node $secondPeriodEnd = null;
private $secondPeriodStart;
private ?\Doctrine\ORM\Query\AST\Node $secondPeriodStart = null;
public function getSql(\Doctrine\ORM\Query\SqlWalker $sqlWalker)
{
@@ -46,47 +44,38 @@ class OverlapsI extends FunctionNode
public function parse(Parser $parser): void
{
$parser->match(Lexer::T_IDENTIFIER);
$parser->match(\Doctrine\ORM\Query\TokenType::T_IDENTIFIER);
$parser->match(Lexer::T_OPEN_PARENTHESIS);
$parser->match(\Doctrine\ORM\Query\TokenType::T_OPEN_PARENTHESIS);
$this->firstPeriodStart = $parser->StringPrimary();
$parser->match(Lexer::T_COMMA);
$parser->match(\Doctrine\ORM\Query\TokenType::T_COMMA);
$this->firstPeriodEnd = $parser->StringPrimary();
$parser->match(Lexer::T_CLOSE_PARENTHESIS);
$parser->match(\Doctrine\ORM\Query\TokenType::T_CLOSE_PARENTHESIS);
$parser->match(Lexer::T_COMMA);
$parser->match(\Doctrine\ORM\Query\TokenType::T_COMMA);
$parser->match(Lexer::T_OPEN_PARENTHESIS);
$parser->match(\Doctrine\ORM\Query\TokenType::T_OPEN_PARENTHESIS);
$this->secondPeriodStart = $parser->StringPrimary();
$parser->match(Lexer::T_COMMA);
$parser->match(\Doctrine\ORM\Query\TokenType::T_COMMA);
$this->secondPeriodEnd = $parser->StringPrimary();
$parser->match(Lexer::T_CLOSE_PARENTHESIS);
$parser->match(\Doctrine\ORM\Query\TokenType::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.');
}
$p = match ($position) {
'start' => '-infinity',
'end' => 'infinity',
default => throw new \Exception('Unexpected position value.'),
};
if ($part instanceof PathExpression) {
return sprintf(

View File

@@ -12,7 +12,6 @@ declare(strict_types=1);
namespace Chill\MainBundle\Doctrine\DQL;
use Doctrine\ORM\Query\AST\Functions\FunctionNode;
use Doctrine\ORM\Query\Lexer;
class Replace extends FunctionNode
{
@@ -24,30 +23,30 @@ class Replace extends FunctionNode
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).
')';
}
public function parse(\Doctrine\ORM\Query\Parser $parser): void
{
$parser->match(Lexer::T_IDENTIFIER);
$parser->match(Lexer::T_OPEN_PARENTHESIS);
$parser->match(\Doctrine\ORM\Query\TokenType::T_IDENTIFIER);
$parser->match(\Doctrine\ORM\Query\TokenType::T_OPEN_PARENTHESIS);
$this->string = $parser->StringPrimary();
$parser->match(Lexer::T_COMMA);
$parser->match(\Doctrine\ORM\Query\TokenType::T_COMMA);
$this->from = $parser->StringPrimary();
$parser->match(Lexer::T_COMMA);
$parser->match(\Doctrine\ORM\Query\TokenType::T_COMMA);
$this->to = $parser->StringPrimary();
$parser->match(Lexer::T_CLOSE_PARENTHESIS);
$parser->match(\Doctrine\ORM\Query\TokenType::T_CLOSE_PARENTHESIS);
}
}

View File

@@ -12,34 +12,33 @@ declare(strict_types=1);
namespace Chill\MainBundle\Doctrine\DQL;
use Doctrine\ORM\Query\AST\Functions\FunctionNode;
use Doctrine\ORM\Query\Lexer;
/**
* Geometry function 'ST_CONTAINS', added by postgis.
*/
class STContains extends FunctionNode
{
private $firstPart;
private ?\Doctrine\ORM\Query\AST\Node $firstPart = null;
private $secondPart;
private ?\Doctrine\ORM\Query\AST\Node $secondPart = null;
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)
{
$parser->match(Lexer::T_IDENTIFIER);
$parser->match(Lexer::T_OPEN_PARENTHESIS);
$parser->match(\Doctrine\ORM\Query\TokenType::T_IDENTIFIER);
$parser->match(\Doctrine\ORM\Query\TokenType::T_OPEN_PARENTHESIS);
$this->firstPart = $parser->StringPrimary();
$parser->match(Lexer::T_COMMA);
$parser->match(\Doctrine\ORM\Query\TokenType::T_COMMA);
$this->secondPart = $parser->StringPrimary();
$parser->match(Lexer::T_CLOSE_PARENTHESIS);
$parser->match(\Doctrine\ORM\Query\TokenType::T_CLOSE_PARENTHESIS);
}
}

View File

@@ -12,13 +12,12 @@ declare(strict_types=1);
namespace Chill\MainBundle\Doctrine\DQL;
use Doctrine\ORM\Query\AST\Functions\FunctionNode;
use Doctrine\ORM\Query\Lexer;
use Doctrine\ORM\Query\Parser;
use Doctrine\ORM\Query\SqlWalker;
class STX extends FunctionNode
{
private $field;
private ?\Doctrine\ORM\Query\AST\ArithmeticExpression $field = null;
public function getSql(SqlWalker $sqlWalker)
{
@@ -27,11 +26,11 @@ class STX extends FunctionNode
public function parse(Parser $parser)
{
$parser->match(Lexer::T_IDENTIFIER);
$parser->match(Lexer::T_OPEN_PARENTHESIS);
$parser->match(\Doctrine\ORM\Query\TokenType::T_IDENTIFIER);
$parser->match(\Doctrine\ORM\Query\TokenType::T_OPEN_PARENTHESIS);
$this->field = $parser->ArithmeticExpression();
$parser->match(Lexer::T_CLOSE_PARENTHESIS);
$parser->match(\Doctrine\ORM\Query\TokenType::T_CLOSE_PARENTHESIS);
}
}

View File

@@ -12,13 +12,12 @@ declare(strict_types=1);
namespace Chill\MainBundle\Doctrine\DQL;
use Doctrine\ORM\Query\AST\Functions\FunctionNode;
use Doctrine\ORM\Query\Lexer;
use Doctrine\ORM\Query\Parser;
use Doctrine\ORM\Query\SqlWalker;
class STY extends FunctionNode
{
private $field;
private ?\Doctrine\ORM\Query\AST\ArithmeticExpression $field = null;
public function getSql(SqlWalker $sqlWalker)
{
@@ -27,11 +26,11 @@ class STY extends FunctionNode
public function parse(Parser $parser)
{
$parser->match(Lexer::T_IDENTIFIER);
$parser->match(Lexer::T_OPEN_PARENTHESIS);
$parser->match(\Doctrine\ORM\Query\TokenType::T_IDENTIFIER);
$parser->match(\Doctrine\ORM\Query\TokenType::T_OPEN_PARENTHESIS);
$this->field = $parser->ArithmeticExpression();
$parser->match(Lexer::T_CLOSE_PARENTHESIS);
$parser->match(\Doctrine\ORM\Query\TokenType::T_CLOSE_PARENTHESIS);
}
}

View File

@@ -12,31 +12,30 @@ declare(strict_types=1);
namespace Chill\MainBundle\Doctrine\DQL;
use Doctrine\ORM\Query\AST\Functions\FunctionNode;
use Doctrine\ORM\Query\Lexer;
class Similarity extends FunctionNode
{
private $firstPart;
private ?\Doctrine\ORM\Query\AST\Node $firstPart = null;
private $secondPart;
private ?\Doctrine\ORM\Query\AST\Node $secondPart = null;
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)
{
$parser->match(Lexer::T_IDENTIFIER);
$parser->match(Lexer::T_OPEN_PARENTHESIS);
$parser->match(\Doctrine\ORM\Query\TokenType::T_IDENTIFIER);
$parser->match(\Doctrine\ORM\Query\TokenType::T_OPEN_PARENTHESIS);
$this->firstPart = $parser->StringPrimary();
$parser->match(Lexer::T_COMMA);
$parser->match(\Doctrine\ORM\Query\TokenType::T_COMMA);
$this->secondPart = $parser->StringPrimary();
$parser->match(Lexer::T_CLOSE_PARENTHESIS);
$parser->match(\Doctrine\ORM\Query\TokenType::T_CLOSE_PARENTHESIS);
}
}

View File

@@ -11,33 +11,32 @@ declare(strict_types=1);
namespace Chill\MainBundle\Doctrine\DQL;
use Doctrine\ORM\Query\Lexer;
use Doctrine\ORM\Query\Parser;
use Doctrine\ORM\Query\SqlWalker;
class StrictWordSimilarityOPS extends \Doctrine\ORM\Query\AST\Functions\FunctionNode
{
private $firstPart;
private ?\Doctrine\ORM\Query\AST\Node $firstPart = null;
private $secondPart;
private ?\Doctrine\ORM\Query\AST\Node $secondPart = null;
public function getSql(SqlWalker $sqlWalker)
{
return $this->firstPart->dispatch($sqlWalker) .
' <<% ' . $this->secondPart->dispatch($sqlWalker);
return $this->firstPart->dispatch($sqlWalker).
' <<% '.$this->secondPart->dispatch($sqlWalker);
}
public function parse(Parser $parser)
{
$parser->match(Lexer::T_IDENTIFIER);
$parser->match(Lexer::T_OPEN_PARENTHESIS);
$parser->match(\Doctrine\ORM\Query\TokenType::T_IDENTIFIER);
$parser->match(\Doctrine\ORM\Query\TokenType::T_OPEN_PARENTHESIS);
$this->firstPart = $parser->StringPrimary();
$parser->match(Lexer::T_COMMA);
$parser->match(\Doctrine\ORM\Query\TokenType::T_COMMA);
$this->secondPart = $parser->StringPrimary();
$parser->match(Lexer::T_CLOSE_PARENTHESIS);
$parser->match(\Doctrine\ORM\Query\TokenType::T_CLOSE_PARENTHESIS);
}
}

View File

@@ -12,7 +12,6 @@ declare(strict_types=1);
namespace Chill\MainBundle\Doctrine\DQL;
use Doctrine\ORM\Query\AST\Functions\FunctionNode;
use Doctrine\ORM\Query\Lexer;
use Doctrine\ORM\Query\Parser;
use Doctrine\ORM\Query\SqlWalker;
@@ -21,9 +20,9 @@ use Doctrine\ORM\Query\SqlWalker;
*/
class ToChar extends FunctionNode
{
private $datetime;
private ?\Doctrine\ORM\Query\AST\ArithmeticExpression $datetime = null;
private $fmt;
private \Doctrine\ORM\Query\AST\Node|string|null $fmt = null;
public function getSql(SqlWalker $sqlWalker)
{
@@ -36,11 +35,11 @@ class ToChar extends FunctionNode
public function parse(Parser $parser)
{
$parser->match(Lexer::T_IDENTIFIER);
$parser->match(Lexer::T_OPEN_PARENTHESIS);
$parser->match(\Doctrine\ORM\Query\TokenType::T_IDENTIFIER);
$parser->match(\Doctrine\ORM\Query\TokenType::T_OPEN_PARENTHESIS);
$this->datetime = $parser->ArithmeticExpression();
$parser->match(Lexer::T_COMMA);
$parser->match(\Doctrine\ORM\Query\TokenType::T_COMMA);
$this->fmt = $parser->StringExpression();
$parser->match(Lexer::T_CLOSE_PARENTHESIS);
$parser->match(\Doctrine\ORM\Query\TokenType::T_CLOSE_PARENTHESIS);
}
}

View File

@@ -12,7 +12,6 @@ declare(strict_types=1);
namespace Chill\MainBundle\Doctrine\DQL;
use Doctrine\ORM\Query\AST\Functions\FunctionNode;
use Doctrine\ORM\Query\Lexer;
/**
* Unaccent string using postgresql extension unaccent :
@@ -22,20 +21,20 @@ use Doctrine\ORM\Query\Lexer;
*/
class Unaccent extends FunctionNode
{
private $string;
private ?\Doctrine\ORM\Query\AST\Node $string = null;
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);
$parser->match(\Doctrine\ORM\Query\TokenType::T_IDENTIFIER);
$parser->match(\Doctrine\ORM\Query\TokenType::T_OPEN_PARENTHESIS);
$this->string = $parser->StringPrimary();
$parser->match(Lexer::T_CLOSE_PARENTHESIS);
$parser->match(\Doctrine\ORM\Query\TokenType::T_CLOSE_PARENTHESIS);
}
}

View File

@@ -14,7 +14,6 @@ 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;
@@ -22,11 +21,8 @@ use Symfony\Component\Security\Core\Security;
class TrackCreateUpdateSubscriber implements EventSubscriber
{
private Security $security;
public function __construct(Security $security)
public function __construct(private readonly Security $security)
{
$this->security = $security;
}
public function getSubscribedEvents()
@@ -42,7 +38,7 @@ class TrackCreateUpdateSubscriber implements EventSubscriber
$object = $args->getObject();
if ($object instanceof TrackCreationInterface) {
$object->setCreatedAt(new DateTimeImmutable('now'));
$object->setCreatedAt(new \DateTimeImmutable('now'));
if ($this->security->getUser() instanceof User) {
$object->setCreatedBy($this->security->getUser());
@@ -62,7 +58,7 @@ class TrackCreateUpdateSubscriber implements EventSubscriber
protected function onUpdate(object $object): void
{
if ($object instanceof TrackUpdateInterface) {
$object->setUpdatedAt(new DateTimeImmutable('now'));
$object->setUpdatedAt(new \DateTimeImmutable('now'));
if ($this->security->getUser() instanceof User) {
$object->setUpdatedBy($this->security->getUser());

View File

@@ -14,9 +14,6 @@ namespace Chill\MainBundle\Doctrine\Migrations;
use Doctrine\Migrations\Version\Comparator;
use Doctrine\Migrations\Version\Version;
use function explode;
use function strcmp;
/**
* Compare Version classes names from different namespaces and order them.
*
@@ -26,12 +23,12 @@ final class VersionComparator implements Comparator
{
public function compare(Version $a, Version $b): int
{
return strcmp($this->getNumber($a), $this->getNumber($b));
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);
}

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