Completed
Push — develop ( 45ab37...1fc05f )
by Nate
16:44
created

Token::getEnvironments()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 16

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 6

Importance

Changes 0
Metric Value
dl 0
loc 16
ccs 0
cts 10
cp 0
rs 9.7333
c 0
b 0
f 0
cc 2
nc 2
nop 1
crap 6
1
<?php
2
3
/**
4
 * @copyright  Copyright (c) Flipbox Digital Limited
5
 * @license    https://flipboxfactory.com/software/patron/license
6
 * @link       https://www.flipboxfactory.com/software/patron/
7
 */
8
9
namespace flipbox\patron\records;
10
11
use Craft;
12
use craft\helpers\DateTimeHelper;
13
use craft\validators\DateTimeValidator;
14
use DateTime;
15
use flipbox\ember\helpers\ModelHelper;
16
use flipbox\ember\helpers\QueryHelper;
17
use flipbox\ember\records\ActiveRecordWithId;
18
use flipbox\ember\records\traits\StateAttribute;
19
use flipbox\patron\db\TokenActiveQuery;
20
use yii\db\ActiveQueryInterface;
21
22
/**
23
 * @author Flipbox Factory <[email protected]>
24
 * @since 1.0.0
25
 *
26
 * @property string $accessToken
27
 * @property string $refreshToken
28
 * @property DateTime|null $dateExpires
29
 * @property array $values
30
 * @property ProviderInstance[] $instances
31
 * @property TokenEnvironment[] $environments
32
 */
33
class Token extends ActiveRecordWithId
34
{
35
    use StateAttribute,
36
        traits\ProviderAttribute,
37
        traits\RelatedEnvironmentsAttribute;
38
39
    /**
40
     * The table alias
41
     */
42
    const TABLE_ALIAS = 'patron_tokens';
43
44
    /**
45
     * @inheritdoc
46
     */
47
    protected $getterPriorityAttributes = [
48
        'providerId'
49
    ];
50
51
    /*******************************************
52
     * QUERY
53
     *******************************************/
54
55
    /**
56
     * @inheritdoc
57
     * @return TokenActiveQuery
58
     * @throws \yii\base\InvalidConfigException
59
     */
60
    public static function find()
61
    {
62
        /** @noinspection PhpIncompatibleReturnTypeInspection */
63
        return Craft::createObject(TokenActiveQuery::class, [get_called_class()]);
64
    }
65
66
    /**
67
     * @return bool
68
     */
69
    public function isActive(): bool
70
    {
71
        return $this->isEnabled() && !$this->hasExpired();
72
    }
73
74
    /**
75
     * @return bool
76
     */
77
    public function hasExpired(): bool
78
    {
79
        $dateExpires = $this->dateExpires ?: new DateTime('now');
80
        return DateTimeHelper::isInThePast($dateExpires);
81
    }
82
83
84
    /*******************************************
85
     * EVENTS
86
     *******************************************/
87
88
    /**
89
     * @inheritdoc
90
     */
91
    public function beforeSave($insert): bool
92
    {
93
        if (!parent::beforeSave($insert)) {
94
            return false;
95
        }
96
97
        return $this->beforeSaveEnvironments($insert);
98
    }
99
100
101
    /*******************************************
102
     * UPDATE / INSERT
103
     *******************************************/
104
105
    /**
106
     * @inheritdoc
107
     * @throws \Throwable
108
     */
109
    protected function insertInternal($attributes = null)
110
    {
111
        if (!parent::insertInternal($attributes)) {
112
            return false;
113
        }
114
115
        return $this->insertInternalEnvironments($attributes);
116
    }
117
118
    /**
119
     * @inheritdoc
120
     * @throws \Throwable
121
     */
122
    protected function updateInternal($attributes = null)
123
    {
124
        if (!parent::updateInternal($attributes)) {
0 ignored issues
show
Bug Best Practice introduced by
The expression parent::updateInternal($attributes) of type false|integer is loosely compared to false; this is ambiguous if the integer can be zero. You might want to explicitly use === null instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For integer values, zero is a special case, in particular the following results might be unexpected:

0   == false // true
0   == null  // true
123 == false // false
123 == null  // false

// It is often better to use strict comparison
0 === false // false
0 === null  // false
Loading history...
125
            return false;
126
        }
127
128
        return $this->upsertInternal($attributes);
0 ignored issues
show
Bug Best Practice introduced by
The return type of return $this->upsertInternal($attributes); (boolean) is incompatible with the return type of the parent method yii\db\BaseActiveRecord::updateInternal of type false|integer.

If you return a value from a function or method, it should be a sub-type of the type that is given by the parent type f.e. an interface, or abstract method. This is more formally defined by the Lizkov substitution principle, and guarantees that classes that depend on the parent type can use any instance of a child type interchangably. This principle also belongs to the SOLID principles for object oriented design.

Let’s take a look at an example:

class Author {
    private $name;

    public function __construct($name) {
        $this->name = $name;
    }

    public function getName() {
        return $this->name;
    }
}

abstract class Post {
    public function getAuthor() {
        return 'Johannes';
    }
}

class BlogPost extends Post {
    public function getAuthor() {
        return new Author('Johannes');
    }
}

class ForumPost extends Post { /* ... */ }

function my_function(Post $post) {
    echo strtoupper($post->getAuthor());
}

Our function my_function expects a Post object, and outputs the author of the post. The base class Post returns a simple string and outputting a simple string will work just fine. However, the child class BlogPost which is a sub-type of Post instead decided to return an object, and is therefore violating the SOLID principles. If a BlogPost were passed to my_function, PHP would not complain, but ultimately fail when executing the strtoupper call in its body.

Loading history...
129
    }
130
131
    /**
132
     * @param null $attributes
133
     * @return bool
134
     * @throws \Throwable
135
     * @throws \yii\db\StaleObjectException
136
     */
137
    protected function upsertInternal($attributes = null): bool
138
    {
139
        if (empty($attributes)) {
140
            return $this->saveEnvironments();
141
        }
142
143
        if (array_key_exists('environments', $attributes)) {
144
            return $this->saveEnvironments(true);
145
        }
146
147
        return true;
148
    }
149
150
    /*******************************************
151
     * ENVIRONMENTS
152
     *******************************************/
153
154
    /**
155
     * @inheritdoc
156
     */
157
    protected static function environmentRecordClass(): string
158
    {
159
        return TokenEnvironment::class;
160
    }
161
162
    /**
163
     * @inheritdoc
164
     */
165
    protected function prepareEnvironmentRecordConfig(array $config = []): array
166
    {
167
        $config['token'] = $this;
168
        return $config;
169
    }
170
171
    /**
172
     * @inheritdoc
173
     */
174
    protected function environmentRelationshipQuery(): ActiveQueryInterface
175
    {
176
        return $this->hasMany(
177
            static::environmentRecordClass(),
178
            ['tokenId' => 'id']
179
        );
180
    }
181
182
    /**
183
     * @inheritdoc
184
     */
185
    public function rules()
186
    {
187
        return array_merge(
188
            parent::rules(),
189
            $this->stateRules(),
190
            $this->providerRules(),
191
            [
192
                [
193
                    [
194
                        'accessToken',
195
                        'refreshToken'
196
                    ],
197
                    'unique'
198
                ],
199
                [
200
                    [
201
                        'dateExpires'
202
                    ],
203
                    DateTimeValidator::class
204
                ],
205
                [
206
                    [
207
                        'providerId',
208
                        'accessToken'
209
                    ],
210
                    'required'
211
                ],
212
                [
213
                    [
214
                        'accessToken',
215
                        'values',
216
                        'dateExpires'
217
                    ],
218
                    'safe',
219
                    'on' => [
220
                        ModelHelper::SCENARIO_DEFAULT
221
                    ]
222
                ]
223
            ]
224
        );
225
    }
226
227
    /**
228
     * Get all of the associated instances.
229
     *
230
     * @param array $config
231
     * @return \yii\db\ActiveQuery
232
     */
233
    public function getInstances(array $config = [])
234
    {
235
        $query = $this->hasMany(
236
            ProviderInstance::class,
237
            ['providerId' => 'providerId']
238
        );
239
240
        if (!empty($config)) {
241
            QueryHelper::configure(
242
                $query,
243
                $config
244
            );
245
        }
246
247
        return $query;
248
    }
249
}
250