{"id":20601168,"url":"https://github.com/cleverage/ruler","last_synced_at":"2025-07-13T09:34:03.279Z","repository":{"id":5098055,"uuid":"6261068","full_name":"cleverage/Ruler","owner":"cleverage","description":null,"archived":false,"fork":false,"pushed_at":"2013-10-30T20:41:32.000Z","size":133,"stargazers_count":22,"open_issues_count":0,"forks_count":1,"subscribers_count":60,"default_branch":"master","last_synced_at":"2025-04-13T11:05:43.515Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"PHP","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":"timothyf/mashup_server","license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/cleverage.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2012-10-17T12:43:34.000Z","updated_at":"2020-01-28T16:24:26.000Z","dependencies_parsed_at":"2022-07-04T19:30:49.729Z","dependency_job_id":null,"html_url":"https://github.com/cleverage/Ruler","commit_stats":null,"previous_names":[],"tags_count":1,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cleverage%2FRuler","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cleverage%2FRuler/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cleverage%2FRuler/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cleverage%2FRuler/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/cleverage","download_url":"https://codeload.github.com/cleverage/Ruler/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248989833,"owners_count":21194649,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-11-16T09:08:54.025Z","updated_at":"2025-04-15T01:35:39.930Z","avatar_url":"https://github.com/cleverage.png","language":"PHP","funding_links":[],"categories":[],"sub_categories":[],"readme":"[![Build Status](https://travis-ci.org/cleverage/Ruler.png)](https://travis-ci.org/cleverage/Ruler)\n\nRuler\n=====\n\ncleverage/Ruler is a PHP 5.3 Library. Use it to implement your own business rules, and link them in order to check if you are satisfying the set.\n\nExemple :\n\nYou want to check if the current user can activate a feature. For this, you have to check that :\n- he is connected,\n- he has the premium suscription,\n- he has enough money in his account.\n\n```php\n\u003c?php // test\n\n// PHP 5.3\n$rule = new IsConnectedRule($user);\n$rule-\u003eandRule(new IsSuscriberRule($user, 'PREMIUM'))\n     -\u003eandRule(new HasMoneyRule($user, 300))\n     -\u003eorRule(new IsAdminRule($user));\n\n// PHP 5.4\n$rule = (new IsConnectedRule($user))\n  -\u003eandRule(new IsSuscriberRule($user, 'PREMIUM'))\n  -\u003eandRule(new HasMoneyRule($user, 300))\n  -\u003eorRule(new IsAdminRule($user));\n\ntry {\n    if ($rule-\u003eisSatisfied()) {\n      echo 'activated';\n    }\n} catch (NotConnectedException $e) {\n    // show connection form\n} catch (NotSuscriberException $e) {\n    // show subscription form\n} catch (NotEnoughMoneyException $e) {\n    echo 'not enough Money';\n} catch(\\CleverAge\\Ruler\\Exception\\Exception $e) {\n    echo 'Failed : '.$e-\u003egetMessage();\n}\n```\n\n```php\n\u003c?php // IsConnectedRule class\nclass IsConnectedRule extends \\CleverAge\\Ruler\\RuleAbstract\n{\n    protected $_user;\n\n    protected $_failure_exception_class = 'NotConnectedException';\n    protected $_failure_message = 'user is not connected';\n\n    public function __construct(\\User $user)\n    {\n        $this-\u003e_user = $user;\n    }\n\n    public function doIsSatisfied()\n    {\n        return $this-\u003e_user-\u003eisLoggedOn();\n    }\n}\n```\n\nCombination of rules can even be done in a single rule class, in order to simplify your application code and increase maintability.\n\n```php\n// ActiveFeatureXRule class\nclass ActiveFeatureXRule extends \\CleverAge\\Ruler\\RuleAbstract\n{\n    public function __construct(\\User $user)\n    {\n        $this-\u003eandRule(new IsSuscriberRule($user, 'PREMIUM'))\n             -\u003eandRule(new HasMoneyRule($user, 300))\n             -\u003eorRule(new IsAdminRule($user));\n    }\n\n    public function doIsSatisfied()\n    {\n        // method is abstract, and this container rule always satisfies.\n        return true;\n    }\n}\n```\n\nNow, you can use this rule class everywhere you need it, and just change the construct to have th rules reverberated everewhere.\n\n## How logic is handled\n\nThe order in which you set OR/AND/NAND rules is not important. At the end, they are grouped by type.\n\n1) You want your ruleset satisfied :\n\n```php\n// A,B,C,D,G,Z are rules\n$A-\u003eandRule($B)\n  -\u003eorRule($C-\u003eandRule($Z))\n  -\u003eandRule($D)\n  -\u003enandRule($G)\n  -\u003eisSatisfied();\n\n// PHP =\u003e($A \u0026\u0026 $B \u0026\u0026 $D \u0026\u0026 !$G) || ($C \u0026\u0026 $Z)\n// Binary =\u003e (A.B.D.!G)+(C.Z)\n```\n\n2) You want your ruleset not satisfied :\n\n```php\n// A,B,C,D,G,Z are rules\n$A-\u003eandRule($B)\n  -\u003eorRule($C-\u003eandRule($Z))\n  -\u003eandRule($D)\n  -\u003enandRule($G)\n  -\u003eisNotSatisfied()\n\n// PHP =\u003e (!$A || !$B || !$D || $G) \u0026\u0026 (!$C || !$Z)\n// Binary =\u003e (!A+!B+!D+G).(!C+!Z)\n```\n\nby default, isNotSatisfied() returns !isSatisfied(). But sometimes, you may want to personnalize the doIsNotSatisfied() method in order to optimize workflow (like SQL queries).\n\n## Customization\n\n### Setting Exception class and message error\n\nIf you have one generic rule (e.g. : ObjectIsEqual), you may need to have different exception thrown when composing complex rules.\nEach Rule has a setter for this :\n\n```php\n$A = new MyRule();\n$A-\u003esetException('My\\Name\\Space\\Ruler\\Exceptions\\MyException', 'my custom error message');\n\n$A-\u003eisSatisfied();\n\n// If rule is not satisfied\n// it throws a new My\\Name\\Space\\Ruler\\Exceptions\\MyException('my custom error message') exception\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcleverage%2Fruler","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fcleverage%2Fruler","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcleverage%2Fruler/lists"}