Skip to content

Commit

Permalink
Laravel 11 (#65)
Browse files Browse the repository at this point in the history
Co-authored-by: peterfox <[email protected]>
  • Loading branch information
peterfox and peterfox committed Mar 19, 2024
1 parent c4dbf92 commit e6bc42d
Show file tree
Hide file tree
Showing 15 changed files with 107 additions and 94 deletions.
18 changes: 7 additions & 11 deletions .github/workflows/run-tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -14,20 +14,16 @@ jobs:
strategy:
fail-fast: false
matrix:
os: [ubuntu-latest, windows-latest]
php: [8.3, 8.2, 8.1]
laravel: [9.*, 10.*]
os: [ubuntu-latest]
php: [8.3, 8.2]
laravel: [11.*, 10.*]
dependencies: [lowest, stable]
include:
- laravel: 9.*
testbench: ^7.0
- laravel: 10.*
testbench: ^8.0
- php: 8.3
dependencies: lowest
carbon: ^2.62.1
- php: 8.2
dependencies: lowest
- laravel: 11.*
testbench: 9.*
- dependencies: lowest
carbon: ^2.62.1

name: P${{ matrix.php }} - L${{ matrix.laravel }} - ${{ matrix.dependencies }} - ${{ matrix.os }}
Expand Down Expand Up @@ -55,7 +51,7 @@ jobs:
--no-interaction --no-update
- name: Require Minimum Packages for version
if: ${{ (matrix.php == '8.2' || matrix.php == '8.3') && matrix.dependencies == 'lowest' }}
if: ${{ matrix.dependencies == 'lowest' }}
run: >
composer require
"nesbot/carbon:${{ matrix.carbon }}"
Expand Down
27 changes: 13 additions & 14 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -16,23 +16,22 @@
}
],
"require": {
"php": "^8.1",
"illuminate/contracts": "10.*|^9.6"
"php": "^8.2",
"illuminate/contracts": "11.*|10.*"
},
"require-dev": {
"laravel/pint": "^1.2",
"nunomaduro/collision": "^6.0|^5.0",
"nunomaduro/larastan": "^2.0|^1.0",
"orchestra/testbench": "^8.0|^7.0",
"pestphp/pest": "^1.21",
"pestphp/pest-plugin-laravel": "^1.1",
"composer/semver": "^3.0",
"larastan/larastan": "^2.0|^1.0",
"laravel/pint": "^1.0",
"nunomaduro/collision": "^8.0|^7.8|^6.0",
"orchestra/testbench": "^9.0|^8.0|^7.0",
"pestphp/pest": "^1.21|^2.34",
"pestphp/pest-plugin-arch": "^2.6",
"pestphp/pest-plugin-laravel": "^1.1|^2.3",
"phpstan/extension-installer": "^1.1",
"phpstan/phpdoc-parser": "^1.15",
"phpstan/phpstan-deprecation-rules": "^1.0",
"phpstan/phpstan-phpunit": "^1.0",
"phpunit/phpunit": "^9.5.13",
"rector/rector": "^0.14.2",
"spatie/laravel-ray": "^1.26"
"rector/rector": "^1.0"
},
"autoload": {
"psr-4": {
Expand All @@ -49,7 +48,7 @@
"lint": "vendor/bin/pint",
"test": "vendor/bin/pest",
"test-coverage": "vendor/bin/pest coverage",
"mod": "vendor/bin/rector"
"fix": "vendor/bin/rector"
},
"config": {
"sort-packages": true,
Expand All @@ -69,5 +68,5 @@
}
},
"minimum-stability": "dev",
"prefer-stable": true
"prefer-stable": false
}
9 changes: 5 additions & 4 deletions rector.php
Original file line number Diff line number Diff line change
Expand Up @@ -15,16 +15,17 @@
// register a single rule
$rectorConfig->rule(InlineConstructorDefaultToPropertyRector::class);
$rectorConfig->rules([
\Rector\PHPUnit\Rector\Class_\AddSeeTestAnnotationRector::class,
\Rector\PHPUnit\Rector\ClassMethod\ReplaceTestAnnotationWithPrefixedFunctionRector::class,
\Rector\PHPUnit\PHPUnit100\Rector\Class_\PublicDataProviderClassMethodRector::class,
\Rector\PHPUnit\PHPUnit100\Rector\Class_\StaticDataProviderClassMethodRector::class,
\Rector\PHPUnit\CodeQuality\Rector\Class_\AddSeeTestAnnotationRector::class,
\Rector\PHPUnit\CodeQuality\Rector\ClassMethod\ReplaceTestAnnotationWithPrefixedFunctionRector::class,
]);

// define sets of rules
$rectorConfig->sets([
LevelSetList::UP_TO_PHP_80,
\Rector\Set\ValueObject\SetList::PHP_80,
\Rector\PHPUnit\Set\PHPUnitLevelSetList::UP_TO_PHPUNIT_90,
\Rector\PHPUnit\Set\PHPUnitSetList::PHPUNIT_90,
\Rector\PHPUnit\Set\PHPUnitSetList::PHPUNIT_100,

]);
};
28 changes: 11 additions & 17 deletions src/FeatureFlagsServiceProvider.php
Original file line number Diff line number Diff line change
Expand Up @@ -96,35 +96,29 @@ public function register(): void
$this->app->singleton(FeaturesContract::class, Manager::class);
}

$this->app->scoped(MaintenanceRepository::class, function (Container $app) {
return new MaintenanceRepository($app->make(FeaturesContract::class), $app);
});

$this->app->extend(MaintenanceModeManager::class, function (MaintenanceModeManager $manager) {
return $manager->extend('features', function (): MaintenanceMode {
return new MaintenanceDriver(
$this->app->make(MaintenanceRepository::class)
);
});
});
$this->app->scoped(MaintenanceRepository::class, fn (Container $app) => new MaintenanceRepository($app->make(FeaturesContract::class), $app));

$this->app->extend(MaintenanceModeManager::class, fn (MaintenanceModeManager $manager) => $manager->extend('features', fn (): MaintenanceMode => new MaintenanceDriver(
$this->app->make(MaintenanceRepository::class)
)));
}

protected function schedulingMacros()
{
if (! Event::hasMacro('skipWithoutFeature')) {
/** @noRector \Rector\Php74\Rector\Closure\ClosureToArrowFunctionRector */
Event::macro('skipWithoutFeature', function (string $feature): Event {
Event::macro('skipWithoutFeature', fn (string $feature): Event =>
/** @var Event $this */
return $this->skip(fn () => ! Features::accessible($feature));
});
/** @phpstan-ignore-next-line annoying issue with macros */
$this->skip(fn () => ! Features::accessible($feature)));
}

if (! Event::hasMacro('skipWithFeature')) {
/** @noRector \Rector\Php74\Rector\Closure\ClosureToArrowFunctionRector */
Event::macro('skipWithFeature', function ($feature): Event {
Event::macro('skipWithFeature', fn ($feature): Event =>
/** @var Event $this */
return $this->skip(fn () => Features::accessible($feature));
});
/** @phpstan-ignore-next-line annoying issue with macros */
$this->skip(fn () => Features::accessible($feature)));
}
}

Expand Down
2 changes: 1 addition & 1 deletion src/Gateways/GateGateway.php
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,6 @@ public function generateKey(string $feature): string
return md5($feature);
}

return implode(':', [md5($feature), get_class($model), $model->getKey()]);
return implode(':', [md5($feature), $model::class, $model->getKey()]);
}
}
3 changes: 3 additions & 0 deletions src/Support/MaintenanceScenario.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,9 @@

use Illuminate\Contracts\Support\Arrayable;

/**
* @see \YlsIdeas\FeatureFlags\Tests\Support\MaintenanceScenarioTest
*/
class MaintenanceScenario implements Arrayable
{
public string $feature;
Expand Down
5 changes: 5 additions & 0 deletions tests/ArchTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
<?php

arch('globals')
->expect(['dd', 'dump'])
->not->toBeUsed();
4 changes: 1 addition & 3 deletions tests/FeatureFlagsServiceProviderTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,7 @@ protected function getPackageProviders($app): array
];
}

/**
* @before
*/
#[\PHPUnit\Framework\Attributes\Before]
protected function cleanUp(): void
{
$this->afterApplicationCreated(function () {
Expand Down
38 changes: 31 additions & 7 deletions tests/MaintenanceModeTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,11 @@
namespace YlsIdeas\FeatureFlags\Tests;

use Illuminate\Contracts\Http\Kernel;
use Illuminate\Foundation\Configuration\Middleware;
use Illuminate\Support\Facades\Route;

use function Orchestra\Testbench\after_resolving;

use Orchestra\Testbench\TestCase;
use YlsIdeas\FeatureFlags\Facades\Features;
use YlsIdeas\FeatureFlags\FeatureFlagsServiceProvider;
Expand All @@ -19,7 +23,7 @@ public function test_maintenance_mode_enabled()
Route::get('/', fn () => 'Foo Bar');

$this->get('/')
->assertStatus(503);
->assertServiceUnavailable();

Features::assertAccessed('system.down');
}
Expand Down Expand Up @@ -70,9 +74,7 @@ public function test_upon_activation()
$this->assertTrue($called);
}

/**
* @dataProvider exceptsValues
*/
#[\PHPUnit\Framework\Attributes\DataProvider('exceptsValues')]
public function test_maintenance_mode_respects_excepts_values(string $path, int $status)
{
Features::fake(['system.down' => true]);
Expand All @@ -83,13 +85,15 @@ public function test_maintenance_mode_respects_excepts_values(string $path, int
Route::get('/', fn () => 'Foo Bar');
Route::get('/test', fn () => 'Foo Bar Foo');

$this->get($path)
$this
->withoutExceptionHandling([\Symfony\Component\HttpKernel\Exception\HttpException::class])
->get($path)
->assertStatus($status);

Features::assertAccessed('system.down');
}

public function exceptsValues(): \Generator
public static function exceptsValues(): \Generator
{
yield 'blocked' => [
'/', 503,
Expand Down Expand Up @@ -122,7 +126,7 @@ protected function defineEnvironment($app): void
}

/**
* Resolve application HTTP Kernel implementation.
* Required override for Pre Laravel 11
*
* @param \Illuminate\Foundation\Application $app
* @return void
Expand All @@ -137,6 +141,26 @@ protected function resolveApplicationHttpKernel($app)
);
}

/**
* Required override for Laravel 11
*
* @param \Illuminate\Foundation\Application $app
* @return void
*/
protected function resolveApplicationHttpMiddlewares($app)
{
after_resolving($app, Kernel::class, function ($kernel, $app) {
/** @var \Illuminate\Foundation\Http\Kernel $kernel */
$middleware = new Middleware();

$kernel->setGlobalMiddleware([
\YlsIdeas\FeatureFlags\Middlewares\PreventRequestsDuringMaintenance::class,
]);
$kernel->setMiddlewareGroups($middleware->getMiddlewareGroups());
$kernel->setMiddlewareAliases($middleware->getMiddlewareAliases());
});
}

protected function getPackageProviders($app): array
{
return [
Expand Down
10 changes: 3 additions & 7 deletions tests/ManagerTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,7 @@
use YlsIdeas\FeatureFlags\Events\FeatureSwitchedOn;
use YlsIdeas\FeatureFlags\Manager;

/**
* @covers \YlsIdeas\FeatureFlags\Manager
*/
#[\PHPUnit\Framework\Attributes\CoversClass(\YlsIdeas\FeatureFlags\Manager::class)]
class ManagerTest extends TestCase
{
use MockeryPHPUnitIntegration;
Expand Down Expand Up @@ -141,9 +139,7 @@ public function test_it_can_turn_off_features(): void
$manager->turnOff('test', 'my-feature');
}

/**
* @dataProvider services
*/
#[\PHPUnit\Framework\Attributes\DataProvider('services')]
public function test_it_can_flag_parts_of_the_package_to_be_turned_off($item): void
{
$manager = new Manager($this->container, \Mockery::mock(Dispatcher::class));
Expand All @@ -155,7 +151,7 @@ public function test_it_can_flag_parts_of_the_package_to_be_turned_off($item): v
$this->assertFalse($manager->{"uses$item"}());
}

public function services(): array
public static function services(): array
{
return [
['Blade'],
Expand Down
31 changes: 19 additions & 12 deletions tests/QueryBuilderMixinTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,11 @@

namespace YlsIdeas\FeatureFlags\Tests;

use Composer\InstalledVersions;
use Composer\Semver\VersionParser;
use Illuminate\Contracts\Database\Query\Builder;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Str;
use Orchestra\Testbench\TestCase;
use YlsIdeas\FeatureFlags\Facades\Features;
use YlsIdeas\FeatureFlags\FeatureFlagsServiceProvider;
Expand All @@ -17,11 +20,13 @@ protected function getPackageProviders($app): array
];
}

/**
* @dataProvider positiveSqlStatements
*/
#[\PHPUnit\Framework\Attributes\DataProvider('positiveSqlStatements')]
public function test_modifying_queries_when_the_feature_is_enabled(bool $flag, string $expectedSql)
{
// Laravel 11 for some reason changed how SQL is generated
if (! InstalledVersions::satisfies(new VersionParser(), 'illuminate/contracts', '^11.0')) {
$expectedSql = Str::replace('"', '`', $expectedSql);
}
Features::fake(['my-feature' => $flag]);

$sql = DB::table('users')
Expand All @@ -31,23 +36,25 @@ public function test_modifying_queries_when_the_feature_is_enabled(bool $flag, s
$this->assertSame($expectedSql, $sql);
}

public function positiveSqlStatements(): \Generator
public static function positiveSqlStatements(): \Generator
{
yield 'flag is true' => [
true,
'select * from `users` where `id` = ?',
'select * from "users" where "id" = ?',
];
yield 'flag is false' => [
false,
'select * from `users`',
'select * from "users"',
];
}

/**
* @dataProvider negativeSqlStatements
*/
#[\PHPUnit\Framework\Attributes\DataProvider('negativeSqlStatements')]
public function test_modifying_queries_when_the_feature_is_not_enabled(bool $flag, string $expectedSql)
{
// Laravel 11 for some reason changed how SQL is generated
if (! InstalledVersions::satisfies(new VersionParser(), 'illuminate/contracts', '^11.0')) {
$expectedSql = Str::replace('"', '`', $expectedSql);
}
Features::fake(['my-feature' => $flag]);

$sql = DB::table('users')
Expand All @@ -57,15 +64,15 @@ public function test_modifying_queries_when_the_feature_is_not_enabled(bool $fla
$this->assertSame($expectedSql, $sql);
}

public function negativeSqlStatements(): \Generator
public static function negativeSqlStatements(): \Generator
{
yield 'flag is true' => [
true,
'select * from `users`',
'select * from "users"',
];
yield 'flag is false' => [
false,
'select * from `users` where `id` = ?',
'select * from "users" where "id" = ?',
];
}
}
4 changes: 1 addition & 3 deletions tests/Support/FeatureFakeTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -52,9 +52,7 @@ public function test_it_can_be_fake_accessibility_results_from_the_container()
Event::fake();
Features::fake(['my-feature' => true]);

$this->assertTrue(app()->call(function (FeaturesContract $accessible): bool {
return $accessible->accessible('my-feature');
}));
$this->assertTrue(app()->call(fn (FeaturesContract $accessible): bool => $accessible->accessible('my-feature')));
}

public function test_it_can_be_fake_accessibility_results_if_no_value_is_provided()
Expand Down

0 comments on commit e6bc42d

Please sign in to comment.