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

Laravel 11 #65

Merged
merged 17 commits into from
Mar 19, 2024
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
Loading
Loading