Skip to content

Commit e4860be

Browse files
committed
clean up docs, add github action,
1 parent 50d58f1 commit e4860be

File tree

6 files changed

+134
-98
lines changed

6 files changed

+134
-98
lines changed

.github/workflows/run-tests.yml

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
name: Test
2+
3+
on: [push]
4+
5+
jobs:
6+
test:
7+
runs-on: ubuntu-20.04
8+
9+
steps:
10+
- uses: actions/checkout@v2
11+
12+
- name: Setup PHP
13+
uses: shivammathur/setup-php@v2
14+
with:
15+
php-version: '8.0'
16+
extensions: zip, sqlite3
17+
coverage: none
18+
19+
- name: Restore caches
20+
uses: actions/cache@v2
21+
with:
22+
path: ~/.composer/cache/files
23+
key: ${{ runner.os }}-composer-${{ hashFiles('**/composer.lock') }}
24+
restore-keys: |
25+
${{ runner.os }}-composer-
26+
27+
- name: Install composer dependencies
28+
run: composer install --no-ansi --no-interaction --no-scripts --no-progress --prefer-dist
29+
30+
- name: Code sniff
31+
run: vendor/bin/php-cs-fixer fix --dry-run
32+
33+
- name: Execute tests
34+
run: composer test

CHANGELOG.md

Lines changed: 0 additions & 7 deletions
This file was deleted.

LICENSE.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
The MIT License (MIT)
22

3-
Copyright (c) Codinglabs <steve@codinglabs.com.au>
3+
Copyright (c) Coding Labs Pty Ltd <steve@codinglabs.com.au>
44

55
Permission is hereby granted, free of charge, to any person obtaining a copy
66
of this software and associated documentation files (the "Software"), to deal

README.md

Lines changed: 97 additions & 86 deletions
Original file line numberDiff line numberDiff line change
@@ -1,97 +1,63 @@
11
# Dynamic feature flags for laravel.
22

33
[![Latest Version on Packagist](https://img.shields.io/packagist/v/codinglabsau/laravel-feature-flags.svg?style=flat-square)](https://packagist.org/packages/codinglabsau/laravel-feature-flags)
4-
[![GitHub Tests Action Status](https://img.shields.io/github/workflow/status/codinglabsau/laravel-feature-flags/run-tests?label=tests)](https://github.com/codinglabsau/laravel-feature-flags/actions?query=workflow%3Arun-tests+branch%3Amain)
5-
[![GitHub Code Style Action Status](https://img.shields.io/github/workflow/status/codinglabsau/laravel-feature-flags/Check%20&%20fix%20styling?label=code%20style)](https://github.com/codinglabsau/laravel-feature-flags/actions?query=workflow%3A"Check+%26+fix+styling"+branch%3Amain)
4+
[![Test](https://github.com/codinglabsau/laravel-feature-flags/actions/workflows/run-tests.yml/badge.svg)](https://github.com/codinglabsau/laravel-feature-flags/actions/workflows/run-tests.yml)
65
[![Total Downloads](https://img.shields.io/packagist/dt/codinglabsau/laravel-feature-flags.svg?style=flat-square)](https://packagist.org/packages/codinglabsau/laravel-feature-flags)
76

8-
This package offers the ability to implement feature flags throughout your codebase allowing you to easily toggle parts of your application. Features are database driven which will allow you to easily configure them via a command or build a front end to manage their states. Here's an example of how they could be used:
9-
10-
```php
11-
@feature('search-v2')
12-
// new search goes here
13-
@else
14-
// legacy search here
15-
@endfeature
16-
```
17-
And in your codebase:
18-
```php
19-
FeatureFlag::isEnabled('search-v2') // true
20-
```
7+
This package offers the ability to implement feature flags in your application which can be easily toggled on or off. You can also set a feature to a dynamic state where you can define custom rules around whether that feature is enabled or not.
218
___
229
## Installation
2310

24-
You can install the package via composer:
11+
### Install With Composer:
2512

2613
```bash
2714
composer require codinglabsau/laravel-feature-flags
2815
```
2916

30-
You can publish and run the migrations with:
17+
### Database Migrations
3118

3219
```bash
33-
php artisan vendor:publish --tag="laravel-feature-flags-migrations"
20+
php artisan vendor:publish --tag="feature-flags-migrations"
3421
php artisan migrate
3522
```
3623

37-
You can publish the config file with:
24+
### Publish Configuration:
3825

3926
```bash
40-
php artisan vendor:publish --tag="laravel-feature-flags-config"
27+
php artisan vendor:publish --tag="feature-flags-config"
4128
```
4229

43-
This is the contents of the published config file:
4430

31+
### Cache Store
32+
update your `.env`:
4533
```php
46-
return [
47-
48-
/*
49-
|--------------------------------------------------------------------------
50-
| Cache
51-
|--------------------------------------------------------------------------
52-
|
53-
| Configure the cache store that will be used to cache the state of a
54-
| feature. You can also configure a prefix for all keys in the cache.
55-
*/
56-
57-
'cache_store' => env('FEATURES_CACHE_STORE'),
58-
'cache_prefix' => 'features',
59-
60-
/*
61-
|--------------------------------------------------------------------------
62-
| Models
63-
|--------------------------------------------------------------------------
64-
|
65-
| If you need to customise any models used then you can swap them out by
66-
| replacing the default models defined here.
67-
*/
68-
69-
'feature_model' => \Codinglabs\FeatureFlags\Models\Feature::class,
70-
71-
];
34+
FEATURES_CACHE_STORE=file
7235
```
36+
Note that under the hood this package uses the `rememberForever()` method for caching and that if you are using the `Memcached` driver, items that are stored "forever" may be removed when the cache reaches its size limit.
7337

74-
## Usage
38+
### Use Your Own Model
7539

76-
### Basic Setup
40+
To use your own model, update the config and replace the existing reference with your own model:
7741

78-
###Migrations
79-
Make sure you have published the migrations as the `features` table is required:
80-
```bash
81-
php artisan vendor:publish --tag="laravel-feature-flags-migrations"
82-
php artisan migrate
83-
```
42+
```php
43+
// app/config/feature-flags.php
8444

85-
### Configuring Cache
86-
Each features state will be cached on access which means it won't be calling the database every time a feature is being checked. You can configure the cache store by publishing the config:
87-
```
88-
php artisan vendor:publish --tag="laravel-feature-flags-config"
45+
'feature_model' => \App\Models\Feature::class,
8946
```
90-
Then update your .env:
47+
48+
Make sure to also cast the state column to a feature state enum using the `FeatureStateCast`:
49+
9150
```php
92-
FEATURES_CACHE_STORE=redis
51+
// app/Models/Feature.php
52+
53+
use Codinglabs\FeatureFlags\Casts\FeatureStateCast;
54+
55+
protected $casts = [
56+
'state' => FeatureStateCast::class
57+
];
9358
```
94-
Note that this package uses the `rememberForever()` method and that if you are using the `Memcached` driver, items that are stored "forever" may be removed when the cache reaches its size limit.
59+
60+
## Usage
9561

9662
Create a new feature in the database and give it a default state:
9763
```php
@@ -100,7 +66,10 @@ Feature::create([
10066
'state' => Codinglabs\FeatureFlags\Enums\FeatureState::on()
10167
]);
10268
```
103-
There are three states a feature can be in:
69+
70+
Its recommended that you seed the features to your database before a new deployment or as soon as possible after a deployment.
71+
72+
A feature can be in one of three states:
10473
```php
10574
use Codinglabs\FeatureFlags\Enums\FeatureState;
10675

@@ -118,7 +87,8 @@ FeatureState::dynamic()
11887
// legacy search here
11988
@endfeature
12089
```
121-
#### Code
90+
91+
#### In Your Code
12292
```php
12393
use Codinglabs\FeatureFlags\Facades\FeatureFlag;
12494

@@ -129,6 +99,47 @@ if (FeatureFlag::isEnabled('search-v2')) {
12999
}
130100
```
131101

102+
#### Sharing features with UI (Inertiajs example)
103+
```php
104+
// config/app.php
105+
106+
'features' => [
107+
[
108+
'name' => 'search-v2',
109+
'state' => \Codinglabs\FeatureFlags\Enums\FeatureState::dynamic()
110+
]
111+
],
112+
```
113+
114+
```php
115+
// app/Middleware/HandleInertiaRequest.php
116+
117+
Inertia::share([
118+
'features' => function () {
119+
return collect(config('app.features'))
120+
->filter(fn ($feature) => FeatureFlag::isEnabled($feature['name']))
121+
->pluck('name');
122+
}
123+
]);
124+
```
125+
126+
```javascript
127+
// app.js
128+
129+
Vue.mixin({
130+
methods: {
131+
hasFeature: function(feature) {
132+
return this.$page.features.includes(feature)
133+
}
134+
}
135+
})
136+
```
137+
```html
138+
<!-- SomeComponent.vue -->
139+
140+
<div v-if="hasFeature('search-v2')">Some cool new feature</div>
141+
```
142+
132143
### Updating A Features State
133144

134145
To change a features state you can call the following methods:
@@ -143,44 +154,52 @@ Alternatively you can set the state directly by passing a feature state enum:
143154
```php
144155
FeatureFlag::updateFeatureState('search-v2', FeatureState::on())
145156
```
146-
It is recommended that you only update a features state using the above methods as it will take care of updating the cache.
157+
It is recommended that you only update a features state using the above methods as it will take care of updating the cache and dispatching the feature updated event:
158+
159+
```php
160+
\Codinglabs\FeatureFlags\Events\FeatureUpdatedEvent::class
161+
```
162+
An example use case of the feature updated event would be if you were caching the result of a dynamic handler and need to clear that cache when a feature is updated.
163+
164+
___
165+
## Advanced Usage
147166

148167
### Dynamic Features
149168

150-
When a features state is in the dynamic state it will look for a dynamic handler to determine whether that feature is enabled or not. A dynamic handler can be defined in the `boot()` method of your `AppServiceProvider`:
169+
A dynamic handler can be defined in the `boot()` method of your `AppServiceProvider`:
151170
```php
152171
use Codinglabs\FeatureFlags\Facades\FeatureFlag;
153172

154173
FeatureFlag::registerDynamicHandler('search-v2', function ($feature, $request) {
155-
return $request->user() && $request->user()->canAccessFeature($feature);
174+
return $request->user() && $request->user()->hasRole('Tester')
156175
});
157176
```
158-
Each handler is given the feature name and the current request as arguments and must return a bool.
177+
Dynamic handlers will only be called when a feature is in the `dynamic` state. This will allow you to define custom rules around whether that feature is enabled like in the example above where the user can only access the feature if they have a tester role.
178+
179+
Each handler is provided with the features name and current request as arguments and must return a bool value.
180+
181+
### Default Handler For Dynamic Features
182+
183+
You may also define a default handler which will be the catch-all handler for features that don't have an explicit handler defined for them:
159184

160-
#### Default Handler For Dynamic Features
161-
You may also define a default dynamic handler which will be the catch-all dynamic handler for features that don't have an explicit handler defined for them:
162185
```php
163186
FeatureFlag::registerDefaultDynamicHandler(function ($feature, $request) {
164187
return $request->user() && $request->user()->hasRole('Tester');
165188
});
166189
```
167-
When a feature is in the dynamic state it will look for an explicit handler for that feature first. If it can't find a handler and a default handler has been defined it will use that instead. If it can't find any handlers the feature will resolve to `off` by default.
168190

169-
### Events
170-
#### Updated
171-
After a feature has been updated an event will be dispatched:
172-
```php
173-
\Codinglabs\FeatureFlags\Events\FeatureUpdatedEvent::class
174-
```
175-
This can be used to create a listener that could for example handle clearing any custom cache data created by dynamic handlers.
191+
An explicit handler defined using `registerDynamicHandler()` will take precedence over the default handler. If neither a default nor explicit handler has been defined then the feature will resolve to `off` by default.
176192

177193
### Handle Missing Features
194+
178195
Features must exist in the database otherwise a `MissingFeatureException` will be thrown. This behaviour can be turned off by explicitly handling cases where a feature doesn't exist:
196+
179197
```php
180198
FeatureFlag::handleMissingFeaturesWith(function ($feature) {
181199
// log or report this somewhere...
182200
})
183201
```
202+
184203
If a handler for missing features has been defined then an exception will **not** be thrown and the feature will resolve to `off`.
185204

186205
## Testing
@@ -189,14 +208,6 @@ If a handler for missing features has been defined then an exception will **not*
189208
composer test
190209
```
191210

192-
## Changelog
193-
194-
Please see [CHANGELOG](CHANGELOG.md) for more information on what has changed recently.
195-
196-
## Contributing
197-
198-
Please see [CONTRIBUTING](https://github.com/spatie/.github/blob/main/CONTRIBUTING.md) for details.
199-
200211
## Security Vulnerabilities
201212

202213
Please review [our security policy](../../security/policy) on how to report security vulnerabilities.

composer.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,8 @@
1212
"license": "MIT",
1313
"authors": [
1414
{
15-
"name": "Steve Thomas",
16-
"email": "steve@codinglabs.com.au",
15+
"name": "Jonathan Louw",
16+
"email": "JonathanLouw@users.noreply.github.com",
1717
"role": "Developer"
1818
}
1919
],

src/FeatureFlagsServiceProvider.php

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,7 @@
44

55
use Illuminate\Support\Facades\Blade;
66
use Spatie\LaravelPackageTools\Package;
7-
use Codinglabs\FeatureFlags\Models\Feature;
87
use Codinglabs\FeatureFlags\Facades\FeatureFlag;
9-
use Codinglabs\FeatureFlags\Commands\FeaturesCommand;
108
use Spatie\LaravelPackageTools\PackageServiceProvider;
119

1210
class FeatureFlagsServiceProvider extends PackageServiceProvider

0 commit comments

Comments
 (0)