Passed
Push — master ( 959790...1ac34b )
by Michael
02:12
created

RelatedPlusTrait::setSearchFields()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 1
nc 1
nop 1
dl 0
loc 3
rs 10
c 0
b 0
f 0
1
<?php
2
3
namespace Blasttech\EloquentRelatedPlus;
4
5
use Illuminate\Database\Eloquent\Builder;
6
use Illuminate\Database\Eloquent\Model;
7
use Illuminate\Database\Eloquent\Relations\BelongsTo;
8
use Illuminate\Database\Eloquent\Relations\HasOneOrMany;
9
use Illuminate\Database\Query\Expression;
10
use Illuminate\Database\Query\JoinClause;
11
use Illuminate\Support\Facades\DB;
12
use Illuminate\Support\Facades\Schema;
13
14
/**
15
 * Trait RelatedPlusTrait
16
 *
17
 * @property array attributes
18
 * @property array nullable
19
 * @property array order_fields
20
 * @property array order_defaults
21
 * @property array order_relations
22
 * @property array order_with
23
 * @property array search_fields
24
 * @property string connection
25
 * @method Model getModel()
26
 * @method string getTable()
27
 */
28
trait RelatedPlusTrait
29
{
30
    use CustomOrderTrait, SearchTrait, HelpersTrait;
31
32
    /**
33
     * Boot method for trait
34
     *
35
     */
36
    public static function bootRelatedPlusTrait()
37
    {
38
        static::saving(function ($model) {
39
            if (!empty($model->nullable)) {
40
                /* @var \Illuminate\Database\Eloquent\Model|RelatedPlusTrait|static $model */
41
                $model->setAttributesNull();
42
            }
43
        });
44
    }
45
46
47
    /**
48
     * Get the search fields for the model
49
     *
50
     * @return array
51
     */
52
    public function getSearchFields()
53
    {
54
        return $this->hasSearchFields() ? $this->search_fields : [];
55
    }
56
57
    /**
58
     * Set the search fields for the model
59
     *
60
     * @param array $searchFields
61
     */
62
    public function setSearchFields(array $searchFields)
63
    {
64
        $this->search_fields = $searchFields;
65
    }
66
67
    /**
68
     * Add joins for one or more relations
69
     * This determines the foreign key relations automatically to prevent the need to figure out the columns.
70
     * Usages:
71
     * $query->modelJoin('customers')
72
     * $query->modelJoin('customer.client')
73
     *
74
     * @param Builder $query
75
     * @param string $relationName
76
     * @param string $operator
77
     * @param string $type
78
     * @param bool $where
79
     * @param bool $relatedSelect
80
     * @param string|null $direction
81
     *
82
     * @return Builder
83
     */
84
    public function scopeModelJoin(
85
        Builder $query,
86
        $relationName,
87
        $operator = '=',
88
        $type = 'left',
89
        $where = false,
90
        $relatedSelect = true,
91
        $direction = null
92
    ) {
93
        foreach ($this->parseRelationNames($this->getModel(), $relationName) as $relation) {
94
            // Add selects
95
            $query = $this->modelJoinSelects($query, $relation, $relatedSelect);
96
97
            $query->relationJoin($relation, $operator, $type, $where, $direction);
98
        }
99
100
        return $query;
101
    }
102
103
    /**
104
     * Get the relations from a relation name
105
     * $relationName can be a single relation
106
     * Usage for User model:
107
     * parseRelationNames('customer') returns [$user->customer()]
108
     * parseRelationNames('customer.contact') returns [$user->customer(), $user->customer->contact()]
109
     *
110
     * @param Model $model
111
     * @param string $relationNameString
112
     * @return RelationPlus[]
113
     */
114
    protected function parseRelationNames($model, $relationNameString)
115
    {
116
        $relationNames = explode('.', $relationNameString);
117
        $parentRelation = null;
118
        $relations = [];
119
120
        foreach ($relationNames as $relationName) {
121
            $relation = $this->getRelationFromName($model, $parentRelation, $relationName);
122
            $relations[] = new RelationPlus($relation);
123
            $parentRelation = $relation->getModel();
124
        }
125
126
        return $relations;
127
    }
128
129
    /**
130
     * @param Model $model
131
     * @param BelongsTo|HasOneOrMany|null $parentRelation
132
     * @param string $relationName
133
     * @return BelongsTo|HasOneOrMany
134
     */
135
    protected function getRelationFromName($model, $parentRelation, $relationName)
136
    {
137
        if (is_null($parentRelation)) {
138
            return $model->$relationName();
139
        }
140
141
        return $parentRelation->$relationName();
142
    }
143
144
    /**
145
     * Add selects for model join
146
     *
147
     * @param Builder $query
148
     * @param RelationPlus $relation
149
     * @param bool $relatedSelect
150
     * @return mixed
151
     */
152
    protected function modelJoinSelects($query, $relation, $relatedSelect)
153
    {
154
        if (empty($query->getQuery()->columns)) {
155
            $query->select($this->getTable() . ".*");
156
        }
157
        if ($relatedSelect) {
158
            $query = $this->selectRelated($query, $relation);
159
        }
160
161
        return $query;
162
    }
163
164
    /**
165
     * Add select for related table fields
166
     *
167
     * @param Builder $query
168
     * @param RelationPlus $relation
169
     * @return Builder
170
     */
171
    protected function selectRelated(Builder $query, $relation)
172
    {
173
        $connection = $this->connection;
174
175
        foreach (Schema::connection($connection)->getColumnListing($relation->tableName) as $relatedColumn) {
176
            $query->addSelect(
177
                new Expression("`$relation->tableAlias`.`$relatedColumn` AS `$relation->tableAlias.$relatedColumn`")
178
            );
179
        }
180
181
        return $query;
182
    }
183
184
    /**
185
     * Set the order of a model
186
     *
187
     * @param Builder $query
188
     * @param string $orderField
189
     * @param string $direction
190
     * @return Builder
191
     */
192
    public function scopeOrderByCustom(Builder $query, $orderField, $direction)
193
    {
194
        if ($this->hasOrderFieldsAndDefaults($orderField, $direction)) {
195
            $query = $this->removeGlobalScopes($this->getModel(), $query, 'order');
196
        }
197
198
        return $query->setCustomOrder($orderField, $direction);
199
    }
200
201
    /**
202
     * Use a model method to add columns or joins if in the order options
203
     *
204
     * @param Builder $query
205
     * @param string $order
206
     * @return Builder
207
     */
208
    public function scopeOrderByWith(Builder $query, $order)
209
    {
210
        if (isset($this->order_with[$order])) {
211
            $query = $this->addOrderWith($query, $order);
212
        }
213
214
        if (isset($this->order_fields[$order])) {
215
            $query = $this->addOrderJoin($query, $order);
216
        }
217
218
        return $query;
219
    }
220
221
    /**
222
     * Join a model
223
     *
224
     * @param Builder $query
225
     * @param RelationPlus $relation
226
     * @param string $operator
227
     * @param string $type
228
     * @param boolean $where
229
     * @param string $direction
230
     * @return Builder|\Illuminate\Database\Query\Builder
231
     */
232
    public function scopeRelationJoin(
233
        Builder $query,
234
        $relation,
235
        $operator,
236
        $type,
237
        $where,
238
        $direction = null
239
    ) {
240
        $fullTableName = $relation->getTableWithAlias();
241
242
        return $query->join($fullTableName, function (JoinClause $join) use (
243
            $relation,
244
            $operator,
245
            $direction
246
        ) {
247
            return $relation->getRelationJoin($join, $operator, $direction);
248
        }, null, null, $type, $where);
249
    }
250
251
    /**
252
     * Add where statements for the model search fields
253
     *
254
     * @param Builder $query
255
     * @param string $searchText
256
     * @return Builder
257
     */
258
    public function scopeSearch(Builder $query, $searchText = '')
259
    {
260
        $searchText = trim($searchText);
261
262
        // If search is set
263
        if ($searchText != "" && $this->hasSearchFields()) {
264
            $query = $this->checkSearchFields($query, $searchText);
265
        }
266
267
        return $query;
268
    }
269
270
    /**
271
     * Switch a query to be a subquery of a model
272
     *
273
     * @param Builder $query
274
     * @param Builder $model
275
     * @return Builder|\Illuminate\Database\Query\Builder
276
     */
277
    public function scopeSetSubquery(Builder $query, $model)
278
    {
279
        $sql = $this->toSqlWithBindings($model);
280
        $table = $model->getQuery()->from;
281
282
        return $query
283
            ->from(DB::raw("({$sql}) as " . $table))
284
            ->select($table . '.*');
285
    }
286
287
    /**
288
     * Set the model order
289
     *
290
     * @param Builder $query
291
     * @param string $column
292
     * @param string $direction
293
     * @return Builder
294
     */
295
    public function scopeSetCustomOrder(Builder $query, $column, $direction)
296
    {
297
        if (isset($this->order_defaults)) {
298
            $column = $this->setOrderColumn($column);
299
            $direction = $this->setOrderDirection($direction);
300
        }
301
302
        return $this->setOrder($query, $column, $direction);
303
    }
304
305
    /**
306
     * Check if column being sorted by is from a related model
307
     *
308
     * @param Builder $query
309
     * @param string $column
310
     * @param string $direction
311
     * @return Builder
312
     */
313
    public function scopeOrderByCheckModel(Builder $query, $column, $direction)
314
    {
315
        $query->orderBy(DB::raw($column), $direction);
316
317
        if (isset($this->order_relations) && (strpos($column, '.') !== false ||
318
                isset($this->order_relations[$column]))) {
319
            $query = $this->joinRelatedTable($query, $this->getTableFromColumn($column));
320
        }
321
322
        return $query;
323
    }
324
}
325