Completed
Push — master ( 501027...a97a17 )
by Arjay
01:39
created

src/EloquentDataTable.php (1 issue)

Labels
Severity

Upgrade to new PHP Analysis Engine

These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more

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\Relation;
8
use Illuminate\Database\Eloquent\Relations\BelongsTo;
9
use Illuminate\Database\Eloquent\Relations\HasOneOrMany;
10
use Illuminate\Database\Eloquent\Relations\BelongsToMany;
11
12
class EloquentDataTable extends QueryDataTable
13
{
14
    /**
15
     * @var \Illuminate\Database\Eloquent\Builder
16
     */
17
    protected $query;
18
19
    /**
20
     * Can the DataTable engine be created with these parameters.
21
     *
22
     * @param mixed $source
23
     * @return bool
24
     */
25
    public static function canCreate($source)
26
    {
27
        return $source instanceof Builder || $source instanceof Relation;
28
    }
29
30
    /**
31
     * EloquentEngine constructor.
32
     *
33
     * @param mixed $model
34
     */
35
    public function __construct($model)
36
    {
37
        $builder = $model instanceof Builder ? $model : $model->getQuery();
38
        parent::__construct($builder->getQuery());
39
40
        $this->query = $builder;
41
    }
42
43
    /**
44
     * Add columns in collection.
45
     *
46
     * @param  array  $names
47
     * @param  bool|int  $order
48
     * @return $this
49
     */
50
    public function addColumns(array $names, $order = false)
51
    {
52
        foreach ($names as $name => $attribute) {
53
            if (is_int($name)) {
54
                $name = $attribute;
55
            }
56
57
            $this->addColumn($name, function ($model) use ($attribute) {
58
                return $model->getAttribute($attribute);
59
            }, is_int($order) ? $order++ : $order);
60
        }
61
62
        return $this;
63
    }
64
65
    /**
66
     * If column name could not be resolved then use primary key.
67
     *
68
     * @return string
69
     */
70
    protected function getPrimaryKeyName()
71
    {
72
        return $this->query->getModel()->getKeyName();
73
    }
74
75
    /**
76
     * Compile query builder where clause depending on configurations.
77
     *
78
     * @param mixed  $query
79
     * @param string $columnName
80
     * @param string $keyword
81
     * @param string $boolean
82
     */
83
    protected function compileQuerySearch($query, $columnName, $keyword, $boolean = 'or')
84
    {
85
        $parts    = explode('.', $columnName);
86
        $column   = array_pop($parts);
87
        $relation = implode('.', $parts);
88
89
        if ($this->isNotEagerLoaded($relation)) {
90
            return parent::compileQuerySearch($query, $columnName, $keyword, $boolean);
91
        }
92
93
        $query->{$boolean . 'WhereHas'}($relation, function (Builder $query) use ($column, $keyword) {
94
            parent::compileQuerySearch($query, $column, $keyword, '');
95
        });
96
    }
97
98
    /**
99
     * Resolve the proper column name be used.
100
     *
101
     * @param string $column
102
     * @return string
103
     */
104
    protected function resolveRelationColumn($column)
105
    {
106
        $parts      = explode('.', $column);
107
        $columnName = array_pop($parts);
108
        $relation   = implode('.', $parts);
109
110
        if ($this->isNotEagerLoaded($relation)) {
111
            return $column;
112
        }
113
114
        return $this->joinEagerLoadedColumn($relation, $columnName);
115
    }
116
117
    /**
118
     * Check if a relation was not used on eager loading.
119
     *
120
     * @param  string $relation
121
     * @return bool
122
     */
123
    protected function isNotEagerLoaded($relation)
124
    {
125
        return ! $relation
126
            || ! array_key_exists($relation, $this->query->getEagerLoads())
127
            || $relation === $this->query->getModel()->getTable();
128
    }
129
130
    /**
131
     * Join eager loaded relation and get the related column name.
132
     *
133
     * @param string $relation
134
     * @param string $relationColumn
135
     * @return string
136
     * @throws \Yajra\DataTables\Exceptions\Exception
137
     */
138
    protected function joinEagerLoadedColumn($relation, $relationColumn)
139
    {
140
        $table     = '';
141
        $deletedAt = false;
142
        $lastQuery = $this->query;
143
        foreach (explode('.', $relation) as $eachRelation) {
144
            $model = $lastQuery->getRelation($eachRelation);
145
            switch (true) {
146
                case $model instanceof BelongsToMany:
147
                    $pivot   = $model->getTable();
148
                    $pivotPK = $model->getExistenceCompareKey();
149
                    $pivotFK = $model->getQualifiedParentKeyName();
150
                    $this->performJoin($pivot, $pivotPK, $pivotFK);
151
152
                    $related = $model->getRelated();
153
                    $table   = $related->getTable();
154
                    $tablePK = $related->getForeignKey();
155
                    $foreign = $pivot . '.' . $tablePK;
156
                    $other   = $related->getQualifiedKeyName();
157
158
                    $lastQuery->addSelect($table . '.' . $relationColumn);
159
                    $this->performJoin($table, $foreign, $other);
160
161
                    break;
162
163
                case $model instanceof HasOneOrMany:
164
                    $table     = $model->getRelated()->getTable();
165
                    $foreign   = $model->getQualifiedForeignKeyName();
166
                    $other     = $model->getQualifiedParentKeyName();
167
                    $deletedAt = $this->checkSoftDeletesOnModel($model->getRelated());
168
                    break;
169
170
                case $model instanceof BelongsTo:
171
                    $table     = $model->getRelated()->getTable();
172
                    $foreign   = $model->getQualifiedForeignKey();
0 ignored issues
show
The method getQualifiedForeignKey() does not exist on Illuminate\Database\Eloquent\Relations\BelongsTo. Did you maybe mean getQualifiedForeignKeyName()?

This check marks calls to methods that do not seem to exist on an object.

This is most likely the result of a method being renamed without all references to it being renamed likewise.

Loading history...
173
                    $other     = $model->getQualifiedOwnerKeyName();
174
                    $deletedAt = $this->checkSoftDeletesOnModel($model->getRelated());
175
                    break;
176
177
                default:
178
                    throw new Exception('Relation ' . get_class($model) . ' is not yet supported.');
179
            }
180
            $this->performJoin($table, $foreign, $other, $deletedAt);
181
            $lastQuery = $model->getQuery();
182
        }
183
184
        return $table . '.' . $relationColumn;
185
    }
186
187
    protected function checkSoftDeletesOnModel($model)
188
    {
189
        if (in_array('Illuminate\Database\Eloquent\SoftDeletes', class_uses($model))) {
190
            return $model->getQualifiedDeletedAtColumn();
191
        }
192
193
        return false;
194
    }
195
196
    /**
197
     * Perform join query.
198
     *
199
     * @param string $table
200
     * @param string $foreign
201
     * @param string $other
202
     * @param string $deletedAt
203
     * @param string $type
204
     */
205
    protected function performJoin($table, $foreign, $other, $deletedAt = false, $type = 'left')
206
    {
207
        $joins = [];
208
        foreach ((array) $this->getBaseQueryBuilder()->joins as $key => $join) {
209
            $joins[] = $join->table;
210
        }
211
212
        if (! in_array($table, $joins)) {
213
            $this->getBaseQueryBuilder()->join($table, $foreign, '=', $other, $type);
214
        }
215
216
        if ($deletedAt !== false) {
217
            $this->getBaseQueryBuilder()->whereNull($deletedAt);
218
        }
219
    }
220
}
221