Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Utils.common.conditioninterface Laravel Package

mouf/utils.common.conditioninterface

A small PHP utility from the Mouf framework that defines a ConditionInterface: a simple contract requiring a single method to evaluate whether a condition is met. Implement it to build reusable, composable conditions that can be checked uniformly across your application code.

View on GitHub
Deep Wiki
Context7

Getting Started

Install and read the whole package first. This is a five-file, sub-100-line library, so there is no reason to skim:

composer require mouf/utils.common.conditioninterface

The namespace is Mouf\Utils\Common\ConditionInterface. Open src/ConditionInterface/ConditionInterface.php first — it is the entire contract:

interface ConditionInterface
{
    public function isOk(): bool; // older tags may omit the return type; check the tag you install
}

Then read AndCondition, OrCondition and NotCondition in the same folder. That is the whole API surface. Anything else you need, you will write yourself.

First use case: replace nested boolean flags in a domain rule. Pick a single "can the user do X" check in your codebase — checkout eligibility is a good one — and express it as conditions instead of a chain of ifs:

use Mouf\Utils\Common\ConditionInterface\ConditionInterface;
use Mouf\Utils\Common\ConditionInterface\AndCondition;
use Mouf\Utils\Common\ConditionInterface\NotCondition;

final class CartHasItems implements ConditionInterface
{
    public function __construct(private Cart $cart) {}
    public function isOk(): bool { return $this->cart->lines()->isNotEmpty(); }
}

final class UserIsVerified implements ConditionInterface
{
    public function __construct(private User $user) {}
    public function isOk(): bool { return $this->user->hasVerifiedEmail(); }
}

$canCheckout = new AndCondition([
    new CartHasItems($cart),
    new UserIsVerified($user),
    new NotCondition(new CartIsLocked($cart)),
]);

if ($canCheckout->isOk()) { /* ... */ }

Where to look next: the package was built for Mouf's DI container, so the docs site is about wiring, not about the interface. In a Laravel/Symfony app you can ignore that entirely — the interface plus two composites are the deliverable.

Implementation Patterns

Keep isOk() pure and cheap. No writes, no dispatching events, no throwing on a failed check. It is a predicate, and composites may call it several times or short-circuit past it. If a condition needs remote data, resolve it in the constructor and cache it on the instance.

Compose, don't inherit. The library's only real value is AndCondition / OrCondition / NotCondition. Build a small vocabulary of atomic conditions (FeatureEnabled, WithinBusinessHours, HasPermission) and assemble them per use case. Atomic classes stay one-liners and are trivially unit-testable without mocks.

Build conditions from config, not from code, when the rule is operational. A factory that maps a config array to condition instances lets ops change rules without a deploy:

final class ConditionFactory
{
    /** @param array<int, array{class: class-string, args?: array}> $specs */
    public function fromSpecs(array $specs): ConditionInterface
    {
        return new AndCondition(array_map(
            fn (array $s) => app()->makeWith($s['class'], $s['args'] ?? []),
            $specs
        ));
    }
}

Use it as a specification in your query/validation layers. Two reliable integration points in a Laravel app:

  • Form requests / validators: wrap a condition in a custom validation rule so the same rule object drives the UI (disabled button) and the server (422 response).
  • Gates and policies: Gate::define('checkout', fn (User $u) => $this->canCheckout->isOk()); — keeps authorization logic out of controllers and out of Blade.

Add a "why" wrapper rather than extending the interface. Since isOk() only returns a bool, wrap it when you need diagnostics:

final class EvaluatedCondition
{
    /** @param list<ConditionInterface> $failed */
    public function __construct(public bool $ok, public array $failed = []) {}
}

Evaluate the atoms yourself and record which ones returned false. This is worth doing the moment a user asks "why can't I check out?".

Bind composites in the container per feature. Register AndCondition instances as singletons keyed by a name (app()->bind('conditions.checkout', ...)) so tests can swap one atom without rebuilding the tree.

Gotchas and Tips

  • Empty composite sets. An AndCondition with zero conditions is vacuously true; an OrCondition with zero conditions is false. Confirm this against the source of the tag you install — it matters a lot when your condition list comes from config and the config array happens to be empty. Guard at the factory level.
  • Maintenance status. Last release 2019, zero dependents, three stars. Do not build a long-lived architecture on the assumption of upstream fixes. Treat it as a copy-paste snippet library: the license is MIT, so vendoring the four classes into app/Support/Conditions/ and deleting the dependency is a perfectly reasonable outcome, and frees you to add return types and readonly.
  • PHP 8 compatibility. Check composer.json's require before adding it to a modern project. Older tags may pin a low PHP constraint; if composer require refuses, either relax with --ignore-platform-req=php (and verify with a quick test run) or vendor the files instead of fighting the resolver.
  • No Result type, no reasons. Any "which condition failed?" UI has to be built on top. Don't be tempted to add a getMessage() to ConditionInterface — you would fork the contract and lose compatibility with anything Mouf-shaped.
  • Ordering in OrCondition is a performance decision. Short-circuits left to right. Put cheap, frequently-true atoms first; put database or HTTP-backed atoms last.
  • Idempotency under short-circuiting. If isOk() mutates state, AndCondition will call it a different number of times depending on earlier results. This is the most common bug in hand-rolled conditions; keep them side-effect free.
  • Name clashes. ConditionInterface is a generic name — alias on import (use ... as MoufCondition) if you also have a domain ConditionInterface of your own.
  • Not for query building. These evaluate in-memory on already-loaded objects. Using them to filter a collection of 50k rows will load everything first; keep Eloquent/query-builder scopes for that and reserve conditions for the final decision.
  • Extension points are essentially nil. There is no registry, no plugin hook. Your extension point is your own naming convention plus the factory above. If you need XorCondition or AtLeastNConditions, write them as ten-line classes next to the built-ins — they compose the same way.
Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
socialdept/tenant-domains
tautvydasr/blade-class-names
socialdept/color-scales
maherelgamil/controller
coleus/widgets
coleus/table
coleus/users
coleus/music
coleus/health
coleus/calendar
coleus/notes
coleus/support
coleus/settings
coleus/apps
seampact/laravel
emmyconceptng/laravel-ng-postcode
jjsquady/round-robin
skyraptor/chatter
edlugz/sasapay
abbasudo/artisan-route