Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[8.0] Support for Eloquent API Resources #1702

Merged
merged 18 commits into from
May 10, 2018
Merged
Show file tree
Hide file tree
Changes from 14 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
81 changes: 81 additions & 0 deletions src/ApiResourceDataTable.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
<?php

namespace Yajra\DataTables;

use Illuminate\Support\Collection;
use Illuminate\Pagination\LengthAwarePaginator;
use Illuminate\Http\Resources\Json\AnonymousResourceCollection;

class ApiResourceDataTable extends CollectionDataTable
{
/**
* Collection object.
*
* @var Illuminate\Http\Resources\Json\AnonymousResourceCollection
*/
public $collection;

/**
* Collection object.
*
* @var Illuminate\Http\Resources\Json\AnonymousResourceCollection
*/
public $original;

/**
* Can the DataTable engine be created with these parameters.
*
* @param mixed $source
* @return bool
*/
public static function canCreate($source)
{
return is_array($source) || $source instanceof AnonymousResourceCollection;
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we can remove is_array here since it's handled by CollectionDataTable.

return $source instanceof AnonymousResourceCollection;

}

/**
* Factory method, create and return an instance for the DataTable engine.
*
* @param array|Illuminate\Http\Resources\Json\AnonymousResourceCollection $source
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@param should be * @param \Illuminate\Http\Resources\Json\AnonymousResourceCollection $source

* @return ApiResourceDataTable|DataTableAbstract
*/
public static function create($source)
{
if (is_array($source)) {
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We can remove the is_array part and let dt collection do the job.

    /**
     * Factory method, create and return an instance for the DataTable engine.
     *
     * @param \Illuminate\Http\Resources\Json\AnonymousResourceCollection $source
     * @return ApiResourceDataTable|DataTableAbstract
     */
    public static function create($source)
    {
        return new ApiResourceDataTable($source);
    }

$source = new AnonymousResourceCollection($source);
}

return parent::create($source);
}

/**
* CollectionEngine constructor.
*
* @param Illuminate\Http\Resources\Json\AnonymousResourceCollection $collection
*/
public function __construct(AnonymousResourceCollection $collection)
{
$this->request = app('datatables.request');
$this->config = app('datatables.config');
$this->collection = collect($collection->toArray($this->request));
$this->original = $collection;
$this->columns = array_keys($this->serialize(collect($collection->toArray($this->request))->first()));
if ($collection->resource instanceof LengthAwarePaginator) {
$this->isFilterApplied = true;
}
}

/**
* Count total items.
*
* @return int
*/
public function totalCount()
{
if ($this->original->resource instanceof LengthAwarePaginator) {
return $this->totalRecords ? $this->totalRecords : $this->original->resource->total();
} else {
return $this->totalRecords ? $this->totalRecords : $this->collection->count();
}
}
}
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this class can inherit from CollectionDataTable to avoid duplicate codes?

11 changes: 11 additions & 0 deletions src/DataTables.php
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,17 @@ public function collection($collection)
return CollectionDataTable::create($collection);
}

/**
* DataTables using Collection.
*
* @param \Illuminate\Http\Resources\Json\AnonymousResourceCollection|array $collection
* @return DataTableAbstract|ApiResourceDataTable
*/
public function resource($resource)
{
return ApiResourceDataTable::create($resource);
}

/**
* Get html builder instance.
*
Expand Down
7 changes: 4 additions & 3 deletions src/config/datatables.php
Original file line number Diff line number Diff line change
Expand Up @@ -39,9 +39,10 @@
* This is where you can register your custom dataTables builder.
*/
'engines' => [
'eloquent' => \Yajra\DataTables\EloquentDataTable::class,
'query' => \Yajra\DataTables\QueryDataTable::class,
'collection' => \Yajra\DataTables\CollectionDataTable::class,
'eloquent' => \Yajra\DataTables\EloquentDataTable::class,
'query' => \Yajra\DataTables\QueryDataTable::class,
'collection' => \Yajra\DataTables\CollectionDataTable::class,
'resource' => \Yajra\DataTables\ApiResourceDataTable::class,
],

/*
Expand Down
20 changes: 20 additions & 0 deletions tests/Http/Resources/UserCollection.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
<?php

namespace Yajra\DataTables\Tests\Http\Resources;

use Illuminate\Http\Resources\Json\ResourceCollection;

class UserCollection extends ResourceCollection
{
/**
* Transform the resource collection into an array.
*
* @param \Illuminate\Http\Request $request
* @return array
*/
public function toArray($request)
{
// return parent::toArray($request);
return $this->collection;
}
}
24 changes: 24 additions & 0 deletions tests/Http/Resources/UserResource.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
<?php

namespace Yajra\DataTables\Tests\Http\Resources;

use Illuminate\Http\Resources\Json\Resource;

class UserResource extends Resource
{
/**
* Transform the resource into an array.
*
* @param \Illuminate\Http\Request $request
* @return array
*/
public function toArray($request)
{
// return parent::toArray($request);
return [
// 'id' => $this->id,
'email' => $this->email,
'name' => $this->name,
];
}
}
114 changes: 114 additions & 0 deletions tests/Integration/ApiResourceEngineTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
<?php

namespace Yajra\DataTables\Tests\Integration;

use Yajra\DataTables\DataTables;
use Illuminate\Http\JsonResponse;
use Yajra\DataTables\Tests\TestCase;
use Yajra\DataTables\Tests\Models\User;
use Yajra\DataTables\ApiResourceDataTable;
use Illuminate\Foundation\Testing\DatabaseTransactions;
use Yajra\DataTables\Tests\Http\Resources\UserResource;
use Yajra\DataTables\Facades\DataTables as DatatablesFacade;

class ApiResourceEngineTest extends TestCase
{
use DatabaseTransactions;

/** @test */
public function it_returns_all_records_when_no_parameters_is_passed()
{
$crawler = $this->call('GET', '/resource/users');
$crawler->assertJson([
'draw' => 0,
'recordsTotal' => 20,
'recordsFiltered' => 20,
]);
}

/** @test */
public function it_only_returns_records_in_structure_defined_in_resource()
{
$crawler = $this->call('GET', '/resource/users');
$crawler->assertJsonStructure([
'draw',
'recordsTotal',
'recordsFiltered',
'data' => [
[
'email',
'name',
],
],
]);
}

/** @test */
public function it_can_perform_global_search()
{
$crawler = $this->call('GET', '/resource/users', [
'columns' => [
['data' => 'name', 'name' => 'name', 'searchable' => 'true', 'orderable' => 'true'],
['data' => 'email', 'name' => 'email', 'searchable' => 'true', 'orderable' => 'true'],
],
'search' => ['value' => 'Record 19'],
]);

$crawler->assertJson([
'draw' => 0,
'recordsTotal' => 20,
'recordsFiltered' => 1,
]);
}

/** @test */
public function it_accepts_a_resource_using_of_factory()
{
$dataTable = DataTables::of(UserResource::collection(User::all()));
$response = $dataTable->make(true);
$this->assertInstanceOf(ApiResourceDataTable::class, $dataTable);
$this->assertInstanceOf(JsonResponse::class, $response);
}

/** @test */
public function it_accepts_a_resource_using_facade()
{
$dataTable = DatatablesFacade::of(UserResource::collection(User::all()));
$response = $dataTable->make(true);
$this->assertInstanceOf(ApiResourceDataTable::class, $dataTable);
$this->assertInstanceOf(JsonResponse::class, $response);
}

/** @test */
public function it_accepts_a_pagination_resource()
{
$dataTable = DataTables::of(UserResource::collection(User::paginate(10)));
$response = $dataTable->make(true);
$this->assertInstanceOf(ApiResourceDataTable::class, $dataTable);
$this->assertInstanceOf(JsonResponse::class, $response);
}

/** @test */
public function it_returns_only_paginated_records()
{
$crawler = $this->call('GET', '/resource/users_p');
$crawler->assertJson([
'draw' => 0,
'recordsTotal' => 20,
'recordsFiltered' => 10,
]);
}

protected function setUp()
{
parent::setUp();

$this->app['router']->get('/resource/users', function (DataTables $datatables) {
return $datatables->resource(UserResource::collection(User::all()))->make('true');
});

$this->app['router']->get('/resource/users_p', function (DataTables $datatables) {
return $datatables->resource(UserResource::collection(User::paginate(10)))->make('true');
});
}
}
66 changes: 38 additions & 28 deletions tests/TestCase.php
Original file line number Diff line number Diff line change
Expand Up @@ -22,34 +22,44 @@ protected function migrateDatabase()
{
/** @var \Illuminate\Database\Schema\Builder $schemaBuilder */
$schemaBuilder = $this->app['db']->connection()->getSchemaBuilder();
$schemaBuilder->create('users', function (Blueprint $table) {
$table->increments('id');
$table->string('name');
$table->string('email');
$table->timestamps();
});
$schemaBuilder->create('posts', function (Blueprint $table) {
$table->increments('id');
$table->string('title');
$table->unsignedInteger('user_id');
$table->timestamps();
});
$schemaBuilder->create('hearts', function (Blueprint $table) {
$table->increments('id');
$table->unsignedInteger('user_id');
$table->string('size');
$table->timestamps();
});
$schemaBuilder->create('roles', function (Blueprint $table) {
$table->increments('id');
$table->string('role');
$table->timestamps();
});
$schemaBuilder->create('role_user', function (Blueprint $table) {
$table->unsignedInteger('role_id');
$table->unsignedInteger('user_id');
$table->timestamps();
});
if (! $schemaBuilder->hasTable('users')) {
$schemaBuilder->create('users', function (Blueprint $table) {
$table->increments('id');
$table->string('name');
$table->string('email');
$table->timestamps();
});
}
if (! $schemaBuilder->hasTable('posts')) {
$schemaBuilder->create('posts', function (Blueprint $table) {
$table->increments('id');
$table->string('title');
$table->unsignedInteger('user_id');
$table->timestamps();
});
}
if (! $schemaBuilder->hasTable('hearts')) {
$schemaBuilder->create('hearts', function (Blueprint $table) {
$table->increments('id');
$table->unsignedInteger('user_id');
$table->string('size');
$table->timestamps();
});
}
if (! $schemaBuilder->hasTable('roles')) {
$schemaBuilder->create('roles', function (Blueprint $table) {
$table->increments('id');
$table->string('role');
$table->timestamps();
});
}
if (! $schemaBuilder->hasTable('role_user')) {
$schemaBuilder->create('role_user', function (Blueprint $table) {
$table->unsignedInteger('role_id');
$table->unsignedInteger('user_id');
$table->timestamps();
});
}
}

protected function seedDatabase()
Expand Down