Skip to content

Invalid (or unclear to me) handling of data returned from MessageHandler::__invoke() #2550

Closed
@Perf

Description

@Perf

Hello,
it seems handling of data returned from __invoke() method of class that implements MessageHandlerInterface is not correct.

Sending request to /users/password-reset-confirmation.

Expected behavior:
Api platform should return a response object that was returned from __invoke().
In this particular case I'm trying to return JWTAuthenticationSuccessResponse which extends JsonResponse.

Current behavior:

Uncaught PHP Exception Symfony\Component\HttpKernel\Exception\ControllerDoesNotReturnResponseException: "The controller must return a "Symfony\Component\HttpFoundation\Response" object but it returned an object of type App\Dto\User\UserPasswordResetConfirmation." at /srv/vendor/api-platform/core/src/Action/PlaceholderAction.php line 32

DTO class UserPasswordResetConfirmation.php:

namespace App\Dto\User;

use App\Validator as AppAssert;
use Symfony\Component\Validator\Constraints as Assert;

final class UserPasswordResetConfirmation
{
    /**
     * @var string
     * @Assert\NotBlank()
     * @AppAssert\IsHash()
     */
    public $passwordResetToken;
    /**
     * @var string
     * @Assert\NotBlank()
     * @AppAssert\PlainPassword()
     */
    public $plainPassword;
}

API Resource config user_password_reset_confirmation.yaml:

App\Dto\User\UserPasswordResetConfirmation:
    attributes:
        messenger: true
        output: false
    itemOperations: {}
    collectionOperations:
        post:
            access_control: 'is_anonymous()'
            path: '/users/password-reset-confirmation'
            status: 200
            swagger_context:
                tags: ['User']
                summary: 'Confirms and sets new password'
                responses:
                    200:
                        description: 'Successfully set new password, returning a new JWT token'
                        schema:
                            type: 'object'
                            properties:
                                token:
                                    type: 'string'
                                    description: 'JWT authentication token'
                    400:
                        description: 'Invalid input'
                    404:
                        description: 'Resource not found'

Message handler class UserPasswordResetConfirmationHandler.php:

namespace App\Handler;

use App\Dto\User\UserPasswordResetConfirmation;
use App\Event\UserEvent;
use App\Service\User\UserService;
use App\Traits\EventDispatcherable;
use Lexik\Bundle\JWTAuthenticationBundle\Security\Http\Authentication\AuthenticationSuccessHandler;
use Symfony\Component\Messenger\Handler\MessageHandlerInterface;

class UserPasswordResetConfirmationHandler implements MessageHandlerInterface
{
    use EventDispatcherable;

    /**
     * @var UserService
     */
    private $userService;
    /**
     * @var AuthenticationSuccessHandler
     */
    private $authenticationHandler;

    public function __construct(UserService $userService, AuthenticationSuccessHandler $authenticationHandler)
    {
        $this->userService = $userService;
        $this->authenticationHandler = $authenticationHandler;
    }

    public function __invoke(UserPasswordResetConfirmation $dto)
    {
        $user = $this->userService->confirmPasswordReset($dto);
        $this->dispatch(UserEvent::PASSWORD_RESET_CONFIRMED, new UserEvent($user));

        // creating a new JWT token
        $response = $this->authenticationHandler->handleAuthenticationSuccess($user);

        return $response;
    }
}

Debugging showed that event is populated with response object vendor/api-platform/core/src/EventListener/WriteListener.php at lines 60-66:

$persistResult = $this->dataPersister->persist($controllerResult);
//
$event->setControllerResult($persistResult ?? $controllerResult);

but later on somewhere controller result is overwritten with DTO object UserPasswordResetConfirmation, than becomes a cause of an exception.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions