Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.
Common duplication problems, and corresponding solutions are:
1 | <?php |
||
22 | class NotOverlappedDatesValidator extends ConstraintValidator |
||
23 | { |
||
24 | /** |
||
25 | * @var NotOverlappedDatesRepository |
||
26 | */ |
||
27 | private $repository; |
||
28 | |||
29 | 4 | public function __construct(NotOverlappedDatesRepository $repository) |
|
33 | |||
34 | /** |
||
35 | * @param EntityInterface $entity |
||
36 | * @param NotOverlappedDates|Constraint $constraint |
||
37 | */ |
||
38 | 4 | public function validate($entity, Constraint $constraint): void |
|
39 | { |
||
40 | 4 | $this->assertInstances($entity, $constraint); |
|
41 | 4 | $this->assertConstraintProperties($entity, $constraint); |
|
|
|||
42 | 4 | $this->assertDatesInstanceOf($entity, $constraint); |
|
43 | |||
44 | 4 | if (false === $this->validateDatesNotEmpty($entity, $constraint)) { |
|
45 | return; |
||
46 | } |
||
47 | |||
48 | 4 | if (false === $this->validateDatesOrder($entity, $constraint)) { |
|
49 | return; |
||
50 | } |
||
51 | |||
52 | 4 | $overlappedEntities = $this->repository->getOverlappedEntities( |
|
53 | 4 | \get_class($entity), |
|
54 | 4 | $constraint->fromDateProperty, |
|
55 | 4 | $constraint->toDateProperty, |
|
56 | 4 | $this->getFromDate($entity, $constraint), |
|
57 | 4 | $this->getToDate($entity, $constraint) |
|
58 | ); |
||
59 | |||
60 | 4 | if (1 === \count($overlappedEntities) && $overlappedEntities[0]->getId() === $entity->getId()) { |
|
61 | return; |
||
62 | } |
||
63 | |||
64 | 4 | if (\count($overlappedEntities) > 0) { |
|
65 | $periodsString = ''; |
||
66 | foreach ($overlappedEntities as $overlappedEntity) { |
||
67 | $periodsString .= sprintf( |
||
68 | '%s - %s,', |
||
69 | $this->getFromDateString($overlappedEntity, $constraint), |
||
70 | $this->getToDateString($overlappedEntity, $constraint) |
||
71 | ); |
||
72 | } |
||
73 | $this->context->buildViolation($constraint::INVALID_PERIOD_OVERLAPPED) |
||
74 | ->setParameter('{{ fromDate }}', $this->getFromDateString($entity, $constraint)) |
||
75 | ->setParameter('{{ toDate }}', $this->getToDateString($entity, $constraint)) |
||
76 | ->setParameter('{{ periods }}', $periodsString) |
||
77 | ->atPath($constraint->toDateProperty) |
||
78 | ->addViolation(); |
||
79 | } |
||
80 | 4 | } |
|
81 | |||
82 | //------------------------------------------------------------------------------------------------------------------ |
||
83 | |||
84 | 4 | private function assertInstances($entity, Constraint $constraint): void |
|
93 | |||
94 | 4 | private function assertConstraintProperties(EntityInterface $entity, NotOverlappedDates $constraint): void |
|
128 | |||
129 | 4 | private function assertDatesInstanceOf(EntityInterface $entity, NotOverlappedDates $constraint): void |
|
140 | |||
141 | 4 | private function validateDatesNotEmpty(EntityInterface $entity, NotOverlappedDates $constraint): bool |
|
161 | |||
162 | 4 | private function validateDatesOrder(EntityInterface $entity, NotOverlappedDates $constraint): bool |
|
179 | |||
180 | 4 | private function getFromDate(EntityInterface $entity, NotOverlappedDates $constraint): \DateTimeInterface |
|
184 | |||
185 | 4 | private function getToDate(EntityInterface $entity, NotOverlappedDates $constraint): \DateTimeInterface |
|
189 | |||
190 | 4 | private function getFromDateString(EntityInterface $entity, NotOverlappedDates $constraint): string |
|
194 | |||
195 | 4 | private function getToDateString(EntityInterface $entity, NotOverlappedDates $constraint): string |
|
199 | } |
||
200 |
This check looks for parameters that are defined as one type in their type hint or doc comment but seem to be used as a narrower type, i.e an implementation of an interface or a subclass.
Consider changing the type of the parameter or doing an instanceof check before assuming your parameter is of the expected type.