Completed
Pull Request — master (#1488)
by Elf
01:39
created

EloquentDataTable::__construct()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 7
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 2
eloc 4
nc 2
nop 1
dl 0
loc 7
rs 9.4285
c 0
b 0
f 0
1
<?php
2
3
namespace Yajra\DataTables;
4
5
use Illuminate\Database\Eloquent\Builder;
6
use Yajra\DataTables\Exceptions\Exception;
7
use Illuminate\Database\Eloquent\Relations\BelongsTo;
8
use Illuminate\Database\Eloquent\Relations\HasOneOrMany;
9
use Illuminate\Database\Eloquent\Relations\BelongsToMany;
10
11
class EloquentDataTable extends QueryDataTable
12
{
13
    /**
14
     * @var \Illuminate\Database\Eloquent\Builder
15
     */
16
    protected $query;
17
18
    /**
19
     * EloquentDataTable constructor.
20
     *
21
     * @param mixed $model
22
     */
23
    public function __construct($model)
24
    {
25
        $builder = $model instanceof Builder ? $model : $model->getQuery();
26
        parent::__construct($builder->getQuery());
27
28
        $this->query = $builder;
29
    }
30
31
    /**
32
     * Add columns in collection.
33
     *
34
     * @param  array  $names
35
     * @param  bool|int  $order
36
     * @return $this
37
     */
38
    public function addColumns(array $names, $order = false)
39
    {
40
        foreach ($names as $name => $attribute) {
41
            if (is_int($name)) {
42
                $name = $attribute;
43
            }
44
45
            $this->addColumn($name, function ($model) use ($attribute) {
46
                return $model->getAttribute($attribute);
47
            }, is_int($order) ? $order++ : $order);
48
        }
49
50
        return $this;
51
    }
52
53
    /**
54
     * If column name could not be resolved then use primary key.
55
     *
56
     * @return string
57
     */
58
    protected function getPrimaryKeyName()
59
    {
60
        return $this->query->getModel()->getKeyName();
61
    }
62
63
    /**
64
     * Compile query builder where clause depending on configurations.
65
     *
66
     * @param mixed  $query
67
     * @param string $columnName
68
     * @param string $keyword
69
     * @param string $boolean
70
     */
71
    protected function compileQuerySearch($query, $columnName, $keyword, $boolean = 'or')
72
    {
73
        $parts    = explode('.', $columnName);
74
        $column   = array_pop($parts);
75
        $relation = implode('.', $parts);
76
77
        if ($this->isNotEagerLoaded($relation)) {
78
            return parent::compileQuerySearch($query, $columnName, $keyword, $boolean);
79
        }
80
81
        $query->{$boolean . 'WhereHas'}($relation, function (Builder $query) use ($column, $keyword) {
82
            parent::compileQuerySearch($query, $column, $keyword, '');
83
        });
84
    }
85
86
    /**
87
     * Resolve the proper column name be used.
88
     *
89
     * @param string $column
90
     * @return string
91
     */
92
    protected function resolveRelationColumn($column)
93
    {
94
        $parts      = explode('.', $column);
95
        $columnName = array_pop($parts);
96
        $relation   = implode('.', $parts);
97
98
        if ($this->isNotEagerLoaded($relation)) {
99
            return $column;
100
        }
101
102
        return $this->joinEagerLoadedColumn($relation, $columnName);
103
    }
104
105
    /**
106
     * Check if a relation was not used on eager loading.
107
     *
108
     * @param  string $relation
109
     * @return bool
110
     */
111
    protected function isNotEagerLoaded($relation)
112
    {
113
        return ! $relation
114
            || ! in_array($relation, array_keys($this->query->getEagerLoads()))
115
            || $relation === $this->query->getModel()->getTable();
116
    }
117
118
    /**
119
     * Join eager loaded relation and get the related column name.
120
     *
121
     * @param string $relation
122
     * @param string $relationColumn
123
     * @return string
124
     * @throws \Yajra\DataTables\Exceptions\Exception
125
     */
126
    protected function joinEagerLoadedColumn($relation, $relationColumn)
127
    {
128
        $table     = '';
129
        $lastQuery = $this->query;
130
        foreach (explode('.', $relation) as $eachRelation) {
131
            $model = $lastQuery->getRelation($eachRelation);
132
            switch (true) {
133
                case $model instanceof BelongsToMany:
134
                    $pivot   = $model->getTable();
135
                    $pivotPK = $model->getExistenceCompareKey();
136
                    $pivotFK = $model->getQualifiedParentKeyName();
137
                    $this->performJoin($pivot, $pivotPK, $pivotFK);
138
139
                    $related = $model->getRelated();
140
                    $table   = $related->getTable();
141
                    $tablePK = $related->getForeignKey();
142
                    $foreign = $pivot . '.' . $tablePK;
143
                    $other   = $related->getQualifiedKeyName();
144
145
                    $lastQuery->addSelect($table . '.' . $relationColumn);
146
                    $this->performJoin($table, $foreign, $other);
147
148
                    break;
149
150
                case $model instanceof HasOneOrMany:
151
                    $table   = $model->getRelated()->getTable();
152
                    $foreign = $model->getQualifiedForeignKeyName();
153
                    $other   = $model->getQualifiedParentKeyName();
154
                    break;
155
156
                case $model instanceof BelongsTo:
157
                    $table   = $model->getRelated()->getTable();
158
                    $foreign = $model->getQualifiedForeignKey();
159
                    $other   = $model->getQualifiedOwnerKeyName();
160
                    break;
161
162
                default:
163
                    throw new Exception('Relation ' . get_class($model) . ' is not yet supported.');
164
            }
165
            $this->performJoin($table, $foreign, $other);
166
            $lastQuery = $model->getQuery();
167
        }
168
169
        return $table . '.' . $relationColumn;
170
    }
171
172
    /**
173
     * Perform join query.
174
     *
175
     * @param string $table
176
     * @param string $foreign
177
     * @param string $other
178
     * @param string $type
179
     */
180
    protected function performJoin($table, $foreign, $other, $type = 'left')
181
    {
182
        $joins = [];
183
        foreach ((array) $this->getBaseQueryBuilder()->joins as $key => $join) {
184
            $joins[] = $join->table;
185
        }
186
187
        if (! in_array($table, $joins)) {
188
            $this->getBaseQueryBuilder()->join($table, $foreign, '=', $other, $type);
189
        }
190
    }
191
}
192