PHPackages                             zenmanage/zenmanage-laravel - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. [API Development](/categories/api)
4. /
5. zenmanage/zenmanage-laravel

ActiveLibrary[API Development](/categories/api)

zenmanage/zenmanage-laravel
===========================

Zenmanage API SDK for Laravel

4.0.3(1mo ago)01.7k↓45.6%MITPHPPHP &gt;=8.1CI failing

Since Feb 1Pushed 1mo ago1 watchersCompare

[ Source](https://github.com/zenmanage/zenmanage-laravel)[ Packagist](https://packagist.org/packages/zenmanage/zenmanage-laravel)[ RSS](/packages/zenmanage-zenmanage-laravel/feed)WikiDiscussions main Synced 1mo ago

READMEChangelog (10)Dependencies (10)Versions (11)Used By (0)

Zenmanage Laravel SDK
=====================

[](#zenmanage-laravel-sdk)

[![Build Status](https://github.com/zenmanage/zenmanage-laravel/actions/workflows/ci.yml/badge.svg)](https://github.com/zenmanage/zenmanage-laravel) [![Quality Gate Status](https://camo.githubusercontent.com/88b68ddea62b2bd75236edb28bcaf7384abb78b8bc85d60bde7e883004408db1/68747470733a2f2f736f6e6172636c6f75642e696f2f6170692f70726f6a6563745f6261646765732f6d6561737572653f70726f6a6563743d7a656e6d616e6167655f7a656e6d616e6167652d6c61726176656c266d65747269633d616c6572745f737461747573)](https://sonarcloud.io/summary/new_code?id=zenmanage_zenmanage-laravel)

Add feature flags to your Laravel application in minutes. Control feature rollouts, A/B test, and manage configurations without deploying code.

Why Zenmanage?
--------------

[](#why-zenmanage)

- 🚀 **Fast**: Rules cached locally - ~1ms evaluation time
- 🎯 **Targeted**: Roll out features to specific users, organizations, or segments
- 🛡️ **Safe**: Graceful fallbacks and error handling built-in
- 📊 **Insightful**: Automatic usage tracking (optional)
- 🧪 **Testable**: Easy to mock in tests
- 🔧 **Laravel Native**: Service provider, facade, and artisan commands included

Installation
------------

[](#installation)

```
composer require zenmanage/zenmanage-laravel
```

**Requirements**: Laravel 11+, PHP 8.1+

Key Compatibility
-----------------

[](#key-compatibility)

- Supported: case-sensitive server keys prefixed with `srv_`
- Not supported in Laravel SDK: client keys (`cli_`) and mobile keys (`mob_`) (initialization fails fast)

The service provider will be auto-discovered. If you need to manually publish the config:

```
php artisan vendor:publish --provider="Zenmanage\Laravel\ZenmanageServiceProvider"
```

Get Started in 60 Seconds
-------------------------

[](#get-started-in-60-seconds)

1. Get your server key (`srv_...`) from [zenmanage.com](https://zenmanage.com)
2. Set your token in `.env`:

```
ZENMANAGE_ENVIRONMENT_TOKEN=srv_your_server_key_here
```

3. Check a feature flag:

```
use Zenmanage\Laravel\Facades\Zenmanage;

if (Zenmanage::single('new-dashboard')->isEnabled()) {
    return view('dashboard-v2');
}

return view('dashboard');
```

That's it! 🎉

Configuration
-------------

[](#configuration)

The only required configuration is the Environment Token (server key prefixed with `srv_`). Configuration values are set in `config/zenmanage.php`:

- `environment_token` - Your Zenmanage server key (`srv_...`) (required)
- `cache_ttl` - Cache duration in seconds (default: 3600)
- `cache_backend` - Cache strategy: 'memory' or 'filesystem' (default: 'memory')
- `cache_directory` - Directory for filesystem cache (optional)
- `enable_usage_reporting` - Enable automatic usage tracking (default: false)
- `api_endpoint` - API endpoint URL (default: )

The SDK client metadata is set automatically and is not configurable via environment:

- `client_agent` is hard-coded to `zenmanage-laravel`
- `sdk_version` is read from this package's Composer version metadata

```
ZENMANAGE_ENVIRONMENT_TOKEN=srv_sample
ZENMANAGE_CACHE_BACKEND=filesystem
ZENMANAGE_CACHE_TTL=3600
ZENMANAGE_USAGE_REPORTING=false
ZENMANAGE_API_ENDPOINT=https://api.zenmanage.com
```

Common Use Cases
----------------

[](#common-use-cases)

### Roll Out a Feature Gradually

[](#roll-out-a-feature-gradually)

```
use Zenmanage\Flags\Context\Context;
use Zenmanage\Laravel\Facades\Zenmanage;

// Check if user has access to beta features
$context = Context::single('user', $user->id, $user->name);

$betaAccess = Zenmanage::withContext($context)
    ->single('beta-program')
    ->isEnabled();

if ($betaAccess) {
    // User is in beta program
    $features = $this->getBetaFeatures();
}
```

### A/B Testing

[](#ab-testing)

```
$context = Context::fromArray([
    'type' => 'user',
    'identifier' => $user->id,
    'name' => $user->name,
    'attributes' => [
        ['key' => 'country', 'values' => [['value' => $user->country]]],
    ],
]);

$variant = Zenmanage::withContext($context)
    ->single('checkout-flow')
    ->asString();

if ($variant === 'one-page') {
    return view('checkout.onepage');
}

return view('checkout.multipage');
```

### Percentage Rollouts

[](#percentage-rollouts)

Gradually roll out features to a percentage of your users. The SDK handles bucketing automatically using a deterministic CRC32B hash — no manual bucket logic needed.

```
use Zenmanage\Flags\Context\Context;
use Zenmanage\Laravel\Facades\Zenmanage;

// Just provide a context with an identifier — the SDK does the rest
$context = Context::single('user', $user->id);

$flag = Zenmanage::withContext($context)->single('new-checkout-flow');

if ($flag->isEnabled()) {
    // This user is in the rollout percentage
    return view('checkout.new');
}

// This user is outside the rollout
return view('checkout.classic');
```

**How it works:**

- Configure the rollout percentage (0–100%) and a unique salt in the Zenmanage dashboard
- The SDK hashes `salt:contextIdentifier` to deterministically assign each user to a bucket (0–99)
- Users whose bucket is below the percentage get the rollout value; others get the fallback
- The same user always gets the same result (deterministic), and increasing the percentage never removes previously included users
- Rollout rules can further refine targeting within the rollout group (e.g., only US users in the rollout)

> **Note:** A context `identifier` is required for bucketing. Without one, the user always receives the fallback value.

### Feature Toggles by Organization

[](#feature-toggles-by-organization)

```
$context = Context::fromArray([
    'type' => 'organization',
    'identifier' => $user->organization->id,
    'name' => $user->organization->name,
    'attributes' => [
        ['key' => 'plan', 'values' => [['value' => $user->organization->plan]]],
    ],
]);

$advancedReports = Zenmanage::withContext($context)
    ->single('advanced-reports')
    ->isEnabled();

if ($advancedReports) {
    return $this->getAdvancedReports();
}
```

### Configuration Values

[](#configuration-values)

```
// Get configuration values from flags
$apiTimeout = Zenmanage::single('api-timeout', 5000)->asNumber();
$maxUploadSize = Zenmanage::single('max-upload-mb', 10)->asNumber();
$welcomeMessage = Zenmanage::single('welcome-text', 'Welcome!')->asString();
```

### Kill Switch for Problem Features

[](#kill-switch-for-problem-features)

```
// Quickly disable a problematic feature via dashboard
if (Zenmanage::single('new-payment-processor', false)->isEnabled()) {
    return $this->processWithNewSystem($payment);
}

return $this->processWithLegacySystem($payment);
```

Working with Contexts
---------------------

[](#working-with-contexts)

Contexts let you target flags to specific users, organizations, or any custom attributes. This is how you do gradual rollouts, A/B tests, and targeted features.

### Simple Context (One Attribute)

[](#simple-context-one-attribute)

```
use Zenmanage\Flags\Context\Context;

// Target by user ID with name
$context = Context::single('user', $user->id, $user->name);

// Target by organization
$context = Context::single('organization', $company->id, $company->name);

// Target by user with just ID
$context = Context::single('user', $user->id);
```

### Rich Context (Multiple Attributes)

[](#rich-context-multiple-attributes)

```
$context = Context::fromArray([
    'type' => 'user',
    'identifier' => $user->id,
    'name' => $user->name,
    'attributes' => [
        ['key' => 'organization', 'values' => [['value' => $user->company->slug]]],
        ['key' => 'plan', 'values' => [['value' => $user->subscription->plan]]],
        ['key' => 'role', 'values' => [['value' => $user->role]]],
        ['key' => 'country', 'values' => [['value' => $user->country]]],
    ],
]);

$premiumFeatures = Zenmanage::withContext($context)
    ->single('premium-dashboard')
    ->isEnabled();
```

**What you get:**

- `type`: Context type (user, organization, etc.)
- `identifier`: Unique identifier for targeting
- `name`: Human-readable display name
- `attributes`: Array of additional attributes for advanced targeting (plan, role, country, etc.)

**When to use contexts:**

- Rolling out to specific users (beta testers)
- Organization-based features (enterprise vs. free)
- Regional features (different countries)
- Role-based access (admins, moderators)
- Plan-based features (pro vs. basic)

Safe Defaults - Never Break Your App
------------------------------------

[](#safe-defaults---never-break-your-app)

Always provide defaults for critical features. The SDK will use them if:

- Flag doesn't exist yet
- API is unreachable
- Network issues occur

### Inline Defaults (Recommended)

[](#inline-defaults-recommended)

```
// If 'new-checkout' doesn't exist, returns true
$enabled = Zenmanage::single('new-checkout', true)->isEnabled();

// Configuration value with fallback
$timeout = Zenmanage::single('api-timeout', 5000)->asNumber();
```

### Default Collections (For Multiple Flags)

[](#default-collections-for-multiple-flags)

```
use Zenmanage\Flags\DefaultsCollection;

$defaults = DefaultsCollection::fromArray([
    'new-ui' => true,
    'max-upload-size' => 10,
    'welcome-message' => 'Welcome to our app!',
    'feature-x' => false,
]);

$flags = Zenmanage::withDefaults($defaults);

// All these will use defaults if flags don't exist
$newUI = $flags->single('new-ui')->isEnabled();
$maxSize = $flags->single('max-upload-size')->asNumber();
$message = $flags->single('welcome-message')->asString();
```

### Priority Order

[](#priority-order)

When retrieving a flag, the SDK checks in this order:

1. **API Value** - If flag exists in Zenmanage
2. **Inline Default** - Value passed to `single('flag', default)`
3. **Collection Default** - From `DefaultsCollection`
4. **Exception** - If none of the above

```
$defaults = DefaultsCollection::fromArray(['timeout' => 3000]);

// Uses API value if exists, otherwise inline (5000), then collection (3000)
$timeout = Zenmanage::withDefaults($defaults)
    ->single('timeout', 5000)
    ->asNumber();
```

Retrieving Feature Flags
------------------------

[](#retrieving-feature-flags)

### Using the Facade (Recommended)

[](#using-the-facade-recommended)

```
use Zenmanage\Laravel\Facades\Zenmanage;

// Get all flags
$flags = Zenmanage::all();

// Get a single flag
$flag = Zenmanage::single('flag-key');

// With default
$flag = Zenmanage::single('flag-key', false);
```

### Using Dependency Injection

[](#using-dependency-injection)

```
use Zenmanage\Laravel\Contracts\Client;

class DashboardController extends Controller
{
    public function __construct(private Client $zenmanage) {}

    public function index()
    {
        if ($this->zenmanage->single('new-dashboard')->isEnabled()) {
            return view('dashboard-v2');
        }

        return view('dashboard');
    }
}
```

Getting Flag Values
-------------------

[](#getting-flag-values)

### All Flags

[](#all-flags)

```
$results = Zenmanage::all();

foreach ($results as $flag) {
    $key = $flag->getKey();
    $type = $flag->getType();

    // Get value based on type
    if ($flag->getType() === 'boolean') {
        $value = $flag->asBool();
    } elseif ($flag->getType() === 'number') {
        $value = $flag->asNumber();
    } else {
        $value = $flag->asString();
    }
}
```

### Single Flag

[](#single-flag)

```
$flag = Zenmanage::single('flag-key');

// Boolean check
if ($flag->isEnabled()) {
    // Feature is enabled
}

// Get typed values
$boolValue = $flag->asBool();
$stringValue = $flag->asString();
$numberValue = $flag->asNumber();
```

Reporting Feature Flag Usage
----------------------------

[](#reporting-feature-flag-usage)

When your application uses a feature flag, it can notify Zenmanage of the usage. This helps Zenmanage determine which flags are active and which may have been abandoned. Note that `single()` automatically reports usage, so you typically don't need to call this manually.

```
use Zenmanage\Flags\Context\Context;
use Zenmanage\Laravel\Facades\Zenmanage;

// Report usage (optional - single() does this automatically)
Zenmanage::reportUsage('flag-key');

// Report with context
$context = Context::single('user', 'user-123');
Zenmanage::reportUsage('flag-key', $context);
```

Refreshing Rules
----------------

[](#refreshing-rules)

You can manually refresh the flag rules from the API:

```
use Zenmanage\Laravel\Facades\Zenmanage;

Zenmanage::refreshRules();
```

Testing
-------

[](#testing)

Mock the Zenmanage facade in your tests:

```
use Zenmanage\Flags\Flag;
use Zenmanage\Laravel\Facades\Zenmanage;

public function test_new_feature_for_beta_users()
{
    Zenmanage::shouldReceive('single')
        ->with('beta-feature')
        ->andReturn(new Flag(...));

    // Your test code
}
```

Or use `::fake()` to disable actual API calls:

```
Zenmanage::fake();

// Now calls to Zenmanage won't hit the real API
```

Contributing
------------

[](#contributing)

Bug reports and pull requests are welcome on GitHub at . This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [Contributor Covenant](http://contributor-covenant.org) code of conduct.

License
-------

[](#license)

The library is available as open source under the terms of the [MIT License](http://opensource.org/licenses/MIT).

Code of Conduct
---------------

[](#code-of-conduct)

Everyone interacting in the Zenmanage's code bases, issue trackers, chat rooms and mailing lists is expected to follow the [code of conduct](https://github.com/zenmanage/zenmanage-laravel/blob/master/CODE_OF_CONDUCT.md).

What is Zenmanage?
------------------

[](#what-is-zenmanage)

[Zenmanage](https://zenmanage.com/) allows you to control which features and settings are enabled in your application giving you better flexibility to deploy code and release features.

Zenmanage was started in 2024 as an alternative to highly complex feature flag tools. Learn more [about us](https://zenmanage.com/).

###  Health Score

46

—

FairBetter than 93% of packages

Maintenance89

Actively maintained with recent releases

Popularity21

Limited adoption so far

Community7

Small or concentrated contributor base

Maturity53

Maturing project, gaining track record

 Bus Factor1

Top contributor holds 100% of commits — single point of failure

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

###  Release Activity

Cadence

Every ~46 days

Recently: every ~15 days

Total

10

Last Release

56d ago

Major Versions

1.0.2 → 2.0.02025-08-22

2.0.1 → 3.0.02026-01-19

3.3.0 → 4.0.02026-03-23

### Community

Maintainers

![](https://www.gravatar.com/avatar/7fe43dc70dad96a50299ea26ec25b0a1c35a5a6b48ac4b71f843b45c25b7eb77?d=identicon)[zenmanage-brk](/maintainers/zenmanage-brk)

---

Top Contributors

[![zenmanage-brk](https://avatars.githubusercontent.com/u/219455051?v=4)](https://github.com/zenmanage-brk "zenmanage-brk (19 commits)")

###  Code Quality

TestsPHPUnit

Static AnalysisPHPStan

Code StylePHP CS Fixer

Type Coverage Yes

### Embed Badge

![Health badge](/badges/zenmanage-zenmanage-laravel/health.svg)

```
[![Health](https://phpackages.com/badges/zenmanage-zenmanage-laravel/health.svg)](https://phpackages.com/packages/zenmanage-zenmanage-laravel)
```

###  Alternatives

[stripe/stripe-php

Stripe PHP Library

4.0k143.3M480](/packages/stripe-stripe-php)[twilio/sdk

A PHP wrapper for Twilio's API

1.6k92.9M272](/packages/twilio-sdk)[facebook/php-business-sdk

PHP SDK for Facebook Business

90821.9M34](/packages/facebook-php-business-sdk)[meilisearch/meilisearch-php

PHP wrapper for the Meilisearch API

74513.7M114](/packages/meilisearch-meilisearch-php)[google/gax

Google API Core for PHP

265103.1M454](/packages/google-gax)[google/common-protos

Google API Common Protos for PHP

173103.7M50](/packages/google-common-protos)

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
