Test Failed
Push — master ( 43fdf3...260789 )
by Zbigniew
04:40
created

NotOverlappedDatesValidator   A

Complexity

Total Complexity 32

Size/Duplication

Total Lines 178
Duplicated Lines 26.97 %

Coupling/Cohesion

Components 1
Dependencies 9

Test Coverage

Coverage 54.46%

Importance

Changes 0
Metric Value
wmc 32
lcom 1
cbo 9
dl 48
loc 178
ccs 55
cts 101
cp 0.5446
rs 9.84
c 0
b 0
f 0

11 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 4 1
B validate() 0 43 7
A assertInstances() 0 9 3
B assertConstraintProperties() 25 34 7
A assertDatesInstanceOf() 0 11 5
A validateDatesNotEmpty() 14 20 3
A validateDatesOrder() 9 17 2
A getFromDate() 0 4 1
A getToDate() 0 4 1
A getFromDateString() 0 4 1
A getToDateString() 0 4 1

How to fix   Duplicated Code   

Duplicated Code

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
2
3
declare(strict_types=1);
4
5
/*
6
 * This file is part of the zibios/sharep.
7
 *
8
 * (c) Zbigniew Ślązak
9
 */
10
11
namespace App\Validator\Constraints;
12
13
use App\Entity\EntityInterface;
14
use App\Enum\Functional\ApplicationEnum;
15
use App\Repository\Functional\NotOverlappedDatesRepository;
16
use Symfony\Component\Validator\Constraint;
17
use Symfony\Component\Validator\ConstraintValidator;
18
use Symfony\Component\Validator\Exception\InvalidArgumentException;
19
use Symfony\Component\Validator\Exception\UnexpectedTypeException;
20
use Symfony\Component\Validator\Exception\UnexpectedValueException;
21
22
class NotOverlappedDatesValidator extends ConstraintValidator
23
{
24
    /**
25
     * @var NotOverlappedDatesRepository
26
     */
27
    private $repository;
28
29 4
    public function __construct(NotOverlappedDatesRepository $repository)
30
    {
31 4
        $this->repository = $repository;
32 4
    }
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);
0 ignored issues
show
Compatibility introduced by
$constraint of type object<Symfony\Component\Validator\Constraint> is not a sub-type of object<App\Validator\Con...nts\NotOverlappedDates>. It seems like you assume a child class of the class Symfony\Component\Validator\Constraint to be always present.

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.

Loading history...
42 4
        $this->assertDatesInstanceOf($entity, $constraint);
0 ignored issues
show
Compatibility introduced by
$constraint of type object<Symfony\Component\Validator\Constraint> is not a sub-type of object<App\Validator\Con...nts\NotOverlappedDates>. It seems like you assume a child class of the class Symfony\Component\Validator\Constraint to be always present.

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.

Loading history...
43
44 4
        if (false === $this->validateDatesNotEmpty($entity, $constraint)) {
0 ignored issues
show
Compatibility introduced by
$constraint of type object<Symfony\Component\Validator\Constraint> is not a sub-type of object<App\Validator\Con...nts\NotOverlappedDates>. It seems like you assume a child class of the class Symfony\Component\Validator\Constraint to be always present.

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.

Loading history...
45
            return;
46
        }
47
48 4
        if (false === $this->validateDatesOrder($entity, $constraint)) {
0 ignored issues
show
Compatibility introduced by
$constraint of type object<Symfony\Component\Validator\Constraint> is not a sub-type of object<App\Validator\Con...nts\NotOverlappedDates>. It seems like you assume a child class of the class Symfony\Component\Validator\Constraint to be always present.

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.

Loading history...
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),
0 ignored issues
show
Compatibility introduced by
$constraint of type object<Symfony\Component\Validator\Constraint> is not a sub-type of object<App\Validator\Con...nts\NotOverlappedDates>. It seems like you assume a child class of the class Symfony\Component\Validator\Constraint to be always present.

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.

Loading history...
57 4
            $this->getToDate($entity, $constraint)
0 ignored issues
show
Compatibility introduced by
$constraint of type object<Symfony\Component\Validator\Constraint> is not a sub-type of object<App\Validator\Con...nts\NotOverlappedDates>. It seems like you assume a child class of the class Symfony\Component\Validator\Constraint to be always present.

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.

Loading history...
58
        );
59
60 4
        if (1 === \count($overlappedEntities) && $overlappedEntities[0]->getId() === $entity->getId()) {
61 1
            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),
0 ignored issues
show
Compatibility introduced by
$constraint of type object<Symfony\Component\Validator\Constraint> is not a sub-type of object<App\Validator\Con...nts\NotOverlappedDates>. It seems like you assume a child class of the class Symfony\Component\Validator\Constraint to be always present.

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.

Loading history...
70
                    $this->getToDateString($overlappedEntity, $constraint)
0 ignored issues
show
Compatibility introduced by
$constraint of type object<Symfony\Component\Validator\Constraint> is not a sub-type of object<App\Validator\Con...nts\NotOverlappedDates>. It seems like you assume a child class of the class Symfony\Component\Validator\Constraint to be always present.

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.

Loading history...
71
                );
72
            }
73
            $this->context->buildViolation($constraint::INVALID_PERIOD_OVERLAPPED)
74
                ->setParameter('{{ fromDate }}', $this->getFromDateString($entity, $constraint))
0 ignored issues
show
Compatibility introduced by
$constraint of type object<Symfony\Component\Validator\Constraint> is not a sub-type of object<App\Validator\Con...nts\NotOverlappedDates>. It seems like you assume a child class of the class Symfony\Component\Validator\Constraint to be always present.

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.

Loading history...
75
                ->setParameter('{{ toDate }}', $this->getToDateString($entity, $constraint))
0 ignored issues
show
Compatibility introduced by
$constraint of type object<Symfony\Component\Validator\Constraint> is not a sub-type of object<App\Validator\Con...nts\NotOverlappedDates>. It seems like you assume a child class of the class Symfony\Component\Validator\Constraint to be always present.

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.

Loading history...
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
85
    {
86 4
        if (!$constraint instanceof NotOverlappedDates) {
87
            throw new UnexpectedTypeException($constraint, NotOverlappedDates::class);
88
        }
89 4
        if (!$entity instanceof EntityInterface) {
90
            throw new UnexpectedValueException($entity, EntityInterface::class);
91
        }
92 4
    }
93
94 4
    private function assertConstraintProperties(EntityInterface $entity, NotOverlappedDates $constraint): void
95
    {
96 4
        if (!method_exists($entity, $constraint->fromDateMethod)) {
97
            throw new InvalidArgumentException(
98
                sprintf('Method \'%s\' not exist \'%s\'', $constraint->fromDateMethod, \get_class($entity))
99
            );
100
        }
101 4 View Code Duplication
        if (!\is_callable([$entity, $constraint->fromDateMethod])) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
102
            throw new InvalidArgumentException(
103
                sprintf('Method \'%s\' not public \'%s\'', $constraint->fromDateMethod, \get_class($entity))
104
            );
105
        }
106 4 View Code Duplication
        if (!property_exists($entity, $constraint->fromDateProperty)) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
107
            throw new InvalidArgumentException(
108
                sprintf('Property \'%s\' not exist \'%s\'', $constraint->fromDateProperty, \get_class($entity))
109
            );
110
        }
111
112 4 View Code Duplication
        if (!method_exists($entity, $constraint->toDateMethod)) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
113
            throw new InvalidArgumentException(
114
                sprintf('Method \'%s\' not exist in \'%s\'', $constraint->toDateMethod, \get_class($entity))
115
            );
116
        }
117 4 View Code Duplication
        if (!\is_callable([$entity, $constraint->toDateMethod])) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
118
            throw new InvalidArgumentException(
119
                sprintf('Method \'%s\' not public \'%s\'', $constraint->toDateMethod, \get_class($entity))
120
            );
121
        }
122 4 View Code Duplication
        if (!property_exists($entity, $constraint->toDateProperty)) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
123
            throw new InvalidArgumentException(
124
                sprintf('Property \'%s\' not exist \'%s\'', $constraint->toDateProperty, \get_class($entity))
125
            );
126
        }
127 4
    }
128
129 4
    private function assertDatesInstanceOf(EntityInterface $entity, NotOverlappedDates $constraint): void
130
    {
131 4
        $fromDate = $entity->{$constraint->fromDateMethod}();
132 4
        if (null !== $fromDate && !$fromDate instanceof \DateTimeInterface) {
133
            throw new UnexpectedValueException($fromDate, \DateTimeInterface::class);
134
        }
135 4
        $toDate = $entity->{$constraint->toDateMethod}();
136 4
        if (null !== $toDate && !$toDate instanceof \DateTimeInterface) {
137
            throw new UnexpectedValueException($toDate, \DateTimeInterface::class);
138
        }
139 4
    }
140
141 4
    private function validateDatesNotEmpty(EntityInterface $entity, NotOverlappedDates $constraint): bool
0 ignored issues
show
Coding Style introduced by
function validateDatesNotEmpty() does not seem to conform to the naming convention (^(?:is|has|should|may|supports)).

This check examines a number of code elements and verifies that they conform to the given naming conventions.

You can set conventions for local variables, abstract classes, utility classes, constant, properties, methods, parameters, interfaces, classes, exceptions and special methods.

Loading history...
142
    {
143 4
        $result = true;
144 4 View Code Duplication
        if (!$this->getFromDate($entity, $constraint) instanceof \DateTimeInterface) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
145
            $this->context->buildViolation($constraint::INVALID_FROM_DATE)
146
                ->setParameter('{{ fromDate }}', 'N/A')
147
                ->atPath($constraint->fromDateProperty)
148
                ->addViolation();
149
            $result = false;
150
        }
151 4 View Code Duplication
        if (!$this->getToDate($entity, $constraint) instanceof \DateTimeInterface) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
152
            $this->context->buildViolation($constraint::INVALID_TO_DATE)
153
                ->setParameter('{{ toDate }}', 'N/A')
154
                ->atPath($constraint->toDateProperty)
155
                ->addViolation();
156
            $result = false;
157
        }
158
159 4
        return $result;
160
    }
161
162 4
    private function validateDatesOrder(EntityInterface $entity, NotOverlappedDates $constraint): bool
0 ignored issues
show
Coding Style introduced by
function validateDatesOrder() does not seem to conform to the naming convention (^(?:is|has|should|may|supports)).

This check examines a number of code elements and verifies that they conform to the given naming conventions.

You can set conventions for local variables, abstract classes, utility classes, constant, properties, methods, parameters, interfaces, classes, exceptions and special methods.

Loading history...
163
    {
164 4
        $fromDateString = $this->getFromDateString($entity, $constraint);
165 4
        $toDateString = $this->getToDateString($entity, $constraint);
166
167 4 View Code Duplication
        if ($fromDateString >= $toDateString) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
168
            $this->context->buildViolation($constraint::INVALID_ORDER)
169
                ->setParameter('{{ fromDate }}', $fromDateString)
170
                ->setParameter('{{ toDate }}', $toDateString)
171
                ->atPath($constraint->toDateProperty)
172
                ->addViolation();
173
174
            return false;
175
        }
176
177 4
        return true;
178
    }
179
180 4
    private function getFromDate(EntityInterface $entity, NotOverlappedDates $constraint): \DateTimeInterface
181
    {
182 4
        return $entity->{$constraint->fromDateMethod}();
183
    }
184
185 4
    private function getToDate(EntityInterface $entity, NotOverlappedDates $constraint): \DateTimeInterface
186
    {
187 4
        return $entity->{$constraint->toDateMethod}();
188
    }
189
190 4
    private function getFromDateString(EntityInterface $entity, NotOverlappedDates $constraint): string
191
    {
192 4
        return $this->getFromDate($entity, $constraint)->format(ApplicationEnum::DATE_FORMAT);
193
    }
194
195 4
    private function getToDateString(EntityInterface $entity, NotOverlappedDates $constraint): string
196
    {
197 4
        return $this->getToDate($entity, $constraint)->format(ApplicationEnum::DATE_FORMAT);
198
    }
199
}
200