Skip to content

Business Rules System

Jim edited this page Jun 7, 2018 · 20 revisions

The API contains a sub system designed to make it easier to apply consistent api-wide business rules for working with end points. The core concept behind the rules system is to define rules for each Model and allow/deny CRUD operations.

Compared to Validation

Rules should not be confused with validation. Where validation is only concerned with pre-write operations and focuses on fine grained control of end point fields, Rules are primarily concerned with READ operations though they do come into place in a few write situations. Still, Rules do not apply to specific field but rather high level allow/disallow access to entire records or end points.

Additionally, Rules do not enforce proactive business logic. ie. Do some other thing when saving a record. The Business Rules system will only block/allow CRUD operations or filter results sets.

How are Rules stored & accessed?

The API generates a RuleList accessible as a Shared Service in Phalcon.
Consider this example where a RuleStore is added to the RuleList:

// BaseModel->initialize()
// get the shared RuleList and add a RuleStore for this model
$ruleList = $this->getDI()->get('ruleList');
$ruleList->update($this->getModelName(), $this->configureRuleStore(new \PhalconRest\Rules\Store($this)));

A RuleStore is named after it's associated Model and stored in a simple associate array. Note Th intentional coupling between the RuleStore and a particular model. This approach rules out custom end points that are not backed by a traditional Controller->Entity->Model approach. This is because many rules are implemented as specific PHQL or query param rules which are applied to defined models.

When are Rules defined?

Since the RuleList is access as a shared service, it can be loaded just about anywhere in your code. Best practice is to define rules in one place, namely your Models.

How and When are Rules are applied?

  • Allow/Deny Access to an Endpoint entirely
  • Enforce simple and complicated filter rules when an end point is loaded or side loaded
  • Apply rules in Create/Read/Update/Delete actions

Rule Types

Deny Rule

Operate in Controllers to enforce broad deny conditions to an end point or individual records.

Filter Rule

Operation on the SearchHelper using syntax very similar to Query params filters. These are applied to core PHQL queries as are generally perform faster than after-query rules. This filter is designed to use the same syntax as those defined in Example Calls and Advanced Filtering

Query Rule

Operate on QueryBuilder to enforce more complicated PHQL based rules. These are applied to core PHQL queries as are generally perform faster than after-query rules.

Model Callback Rule

This is a special kind of rule which allows the developer to register a closure to be processed later when Add/Edit logic is submitted to the api. This is mainly used for cases where the allow/deny rule depends on the actual data posted in that particular request and thus can't be evaluated right away.

WHEN are Business Rules applied?

Event Deny Filter Query ModelCallback
GET Many ✔️ ✔️ ✔️ N/A
Get 1 N/A
Side Loading ✔️ ✔️ N/A
POST ✔️ N/A N/A
Delete ✔️
PUT/PATCH ✔️

HOW are Business Rules applied?

Event Deny Filter Query
GET Controller->onConstruct Entity->configureSearchHelper Entity->runSearch
Side Loading - Entity->processRelationRules Entity->processRelationRules
POST Controller->onConstruct N/A N/A
Delete Controller->onConstruct
PUT/PATCH Controller->onConstruct N/A N/A

Example Rules

Basic Filter Rule

$ruleStore->addFilterRule('id', '45040', '<');

Related Field Rule

$ruleStore->addFilterRule('invoice_groups:name', 'New Default');
// how bout OR filters?
$this->ruleStore->addFilterRule('invoice_groups:name', 'New Default||Default');

Simple DenyRule
Since these rules can be applied selectively, you can run your own logic and only implement rules under some situations.

// Determine User's Group Membership and Block
if(!$user->hasGroup('MYGROUP'){
$ruleStore->addDenyRule(DELETERULES + CREATERULES);
}

Basic QueryRule

Clone this wiki locally