Core: One resource can have multiple input/output class for per operactions

Created on 26 Mar 2019  路  9Comments  路  Source: api-platform/core

Follow code from document, the code that both messenger component and dto integration work

<?php

// api/src/Entity/User.php

namespace App\Entity;

use ApiPlatform\Core\Annotation\ApiResource;
use App\Dto\ResetPasswordRequest;

/**
 * @ApiResource(
 *     collectionOperations={
 *         "post"={"status"=202}
 *     },
 *     itemOperations={},
 *     messenger=true,
 *     input=ResetPasswordRequest::class,
 *     output=false
 * )
 */
final class User
{
}

but this only work for one input action. if I have ResetPasswordRequest,SMSValidationForRegistration,EmailValidationForRegistration...
,so how I can get multiple input for there owner handler?

Most helpful comment

input and output are supported as operation attributes so it should not be an issue.

All 9 comments

input and output are supported as operation attributes so it should not be an issue.

@antograssiot it's true, but the email which will be send by messenger handle just is a validation code email.I not hope persist the user object to database, unless after the user received email and validated the code,so, how can I solve this problem?

It'll not be persisted if you don't persist it yourself in the messenger handler. indeed, when using messenger=true it replaces the persister by the MessengerDataPersister.

@soyuka yeah,that's right.now my annotation like this:

 *         "post"={
 *             "access_control"="is_granted('user.create',object)",
 *             "access_control_message"="Sorry, you are not a super admin or anonymous."
 *         },
 *         "send_mail_for_registration"={
 *             "method"="post",
 *             "path"="/users/register",
 *             "status"=202,
 *             "messenger"=true,
 *             "output"=false,
 *             "input"="App\Data\TransportObject\Auth\SendRegMailRequest"
 *         }

and message SendRegMailRequest like this

    private $code;
    private $key;
    private $email;
    public function __construct()
    {
        $this->code = Str::random(6);
        $this->key = Str::random(15);
    }

    public function setEmail($email): self
    {
        $this->email = $email;
        return $this;
    }

    public function setMessage(Templating $templating): self
    {
        $this->setTitle("Register for user {$this->email}")
            ->setFrom('[email protected]')
            ->setAddress($this->email)
            ->setBody($templating->render(
                'emails/registration.html.twig',
                [
                    'email' => $this->email,
                    'code' => $this->code
                ]
            ));
        return $this;
    }

but I must type-in a service named @twig to SendRegMailRequest,because email template should be load, in traditional controller it will called like this:

use Twig\Environment as Templating;
public function index(\Swift_Mailer $mailer,Templating $templating)
    {
        $this->bus->dispatch(
            (new SendRegMailRequest())
                ->setEmail('[email protected]')
                ->setMessage($templating)
        );
    }

and in api platform's entity annotation, how to call it?

If you want the SendRegMailRequestto be sent to the messenger handler immediately you can also use messenger="input". The rest looks just fine. I think that you can use a service name instead of the class to use a service but that's out of ApiPlatform's scope.

@soyuka every things is fine, but where I injection the service to the message SendRegMailRequest,or where I called ->setMessage($templating) in api platform like Symfony traditional controller?
in Symfony controller DefaultController,it look likes this:

use Twig\Environment as Templating;
public function index(\Swift_Mailer $mailer,Templating $templating)
    {
        $this->bus->dispatch(
            (new SendRegMailRequest())
                ->setEmail('[email protected]')
                ->setMessage($templating)
        );
    }

but in api platform, how can I call it(->setMessage($templating))?
I call it with a custom controller?or event listener?

Are you using a messenger handler? You could do it in there:

class RegistrationMailMessengerHandler {
    __construct(Templating $templating, Mailer $mailer) {
    ...
  } 

__invoke(SendRegMailRequest $message) {
    $message->setMessage($this->templating) //something like this
}
}

/!\ this is pseudo code !

it may not be a good way.because the method return of getBody is string(not null) from MailerHandleInteface,

/**
     * @return string
     */
    public function getBody(): string;

so,I want to set them(like body,title...) in message,because handler is used to handle something.like save the validate code to cache and send validate email.
If there is no way, custom a controller maybe is the only way锛宨s right?

@soyuka I test a custom controller,it only get User instance but not SendRegMailRequest,so I have to injection the @twig service to handle to let it work fine,thx again your great work

Was this page helpful?
0 / 5 - 0 ratings

Related issues

gustawdaniel picture gustawdaniel  路  3Comments

silverbackdan picture silverbackdan  路  3Comments

theshaunwalker picture theshaunwalker  路  3Comments

desmax picture desmax  路  3Comments

dematerializer picture dematerializer  路  3Comments