0

I will start saying I am using Symfony 4.3.4 and Api Platform (called AP from now on). Having said that this how my custom controller (used for AP) looks like:

declare(strict_types=1);

namespace App\Controller\CaseWork\Pend;

use App\Request\PendCaseRequest;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\ParamConverter;
use Symfony\Component\Routing\Annotation\Route;

class PendCaseController
{
    /**
     * @Route("/myroute/{id}/pend", name="routeName")
     * @ParamConverter("case", class="App\Entity\Cases")
     */
    public function __invoke(PendCaseRequest $request, int $id)
    {
        // do something with the $request
    }
}

As you may notice I also have a Request Data Transformer Object and here is a code snippet for it:

declare(strict_types=1);

namespace App\Request;

use App\Interfaces\RequestDTOInterface;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\Validator\Constraints as Assert;

class PendCaseRequest implements RequestDTOInterface
{
    /**
     * @var int
     *
     * @Assert\NotBlank()
     * @Assert\NotNull()
     * @Assert\Type("integer")
     */
    private $param;

    public function __construct(Request $request)
    {
        $data = json_decode($request->getContent(), true);
        $this->param = (int) $data['param'];
        // ...
    }
}

It's suppose (as per docs here) that when the request comes in and an id matching a App\Entity\Cases is found a new attribute named case should be append to my $request object but in my scenario is not happening and I am not sure why or what I am missing.

While debugging and setting a break point at this line $this->param = (int) $data['param']; in my DTO, if I print out $this->attributes I got the following output:

‌Symfony\Component\HttpFoundation\ParameterBag::__set_state(array(
   'parameters' => 
  array (
  ),
))

What I am missing here? What is wrong with my approach?

ReynierPM
  • 17,594
  • 53
  • 193
  • 363

1 Answers1

0

I have found a "solution" here. I end up using a Decorator as suggested by the answer on that post.

My main controller changed into this:

declare(strict_types=1);

namespace App\Controller\CaseWork\Pend;

use App\Request\PendCaseRequest;
use App\Entity\Cases;

class PendCaseController
{
    public function __invoke(PendCaseRequest $request, Cases $case)
    {
        // do something with the $request
    }
}

A decorator was created:

declare(strict_types=1);

namespace App\Decorator;

use App\Controller\CaseWork\Pend\PendCaseController;
use Doctrine\ORM\EntityManagerInterface;
use App\Entity\Cases;
use App\Request\PendCaseRequest;

class PendCaseDecorator
{
    /** @var PendCaseController */
    protected $decoratedController;

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

    public function __construct(PendCaseController $controller, EntityManagerInterface $entityManager)
    {
        $this->decoratedController = $controller;
        $this->entityManager = $entityManager;
    }

    public function __invoke(PendCaseRequest $request, int $id)
    {
        $object = $this->entityManager->getRepository(Cases::class)->find($id);
        if (!$object instanceof Cases) {
            throw new NotFoundHttpException('Entity with '.$id.' not found');
        }

        return $this->decoratedController($request, $object);
    }
}

And I had registered it at services.yml:

services:
    App\Controller\CaseWork\Pend\PendCaseController: ~
    App\Decorator\PendCaseDecorator:
        decorates: App\Controller\CaseWork\Pend\PendCaseController

That way I keep using my DTO and pass back a Cases entity object.

ReynierPM
  • 17,594
  • 53
  • 193
  • 363