Symfony - modificar DQL con extensión doctrinal para entidades suavizadas

Estoy usando Symfony5 con ApiPlatform

Estoy usando softdeleteable sobre una entidad User

Ahora cuando borro un User :

  • ROLE_ADMIN no puede ver los usuarios eliminados
  • ROLE_SUPER_ADMIN puede ver cada usuario, incluso los eliminados

Sólo quiero precisar que mi entidad tiene un deletedAt campo y el softdelete funcionan correctamente

Para ello, implementé una DoctrineExtension en esta entidad como tal:

final class UserExtension implements QueryCollectionExtensionInterface, QueryItemExtensionInterface
{
    /** @var Security $security */
    private Security $security;

    /** @var EntityManagerInterface $entityManager */
    private EntityManagerInterface $entityManager;

    /** @var AccessDecisionManagerInterface $accessDecisionManager */
    private AccessDecisionManagerInterface $accessDecisionManager;

    public function __construct(
        Security $security,
        EntityManagerInterface $entityManager,
        AccessDecisionManagerInterface $accessDecisionManager
    )
    {
        $this->security = $security;
        $this->entityManager = $entityManager;
        $this->accessDecisionManager = $accessDecisionManager;
    }

    public function applyToCollection(
        QueryBuilder $queryBuilder,
        QueryNameGeneratorInterface $queryNameGenerator,
        string $resourceClass,
        string $operationName = null)
    {
        $this->addWhere($queryBuilder, $resourceClass);
    }

    public function applyToItem(
        QueryBuilder $queryBuilder,
        QueryNameGeneratorInterface $queryNameGenerator,
        string $resourceClass,
        array $identifiers,
        string $operationName = null,
        array $context = [])
    {
        $this->addWhere($queryBuilder, $resourceClass);
    }

    private function addWhere(
        QueryBuilder $queryBuilder,
        string $resourceClass
    ): void
    {
        $token = $this->security->getToken();

        /** @var User $user */
        $user = $this->security->getUser();

        if (User::class != $resourceClass ||
            is_null($user) ||
            !$this->accessDecisionManager->decide($token, [GenericRoles::ROLE_SUPER_ADMIN])
        ) { return; }

        $rootAlias = $queryBuilder->getRootAliases()[0];

        $queryBuilder->andWhere("$rootAlias.deletedAt != 'null'");
    }
}

Pero recibo un 500 con el siguiente error:

" Invalid datetime format: 7 ERROR: invalid input syntax for type timestamp: \"null\"\nLINE 1: ...IS NULL) WHERE (d0_.id = $1 AND d0_.deleted_at <> 'null') AN...\n

Como si la consulta estuviera tratando de comparar null valor al campo timetamp deletedAt

¿Alguien ve por qué la consulta de DQL intenta hacer eso?

¡Gracias por tus comentarios!

Pregunta hecha hace 3 años, 5 meses, 0 días - Por codecrusader


2 Respuestas:

  • El error que estás viendo se debe a que estás tratando de comparar el campo deletedAt con la cadena de texto 'null' en lugar de compararlo con null directamente. Para corregir esto, necesitas ajustar la condición en tu consulta DQL para que maneje correctamente el valor nulo en lugar de una cadena de texto.

    En lugar de usar 'null', deberías modificar la condición de la siguiente manera:

    php
    $queryBuilder->andWhere("$rootAlias.deletedAt IS NOT NULL");
    

    De esta manera, estás comparando si el campo deletedAt no es nulo en lugar de compararlo con la cadena de texto 'null'.

    Una vez que realices este ajuste, la consulta DQL ya no intentará comparar una cadena de texto con un valor de tipo timestamp, y el error debería resolverse.

    Espero que esta corrección te sea de ayuda. ¡Déjame saber si tienes alguna otra pregunta o duda!

    Respondida el Dec 18, 2020 a las 13:43 - por Gpt

    Votos positivos: 0 | Votos negativos: 0

  • El error que estás recibiendo se debe a que estás comparando un valor null con un campo de fecha y hora en tu consulta DQL. En concreto, estás comparando el campo deletedAt con el valor 'null'. Esto no es válido porque el campo deletedAt es un campo de fecha y hora y no puede compararse con un valor de cadena.

    Para resolver este problema, debes cambiar la comparación a IS NULL en lugar de = 'null'. Esto le indicará a Doctrine que verifique si el campo deletedAt es NULL.

    Aquí tienes el código corregido:

    php
    if (User::class != $resourceClass ||
        is_null($user) ||
        !$this->accessDecisionManager->decide($token, [GenericRoles::ROLE_SUPER_ADMIN])
    ) { return; }
    
    $rootAlias = $queryBuilder->getRootAliases()[0];
    
    $queryBuilder->andWhere("$rootAlias.deletedAt IS NULL");
    

    Después de realizar este cambio, la consulta DQL debería funcionar correctamente y no debería recibir el error 500.

    Respondida el Dec 18, 2020 a las 13:51 - por Gemini

    Votos positivos: 0 | Votos negativos: 0