Passed
Pull Request — master (#500)
by Alejandro
08:38
created

ShortUrl::matchesCriteria()   B

Complexity

Conditions 11
Paths 6

Size

Total Lines 25
Code Lines 15

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 13
CRAP Score 11.7975

Importance

Changes 0
Metric Value
cc 11
eloc 15
c 0
b 0
f 0
nc 6
nop 2
dl 0
loc 25
ccs 13
cts 16
cp 0.8125
crap 11.7975
rs 7.3166

How to fix   Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
declare(strict_types=1);
3
4
namespace Shlinkio\Shlink\Core\Entity;
5
6
use Cake\Chronos\Chronos;
7
use Doctrine\Common\Collections\ArrayCollection;
8
use Doctrine\Common\Collections\Collection;
9
use Shlinkio\Shlink\Common\Entity\AbstractEntity;
10
use Shlinkio\Shlink\Core\Domain\Resolver\DomainResolverInterface;
11
use Shlinkio\Shlink\Core\Domain\Resolver\SimpleDomainResolver;
12
use Shlinkio\Shlink\Core\Model\ShortUrlMeta;
13
use Zend\Diactoros\Uri;
14
15
use function array_reduce;
16
use function count;
17
use function Functional\contains;
18
use function Functional\invoke;
19
20
class ShortUrl extends AbstractEntity
21
{
22
    /** @var string */
23
    private $longUrl;
24
    /** @var string */
25
    private $shortCode;
26
    /** @var Chronos */
27
    private $dateCreated;
28
    /** @var Collection|Visit[] */
29
    private $visits;
30
    /** @var Collection|Tag[] */
31
    private $tags;
32
    /** @var Chronos|null */
33
    private $validSince;
34
    /** @var Chronos|null */
35
    private $validUntil;
36
    /** @var integer|null */
37
    private $maxVisits;
38
    /** @var Domain|null */
39
    private $domain;
40
41 46
    public function __construct(
42
        string $longUrl,
43
        ?ShortUrlMeta $meta = null,
44
        ?DomainResolverInterface $domainResolver = null
45
    ) {
46 46
        $meta = $meta ?? ShortUrlMeta::createEmpty();
47
48 46
        $this->longUrl = $longUrl;
49 46
        $this->dateCreated = Chronos::now();
50 46
        $this->visits = new ArrayCollection();
51 46
        $this->tags = new ArrayCollection();
52 46
        $this->validSince = $meta->getValidSince();
53 46
        $this->validUntil = $meta->getValidUntil();
54 46
        $this->maxVisits = $meta->getMaxVisits();
55 46
        $this->shortCode = $meta->getCustomSlug() ?? ''; // TODO logic to calculate short code should be passed somehow
56 46
        $this->domain = ($domainResolver ?? new SimpleDomainResolver())->resolveDomain($meta->getDomain());
57
    }
58
59 17
    public function getLongUrl(): string
60
    {
61 17
        return $this->longUrl;
62
    }
63
64 12
    public function getShortCode(): string
65
    {
66 12
        return $this->shortCode;
67
    }
68
69
    // TODO Short code is currently calculated based on the ID, so a setter is needed
70 10
    public function setShortCode(string $shortCode): self
71
    {
72 10
        $this->shortCode = $shortCode;
73 10
        return $this;
74
    }
75
76 10
    public function getDateCreated(): Chronos
77
    {
78 10
        return $this->dateCreated;
79
    }
80
81
    /**
82
     * @return Collection|Tag[]
83
     */
84 19
    public function getTags(): Collection
85
    {
86 19
        return $this->tags;
87
    }
88
89
    /**
90
     * @param Collection|Tag[] $tags
91
     */
92 3
    public function setTags(Collection $tags): self
93
    {
94 3
        $this->tags = $tags;
95 3
        return $this;
96
    }
97
98 1
    public function updateMeta(ShortUrlMeta $shortCodeMeta): void
99
    {
100 1
        if ($shortCodeMeta->hasValidSince()) {
101 1
            $this->validSince = $shortCodeMeta->getValidSince();
102
        }
103 1
        if ($shortCodeMeta->hasValidUntil()) {
104 1
            $this->validUntil = $shortCodeMeta->getValidUntil();
105
        }
106 1
        if ($shortCodeMeta->hasMaxVisits()) {
107 1
            $this->maxVisits = $shortCodeMeta->getMaxVisits();
108
        }
109
    }
110
111 11
    public function getValidSince(): ?Chronos
112
    {
113 11
        return $this->validSince;
114
    }
115
116 11
    public function getValidUntil(): ?Chronos
117
    {
118 11
        return $this->validUntil;
119
    }
120
121 12
    public function getVisitsCount(): int
122
    {
123 12
        return count($this->visits);
124
    }
125
126
    /**
127
     * @param Collection|Visit[] $visits
128
     * @return ShortUrl
129
     * @internal
130
     */
131 4
    public function setVisits(Collection $visits): self
132
    {
133 4
        $this->visits = $visits;
134 4
        return $this;
135
    }
136
137 11
    public function getMaxVisits(): ?int
138
    {
139 11
        return $this->maxVisits;
140
    }
141
142
    public function maxVisitsReached(): bool
143
    {
144
        return $this->maxVisits !== null && $this->getVisitsCount() >= $this->maxVisits;
145
    }
146
147 12
    public function toString(array $domainConfig): string
148
    {
149 12
        return (string) (new Uri())->withPath($this->shortCode)
150 12
                                   ->withScheme($domainConfig['schema'] ?? 'http')
151 12
                                   ->withHost($this->resolveDomain($domainConfig['hostname'] ?? ''));
152
    }
153
154 12
    private function resolveDomain(string $fallback = ''): string
155
    {
156 12
        if ($this->domain === null) {
157 12
            return $fallback;
158
        }
159
160
        return $this->domain->getAuthority();
161
    }
162
163 8
    public function matchesCriteria(ShortUrlMeta $meta, array $tags): bool
164
    {
165 8
        if ($meta->hasMaxVisits() && $meta->getMaxVisits() !== $this->maxVisits) {
166 1
            return false;
167
        }
168 8
        if ($meta->hasDomain() && $meta->getDomain() !== $this->resolveDomain()) {
169
            return false;
170
        }
171 8
        if ($meta->hasValidSince() && ! $meta->getValidSince()->eq($this->validSince)) {
0 ignored issues
show
Bug introduced by
It seems like $this->validSince can also be of type null; however, parameter $dt of Cake\Chronos\Chronos::eq() does only seem to accept Cake\Chronos\ChronosInterface, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

171
        if ($meta->hasValidSince() && ! $meta->getValidSince()->eq(/** @scrutinizer ignore-type */ $this->validSince)) {
Loading history...
172
            return false;
173
        }
174 8
        if ($meta->hasValidUntil() && ! $meta->getValidUntil()->eq($this->validUntil)) {
175
            return false;
176
        }
177
178 8
        $shortUrlTags = invoke($this->getTags(), '__toString');
179 8
        $hasAllTags = count($shortUrlTags) === count($tags) && array_reduce(
180 8
            $tags,
181
            function (bool $hasAllTags, string $tag) use ($shortUrlTags) {
182 3
                return $hasAllTags && contains($shortUrlTags, $tag);
183 8
            },
184 8
            true
185
        );
186
187 8
        return $hasAllTags;
188
    }
189
}
190