Passed
Push — master ( 37b02e...ebbbe1 )
by James
08:59
created

app/Models/Account.php (1 issue)

Labels
Severity
1
<?php
2
/**
3
 * Account.php
4
 * Copyright (c) 2017 [email protected]
5
 *
6
 * This file is part of Firefly III.
7
 *
8
 * Firefly III is free software: you can redistribute it and/or modify
9
 * it under the terms of the GNU General Public License as published by
10
 * the Free Software Foundation, either version 3 of the License, or
11
 * (at your option) any later version.
12
 *
13
 * Firefly III is distributed in the hope that it will be useful,
14
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16
 * GNU General Public License for more details.
17
 *
18
 * You should have received a copy of the GNU General Public License
19
 * along with Firefly III. If not, see <http://www.gnu.org/licenses/>.
20
 */
21
declare(strict_types=1);
22
23
namespace FireflyIII\Models;
24
25
use Crypt;
26
use FireflyIII\Exceptions\FireflyException;
27
use Illuminate\Contracts\Encryption\DecryptException;
28
use Illuminate\Database\Eloquent\Builder as EloquentBuilder;
29
use Illuminate\Database\Eloquent\Model;
30
use Illuminate\Database\Eloquent\Relations\BelongsTo;
31
use Illuminate\Database\Eloquent\Relations\HasMany;
32
use Illuminate\Database\Eloquent\SoftDeletes;
33
use Illuminate\Database\Query\JoinClause;
34
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
35
use Watson\Validating\ValidatingTrait;
36
37
/**
38
 * Class Account.
39
 */
40
class Account extends Model
41
{
42
    use SoftDeletes, ValidatingTrait;
0 ignored issues
show
The trait Watson\Validating\ValidatingTrait requires the property $validationMessages which is not provided by FireflyIII\Models\Account.
Loading history...
43
44
    /**
45
     * The attributes that should be casted to native types.
46
     *
47
     * @var array
48
     */
49
    protected $casts
50
        = [
51
            'created_at' => 'datetime',
52
            'updated_at' => 'datetime',
53
            'deleted_at' => 'datetime',
54
            'active'     => 'boolean',
55
            'encrypted'  => 'boolean',
56
        ];
57
    /** @var array */
58
    protected $fillable = ['user_id', 'account_type_id', 'name', 'active', 'virtual_balance', 'iban'];
59
    /** @var array */
60
    protected $hidden = ['encrypted'];
61
    /**
62
     * @var array
63
     */
64
    protected $rules
65
        = [
66
            'user_id'         => 'required|exists:users,id',
67
            'account_type_id' => 'required|exists:account_types,id',
68
            'name'            => 'required|between:1,200',
69
            'active'          => 'required|boolean',
70
            'iban'            => 'between:1,50|iban',
71
        ];
72
    /** @var bool */
73
    private $joinedAccountTypes;
74
75
    /**
76
     * @param array $fields
77
     *
78
     * @return Account
79
     *
80
     * @throws FireflyException
81
     */
82
    public static function firstOrCreateEncrypted(array $fields)
83
    {
84
        if (!isset($fields['user_id'])) {
85
            throw new FireflyException('Missing required field "user_id".');
86
        }
87
        // everything but the name:
88
        $query  = self::orderBy('id');
89
        $search = $fields;
90
        unset($search['name'], $search['iban']);
91
92
        foreach ($search as $name => $value) {
93
            $query->where($name, $value);
94
        }
95
        $set = $query->get(['accounts.*']);
96
97
        // account must have a name. If not set, use IBAN.
98
        if (!isset($fields['name'])) {
99
            $fields['name'] = $fields['iban'];
100
        }
101
102
        /** @var Account $account */
103
        foreach ($set as $account) {
104
            if ($account->name === $fields['name']) {
105
                return $account;
106
            }
107
        }
108
109
        // create it!
110
        $account = self::create($fields);
111
112
        return $account;
113
    }
114
115
    /**
116
     * @param string $value
117
     *
118
     * @return Account
119
     * @throws \Symfony\Component\HttpKernel\Exception\NotFoundHttpException
120
     */
121
    public static function routeBinder(string $value): Account
122
    {
123
        if (auth()->check()) {
124
            $accountId = intval($value);
125
            $account   = auth()->user()->accounts()->find($accountId);
126
            if (!is_null($account)) {
127
                return $account;
128
            }
129
        }
130
        throw new NotFoundHttpException;
131
    }
132
133
    /**
134
     * @return HasMany
135
     * @codeCoverageIgnore
136
     */
137
    public function accountMeta(): HasMany
138
    {
139
        return $this->hasMany('FireflyIII\Models\AccountMeta');
140
    }
141
142
    /**
143
     * @return BelongsTo
144
     * @codeCoverageIgnore
145
     */
146
    public function accountType(): BelongsTo
147
    {
148
        return $this->belongsTo('FireflyIII\Models\AccountType');
149
    }
150
151
    /**
152
     * @return string
153
     * @codeCoverageIgnore
154
     */
155
    public function getEditNameAttribute(): string
156
    {
157
        $name = $this->name;
158
159
        if (AccountType::CASH === $this->accountType->type) {
160
            return '';
161
        }
162
163
        return $name;
164
    }
165
166
    /**
167
     * @param $value
168
     *
169
     * @return string
170
     *
171
     * @throws FireflyException
172
     */
173
    public function getIbanAttribute($value): string
174
    {
175
        if (null === $value || 0 === strlen(strval($value))) {
176
            return '';
177
        }
178
        try {
179
            $result = Crypt::decrypt($value);
180
        } catch (DecryptException $e) {
181
            throw new FireflyException('Cannot decrypt value "' . $value . '" for account #' . $this->id);
182
        }
183
        if (null === $result) {
184
            return '';
185
        }
186
187
        return $result;
188
    }
189
190
    /**
191
     * @codeCoverageIgnore
192
     *
193
     * @param string $fieldName
194
     * @deprecated
195
     * @return string
196
     */
197
    public function getMeta(string $fieldName): string
198
    {
199
        foreach ($this->accountMeta as $meta) {
200
            if ($meta->name === $fieldName) {
201
                return strval($meta->data);
202
            }
203
        }
204
205
        return '';
206
    }
207
208
    /**
209
     * @codeCoverageIgnore
210
     *
211
     * @param $value
212
     *
213
     * @return string
214
     * @throws \Illuminate\Contracts\Encryption\DecryptException
215
     */
216
    public function getNameAttribute($value): ?string
217
    {
218
        if ($this->encrypted) {
219
            return Crypt::decrypt($value);
220
        }
221
222
        return $value;
223
    }
224
225
    /**
226
     * Returns the opening balance.
227
     *
228
     * @return TransactionJournal
229
     */
230
    public function getOpeningBalance(): TransactionJournal
231
    {
232
        $journal = TransactionJournal::leftJoin('transactions', 'transactions.transaction_journal_id', '=', 'transaction_journals.id')
233
                                     ->where('transactions.account_id', $this->id)
234
                                     ->transactionTypes([TransactionType::OPENING_BALANCE])
235
                                     ->first(['transaction_journals.*']);
236
        if (null === $journal) {
237
            return new TransactionJournal;
238
        }
239
240
        return $journal;
241
    }
242
243
    /**
244
     * @codeCoverageIgnore
245
     * Get all of the notes.
246
     */
247
    public function notes()
248
    {
249
        return $this->morphMany(Note::class, 'noteable');
250
    }
251
252
    /**
253
     * @return HasMany
254
     * @codeCoverageIgnore
255
     */
256
    public function piggyBanks(): HasMany
257
    {
258
        return $this->hasMany('FireflyIII\Models\PiggyBank');
259
    }
260
261
    /**
262
     * @codeCoverageIgnore
263
     *
264
     * @param EloquentBuilder $query
265
     * @param array           $types
266
     */
267
    public function scopeAccountTypeIn(EloquentBuilder $query, array $types)
268
    {
269
        if (null === $this->joinedAccountTypes) {
270
            $query->leftJoin('account_types', 'account_types.id', '=', 'accounts.account_type_id');
271
            $this->joinedAccountTypes = true;
272
        }
273
        $query->whereIn('account_types.type', $types);
274
    }
275
276
    /**
277
     * @codeCoverageIgnore
278
     * @deprecated
279
     *
280
     * @param EloquentBuilder $query
281
     * @param string          $name
282
     * @param string          $value
283
     *
284
     * @throws \InvalidArgumentException
285
     */
286
    public function scopeHasMetaValue(EloquentBuilder $query, $name, $value)
287
    {
288
        $joinName = str_replace('.', '_', $name);
289
        $query->leftJoin(
290
            'account_meta as ' . $joinName,
291
            function (JoinClause $join) use ($joinName, $name) {
292
                $join->on($joinName . '.account_id', '=', 'accounts.id')->where($joinName . '.name', '=', $name);
293
            }
294
        );
295
        $query->where($joinName . '.data', json_encode($value));
296
    }
297
298
    /**
299
     * @codeCoverageIgnore
300
     *
301
     * @param $value
302
     *
303
     * @codeCoverageIgnore
304
     * @throws \Illuminate\Contracts\Encryption\EncryptException
305
     */
306
    public function setIbanAttribute($value)
307
    {
308
        $this->attributes['iban'] = Crypt::encrypt($value);
309
    }
310
311
    /**
312
     * @codeCoverageIgnore
313
     *
314
     * @param $value
315
     * @throws \Illuminate\Contracts\Encryption\EncryptException
316
     */
317
    public function setNameAttribute($value)
318
    {
319
        $encrypt                       = config('firefly.encryption');
320
        $this->attributes['name']      = $encrypt ? Crypt::encrypt($value) : $value;
321
        $this->attributes['encrypted'] = $encrypt;
322
    }
323
324
    /**
325
     * @codeCoverageIgnore
326
     *
327
     * @param $value
328
     *
329
     * @codeCoverageIgnore
330
     */
331
    public function setVirtualBalanceAttribute($value)
332
    {
333
        $this->attributes['virtual_balance'] = strval($value);
334
    }
335
336
    /**
337
     * @return HasMany
338
     * @codeCoverageIgnore
339
     */
340
    public function transactions(): HasMany
341
    {
342
        return $this->hasMany('FireflyIII\Models\Transaction');
343
    }
344
345
    /**
346
     * @return BelongsTo
347
     * @codeCoverageIgnore
348
     */
349
    public function user(): BelongsTo
350
    {
351
        return $this->belongsTo('FireflyIII\User');
352
    }
353
}
354