Weave Code
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

Rule Engine Laravel Package

drinks-it/rule-engine

View on GitHub
Deep Wiki
Context7

Getting Started

Minimal Setup

  1. Installation:

    composer require drinks-it/rule-engine
    

    For full dependency support (Doctrine, Symfony):

    composer require drinks-it/rule-engine --with-dependencies
    
  2. Bundle Registration: Add to config/bundles.php:

    DrinksIt\RuleEngineBundle\RuleEngineBundle::class => ['all' => true]
    
  3. Doctrine DBAL Configuration (if using Doctrine):

    # config/packages/doctrine.yaml
    doctrine:
        dbal:
            types:
                rule-engine-conditions: DrinksIt\RuleEngineBundle\Doctrine\Types\ConditionsType
                rule-engine-action: DrinksIt\RuleEngineBundle\Doctrine\Types\ActionType
                rule-engine-event: DrinksIt\RuleEngineBundle\Doctrine\Types\TriggerEventType
    
  4. Generate Rule Engine Entity:

    php bin/console make:rule-engine MyRuleEngine
    php bin/console make:migration
    php bin/console doctrine:migrations:migrate
    

First Use Case: Simple Rule Evaluation

use DrinksIt\RuleEngineBundle\RuleEngine\RuleEngineInterface;

// In a controller/service
$ruleEngine = $container->get(RuleEngineInterface::class);
$context = ['user_age' => 25, 'is_premium' => true];

// Evaluate a rule (assuming you've created one via the CLI)
$ruleEngine->evaluate('discount_rule', $context);

Implementation Patterns

Rule Creation Workflow

  1. Define Rules via CLI:

    php bin/console make:rule-engine MyDiscountRule
    

    This generates a CRUD interface for managing rules in the admin panel.

  2. Rule Structure:

    • Conditions: JSON array of conditions (e.g., {"user_age": {"operator": ">", "value": 18}}).
    • Actions: JSON array of actions (e.g., {"apply_discount": {"value": 10}}).
    • Events: Trigger conditions (e.g., user_checkout).
  3. Integration with Business Logic:

    // Trigger an event (e.g., after user checkout)
    $eventDispatcher = $container->get('event_dispatcher');
    $eventDispatcher->dispatch(new UserCheckoutEvent($user));
    
    // Or manually evaluate rules
    $ruleEngine->evaluate('discount_rule', ['user' => $user]);
    

Common Patterns

  • Context Passing: Always pass a structured array/object as context to rules. Example:

    $context = [
        'user' => $userEntity,
        'cart' => $cart,
        'request' => $request->toArray(),
    ];
    
  • Dynamic Rule Loading: Fetch rules from the database dynamically:

    $rules = $ruleEngine->findRulesByEvent('user_checkout');
    foreach ($rules as $rule) {
        $ruleEngine->evaluate($rule->getName(), $context);
    }
    
  • Action Handling: Register custom actions via services:

    # config/services.yaml
    services:
        App\Service\CustomActionHandler:
            tags: [drinks_it.rule_engine.action_handler]
    
  • Event-Driven Architecture: Use Symfony’s event system to trigger rules:

    // In an event subscriber
    public function onUserCheckout(UserCheckoutEvent $event) {
        $ruleEngine->evaluate('post_checkout_rules', ['user' => $event->getUser()]);
    }
    

Gotchas and Tips

Pitfalls

  1. Doctrine Type Mismatches:

    • If using Doctrine, ensure the rule-engine-* types are registered before migrations run. Otherwise, you may encounter:
      Unknown Doctrine type [rule-engine-conditions]
      
    • Fix: Run php bin/console doctrine:schema:update --force after adding types.
  2. Context Data Serialization:

    • Rules evaluate context as JSON. Non-serializable objects (e.g., closures, resources) will fail.
    • Tip: Convert objects to arrays or use __toArray() methods:
      $context['user'] = $user->toArray(); // Assuming a toArray() method exists
      
  3. Rule Naming Collisions:

    • Rule names must be unique. Reusing names without proper cleanup can lead to silent failures.
    • Tip: Prefix rule names with a namespace (e.g., marketing_discount_rule).
  4. Action Execution Order:

    • Actions are executed in the order defined in the rule JSON. There’s no built-in priority system.
    • Workaround: Use a custom action handler to implement ordering logic.
  5. Admin Panel Dependencies:

    • The make:rule-engine command generates a CRUD interface that relies on Symfony’s maker bundle and easy_admin.
    • Tip: If not using EasyAdmin, manually create the entity and manage rules via API or custom UI.

Debugging Tips

  1. Log Rule Evaluations: Enable debug mode to log rule evaluations:

    # config/packages/dev/rule_engine.yaml
    drinks_it_rule_engine:
        debug: true
    

    This logs conditions, actions, and evaluation results.

  2. Validate Rule JSON: Use the RuleEngineBundle’s validator to check rule syntax:

    $validator = $container->get('validator');
    $errors = $validator->validate($ruleEntity->getConditions());
    
  3. Test Rules in Isolation: Write unit tests for rules using the RuleEngineInterface:

    public function testDiscountRule() {
        $ruleEngine = $this->createMock(RuleEngineInterface::class);
        $ruleEngine->method('evaluate')
            ->with('discount_rule', ['user_age' => 25])
            ->willReturn(true);
    
        $this->assertTrue($ruleEngine->evaluate('discount_rule', ['user_age' => 25]));
    }
    

Extension Points

  1. Custom Conditions/Operators: Extend the condition system by creating a custom operator:

    use DrinksIt\RuleEngineBundle\RuleEngine\Condition\OperatorInterface;
    
    class IsPremiumOperator implements OperatorInterface {
        public function evaluate($value, $operatorValue) {
            return $value->isPremium() === $operatorValue;
        }
    }
    

    Register it in services:

    services:
        App\RuleEngine\IsPremiumOperator:
            tags: [drinks_it.rule_engine.operator]
    
  2. Custom Actions: Create reusable actions:

    use DrinksIt\RuleEngineBundle\RuleEngine\Action\ActionInterface;
    
    class SendEmailAction implements ActionInterface {
        public function execute($actionData, $context) {
            // Logic to send email
        }
    }
    

    Tag the service:

    services:
        App\RuleEngine\SendEmailAction:
            tags: [drinks_it.rule_engine.action_handler]
    
  3. Override Default Storage: By default, rules are stored in the database. To use an alternative (e.g., Redis):

    $ruleEngine = new CustomRuleEngine(
        $container->get('redis'),
        $container->get('validator')
    );
    

    Bind it in services.yaml:

    services:
        DrinksIt\RuleEngineBundle\RuleEngine\RuleEngineInterface: '@custom_rule_engine'
    
  4. Event Listeners for Rules: Listen to rule evaluation events:

    use DrinksIt\RuleEngineBundle\Event\RuleEvaluatedEvent;
    
    public function onRuleEvaluated(RuleEvaluatedEvent $event) {
        if (!$event->isPassed()) {
            $this->logger->warning('Rule failed: ' . $event->getRuleName());
        }
    }
    

    Tag the listener:

    services:
        App\EventListener\RuleListener:
            tags: [kernel.event_listener, name: rule_evaluated]
    
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.
besmartand-pro/php-quality-config
sentix/ai-chatbot
terminal42/code-quality-tools
codifyo/ts-generator-bundle
testo/fiber
mintobit/jobqueue
a4sex/maintenance-bundle
a4sex/entity-date-update
a4sex/client-identifier
a4sex/base-utilites
a4sex/key-value-storage
a4sex/micro-status
chilldev/dependency-injection-extra
datinglibre/datinglibre-app-api
biberltd/corebundle
bricre/symfony-bundle-test
biberltd/logbundle
dominium/http-adapter-bundle
dominium/google-analytics
a4sex/auto-clean-entity