Filter   A
last analyzed

Complexity

Total Complexity 9

Size/Duplication

Total Lines 129
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 5

Importance

Changes 0
Metric Value
wmc 9
lcom 1
cbo 5
dl 0
loc 129
rs 10
c 0
b 0
f 0

6 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 4 1
A apply() 0 14 2
A filters() 0 4 1
A callFilterMethod() 0 4 1
A getTableName() 0 4 1
A resolve() 0 18 3
1
<?php
2
3
namespace Koch\Filters;
4
5
use Illuminate\Http\Request;
6
use Koch\Filters\Behavior\Orderable;
7
use Koch\Filters\Behavior\Searchable;
8
use Illuminate\Database\Eloquent\Builder;
9
use Koch\Filters\Contracts\Filter as FilterContract;
10
11
abstract class Filter implements FilterContract
12
{
13
    use Searchable, Orderable;
14
15
    /**
16
     * Already loaded relations.
17
     *
18
     * @var array
19
     */
20
    protected $loaded = [];
21
22
    /**
23
     * Default searchable columns.
24
     *
25
     * @var array
26
     */
27
    protected $searchable = ['name'];
28
29
    /**
30
     * Default orderable columns.
31
     *
32
     * @var array
33
     */
34
    protected $orderable = ['name' => 'name'];
35
36
    /**
37
     * Request data.
38
     *
39
     * @var \Illuminate\Http\Request
40
     */
41
    protected $request;
42
43
    /**
44
     * Builder instance.
45
     *
46
     * @var \Illuminate\Database\Eloquent\Builder
47
     */
48
    protected $builder;
49
50
    /**
51
     * Class constructor.
52
     *
53
     * @return void
0 ignored issues
show
Comprehensibility Best Practice introduced by
Adding a @return annotation to constructors is generally not recommended as a constructor does not have a meaningful return value.

Adding a @return annotation to a constructor is not recommended, since a constructor does not have a meaningful return value.

Please refer to the PHP core documentation on constructors.

Loading history...
54
     */
55
    public function __construct(Request $request)
0 ignored issues
show
Bug introduced by
You have injected the Request via parameter $request. This is generally not recommended as there might be multiple instances during a request cycle (f.e. when using sub-requests). Instead, it is recommended to inject the RequestStack and retrieve the current request each time you need it via getCurrentRequest().
Loading history...
56
    {
57
        $this->request = $request;
58
    }
59
60
    /**
61
     * Applies all available filters.
62
     *
63
     * @param  \Illuminate\Database\Eloquent\Builder  $builder
64
     * @return \Illuminate\Database\Eloquent\Builder
65
     */
66
    public function apply(Builder $builder)
67
    {
68
        $this->builder = $builder;
69
70
        // We need to select all columns from the original
71
        // table, since many joins can mess up the selected fields
72
        $this->builder->select("{$this->getTableName()}.*");
73
74
        foreach ($this->filters() as $name => $value) {
75
            $this->callFilterMethod($name, $value);
76
        }
77
78
        return $this->builder;
79
    }
80
81
    /**
82
     * Returns all filters from the request.
83
     *
84
     * @return array
85
     */
86
    public function filters()
87
    {
88
        return $this->request->all();
89
    }
90
91
    /**
92
     * Helper function to call each filter method.
93
     *
94
     * @param  string  $name
95
     * @param  string  $value
96
     */
97
    protected function callFilterMethod($name, $value)
98
    {
99
        call_user_func_array([$this, $name], array_filter([$value]));
100
    }
101
102
    /**
103
     * Returns the associated table name.
104
     *
105
     * @return string
106
     */
107
    protected function getTableName()
108
    {
109
        return $this->builder->getModel()->getTable();
110
    }
111
112
    /**
113
     * Recursively build up the query.
114
     *
115
     * @param  string  $column
116
     * @param  string  $key
117
     * @param  string  $last
118
     * @param  callable  $callback
119
     * @return void
120
     */
121
    protected function resolve($column, $key, $last, callable $callback)
122
    {
123
        if (! strpos($column, '.')) {
124
            return $callback("{$last}.{$column}", $key);
125
        }
126
127
        $scope = strstr($column, '.', true);
128
        $singular = str_singular($scope);
129
        $next = substr(strstr($column, '.'), 1);
130
131
        if (! in_array($scope, $this->loaded)) {
132
            $this->loaded[] = $scope;
133
134
            $this->builder->join($scope, "{$last}.{$singular}_id", "{$scope}.id");
135
        }
136
137
        return $this->resolve($next, $key, $scope, $callback);
138
    }
139
}
140