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.