Completed
Push — master ( abb491...352f9f )
by Olivier
01:38
created

Subscription   B

Complexity

Total Complexity 46

Size/Duplication

Total Lines 359
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 6

Test Coverage

Coverage 77.35%

Importance

Changes 0
Metric Value
wmc 46
lcom 1
cbo 6
dl 0
loc 359
ccs 82
cts 106
cp 0.7735
rs 8.72
c 0
b 0
f 0

36 Methods

Rating   Name   Duplication   Size   Complexity  
B createFromArray() 0 32 8
A isBilledAutomatically() 0 4 1
A isIncomplete() 0 4 1
A isExpired() 0 4 1
A isTrialing() 0 4 1
A isActive() 0 4 1
A isPastDue() 0 4 1
A isCanceled() 0 4 1
A isUnpaid() 0 4 1
A hasDefaultSource() 0 4 1
A getId() 0 4 1
A getApplicationFeePercent() 0 4 1
A getBilling() 0 4 1
A getBillingCycleAnchor() 0 4 1
A willBeCanceledAtPeriodEnd() 0 4 1
A getCanceledAt() 0 4 1
A getCreatedAt() 0 4 1
A getCurrentPeriodEndAt() 0 4 1
A getCurrentPeriodStartAt() 0 4 1
A getCustomer() 0 4 1
A getDaysUntilDue() 0 4 1
A getDefaultSource() 0 4 1
A getDefaultTaxRates() 0 4 1
A getDiscount() 0 4 1
A hasDiscount() 0 4 1
A hasActiveDiscountForCurrentPeriod() 0 19 4
A getEndedAt() 0 4 1
A getItems() 0 4 1
A getLatestInvoiceId() 0 4 1
A getPendingSetupIntentId() 0 4 1
A getPlan() 0 4 1
A getQuantity() 0 4 1
A getStartAt() 0 4 1
A getStatus() 0 4 1
A getTrialEndAt() 0 4 1
A getTrialStartAt() 0 4 1

How to fix   Complexity   

Complex Class

Complex classes like Subscription often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes. You can also have a look at the cohesion graph to spot any un-connected, or weakly-connected components.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use Subscription, and based on these observations, apply Extract Interface, too.

1
<?php
2
3
declare(strict_types=1);
4
5
/*
6
 * This software may be modified and distributed under the terms
7
 * of the MIT license. See the LICENSE file for details.
8
 */
9
10
namespace Shapin\Stripe\Model\Subscription;
11
12
use Shapin\Stripe\Model\ContainsMetadata;
13
use Shapin\Stripe\Model\CreatableFromArray;
14
use Shapin\Stripe\Model\Discount\Discount;
15
use Shapin\Stripe\Model\LivemodeTrait;
16
use Shapin\Stripe\Model\MetadataTrait;
17
use Shapin\Stripe\Model\MetadataCollection;
18
use Shapin\Stripe\Model\Plan\Plan;
19
20
final class Subscription implements CreatableFromArray, ContainsMetadata
21
{
22
    use LivemodeTrait;
23
    use MetadataTrait;
24
25
    const BILLING_CHARGE_AUTOMATICALLY = 'charge_automatically';
26
    const BILLING_SEND_INVOICE = 'send_invoice';
27
28
    const STATUS_EXPIRED = 'incomplete_expired';
29
    const STATUS_INCOMPLETE = 'incomplete';
30
    const STATUS_TRIALING = 'trialing';
31
    const STATUS_ACTIVE = 'active';
32
    const STATUS_PAST_DUE = 'past_due';
33
    const STATUS_CANCELED = 'canceled';
34
    const STATUS_UNPAID = 'unpaid';
35
36
    /**
37
     * @var string
38
     */
39
    private $id;
40
41
    /**
42
     * @var ?float
43
     */
44
    private $applicationFeePercent;
45
46
    /**
47
     * @var string
48
     */
49
    private $billing;
50
51
    /**
52
     * @var mixed
53
     */
54
    private $billingCycleAnchor;
55
56
    /**
57
     * @var bool
58
     */
59
    private $cancelAtPeriodEnd;
60
61
    /**
62
     * @var ?\DateTimeImmutable
63
     */
64
    private $canceledAt;
65
66
    /**
67
     * @var \DateTimeImmutable
68
     */
69
    private $createdAt;
70
71
    /**
72
     * @var \DateTimeImmutable
73
     */
74
    private $currentPeriodEndAt;
75
76
    /**
77
     * @var \DateTimeImmutable
78
     */
79
    private $currentPeriodStartAt;
80
81
    /**
82
     * @var string
83
     */
84
    private $customer;
85
86
    /**
87
     * @var ?int
88
     */
89
    private $daysUntilDue;
90
91
    /**
92
     * @var ?string
93
     */
94
    private $defaultSource;
95
96
    /**
97
     * @var array
98
     */
99
    private $defaultTaxRates;
100
101
    /**
102
     * @var ?Discount
103
     */
104
    private $discount;
105
106
    /**
107
     * @var ?\DateTimeImmutable
108
     */
109
    private $endedAt;
110
111
    /**
112
     * @var ItemCollection
113
     */
114
    private $items;
115
116
    /**
117
     * @var ?string
118
     */
119
    private $latestInvoiceId;
120
121
    /**
122
     * @var ?string
123
     */
124
    private $pendingSetupIntentId;
125
126
    /**
127
     * @var Plan
128
     */
129
    private $plan;
130
131
    /**
132
     * @var int
133
     */
134
    private $quantity;
135
136
    /**
137
     * @var \DateTimeImmutable
138
     */
139
    private $startAt;
140
141
    /**
142
     * @var string
143
     */
144
    private $status;
145
146
    /**
147
     * @var ?\DateTimeImmutable
148
     */
149
    private $trialEndAt;
150
151
    /**
152
     * @var ?\DateTimeImmutable
153
     */
154
    private $trialStartAt;
155
156 8
    public static function createFromArray(array $data): self
157
    {
158 8
        $model = new self();
159 8
        $model->id = $data['id'];
160 8
        $model->applicationFeePercent = null !== $data['application_fee_percent'] ? (float) $data['application_fee_percent'] : null;
161 8
        $model->billing = $data['billing'];
162 8
        $model->billingCycleAnchor = $data['billing_cycle_anchor'];
163 8
        $model->cancelAtPeriodEnd = (bool) $data['cancel_at_period_end'];
164 8
        $model->canceledAt = null !== $data['canceled_at'] ? new \DateTimeImmutable('@'.$data['canceled_at']) : null;
165 8
        $model->createdAt = new \DateTimeImmutable('@'.$data['created']);
166 8
        $model->currentPeriodEndAt = new \DateTimeImmutable('@'.$data['current_period_end']);
167 8
        $model->currentPeriodStartAt = new \DateTimeImmutable('@'.$data['current_period_start']);
168 8
        $model->customer = $data['customer'];
169 8
        $model->daysUntilDue = null !== $data['days_until_due'] ? (int) $data['days_until_due'] : null;
170 8
        $model->defaultSource = $data['default_source'] ?? null;
171 8
        $model->defaultTaxRates = $data['default_tax_rates'];
172 8
        $model->discount = isset($data['discount']) ? Discount::createFromArray($data['discount']) : null;
173 8
        $model->endedAt = null !== $data['ended_at'] ? new \DateTimeImmutable('@'.$data['ended_at']) : null;
174 8
        $model->items = ItemCollection::createFromArray($data['items']);
0 ignored issues
show
Documentation Bug introduced by
It seems like \Shapin\Stripe\Model\Sub...omArray($data['items']) of type object<self> is incompatible with the declared type object<Shapin\Stripe\Mod...ription\ItemCollection> of property $items.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
175 8
        $model->latestInvoiceId = $data['latest_invoice'];
176 8
        $model->live = $data['livemode'];
177 8
        $model->metadata = MetadataCollection::createFromArray($data['metadata']);
0 ignored issues
show
Documentation Bug introduced by
It seems like \Shapin\Stripe\Model\Met...rray($data['metadata']) of type object<self> is incompatible with the declared type object<Shapin\Stripe\Model\MetadataCollection> of property $metadata.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
178 8
        $model->pendingSetupIntentId = $data['pending_setup_intent'] ?? null;
179 8
        $model->plan = Plan::createFromArray($data['plan']);
0 ignored issues
show
Documentation Bug introduced by
It seems like \Shapin\Stripe\Model\Pla...romArray($data['plan']) of type object<self> is incompatible with the declared type object<Shapin\Stripe\Model\Plan\Plan> of property $plan.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
180 8
        $model->quantity = (int) $data['quantity'];
181 8
        $model->startAt = new \DateTimeImmutable('@'.$data['start']);
182 8
        $model->status = $data['status'];
183 8
        $model->trialEndAt = null !== $data['trial_end'] ? new \DateTimeImmutable('@'.$data['trial_end']) : null;
184 8
        $model->trialStartAt = null !== $data['trial_start'] ? new \DateTimeImmutable('@'.$data['trial_start']) : null;
185
186 8
        return $model;
187
    }
188
189 1
    public function isBilledAutomatically(): bool
190
    {
191 1
        return self::BILLING_CHARGE_AUTOMATICALLY === $this->billing;
192
    }
193
194
    public function isIncomplete(): bool
195
    {
196
        return self::STATUS_INCOMPLETE === $this->status;
197
    }
198
199
    public function isExpired(): bool
200
    {
201
        return self::STATUS_EXPIRED === $this->status;
202
    }
203
204
    public function isTrialing(): bool
205
    {
206
        return self::STATUS_TRIALING === $this->status;
207
    }
208
209
    public function isActive(): bool
210
    {
211
        return self::STATUS_ACTIVE === $this->status;
212
    }
213
214
    public function isPastDue(): bool
215
    {
216
        return self::STATUS_PAST_DUE === $this->status;
217
    }
218
219
    public function isCanceled(): bool
220
    {
221
        return self::STATUS_CANCELED === $this->status;
222
    }
223
224
    public function isUnpaid(): bool
225
    {
226
        return self::STATUS_UNPAID === $this->status;
227
    }
228
229
    public function hasDefaultSource(): bool
230
    {
231
        return null !== $this->defaultSource;
232
    }
233
234 1
    public function getId(): string
235
    {
236 1
        return $this->id;
237
    }
238
239 1
    public function getApplicationFeePercent(): ?float
240
    {
241 1
        return $this->applicationFeePercent;
242
    }
243
244 1
    public function getBilling(): string
245
    {
246 1
        return $this->billing;
247
    }
248
249 1
    public function getBillingCycleAnchor()
250
    {
251 1
        return $this->billingCycleAnchor;
252
    }
253
254 1
    public function willBeCanceledAtPeriodEnd(): bool
255
    {
256 1
        return $this->cancelAtPeriodEnd;
257
    }
258
259 1
    public function getCanceledAt(): ?\DateTimeImmutable
260
    {
261 1
        return $this->canceledAt;
262
    }
263
264 1
    public function getCreatedAt(): \DateTimeImmutable
265
    {
266 1
        return $this->createdAt;
267
    }
268
269 1
    public function getCurrentPeriodEndAt(): \DateTimeImmutable
270
    {
271 1
        return $this->currentPeriodEndAt;
272
    }
273
274 1
    public function getCurrentPeriodStartAt(): \DateTimeImmutable
275
    {
276 1
        return $this->currentPeriodStartAt;
277
    }
278
279 1
    public function getCustomer(): string
280
    {
281 1
        return $this->customer;
282
    }
283
284 1
    public function getDaysUntilDue(): ?int
285
    {
286 1
        return $this->daysUntilDue;
287
    }
288
289 1
    public function getDefaultSource(): ?string
290
    {
291 1
        return $this->defaultSource;
292
    }
293
294 1
    public function getDefaultTaxRates(): array
295
    {
296 1
        return $this->defaultTaxRates;
297
    }
298
299 1
    public function getDiscount(): ?Discount
300
    {
301 1
        return $this->discount;
302
    }
303
304 1
    public function hasDiscount(): bool
305
    {
306 1
        return null !== $this->discount;
307
    }
308
309 1
    public function hasActiveDiscountForCurrentPeriod(): bool
310
    {
311 1
        if (!$this->hasDiscount()) {
312 1
            return false;
313
        }
314
315
        // Discount start after the current period
316
        if ($this->getCurrentPeriodEndAt() < $this->discount->getStartAt()) {
317
            return false;
318
        }
319
320
        // Discount has ended before the current period
321
        $endAt = $this->discount->getEndAt() ?? $this->discount->getStartAt();
322
        if ($this->getCurrentPeriodStartAt() > $endAt) {
323
            return false;
324
        }
325
326
        return true;
327
    }
328
329 1
    public function getEndedAt(): ?\DateTimeImmutable
330
    {
331 1
        return $this->endedAt;
332
    }
333
334 1
    public function getItems(): ItemCollection
335
    {
336 1
        return $this->items;
337
    }
338
339 1
    public function getLatestInvoiceId(): ?string
340
    {
341 1
        return $this->latestInvoiceId;
342
    }
343
344 1
    public function getPendingSetupIntentId(): ?string
345
    {
346 1
        return $this->pendingSetupIntentId;
347
    }
348
349
    public function getPlan(): Plan
350
    {
351
        return $this->plan;
352
    }
353
354 1
    public function getQuantity(): int
355
    {
356 1
        return $this->quantity;
357
    }
358
359 1
    public function getStartAt(): \DateTimeImmutable
360
    {
361 1
        return $this->startAt;
362
    }
363
364 1
    public function getStatus(): string
365
    {
366 1
        return $this->status;
367
    }
368
369 1
    public function getTrialEndAt(): ?\DateTimeImmutable
370
    {
371 1
        return $this->trialEndAt;
372
    }
373
374 1
    public function getTrialStartAt(): ?\DateTimeImmutable
375
    {
376 1
        return $this->trialStartAt;
377
    }
378
}
379