diff --git a/.gitattributes b/.gitattributes index 1185e15..47ea9b3 100644 --- a/.gitattributes +++ b/.gitattributes @@ -5,7 +5,7 @@ .editorconfig export-ignore .gitattributes export-ignore .gitignore export-ignore -.php_cs export-ignore .scrutinizer.yml export-ignore -.travis.yml export-ignore -phpunit.xml export-ignore +.styleci.yml export-ignore +phpstan.neon.dist export-ignore +phpunit.xml.dist export-ignore diff --git a/.github/workflows/continuous-integration.yml b/.github/workflows/continuous-integration.yml new file mode 100644 index 0000000..a521b25 --- /dev/null +++ b/.github/workflows/continuous-integration.yml @@ -0,0 +1,48 @@ +name: "Continuous Integration" + +on: + push: + branches: + - master + - 11.x + pull_request: + schedule: + - cron: '0 0 * * *' + +jobs: + phpunit: + + runs-on: ubuntu-latest + + strategy: + fail-fast: true + matrix: + php: [8.2, 8.3, 8.4] + stability: [prefer-stable] + + name: PHP ${{ matrix.php }} - ${{ matrix.stability }} + + steps: + - name: Checkout code + uses: actions/checkout@v4 + + - name: Setup PHP + uses: shivammathur/setup-php@v2 + with: + php-version: ${{ matrix.php }} + extensions: dom, curl, libxml, mbstring, zip, pcntl, pdo, sqlite, pdo_sqlite, gd, memcached + tools: composer:v2 + coverage: none + + - name: Setup Memcached + uses: niden/actions-memcached@v7 + + - name: Install dependencies + uses: nick-invision/retry@v1 + with: + timeout_minutes: 5 + max_attempts: 5 + command: COMPOSER_ROOT_VERSION=dev-master composer update --${{ matrix.stability }} --prefer-dist --no-interaction --no-progress + + - name: Execute tests + run: vendor/bin/phpunit diff --git a/.github/workflows/lock-closed-issues.yml b/.github/workflows/lock-closed-issues.yml new file mode 100644 index 0000000..6b89427 --- /dev/null +++ b/.github/workflows/lock-closed-issues.yml @@ -0,0 +1,21 @@ +name: Lock Closed Issues + +on: + schedule: + - cron: "0 0 * * *" + +permissions: + issues: write + +jobs: + action: + runs-on: ubuntu-latest + steps: + - uses: dessant/lock-threads@v3 + with: + github-token: ${{ secrets.GITHUB_TOKEN }} + issue-inactive-days: "14" + #issue-comment: | + # This issue has been locked since it has been closed for more than 14 days. + issue-lock-reason: "" + process-only: "issues" diff --git a/.github/workflows/pint.yml b/.github/workflows/pint.yml new file mode 100644 index 0000000..bac3eab --- /dev/null +++ b/.github/workflows/pint.yml @@ -0,0 +1,28 @@ +name: PHP Linting +on: + pull_request: + push: + branches: + - master +jobs: + phplint: + runs-on: ubuntu-latest + + permissions: + contents: write + pull-requests: write + + steps: + - uses: actions/checkout@v4 + with: + ref: ${{ github.head_ref }} + + - name: "laravel-pint" + uses: aglipanci/laravel-pint-action@latest + with: + preset: laravel + verboseMode: true + + - uses: stefanzweifel/git-auto-commit-action@v5 + with: + commit_message: "fix: pint" diff --git a/.github/workflows/static-analysis.yml b/.github/workflows/static-analysis.yml new file mode 100644 index 0000000..bdf913b --- /dev/null +++ b/.github/workflows/static-analysis.yml @@ -0,0 +1,54 @@ +name: "Static Analysis" + +on: + push: + paths: + - .github/workflows/static-analysis.yml + - composer.* + - phpstan.neon.dist + - src/** + - tests/** + + pull_request: + paths: + - .github/workflows/static-analysis.yml + - composer.* + - phpstan.neon.dist + - src/** + - tests/** + + schedule: + - cron: '0 0 * * *' + +jobs: + static-analysis-phpstan: + + name: "Static Analysis with PHPStan" + runs-on: ubuntu-latest + + strategy: + fail-fast: true + matrix: + php: [8.2, 8.3, 8.4] + stability: [prefer-stable] + + steps: + - name: Checkout code + uses: actions/checkout@v4 + + - name: Setup PHP + uses: shivammathur/setup-php@v2 + with: + php-version: ${{ matrix.php }} + tools: composer:v2 + coverage: none + + - name: Install dependencies + uses: nick-invision/retry@v1 + with: + timeout_minutes: 5 + max_attempts: 5 + command: COMPOSER_ROOT_VERSION=dev-master composer update --${{ matrix.stability }} --prefer-dist --no-interaction --no-progress + + - name: "Run a static analysis with phpstan/phpstan" + run: "vendor/bin/phpstan --error-format=table" diff --git a/.gitignore b/.gitignore index df0e1ea..384d40a 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,5 @@ /vendor /coverage +/.phpunit.cache composer.phar composer.lock diff --git a/.php_cs b/.php_cs deleted file mode 100644 index e8c5a2a..0000000 --- a/.php_cs +++ /dev/null @@ -1,77 +0,0 @@ -finder(DefaultFinder::create()->in(__DIR__)) - ->fixers($fixers) - ->level(FixerInterface::NONE_LEVEL) - ->setUsingCache(true); diff --git a/.styleci.yml b/.styleci.yml deleted file mode 100644 index 35eca69..0000000 --- a/.styleci.yml +++ /dev/null @@ -1,9 +0,0 @@ -preset: laravel - -enabled: - - align_double_arrow - - align_equals - -disabled: - - concat_without_spaces - - unalign_equals diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index c0ece51..0000000 --- a/.travis.yml +++ /dev/null @@ -1,18 +0,0 @@ -language: php - -php: - - 7.0 - - 7.1 - -env: - global: - - setup=basic - -sudo: false - -install: - - if [[ $setup = 'basic' ]]; then travis_retry composer install --no-interaction --prefer-source; fi - - if [[ $setup = 'stable' ]]; then travis_retry composer update --prefer-source --no-interaction --prefer-stable; fi - - if [[ $setup = 'lowest' ]]; then travis_retry composer update --prefer-source --no-interaction --prefer-lowest --prefer-stable; fi - -script: vendor/bin/phpunit diff --git a/CHANGELOG.md b/CHANGELOG.md index 3c15cfe..5611df5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,44 +2,8 @@ ## Changelog -### v1.6.0 - 2020-06-07 +### v12.0.0 - 2025-02-26 --- Bump league/fractal to ^0.19.0. [#25](https://github.com/yajra/laravel-datatables-fractal/pull/25), credits to @sheriffmarley. - -### v1.5.0 - 2019-06-12 - -- Bump league/fractal to ^0.18.0. [#21](https://github.com/yajra/laravel-datatables-fractal/pull/21), credits to @abdullah-abunada. - -### v1.4.0 - 2019-03-05 - -- Add support for Laravel 5.8 [#20](https://github.com/yajra/laravel-datatables-fractal/pull/20). - -### v1.3.0 - 2018-11-15 - -- Allow using closures as transformer. [#17](https://github.com/yajra/laravel-datatables-fractal/pull/17) credits to [@c00p3r](https://github.com/c00p3r) -- Fix [#1863](https://github.com/yajra/laravel-datatables/issues/1863). - -### v1.2.1 - 2018-06-12 - -- TransformerMakeCommand namespace typo [#14](https://github.com/yajra/laravel-datatables-fractal/pull/14) - -### v1.2.0 - 2018-03-28 - -- Add make:transformer command [#13](https://github.com/yajra/laravel-datatables-fractal/pull/13) - -### v1.1.1 - 2017-12-26 - -- Use collection if data key is not set. [#11](https://github.com/yajra/laravel-datatables-fractal/pull/11) - -### v1.1.0 - 2017-12-12 - -- Fix typo issue [#7](https://github.com/yajra/laravel-datatables-fractal/issues/7). [#8](https://github.com/yajra/laravel-datatables-fractal/pull/8) -- Add multi transformer ability [#6](https://github.com/yajra/laravel-datatables-fractal/pull/6) - -### v1.0.1 - 2017-08-31 - -- Update fractal to 0.17.0. - -### v1.0.0 - 2017-08-31 - -- First stable release. +- Add support for Laravel 12 +- Add Laravel Pint +- Add Rector diff --git a/README.md b/README.md index ce7c5f3..73f6dc1 100644 --- a/README.md +++ b/README.md @@ -1,8 +1,8 @@ # Laravel DataTables Fractal Plugin -[![Laravel 5.4+](https://img.shields.io/badge/Laravel-5.4+-orange.svg)](http://laravel.com) +[![Laravel 12.x](https://img.shields.io/badge/Laravel-12.x-orange.svg)](http://laravel.com) [![Latest Stable Version](https://img.shields.io/packagist/v/yajra/laravel-datatables-fractal.svg)](https://packagist.org/packages/yajra/laravel-datatables-fractal) -[![Build Status](https://travis-ci.org/yajra/laravel-datatables-fractal.svg?branch=master)](https://travis-ci.org/yajra/laravel-datatables-fractal) +[![Continuous Integration](https://github.com/yajra/laravel-datatables-fractal/actions/workflows/continuous-integration.yml/badge.svg)](https://github.com/yajra/laravel-datatables-fractal/actions/workflows/continuous-integration.yml) [![Scrutinizer Code Quality](https://scrutinizer-ci.com/g/yajra/laravel-datatables-fractal/badges/quality-score.png?b=master)](https://scrutinizer-ci.com/g/yajra/laravel-datatables-fractal/?branch=master) [![Total Downloads](https://img.shields.io/packagist/dt/yajra/laravel-datatables-fractal.svg)](https://packagist.org/packages/yajra/laravel-datatables-fractal) [![License](https://img.shields.io/github/license/mashape/apistatus.svg)](https://packagist.org/packages/yajra/laravel-datatables-fractal) @@ -11,17 +11,27 @@ This package is a plugin of [Laravel DataTables](https://github.com/yajra/larave ## Requirements -- [PHP >=7.0](http://php.net/) -- [Laravel 5.4+](https://github.com/laravel/framework) -- [Laravel DataTables v8.x](https://github.com/yajra/laravel-datatables) +- [PHP >= 8.2](http://php.net/) +- [Laravel 12.x](https://github.com/laravel/framework) +- [Laravel DataTables](https://github.com/yajra/laravel-datatables) ## Documentations - [Laravel DataTables Fractal Documentation](https://yajrabox.com/docs/laravel-datatables/master/response-fractal) +## Laravel Version Compatibility + +| Laravel | Package | +|:--------------|:--------| +| 8.x and below | 1.x | +| 9.x | 9.x | +| 10.x | 10.x | +| 11.x | 11.x | +| 12.x | 12.x | + ## Quick Installation -`composer require yajra/laravel-datatables-fractal` +`composer require yajra/laravel-datatables-fractal:^12.0` ### Register Service Provider (Optional on Laravel 5.5+) @@ -49,8 +59,3 @@ If you discover any security related issues, please email [aqangeles@gmail.com]( ## License The MIT License (MIT). Please see [License File](https://github.com/yajra/laravel-datatables-fractal/blob/master/LICENSE.md) for more information. - -## Buy me a coffee - -[![paypal](https://www.paypalobjects.com/en_US/i/btn/btn_donateCC_LG.gif)](https://www.paypal.me/yajra) -Become a Patron diff --git a/composer.json b/composer.json index 28c3f14..4b516df 100644 --- a/composer.json +++ b/composer.json @@ -1,48 +1,62 @@ { - "name": "yajra/laravel-datatables-fractal", - "description": "Laravel DataTables Fractal Plugin.", - "keywords": [ - "laravel", - "datatables", - "fractal", - "api" - ], - "license": "MIT", - "authors": [ - { - "name": "Arjay Angeles", - "email": "aqangeles@gmail.com" - } - ], - "require": { - "php": ">=7.0", - "yajra/laravel-datatables-oracle": "8.*|9.*", - "league/fractal": "^0.19.0" - }, - "require-dev": { - "mockery/mockery": "0.9.*", - "phpunit/phpunit": "~6.0" - }, - "autoload": { - "psr-4": { - "Yajra\\DataTables\\": "src/" - } - }, - "autoload-dev": { - "psr-4": { - "Yajra\\DataTables\\Tests\\": "tests/" - } - }, - "extra": { - "branch-alias": { - "dev-master": "1.0-dev" + "name": "yajra/laravel-datatables-fractal", + "description": "Laravel DataTables Fractal Plugin.", + "keywords": [ + "laravel", + "datatables", + "fractal", + "api" + ], + "license": "MIT", + "authors": [ + { + "name": "Arjay Angeles", + "email": "aqangeles@gmail.com" + } + ], + "require": { + "php": "^8.2", + "yajra/laravel-datatables-oracle": "^12", + "league/fractal": "^0.20.1" }, - "laravel": { - "providers": [ - "Yajra\\DataTables\\FractalServiceProvider" - ] - } - }, - "minimum-stability": "dev", - "prefer-stable": true + "require-dev": { + "larastan/larastan": "^3.1", + "orchestra/testbench": "^10", + "laravel/pint": "^1.21", + "rector/rector": "^2.0" + }, + "autoload": { + "psr-4": { + "Yajra\\DataTables\\": "src/" + } + }, + "autoload-dev": { + "psr-4": { + "Yajra\\DataTables\\Fractal\\Tests\\": "tests/" + } + }, + "extra": { + "branch-alias": { + "dev-master": "12.x-dev" + }, + "laravel": { + "providers": [ + "Yajra\\DataTables\\FractalServiceProvider" + ] + } + }, + "scripts": { + "test": "./vendor/bin/phpunit", + "pint": "./vendor/bin/pint", + "rector": "./vendor/bin/rector", + "stan": "./vendor/bin/phpstan analyse --memory-limit=2G --ansi --no-progress --no-interaction --configuration=phpstan.neon.dist", + "pr": [ + "@pint", + "@rector", + "@stan", + "@test" + ] + }, + "minimum-stability": "dev", + "prefer-stable": true } diff --git a/config/datatables-fractal.php b/config/datatables-fractal.php index 25f547a..39250f1 100644 --- a/config/datatables-fractal.php +++ b/config/datatables-fractal.php @@ -4,7 +4,7 @@ /* * Request key name to parse includes on fractal. */ - 'includes' => 'include', + 'includes' => 'include', /* * Default fractal serializer. diff --git a/phpstan.neon.dist b/phpstan.neon.dist new file mode 100644 index 0000000..ccac0c6 --- /dev/null +++ b/phpstan.neon.dist @@ -0,0 +1,15 @@ +includes: + - ./vendor/larastan/larastan/extension.neon + +parameters: + + paths: + - src + + level: 5 + + ignoreErrors: + - identifier: function.alreadyNarrowedType + + excludePaths: + diff --git a/phpunit.xml b/phpunit.xml deleted file mode 100644 index 3366726..0000000 --- a/phpunit.xml +++ /dev/null @@ -1,23 +0,0 @@ - - - - - ./tests/ - - - - - ./vendor - - - diff --git a/phpunit.xml.dist b/phpunit.xml.dist new file mode 100644 index 0000000..2cb7512 --- /dev/null +++ b/phpunit.xml.dist @@ -0,0 +1,8 @@ + + + + + ./tests/ + + + diff --git a/rector.php b/rector.php new file mode 100644 index 0000000..74003ed --- /dev/null +++ b/rector.php @@ -0,0 +1,22 @@ +paths([ + __DIR__.'/config', + __DIR__.'/src', + ]); + + // register a single rule + $rectorConfig->rule(InlineConstructorDefaultToPropertyRector::class); + + // define sets of rules + $rectorConfig->sets([ + LevelSetList::UP_TO_PHP_82, + ]); +}; diff --git a/src/Commands/TransformerMakeCommand.php b/src/Commands/TransformerMakeCommand.php index 4e4fe39..a86a5ce 100644 --- a/src/Commands/TransformerMakeCommand.php +++ b/src/Commands/TransformerMakeCommand.php @@ -33,14 +33,12 @@ class TransformerMakeCommand extends GeneratorCommand /** * Replace the class name for the given stub. * - * @param string $stub Contents of the stub - * @param string $name The class name - * - * @return string + * @param string $stub Contents of the stub + * @param string $name The class name */ - protected function replaceClass($stub, $name) + protected function replaceClass($stub, $name): string { - $stub = parent::replaceClass($stub, $name . 'Transformer'); + $stub = parent::replaceClass($stub, $name.'Transformer'); $stub = str_replace('Dummy', ucfirst($this->argument('name')), $stub); $stub = str_replace('dummy', lcfirst($this->argument('name')), $stub); @@ -54,24 +52,20 @@ protected function replaceClass($stub, $name) /** * Get the stub file for the generator. - * - * @return string */ - protected function getStub() + protected function getStub(): string { return $this->argument('include') ? - __DIR__ . '/stubs/transformer.inc.stub' : - __DIR__ . '/stubs/transformer.stub'; + __DIR__.'/stubs/transformer.inc.stub' : + __DIR__.'/stubs/transformer.stub'; } /** * Get the default namespace for the class. * - * @param string $rootNamespace The root namespace - * - * @return string + * @param string $rootNamespace The root namespace */ - protected function getDefaultNamespace($rootNamespace) + protected function getDefaultNamespace($rootNamespace): string { return $rootNamespace.'\Transformers'; } @@ -79,11 +73,9 @@ protected function getDefaultNamespace($rootNamespace) /** * Get the destination class path. * - * @param string $name Name of the class with namespace - * - * @return string + * @param string $name Name of the class with namespace */ - protected function getPath($name) + protected function getPath($name): string { $name = Str::replaceFirst($this->rootNamespace(), '', $name); diff --git a/src/Commands/stubs/transformer.inc.stub b/src/Commands/stubs/transformer.inc.stub index 8690ec5..0b2874e 100644 --- a/src/Commands/stubs/transformer.inc.stub +++ b/src/Commands/stubs/transformer.inc.stub @@ -14,7 +14,7 @@ class DummyClass extends TransformerAbstract * @param \App\Dummy $dummy * @return array */ - public function transform(Dummy $dummy) + public function transform(Dummy $dummy): array { return [ 'id' => (int) $dummy->id, diff --git a/src/Commands/stubs/transformer.stub b/src/Commands/stubs/transformer.stub index 82cd7b1..5ffe2ec 100644 --- a/src/Commands/stubs/transformer.stub +++ b/src/Commands/stubs/transformer.stub @@ -11,7 +11,7 @@ class DummyClass extends TransformerAbstract * @param \App\Dummy $dummy * @return array */ - public function transform(Dummy $dummy) + public function transform(Dummy $dummy): array { return [ 'id' => (int) $dummy->id, diff --git a/src/FractalServiceProvider.php b/src/FractalServiceProvider.php index e966455..41c0492 100644 --- a/src/FractalServiceProvider.php +++ b/src/FractalServiceProvider.php @@ -10,21 +10,12 @@ class FractalServiceProvider extends ServiceProvider { - /** - * Indicates if loading of the provider is deferred. - * - * @var bool - */ - protected $defer = false; - /** * Bootstrap the application events. - * - * @return void */ - public function boot() + public function boot(): void { - $this->mergeConfigFrom(__DIR__ . '/../config/datatables-fractal.php', 'datatables-fractal'); + $this->mergeConfigFrom(__DIR__.'/../config/datatables-fractal.php', 'datatables-fractal'); $this->publishAssets(); $this->registerMacro(); @@ -32,94 +23,72 @@ public function boot() /** * Publish datatables assets. - * - * @return void */ - protected function publishAssets() + protected function publishAssets(): void { $this->publishes( [ - __DIR__ . '/../config/datatables-fractal.php' => config_path('datatables-fractal.php'), + __DIR__.'/../config/datatables-fractal.php' => config_path('datatables-fractal.php'), ], 'datatables-fractal' ); } /** * Register DataTables macro methods. - * - * @return void */ - protected function registerMacro() + protected function registerMacro(): void { - DataTableAbstract::macro( - 'setTransformer', function ($transformer) { - $this->transformer = [$transformer]; + DataTableAbstract::macro('setTransformer', function ($transformer) { + $this->transformer = [$transformer]; - return $this; - } - ); + return $this; + }); - DataTableAbstract::macro( - 'addTransformer', function ($transformer) { - $this->transformer[] = $transformer; + DataTableAbstract::macro('addTransformer', function ($transformer) { + $this->transformer[] = $transformer; - return $this; - } - ); + return $this; + }); - DataTableAbstract::macro( - 'setSerializer', function ($serializer) { - $this->serializer = $serializer; + DataTableAbstract::macro('setSerializer', function ($serializer) { + $this->serializer = $serializer; - return $this; - } - ); + return $this; + }); } /** * Register the service provider. - * - * @return void */ - public function register() + public function register(): void { - $this->app->singleton( - 'datatables.fractal', function () { - $fractal = new Manager; - $config = $this->app['config']; - $request = $this->app['request']; - - $includesKey = $config->get('datatables-fractal.includes', 'include'); - if ($request->get($includesKey)) { - $fractal->parseIncludes($request->get($includesKey)); - } + $this->app->singleton('datatables.fractal', function () { + $fractal = new Manager; + $config = $this->app['config']; + $request = $this->app['request']; + + $includesKey = $config->get('datatables-fractal.includes', 'include'); + if ($request->get($includesKey)) { + $fractal->parseIncludes($request->get($includesKey)); + } - $serializer = $config->get('datatables-fractal.serializer', DataArraySerializer::class); - $fractal->setSerializer(new $serializer); + $serializer = $config->get('datatables-fractal.serializer', DataArraySerializer::class); + $fractal->setSerializer(new $serializer); - return $fractal; - } - ); + return $fractal; + }); - $this->app->singleton( - 'datatables.transformer', function () { - return new FractalTransformer($this->app->make('datatables.fractal')); - } - ); + $this->app->singleton('datatables.transformer', fn () => new FractalTransformer($this->app->make('datatables.fractal'))); - $this->commands( - [ - TransformerMakeCommand::class, - ] - ); + $this->commands([ + TransformerMakeCommand::class, + ]); } /** * Get the services provided by the provider. - * - * @return array */ - public function provides() + public function provides(): array { return [ 'datatables.fractal', diff --git a/src/Transformers/FractalTransformer.php b/src/Transformers/FractalTransformer.php index 3a2f7e0..3748367 100644 --- a/src/Transformers/FractalTransformer.php +++ b/src/Transformers/FractalTransformer.php @@ -2,6 +2,8 @@ namespace Yajra\DataTables\Transformers; +use Closure; +use Illuminate\Support\Collection as LaravelCollection; use League\Fractal\Manager; use League\Fractal\Resource\Collection; use League\Fractal\Serializer\SerializerAbstract; @@ -9,31 +11,19 @@ class FractalTransformer { - /** - * @var \League\Fractal\Manager - */ - protected $fractal; - /** * FractalTransformer constructor. - * - * @param \League\Fractal\Manager $fractal */ - public function __construct(Manager $fractal) - { - $this->fractal = $fractal; - } + public function __construct(protected Manager $fractal) {} /** * Transform output using the given transformer and serializer. - * - * @param mixed $output - * @param mixed $transformer - * @param mixed $serializer - * @return array */ - public function transform($output, $transformer, $serializer = null) - { + public function transform( + array|LaravelCollection $output, + iterable $transformer, + ?SerializerAbstract $serializer = null + ): array { if ($serializer !== null) { $this->fractal->setSerializer($this->createSerializer($serializer)); } @@ -41,12 +31,12 @@ public function transform($output, $transformer, $serializer = null) $collector = []; foreach ($transformer as $transform) { if ($transform != null) { - $resource = new Collection($output, $this->createTransformer($transform)); - $collection = $this->fractal->createData($resource)->toArray(); - $transformed = $collection['data'] ?? $collection; - $collector = array_map( + $resource = new Collection($output, $this->createTransformer($transform)); + $collection = $this->fractal->createData($resource)->toArray(); + $transformed = $collection['data'] ?? $collection; + $collector = array_map( function ($item_collector, $item_transformed) { - if ($item_collector === null) { + if (! is_array($item_collector)) { $item_collector = []; } @@ -62,30 +52,28 @@ function ($item_collector, $item_transformed) { /** * Get or create transformer serializer instance. * - * @param mixed $serializer - * @return \League\Fractal\Serializer\SerializerAbstract + * @param class-string|SerializerAbstract $serializer */ - protected function createSerializer($serializer) + protected function createSerializer(SerializerAbstract|string $serializer): SerializerAbstract { if ($serializer instanceof SerializerAbstract) { return $serializer; } - return new $serializer(); + return new $serializer; } /** * Get or create transformer instance. * - * @param mixed $transformer - * @return \League\Fractal\TransformerAbstract + * @param \Closure|class-string|TransformerAbstract $transformer */ - protected function createTransformer($transformer) + protected function createTransformer(Closure|string|TransformerAbstract $transformer): Closure|TransformerAbstract { - if ($transformer instanceof TransformerAbstract || $transformer instanceof \Closure) { + if ($transformer instanceof TransformerAbstract || $transformer instanceof Closure) { return $transformer; } - return new $transformer(); + return new $transformer; } } diff --git a/tests/.gitkeep b/tests/.gitkeep deleted file mode 100644 index e69de29..0000000 diff --git a/tests/FractalTest.php b/tests/FractalTest.php new file mode 100644 index 0000000..cd75fa4 --- /dev/null +++ b/tests/FractalTest.php @@ -0,0 +1,66 @@ +getAjax('/users'); + + $json->assertJson([ + 'draw' => 0, + 'recordsTotal' => 20, + 'recordsFiltered' => 20, + ]); + + $this->assertIsInt($json['data'][0]['id']); + $this->assertIsString($json['data'][0]['name']); + } + + #[Test] + public function it_works_with_closure() + { + $json = $this->getAjax('/closure'); + + $json->assertJson([ + 'draw' => 0, + 'recordsTotal' => 20, + 'recordsFiltered' => 20, + ]); + + $this->assertIsInt($json['data'][0]['id']); + $this->assertIsString($json['data'][0]['name']); + } + + protected function setUp(): void + { + parent::setUp(); + + $this->app['router']->get('/users', function () { + return DataTables::eloquent(User::query()) + ->setTransformer(UserTransformer::class) + ->toJson(); + }); + + $this->app['router']->get('/closure', function () { + return DataTables::eloquent(User::query()) + ->setTransformer(function (User $user) { + return [ + 'id' => (int) $user->id, + 'name' => $user->name, + ]; + }) + ->toJson(); + }); + } +} diff --git a/tests/Models/Post.php b/tests/Models/Post.php new file mode 100644 index 0000000..eab0305 --- /dev/null +++ b/tests/Models/Post.php @@ -0,0 +1,21 @@ +belongsTo(User::class); + } +} diff --git a/tests/Models/Role.php b/tests/Models/Role.php new file mode 100644 index 0000000..1a7eef5 --- /dev/null +++ b/tests/Models/Role.php @@ -0,0 +1,16 @@ +belongsToMany(User::class); + } +} diff --git a/tests/Models/User.php b/tests/Models/User.php new file mode 100644 index 0000000..4099137 --- /dev/null +++ b/tests/Models/User.php @@ -0,0 +1,28 @@ +hasMany(Post::class); + } + + public function roles(): BelongsToMany + { + return $this->belongsToMany(Role::class); + } + + public function user(): MorphTo + { + return $this->morphTo(); + } +} diff --git a/tests/TestCase.php b/tests/TestCase.php new file mode 100644 index 0000000..d7dc86e --- /dev/null +++ b/tests/TestCase.php @@ -0,0 +1,119 @@ +migrateDatabase(); + $this->seedDatabase(); + } + + protected function migrateDatabase() + { + /** @var \Illuminate\Database\Schema\Builder $schemaBuilder */ + $schemaBuilder = $this->app['db']->connection()->getSchemaBuilder(); + if (! $schemaBuilder->hasTable('users')) { + $schemaBuilder->create('users', function (Blueprint $table) { + $table->increments('id'); + $table->string('name'); + $table->string('email'); + $table->string('user_type')->nullable(); + $table->unsignedInteger('user_id')->nullable(); + $table->timestamps(); + }); + } + if (! $schemaBuilder->hasTable('posts')) { + $schemaBuilder->create('posts', function (Blueprint $table) { + $table->increments('id'); + $table->string('title'); + $table->unsignedInteger('user_id'); + $table->timestamps(); + $table->softDeletes(); + }); + } + 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() + { + $adminRole = Role::create(['role' => 'Administrator']); + $userRole = Role::create(['role' => 'User']); + + collect(range(1, 20))->each(function ($i) use ($userRole) { + /** @var User $user */ + $user = User::query()->create([ + 'name' => 'Record-'.$i, + 'email' => 'Email-'.$i.'@example.com', + ]); + + collect(range(1, 3))->each(function ($i) use ($user) { + $user->posts()->create([ + 'title' => "User-{$user->id} Post-{$i}", + ]); + }); + + if ($i % 2) { + $user->roles()->attach(Role::all()); + } else { + $user->roles()->attach($userRole); + } + }); + } + + /** + * Set up the environment. + * + * @param \Illuminate\Foundation\Application $app + */ + protected function getEnvironmentSetUp($app) + { + $app['config']->set('app.debug', true); + $app['config']->set('database.default', 'sqlite'); + $app['config']->set('database.connections.sqlite', [ + 'driver' => 'sqlite', + 'database' => ':memory:', + 'prefix' => '', + ]); + } + + protected function getPackageProviders($app): array + { + return [ + \Yajra\DataTables\DataTablesServiceProvider::class, + \Yajra\DataTables\FractalServiceProvider::class, + ]; + } + + public function getAjax($uri, array $headers = []): TestResponse + { + return $this->getJson($uri, array_merge(['X-Requested-With' => 'XMLHttpRequest'], $headers)); + } + + public function postAjax($uri, array $headers = []): TestResponse + { + return $this->postJson($uri, array_merge(['X-Requested-With' => 'XMLHttpRequest'], $headers)); + } +} diff --git a/tests/Transformers/UserTransformer.php b/tests/Transformers/UserTransformer.php new file mode 100644 index 0000000..806b5f2 --- /dev/null +++ b/tests/Transformers/UserTransformer.php @@ -0,0 +1,17 @@ + (int) $user->id, + 'name' => $user->name, + ]; + } +}