Est-ce que nous allons parler de gestion des ressources humaines au PHP tour ? Non, je vous vais vous parler des modèles anémiques et des modèles riches. Depuis des années frameworks et ORM nous conditionnent à utiliser des modèles anémiques, une classe avec de simples setters et getters. A travers l’histoire d’Estelle, une RH, qui veut une application pour gérer ses salariés, je vais vous montrer comment changer nos vieilles habitudes afin de nous focaliser sur le métier que nous implémentons. Nous verrons ensemble quels outils utiliser, comme par exemple, le design pattern command bus, l’opérateur NEW de doctrine pour vos Data Transfert Object dans une application Symfony.
Example de code : https://github.com/arnolanglade/code-me-hr
10. namespace AlPresenterForm;
final class EmployeeType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder->add('name');
$builder->add('position');
}
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults(array(
'data_class' => Employee::class,
));
}
}
11. namespace AlPresenterController;
class EmployeeController extends Controller
{
public function indexAction(Request $request)
{
}
public function showAction(Request $request)
{
}
public function createAction(Request $request)
{
}
public function updateAction(Request $request)
{
}
public function deleteAction(Request $request)
{
}
}
12. namespace AlPresenterController;
class EmployeeController extends Controller
{
public function createAction(Request $request)
{
$form = $this->createForm(EmployeeType::class, new Employee());
$form->handleRequest($request);
// First, data are mapped to the model and it is validated thereafter.
if ($form->isSubmitted() && $form->isValid()) {
$em = $this->get('doctrine.orm.entity_manager');
$em->persist($form->getData());
$em->flush();
return $this->redirectToRoute('employee_list');
}
return $this->render('employee/hire.html.twig', [
'form' => $form->createView()
]);
}
}
17. namespace AlDomain;
final class Employee implements EmployeeInterface
{
public function hire(Uuid $identifier, string $name, string $forPosition)
{
}
public function promote(string $toNewPosition)
{
}
public function fire()
{
}
public function retire()
{
}
}
19. namespace AlDomain;
final class Employee implements EmployeeInterface
{
private function __construct(Uuid $identifier, string $name, string $position)
{
$this->id = $identifier;
$this->name = $name;
$this->position = $position;
$this->hireAt = new DateTime();
}
public static function hire(Uuid $identifier, string $name, string $forPosition)
{
return new self($identifier, $name, $forPosition, $hiredAt);
}
public function promote(string $toNewPosition)
{
$this->position = $toNewPosition;
}
public function fire()
{
$this->firedAt = new DateTime();
}
public function retire()
{
$this->retiredAt = new DateTime();
}
}
20. namespace AlDomain;
final class Employee implements EmployeeInterface
{
private function __construct(Uuid $identifier, string $name, string $position)
{
if ($hiredAt < new DateTime('2013-01-01')) {
throw new OutOfRangeException(
'The company did not exist before 2013-01-01'
);
}
$this->id = $identifier;
$this->name = $name;
$this->position = $position;
$this->hireAt = new DateTime();
}
public function retire()
{
if (null !== $this->fired) {
throw new Exception(
sprint('%s employee has been fired!', $this->name)
);
}
$this->retiredAt = new DateTime();
}
}
22. FIRSTPROBLEM:HOWDOWEUSE
DOCTRINE?
We use them as query repositories
interface EmployeeRepository
{
public function findByNameAndPositionWithoutFiredPeople(
string $name,
string $position
);
}
25. namespace AlInfrastructure;
final class EmployeeRepository implements EmployeeRepositoryInterface
{
public function get(Uuid $identifier)
{
}
public function add(EmployeeInterface $employee)
{
}
public function remove(EmployeeInterface $employee)
{
}
}
26. namespace AlInfrastructure;
final class EmployeeRepository implements EmployeeRepositoryInterface
{
/** @var EntityManagerInterface */
private $entityManager;
public function __construct(EntityManagerInterface $entityManager)
{
$this->entityManager = $entityManager;
}
}
27. namespace AlInfrastructure;
final class EmployeeRepository implements EmployeeRepositoryInterface
{
public function get(Uuid $identifier)
{
$employee = $this->entityManager->find(
Employee::class,
$identifier->toString()
);
if (null === $employee) {
throw new NonExistingEmployee($identifier->toString());
}
return $employee;
}
public function add(EmployeeInterface $employee)
{
$this->entityManager->persist($employee);
$this->entityManager->flush($employee);
}
public function remove(EmployeeInterface $employee)
{
$this->entityManager->remove($employee);
$this->entityManager->flush($employee);
}
}