DTOs (Data Transfer Objects) can be used to either serialize or de-serialize data along with data validation. In PHP Symfony is very easy to build a Json response even if the Data is complex and has several associated Entities.

Prerequisites:

 

 

Have an Action Method to handle the GET Request:

#ApiModule/Controller/CustomersController.php

//...
    /**
     * @Route("/api/v1/customer/{id}", name="getCustomerByIdEndpoint", methods={"GET"}, defaults={"_format": "json"})
     * @param $id
     * @param CustomersService $customersService
     * @return JsonResponse
     */
    public function customerByIdAction($id, CustomersService $customersService)
    {
        $result = $customersService->getCustomerById($id);
        
        return new JsonResponse($result, ErrorCodes::HTTP_200);
    }

//...

Then in the Customers Service Class:

//...

    /**
     * @param int $id
     * @return Customer
     */
    public function getCustomerById(int $id): DTO\Customer
    {
        try {
            $customer = $this->em->getRepository(Customers::class)->find($id);
            $customerTransformer = new CustomerTransformer($customer);
            $apiCustomer = $customerTransformer->transform();
        } catch (\Throwable $e) {
            throw new PreconditionFailedException('Exceptions can be catched here: ' . $e->getMessage());
        }
        
        return $this->apiResponseTransformer->buildOkResponse($apiCustomer);
    }

//...

Then the Customer Transformer:

namespace App\ApiModule\Transformers;

use App\ApiModule\Dtos as DTO;
use App\ApiModule\Entity\Customers;
use JMS\Serializer\Serializer;
use JMS\Serializer\SerializerBuilder;

class CustomerTransformer
{
    /**
     * @var Serializer
     */
    private Serializer $serializer;
    /**
     * @var Customers
     */
    private Customers $customer;
    
    /**
     * @var DTO\Customer
     */
    private DTO\Customer $apiCustomer;
    
    /**
     * @param Customers $customer
     */
    public function __construct(Customers $customer)
    {
        $this->serializer = SerializerBuilder::create()->build();
        $this->customer = $customer;
        $this->apiCustomer = $this->serializer->deserialize($this->getCustomerDtoDataStructure(), 'App\ApiModule\Dtos\Customer', 'json');
    }
    
    public function transform(): DTO\Customer
    {
        if ($this->validate()) {
            $this->apiCustomer->id = $this->customer->getId();
            $this->apiCustomer->firstName = $this->customer->getFirstName();
            $this->apiCustomer->lastName = $this->customer->getLastName();
            $this->apiCustomer->primaryEmail = $this->customer->getPrimaryEmail();
            $this->apiCustomer->phoneNumber = $this->customer->getPhoneNumber();
            $this->apiCustomer->address = $this->customer->getAddress();
            $this->apiCustomer->zipCode->id = $this->customer->getZipCode()->getId();
            $this->apiCustomer->zipCode->zipCode = $this->customer->getZipCode()->getZipCode();
            $this->apiCustomer->zipCode->city->id = $this->customer->getZipCode()->getCities()->getId();
            $this->apiCustomer->zipCode->city->cityName = $this->customer->getZipCode()->getCities()->getCityName();
            $this->apiCustomer->zipCode->city->state->id = $this->customer->getZipCode()->getCities()->getStates()->getId();
            $this->apiCustomer->zipCode->city->state->stateName = $this->customer->getZipCode()->getCities()->getStates()->getStateName();
            $this->apiCustomer->zipCode->city->state->stateShortName = $this->customer->getZipCode()->getCities()->getStates()->getStateShortName();
            $this->apiCustomer->zipCode->city->state->country->id = $this->customer->getZipCode()->getCities()->getStates()->getCountries()->getId();
            $this->apiCustomer->zipCode->city->state->country->countryName = $this->customer->getZipCode()->getCities()->getStates()->getCountries()->getCountryName();
        }
        
        return $this->apiCustomer;
    }
    
    /**
     * @return bool
     */
    private function validate(): bool
    {
        //Apply some custom validation here not handled by the Dto or the Entity
        //
        return true;
    }
    
    /**
     * @return string
     */
    private function getCustomerDtoDataStructure(): string
    {
        return '
            {
                "zipCode":{
                    "city":{
                        "state":{
                            "country":{}
                        }
                    }
                }
            }';
    }
    
}

With this, the Json response will look like:

{
	"id": 4996,
	"firstName": "alexandra",
	"lastName": "mackay",
	"primaryEmail": "This email address is being protected from spambots. You need JavaScript enabled to view it.",
	"phoneNumber": "(003)177-9563x173",
	"address": "925 wilber rapids",
	"zipCode": {
		"id": 2,
		"zipCode": "544",
		"city": {
			"id": 1,
			"cityName": "holtsville",
			"state": {
				"id": 32,
				"stateName": "new york",
				"stateShortName": "NY",
				"country": {
					"id": 1,
					"countryName": "United States"
				}
			}
		}
	}
}

 Notice how easy is to get the Data from the Customer Entity and all its associated ones, then leveraging the functionality of the JMS Serializer, we can instantiate a fully Customer DTO along with all nested ones.

 

Related Videos