Completed
Push — develop ( 8109ce...b15e90 )
by Alejandro
17s queued 12s
created

ShortUrl::resolveDomain()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 7
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 4
CRAP Score 2

Importance

Changes 0
Metric Value
cc 2
eloc 3
nc 2
nop 1
dl 0
loc 7
rs 10
c 0
b 0
f 0
ccs 4
cts 4
cp 1
crap 2
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Shlinkio\Shlink\Core\Entity;
6
7
use Cake\Chronos\Chronos;
8
use Doctrine\Common\Collections\ArrayCollection;
9
use Doctrine\Common\Collections\Collection;
10
use Laminas\Diactoros\Uri;
11
use Shlinkio\Shlink\Common\Entity\AbstractEntity;
12
use Shlinkio\Shlink\Core\Domain\Resolver\DomainResolverInterface;
13
use Shlinkio\Shlink\Core\Domain\Resolver\SimpleDomainResolver;
14
use Shlinkio\Shlink\Core\Exception\ShortCodeCannotBeRegeneratedException;
15
use Shlinkio\Shlink\Core\Model\ShortUrlEdit;
16
use Shlinkio\Shlink\Core\Model\ShortUrlMeta;
17
18
use function count;
19
use function Shlinkio\Shlink\Core\generateRandomShortCode;
20
21
class ShortUrl extends AbstractEntity
22
{
23
    private string $longUrl;
24
    private string $shortCode;
25
    private Chronos $dateCreated;
26
    /** @var Collection|Visit[] */
27
    private Collection $visits;
28
    /** @var Collection|Tag[] */
29
    private Collection $tags;
30
    private ?Chronos $validSince = null;
31
    private ?Chronos $validUntil = null;
32
    private ?int $maxVisits = null;
33
    private ?Domain $domain = null;
34
    private bool $customSlugWasProvided;
35
    private int $shortCodeLength;
36
37 99
    public function __construct(
38
        string $longUrl,
39
        ?ShortUrlMeta $meta = null,
40
        ?DomainResolverInterface $domainResolver = null
41
    ) {
42 99
        $meta = $meta ?? ShortUrlMeta::createEmpty();
43
44 99
        $this->longUrl = $longUrl;
45 99
        $this->dateCreated = Chronos::now();
46 99
        $this->visits = new ArrayCollection();
47 99
        $this->tags = new ArrayCollection();
48 99
        $this->validSince = $meta->getValidSince();
49 99
        $this->validUntil = $meta->getValidUntil();
50 99
        $this->maxVisits = $meta->getMaxVisits();
51 99
        $this->customSlugWasProvided = $meta->hasCustomSlug();
52 99
        $this->shortCodeLength = $meta->getShortCodeLength();
53 99
        $this->shortCode = $meta->getCustomSlug() ?? generateRandomShortCode($this->shortCodeLength);
54 99
        $this->domain = ($domainResolver ?? new SimpleDomainResolver())->resolveDomain($meta->getDomain());
55 99
    }
56
57 35
    public function getLongUrl(): string
58
    {
59 35
        return $this->longUrl;
60
    }
61
62 44
    public function getShortCode(): string
63
    {
64 44
        return $this->shortCode;
65
    }
66
67 15
    public function getDateCreated(): Chronos
68
    {
69 15
        return $this->dateCreated;
70
    }
71
72 15
    public function getDomain(): ?Domain
73
    {
74 15
        return $this->domain;
75
    }
76
77
    /**
78
     * @return Collection|Tag[]
79
     */
80 16
    public function getTags(): Collection
81
    {
82 16
        return $this->tags;
83
    }
84
85
    /**
86
     * @param Collection|Tag[] $tags
87
     */
88 5
    public function setTags(Collection $tags): self
89
    {
90 5
        $this->tags = $tags;
91 5
        return $this;
92
    }
93
94 4
    public function update(ShortUrlEdit $shortUrlEdit): void
95
    {
96 4
        if ($shortUrlEdit->hasValidSince()) {
97 3
            $this->validSince = $shortUrlEdit->validSince();
98
        }
99 4
        if ($shortUrlEdit->hasValidUntil()) {
100 2
            $this->validUntil = $shortUrlEdit->validUntil();
101
        }
102 4
        if ($shortUrlEdit->hasMaxVisits()) {
103 3
            $this->maxVisits = $shortUrlEdit->maxVisits();
104
        }
105 4
        if ($shortUrlEdit->hasLongUrl()) {
106 3
            $this->longUrl = $shortUrlEdit->longUrl();
107
        }
108 4
    }
109
110
    /**
111
     * @throws ShortCodeCannotBeRegeneratedException
112
     */
113 4
    public function regenerateShortCode(): self
114
    {
115
        // In ShortUrls where a custom slug was provided, do nothing
116 4
        if ($this->customSlugWasProvided) {
117 1
            throw ShortCodeCannotBeRegeneratedException::forShortUrlWithCustomSlug();
118
        }
119
120
        // The short code can be regenerated only on ShortUrl which have not been persisted yet
121 3
        if ($this->id !== null) {
122 1
            throw ShortCodeCannotBeRegeneratedException::forShortUrlAlreadyPersisted();
123
        }
124
125 2
        $this->shortCode = generateRandomShortCode($this->shortCodeLength);
126 2
        return $this;
127
    }
128
129 18
    public function getValidSince(): ?Chronos
130
    {
131 18
        return $this->validSince;
132
    }
133
134 18
    public function getValidUntil(): ?Chronos
135
    {
136 18
        return $this->validUntil;
137
    }
138
139 19
    public function getVisitsCount(): int
140
    {
141 19
        return count($this->visits);
142
    }
143
144
    /**
145
     * @param Collection|Visit[] $visits
146
     * @internal
147
     */
148 4
    public function setVisits(Collection $visits): self
149
    {
150 4
        $this->visits = $visits;
151 4
        return $this;
152
    }
153
154 18
    public function getMaxVisits(): ?int
155
    {
156 18
        return $this->maxVisits;
157
    }
158
159 6
    public function isEnabled(): bool
160
    {
161 6
        $maxVisitsReached = $this->maxVisits !== null && $this->getVisitsCount() >= $this->maxVisits;
162 6
        if ($maxVisitsReached) {
163 3
            return false;
164
        }
165
166 4
        $now = Chronos::now();
167 4
        $beforeValidSince = $this->validSince !== null && $this->validSince->gt($now);
168 4
        if ($beforeValidSince) {
169 2
            return false;
170
        }
171
172 3
        $afterValidUntil = $this->validUntil !== null && $this->validUntil->lt($now);
173 3
        if ($afterValidUntil) {
174 2
            return false;
175
        }
176
177 2
        return true;
178
    }
179
180 26
    public function toString(array $domainConfig): string
181
    {
182 26
        return (string) (new Uri())->withPath($this->shortCode)
183 26
                                   ->withScheme($domainConfig['schema'] ?? 'http')
184 26
                                   ->withHost($this->resolveDomain($domainConfig['hostname'] ?? ''));
185
    }
186
187 26
    private function resolveDomain(string $fallback = ''): string
188
    {
189 26
        if ($this->domain === null) {
190 26
            return $fallback;
191
        }
192
193 1
        return $this->domain->getAuthority();
194
    }
195
}
196