Symfony2 DTO, Entity conversion

Nik Denisov picture Nik Denisov · May 30, 2014 · Viewed 10.5k times · Source

I'm creating symfony2 application with doctrine2 and I would like to ask for advice regarding common/good practice for DTO-Entity, Entity-DTO conversion. I've found some information for all languages and frameworks, but none for SF2.

I would like to isolate Entities, so they are used only in Services and DAO's (Managers, Repositories in SF2 terminology). Controllers won't ever see DAO's or Entities and will interact with business logic only via Services. All communication between Services and Controllers should be done via primitive types, scalars, DTO's.

Example :

Controller

class RegistrationController extends Controller
{
    public function registerAction($name)
    {
        $userDTO = new UserDTO();
        $form = $this->createForm(new UserType(), $userDTO);

        $form->handleRequest($request);

        if ($form->isValid()) {
            $userService = $this->get('userService');

            $userService->createUser($userDTO);

            return $this->redirect($this->generateUrl('success'));
        }

    --//--
    }
}

Service

class UserServiceImpl implements UserService
{

    private $userDao;

    public function __construct(UserDao $userDao)
    {
        $this->userDao = $userDao;
    }

    public function createUser(UserDTO $user)
    {
        $user = new User(); #doctrine entity
        $user->setFirstName($userDTO->getFirstName());
        $user->setLastName($userDTO->getLastName());

        $this->userDao->persist($user);
        $this->userDao->flush();

        --//--
    }
}

Problem quickly appears with rising amount of properties in User object. In my application User has 13 fields. Are there any SF2 tools (classes) to simplify this process ? Do you write your own convertors / transformers ? Could you please show example of how it should look like ? Maby PHP magic methods could help ? What about reflection ?

Thanks for advices and opinions.

Answer

Cerad picture Cerad · May 30, 2014

Start by using public properties on your dto's. That eliminates a bunch of getter/setter methods which really should not do anything for dto's. You can always add some majic methods for special cases.

Next, rethink the design of your DoctrineUserEntity aka Domain object. Do you really need getter/setter for each attribute? If so then what's the point?

Instead try to group properties into value objects:

$userNameValueObject = new UserNameValueObject($userDto->firstName, $userDto->lastName);

$userEntity = new UserEntity($userDTO->username,$userDTO->password, $userNameValueObject);

// And maybe this for updates
$userEntity->updateName($userNameValueObject);

But again, make sure you are actually getting some value for your work. A bunch of one to one mappings might make sense on other platforms where domain objects can stay alive between request. In php, everything starts from ground zero.