Issues (19)

src/Traits/HasAddresses.php (11 issues)

1
<?php
2
3
namespace Chuckcms\Addresses\Traits;
4
5
use Chuckcms\Addresses\Contracts\Address;
6
use Chuckcms\Addresses\Exceptions\FailedValidation;
7
use Chuckcms\Addresses\Models\Address as AddressModel;
8
use Illuminate\Database\Eloquent\Relations\MorphMany;
9
use Illuminate\Support\Collection;
10
use Illuminate\Validation\Validator;
0 ignored issues
show
The type Illuminate\Validation\Validator was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
11
12
trait HasAddresses
13
{
14
    private $addressClass;
15
16
    /**
17
     * Boot the addressable trait for the model.
18
     *
19
     * @return void
20
     */
21
    public static function bootHasAddresses()
22
    {
23
        static::deleting(function (self $model) {
24
            if (method_exists($model, 'isForceDeleting') && $model->isForceDeleting()) {
25
                $model->addresses()->forceDelete();
26
27
                return;
28
            }
29
30
            $model->addresses()->delete();
31
        });
32
    }
33
34
    public function getAddressClass()
35
    {
36
        if (!isset($this->addressClass)) {
37
            $this->addressClass = config('addresses.models.address');
0 ignored issues
show
The function config was not found. Maybe you did not declare it correctly or list all dependencies? ( Ignorable by Annotation )

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

37
            $this->addressClass = /** @scrutinizer ignore-call */ config('addresses.models.address');
Loading history...
38
        }
39
40
        return $this->addressClass;
41
    }
42
43
    /**
44
     * A model may have multiple addresses.
45
     *
46
     * @return MorphMany
47
     */
48
    public function addresses(): MorphMany
49
    {
50
        return $this->morphMany(
0 ignored issues
show
It seems like morphMany() must be provided by classes using this trait. How about adding it as abstract method to this trait? ( Ignorable by Annotation )

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

50
        return $this->/** @scrutinizer ignore-call */ morphMany(
Loading history...
51
            config('addresses.models.address'),
0 ignored issues
show
The function config was not found. Maybe you did not declare it correctly or list all dependencies? ( Ignorable by Annotation )

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

51
            /** @scrutinizer ignore-call */ 
52
            config('addresses.models.address'),
Loading history...
52
            config('addresses.column_names.model_morph_name'),
53
            config('addresses.column_names.model_morph_type'),
54
            config('addresses.column_names.model_morph_key')
55
        );
56
    }
57
58
    /**
59
     * Check if model has addresses.
60
     *
61
     * @return bool
62
     */
63
    public function hasAddresses(): bool
64
    {
65
        return (bool) count($this->addresses);
0 ignored issues
show
The property addresses does not exist on Chuckcms\Addresses\Traits\HasAddresses. Did you mean addressClass?
Loading history...
66
    }
67
68
    /**
69
     * Add an address to this model.
70
     *
71
     * @param array $attributes
72
     *
73
     * @throws Exception
74
     *
75
     * @return mixed
76
     */
77
    public function addAddress(array $attributes)
78
    {
79
        $attributes = $this->loadAddressAttributes($attributes);
80
81
        return $this->addresses()->create($attributes);
82
    }
83
84
    /**
85
     * Updates the given address.
86
     *
87
     * @param Address $address
88
     * @param array   $attributes
89
     *
90
     * @throws Exception
91
     *
92
     * @return bool
93
     */
94
    public function updateAddress(Address $address, array $attributes): bool
95
    {
96
        $attributes = $this->loadAddressAttributes($attributes);
97
98
        return $address->fill($attributes)->save();
0 ignored issues
show
The method fill() does not exist on Chuckcms\Addresses\Contracts\Address. Since it exists in all sub-types, consider adding an abstract or default implementation to Chuckcms\Addresses\Contracts\Address. ( Ignorable by Annotation )

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

98
        return $address->/** @scrutinizer ignore-call */ fill($attributes)->save();
Loading history...
99
    }
100
101
    /**
102
     * Deletes given address(es).
103
     *
104
     * @param int|array|\Chuck\Address\Contracts\Address $addresses
0 ignored issues
show
The type Chuck\Address\Contracts\Address was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
105
     * @param bool                                       $force
106
     *
107
     * @throws Exception
108
     *
109
     * @return mixed
110
     */
111
    public function deleteAddress($addresses, $force = false): bool
112
    {
113
        if (is_int($addresses) && $this->hasAddress($addresses)) {
114
            return $force ?
115
                    $this->addresses()->where('id', $addresses)->forceDelete() :
116
                    $this->addresses()->where('id', $addresses)->delete();
117
        }
118
119
        if ($addresses instanceof Address && $this->hasAddress($addresses)) {
120
            return $force ?
121
                    $this->addresses()->where('id', $addresses->id)->forceDelete() :
0 ignored issues
show
Accessing id on the interface Chuckcms\Addresses\Contracts\Address suggest that you code against a concrete implementation. How about adding an instanceof check?
Loading history...
122
                    $this->addresses()->where('id', $addresses->id)->delete();
123
        }
124
125
        if (is_array($addresses)) {
126
            foreach ($addresses as $address) {
127
                if ($this->deleteAddress($address, $force)) {
128
                    continue;
129
                }
130
            }
131
132
            return true;
133
        }
134
135
        return false;
136
    }
137
138
    /**
139
     * Forcefully deletes given address(es).
140
     *
141
     * @param int|array|\Chuck\Address\Contracts\Address $addresses
142
     * @param bool                                       $force
143
     *
144
     * @throws Exception
145
     *
146
     * @return mixed
147
     */
148
    public function forceDeleteAddress($addresses): bool
149
    {
150
        return $this->deleteAddress($addresses, true);
151
    }
152
153
    /**
154
     * Determine if the model has (one of) the given address(es).
155
     *
156
     * @param int|array|\Chuck\Address\Contracts\Address|\Illuminate\Support\Collection $addresses
157
     *
158
     * @return bool
159
     */
160
    public function hasAddress($addresses): bool
161
    {
162
        if (is_int($addresses)) {
163
            return $this->addresses->contains('id', $addresses);
0 ignored issues
show
The property addresses does not exist on Chuckcms\Addresses\Traits\HasAddresses. Did you mean addressClass?
Loading history...
164
        }
165
166
        if ($addresses instanceof Address) {
167
            return $this->addresses->contains('id', $addresses->id);
168
        }
169
170
        if (is_array($addresses)) {
171
            foreach ($addresses as $address) {
172
                if ($this->hasAddress($address)) {
173
                    return true;
174
                }
175
            }
176
177
            return false;
178
        }
179
180
        return $addresses->intersect($this->addresses)->isNotEmpty();
181
    }
182
183
    public function getAddressLabels(): Collection
184
    {
185
        return $this->addresses->pluck('label');
0 ignored issues
show
The property addresses does not exist on Chuckcms\Addresses\Traits\HasAddresses. Did you mean addressClass?
Loading history...
186
    }
187
188
    /**
189
     * Get the public address.
190
     *
191
     * @param string $direction
192
     *
193
     * @return Address|null
194
     */
195
    public function getPublicAddress(string $direction = 'desc'): ?Address
196
    {
197
        return $this->addresses()
198
                    ->isPublic()
199
                    ->orderBy('is_public', $direction)
200
                    ->first();
201
    }
202
203
    /**
204
     * Get the primary address.
205
     *
206
     * @param string $direction
207
     *
208
     * @return Address|null
209
     */
210
    public function getPrimaryAddress(string $direction = 'desc'): ?Address
211
    {
212
        return $this->addresses()
213
                    ->isPrimary()
214
                    ->orderBy('is_primary', $direction)
215
                    ->first();
216
    }
217
218
    /**
219
     * Get the billing address.
220
     *
221
     * @param string $direction
222
     *
223
     * @return Address|null
224
     */
225
    public function getBillingAddress(string $direction = 'desc'): ?Address
226
    {
227
        return $this->addresses()
228
                    ->isBilling()
229
                    ->orderBy('is_billing', $direction)
230
                    ->first();
231
    }
232
233
    /**
234
     * Get the first shipping address.
235
     *
236
     * @param string $direction
237
     *
238
     * @return Address|null
239
     */
240
    public function getShippingAddress(string $direction = 'desc'): ?Address
241
    {
242
        return $this->addresses()
243
                    ->isShipping()
244
                    ->orderBy('is_shipping', $direction)
245
                    ->first();
246
    }
247
248
    /**
249
     * Add country id to attributes array.
250
     *
251
     * @param array $attributes
252
     *
253
     * @throws FailedValidation
254
     *
255
     * @return array
256
     */
257
    public function loadAddressAttributes(array $attributes): array
258
    {
259
        if (!isset($attributes['label'])) {
260
            throw new FailedValidation('[Addresses] No label given.');
261
        }
262
263
        $validator = $this->validateAddress($attributes);
264
265
        if ($validator->fails()) {
266
            $errors = $validator->errors()->all();
267
            $error = '[Addresses] '.implode(' ', $errors);
268
269
            throw new FailedValidation($error);
270
        }
271
272
        return $attributes;
273
    }
274
275
    /**
276
     * Validate the address.
277
     *
278
     * @param array $attributes
279
     *
280
     * @return Validator
281
     */
282
    public function validateAddress(array $attributes): Validator
283
    {
284
        $rules = (new AddressModel())->getValidationRules();
285
286
        return validator($attributes, $rules);
0 ignored issues
show
The function validator was not found. Maybe you did not declare it correctly or list all dependencies? ( Ignorable by Annotation )

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

286
        return /** @scrutinizer ignore-call */ validator($attributes, $rules);
Loading history...
287
    }
288
}
289