prohalexey / the-choice
Installs: 2 796
Dependents: 0
Suggesters: 0
Security: 0
Stars: 25
Watchers: 2
Forks: 5
Open Issues: 3
Requires
- php: >=8.0
- ext-json: *
- ext-mbstring: *
- chriskonnertz/string-calc: ^2.0
- symfony/yaml: ^7.3
Requires (Dev)
- friendsofphp/php-cs-fixer: ^v3.68
- phan/phan: ^5.4
- phpstan/phpstan: ^2.1
- phpstan/phpstan-phpunit: ^2.0
- phpstan/phpstan-strict-rules: ^2.0
- phpunit/phpunit: ^12.0.2
- psr/container: ^2.0.0
- rector/rector: ^2.0
- rector/swiss-knife: ^2.1.7
- roave/security-advisories: dev-latest
- thecodingmachine/phpstan-safe-rule: ^1.3
This package is auto-updated.
Last update: 2025-08-06 07:59:16 UTC
README
A powerful and flexible Business Rule Engine for PHP that allows you to separate business logic from your application code.
Features
This library helps you simplify the implementation of complex business rules such as:
- Complex discount calculations
- Customer bonus systems
- User permission resolution
- Dynamic pricing strategies
Why use TheChoice? If you find yourself constantly modifying business conditions in your code, this library allows you to move those conditions to external configuration sources. You can even create a web interface to edit configurations dynamically.
Key Benefits
- ✅ Rules written in JSON or YAML format
- ✅ Store rules in files or databases
- ✅ Serializable and cacheable configurations
- ✅ PSR-11 compatible container support
- ✅ Extensible with custom operators and contexts
Installation
composer require prohalexey/the-choice
Quick Start
JSON Configuration Example
{ "node": "condition", "if": { "node": "collection", "type": "and", "elements": [ { "node": "context", "context": "withdrawalCount", "operator": "equal", "value": 0 }, { "node": "context", "context": "inGroup", "operator": "arrayContain", "value": [ "testgroup", "testgroup2" ] } ] }, "then": { "node": "context", "description": "Giving 10% of deposit sum as discount for the next order", "context": "getDepositSum", "modifiers": [ "$context * 0.1" ], "params": { "discountType": "VIP client" } }, "else": { "node": "value", "description": "Giving 5% discount for the next order", "value": "5" } }
YAML Configuration Example
node: condition if: node: collection type: and elements: - node: context context: withdrawalCount operator: equal value: 0 - node: context context: inGroup operator: arrayContain value: - testgroup - testgroup2 then: node: context context: getDepositSum description: "Giving 10% of deposit sum as discount for the next order" modifiers: - "$context * 0.1" params: discountType: "VIP client" else: node: value description: "Giving 5% discount for the next order" value: 5
PHP Usage
<?php use TheChoice\Container; // Configure contexts in the PSR-11 compatible container $container = new Container([ 'visitCount' => VisitCount::class, 'hasVipStatus' => HasVipStatus::class, 'inGroup' => InGroup::class, 'withdrawalCount' => WithdrawalCount::class, 'depositCount' => DepositCount::class, 'utmSource' => UtmSource::class, 'contextWithParams' => ContextWithParams::class, 'action1' => Action1::class, 'action2' => Action2::class, 'actionReturnInt' => ActionReturnInt::class, 'actionWithParams' => ActionWithParams::class, ]); // Create a parser $parser = $container->get(JsonBuilder::class); // Load rules from file or other sources $rules = $parser->parseFile('rules/discount-rules.json'); // Get the processor $resolver = $container->get(ProcessorResolverInterface::class); $processor = $resolver->resolve($rules); // Execute the rules $result = $processor->process($rules);
Core Concepts
Node Types
Each node has a node
property that describes its type and an optional description
property for UI purposes.
Root Node
The root of the rules tree that maintains state and stores execution results.
Properties:
storage
- Container for variablesrules
- Contains the first node to be processed
Example:
node: root description: "Discount settings" rules: node: value value: 5
Value Node
Returns a static value.
Properties:
value
- The value to return (can be array, string, or numeric)
Example:
node: value description: "5% discount for next order" value: 5
Context Node
Executes callable objects and can modify the global state which is stored in the "Root" node.
Properties:
break
- Special property to stop execution ("immediately"
stops and returns context result)context
- Name of the context for calculationsmodifiers
- Array of mathematical modifiersoperator
- Operator for calculations or comparisonsparams
- Parameters to set in contextpriority
- Priority for collection sortingvalue
- Default value for the$context
variable
Example:
node: context context: getDepositSum description: "Calculate 10% of deposit sum" modifiers: - "$context * 0.1" params: discountType: "VIP client" priority: 5
With Operator Example:
node: context context: withdrawalCount operator: equal value: 0
Collection Node
Contains multiple nodes with AND/OR logic.
Properties:
type
- Collection type (and
oror
)elements
- Array of child nodespriority
- Priority for nested collections
Example:
node: collection type: and elements: - node: context context: withdrawalCount operator: equal value: 0 - node: context context: inGroup operator: arrayContain value: - testgroup - testgroup2
Condition Node
Conditional logic with if-then-else structure.
Properties:
if
- Condition node (expects boolean result)then
- Node to execute if condition is trueelse
- Node to execute if condition is false
Built-in Operators
The following operators are available for context nodes:
ArrayContain
- Check if array contains valueArrayNotContain
- Check if array doesn't contain valueEqual
- Equality comparisonGreaterThan
- Greater than comparisonGreaterThanOrEqual
- Greater than or equal comparisonLowerThan
- Less than comparisonLowerThanOrEqual
- Less than or equal comparisonNotEqual
- Not equal comparisonNumericInRange
- Check if number is within rangeStringContain
- Check if string contains substringStringNotContain
- Check if string doesn't contain substring
Modifiers
Modifiers allow you to transform context values using mathematical expressions. Use the predefined $context
variable in your expressions.
For more information about calculations, see: https://github.com/chriskonnertz/string-calc
Advanced Features
Custom Contexts
Create custom context classes by implementing the required interface and register them in the container.
Custom Operators
Extend the system by creating custom operators and adding them to the container.
Caching
Configurations can be serialized and cached for improved performance.
Examples and Testing
For more detailed examples and usage patterns, see the test files in the test/
directory, especially the container configuration examples.
Contributing
Contributions are welcome! Please feel free to submit a Pull Request.
License
This project is licensed under the MIT License - see the LICENSE file for details.