Skip to content

Commit f96aaa3

Browse files
Merge pull request #15 from langleyfoxall/feature/direct-query-builder
Add option to directly run against query builders for where there is no appropriate model.
2 parents 02fd0b2 + 882a078 commit f96aaa3

File tree

2 files changed

+71
-27
lines changed

2 files changed

+71
-27
lines changed

README.md

+28
Original file line numberDiff line numberDiff line change
@@ -65,3 +65,31 @@ if (document.getElementById('example')) {
6565
ReactDOM.render(<Example />, document.getElementById('example'));
6666
}
6767
```
68+
69+
### Without a model
70+
71+
Sometimes you need to create a table of data for which there is no model (and the data is some kind of aggregation, so a model would not be appropriate).
72+
73+
```php
74+
use App\User;
75+
use Illuminate\Http\Request;
76+
use LangleyFoxall\ReactDynamicDataTableLaravelApi\DataTableResponder;
77+
78+
class UsersController extends Controller
79+
{
80+
public function dataTable(Request $request)
81+
{
82+
return (new DataTableResponder(DB::table('users')->select(['id', 'name']), $request))
83+
->query(function($query) { // Optional, default: none
84+
$query->where('name', 'like', 'B%');
85+
})
86+
->collectionManipulator(function (Collection $collection) { // Optional, default: none
87+
$collection->map(function($user) {
88+
$user->name = title_case($user->name);
89+
});
90+
})
91+
->setPerPage(10) // Optional, default: 15
92+
->respond();
93+
}
94+
}
95+
```

src/DataTableResponder.php

+43-27
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
use Illuminate\Contracts\Pagination\LengthAwarePaginator;
55
use Illuminate\Database\Eloquent\Model;
66
use Illuminate\Database\Eloquent\Builder;
7+
use Illuminate\Database\Query\Builder as QueryBuilder;
78
use Illuminate\Http\JsonResponse;
89
use Illuminate\Http\Request;
910
use Illuminate\Support\Collection;
@@ -21,6 +22,11 @@ class DataTableResponder
2122
*/
2223
private $model;
2324

25+
/**
26+
* @var Builder
27+
*/
28+
private $queryBuilder;
29+
2430
/**
2531
* @var Request
2632
*/
@@ -54,21 +60,28 @@ class DataTableResponder
5460
/**
5561
* DataTableResponder constructor.
5662
*
57-
* @param $className
63+
* @param $classNameOrQueryBuilder
5864
* @param Request $request
5965
*/
60-
public function __construct($className, Request $request)
66+
public function __construct($classNameOrQueryBuilder, Request $request)
6167
{
62-
if (!class_exists($className)) {
63-
throw new InvalidArgumentException('Provided class does not exist.');
64-
}
68+
if ($classNameOrQueryBuilder instanceof QueryBuilder) {
69+
$this->model = null;
70+
$this->queryBuilder = $classNameOrQueryBuilder;
71+
} else {
72+
if (!class_exists($classNameOrQueryBuilder)) {
73+
throw new InvalidArgumentException('Provided class does not exist.');
74+
}
6575

66-
$this->model = new $className();
67-
$this->request = $request;
76+
$this->model = new $classNameOrQueryBuilder();
77+
$this->queryBuilder = null;
6878

69-
if (!$this->model instanceof Model) {
70-
throw new InvalidArgumentException('Provided class is not an Eloquent model.');
79+
if (!$this->model instanceof Model) {
80+
throw new InvalidArgumentException('Provided class is not an Eloquent model.');
81+
}
7182
}
83+
84+
$this->request = $request;
7285
}
7386

7487
/**
@@ -141,7 +154,7 @@ public function setResponseMeta(array $meta = [])
141154
*/
142155
private function buildQuery(Request $request)
143156
{
144-
$query = $this->model->query();
157+
$query = $this->queryBuilder ?? $this->model->query();
145158

146159
$queryManipulator = $this->queryManipulator;
147160

@@ -171,10 +184,10 @@ private function buildQuery(Request $request)
171184
}
172185

173186
/**
174-
* @param Builder $query
187+
* @param Builder|QueryBuilder $query
175188
* @return LengthAwarePaginator
176189
*/
177-
private function paginateQuery(Builder $query)
190+
private function paginateQuery($query)
178191
{
179192
return $query->paginate($this->perPage);
180193
}
@@ -208,11 +221,11 @@ private function manipulateCollection($results)
208221
* `disallow_ordering_by` will always be overwritten
209222
* as it is managed internally
210223
*
211-
* @param Builder $query
224+
* @param Builder|QueryBuilder $query
212225
* @param Collection $collection
213226
* @return array
214227
*/
215-
private function makeMeta(Builder $query, Collection $collection)
228+
private function makeMeta($query, Collection $collection)
216229
{
217230
$meta = $this->meta;
218231
$out = [];
@@ -239,25 +252,28 @@ private function makeMeta(Builder $query, Collection $collection)
239252
*/
240253
private function disallowOrderingBy()
241254
{
242-
$methods = get_class_methods($this->model);
243255
$customAttributes = [];
244256

245-
foreach($methods as $method) {
246-
if (!preg_match('/^get(\w+)Attribute$/', $method, $matches)) {
247-
continue;
248-
}
257+
if ($this->model !== null) {
258+
$methods = get_class_methods($this->model);
259+
260+
foreach($methods as $method) {
261+
if (!preg_match('/^get(\w+)Attribute$/', $method, $matches)) {
262+
continue;
263+
}
249264

250-
if (empty($matches[1])) {
251-
continue;
252-
}
265+
if (empty($matches[1])) {
266+
continue;
267+
}
253268

254-
$customAttribute = Str::snake($matches[1]);
269+
$customAttribute = Str::snake($matches[1]);
255270

256-
if (in_array($customAttribute, array_keys($this->orderByOverrides))) {
257-
continue;
258-
}
271+
if (in_array($customAttribute, array_keys($this->orderByOverrides))) {
272+
continue;
273+
}
259274

260-
$customAttributes[] = $customAttribute;
275+
$customAttributes[] = $customAttribute;
276+
}
261277
}
262278

263279
return $customAttributes;

0 commit comments

Comments
 (0)