Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
DTO example
<?php
namespace SomeApp\Application\DTO;
use Symfony\Component\OptionsResolver\OptionsResolver;
abstract class AbstractRequest
{
public function __construct(array $data)
{
$options = new OptionsResolver();
$this->configureOptions($options);
$this->map($options);
}
abstract protected function configureOptions(OptionsResolver $options);
protected function map(OptionsResolver $options)
{
// just plain mapping, all other things
// like snake case to camel case convertion or keys aliases resolving
// should be done in controller
// values normalization could be done via option resolver's normalizers
$options->resolve($data);
foreach ($options->getDefinedOptions() as $prop) {
$this->$prop = $options[$prop];
}
}
}
<?php
namespace SomeApp\Application\DTO\Something;
use Symfony\Component\OptionsResolver\OptionsResolver;
use SomeApp\Infrastructure\Security\UserSession;
class DoSomethingRequest extends AbstractRequest
{
protected $userSession;
protected $foo;
protected $fooBar;
/**
* @param UserSession $userSession - id of user
* @param array $data - array of options to be resolved
*/
public function __construct(UserSession $userSession, array $data)
{
// this is only for example,
// I usually have UserSession object wich implements UserInterface
// UserSession isn't doctrine entity, it just data container which hydrates from JWT token
// It contains user Id, some other information (isAdmin flag for example) and so on.
$this->userSession = $userSession;
parent::__contruct($data);
}
protected function configureOptions(OptionsResolver $options)
{
$options
->setRequired(['foo', 'bar'])
->setAllowedTypes([
'foo' => 'string',
'fooBar' => ['int', 'string']
])
;
}
public function getUserID()
{
return $this->userSession->getUserID();
}
public function getFoo()
{
return $this->foo;
}
public function getFooBar()
{
return $this->fooBar;
}
}
<?php
class SomethingController extends Controller
{
public function createSomething(Request $request) {
// handled via symfony/serializer in middleware
// or you can map it with jms serializer or just by yourself here in controller
$requestData = $request->request->all();
// create request DTO
$requestDTO = new DoSomethingRequest($this->getUser(), $requestData);
// pass it to application layer, which will return response dto
$responseDTO = $this->get('something_maker')->doStuff($requestDTO);
return $responseDTO; // middleware will serialize it, or we can use JsonResponse and map data to array...
}
}
@sndpl

This comment has been minimized.

Copy link

sndpl commented Jul 12, 2016

nice solution, shouldn't the $this->map($options); in the constructor of the AbstractRequest class also pass the $data in to the map function?

@vaso123

This comment has been minimized.

Copy link

vaso123 commented Mar 8, 2017

I've did not check the whole code, but you can improve your abstract request class.

First, what kind of request is it? A http request? I know, this is for demonstration purpose, but in that case the AbstractSomerRequest could be more luckily.

Based on this: (http://misko.hevery.com/code-reviewers-guide/flaw-constructor-does-real-work/) the constructor of this class should be:

public function __construct(array $data, OptionResolver $options)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.