Skip to content

RuleFlow Plugin Documentation ​

Overview ​

The RuleFlow Plugin is a CakePHP plugin that seamlessly transforms server-side validation rules into client-side JSON Logic validation. It provides automatic form validation without requiring separate client-side validation code, maintaining consistency between server and client validation rules.

What is JSON Logic? ​

JSON Logic is a lightweight rule engine expressed in JSON format. It allows you to write conditional logic and validation rules in a structured, language-independent format that can be evaluated both server-side and client-side.

JSON Logic Examples: ​

json
// Simple comparison: age > 18
{">" : [{"var" : "age"}, 18]}

// Complex logic: name is not empty AND (age > 18 OR hasPermit is true)
{
  "and": [
    {"!=": [{"var": "name"}, ""]},
    {
      "or": [
        {">": [{"var": "age"}, 18]},
        {"var": "hasPermit"}
      ]
    }
  ]
}

CakePHP Rules Transformation ​

The plugin automatically converts CakePHP validation rules to JSON Logic format using the ValidationRuleConverter class.

Supported CakePHP Validation Rules ​

Basic Validation Rules ​

  • notBlank / notEmpty → JSON Logic field presence validation
  • equals / notEquals → Comparison operations (==, !=)
  • greaterThan / lessThan → Numeric comparisons (>, <)
  • greaterThanOrEqual / lessThanOrEqual → Inclusive comparisons (>=, <=)

Field Comparison Rules ​

  • compareFields → Cross-field validation
  • sameAs / notSameAs → Field equality validation

String/Length Rules ​

  • minLength / maxLength → String length validation
  • lengthBetween → String length range validation

List/Array Rules ​

  • inList / notInList → Value inclusion/exclusion validation
  • range / between → Numeric range validation

Collection Rules (Advanced) ​

  • hasAtLeast / hasAtMost → Array element count validation
  • multipleOptions → Multiple selection validation

Transformation Example ​

CakePHP Validator Code:

php
$validator
    ->notBlank('username')
    ->minLength('username', 3)
    ->maxLength('username', 50)
    ->greaterThan('age', 18)
    ->inList('status', ['active', 'inactive']);

Generated JSON Logic:

json
{
  "username": {
    "rules": [
      {
        "rule": {"!=": [{"var": "username"}, ""]},
        "message": "Username cannot be blank"
      },
      {
        "rule": {">=": [{"length": {"var": "username"}}, 3]},
        "message": "Username must be at least 3 characters"
      },
      {
        "rule": {"<=": [{"length": {"var": "username"}}, 50]},
        "message": "Username cannot exceed 50 characters"
      }
    ]
  },
  "age": {
    "rules": [
      {
        "rule": {">": [{"var": "age"}, 18]},
        "message": "Age must be greater than 18"
      }
    ]
  },
  "status": {
    "rules": [
      {
        "rule": {"in": [{"var": "status"}, ["active", "inactive"]]},
        "message": "Status must be either active or inactive"
      }
    ]
  }
}

RuleComponent - Controller Integration ​

The RuleComponent is responsible for extracting validation rules from your table validators and making them available to views.

Usage in Controller ​

php
// Load the component
public function initialize(): void
{
    parent::initialize();
    $this->loadComponent('RuleFlow.Rule');
}

// In your action
public function add()
{
    $article = $this->Articles->newEmptyEntity();

    // Configure validation rules for the form
    $this->Rule->configureFormRules($this->Articles);

    // The rules are now available in the view as $jsonLogic variable
    $this->set(compact('article'));
}

// Using custom validator
public function edit($id = null)
{
    $article = $this->Articles->get($id);

    // Use a specific validator (e.g., 'update' validator)
    $this->Rule->configureFormRules($this->Articles, 'update');

    $this->set(compact('article'));
}

What the Component Does ​

  1. Extracts Validator: Gets the specified validator from your table
  2. Converts Rules: Uses ValidationRuleConverter to transform CakePHP rules to JSON Logic
  3. Sets View Variable: Makes the $jsonLogic variable available in your view templates

FormHelper Integration ​

The plugin provides an enhanced FormHelper that automatically integrates validation rules with forms.

Using the Enhanced FormHelper ​

In your AppView.php:

php
public function initialize(): void
{
    parent::initialize();
    // Replace default FormHelper with RuleFlow FormHelper
    $this->loadHelper('RuleFlow.Form');
}

In your templates:

php
<?= $this->Form->create($article) ?>
<!-- Form will automatically have data-json-logic="#json-logic-rules" attribute -->

<?= $this->Form->control('title') ?>
<?= $this->Form->control('content') ?>
<?= $this->Form->control('status', ['type' => 'select', 'options' => $statusOptions]) ?>

<?= $this->Form->button('Submit') ?>
<?= $this->Form->end() ?>

What the FormHelper Does ​

  1. Automatic Attribute: Adds data-json-logic="#json-logic-rules" to form elements
  2. Rule Embedding: Uses RuleLogicTrait to embed JSON script block in page
  3. Script Generation: Creates <script id="json-logic-rules" type="application/json"> with validation rules

Manual Integration (Without FormHelper) ​

If you prefer not to use the enhanced FormHelper, you can manually integrate validation rules:

Manual Form Attributes ​

php
<?= $this->Form->create($article, ['data-json-logic' => '#json-logic-rules']) ?>
<!-- Your form fields -->
<?= $this->Form->end() ?>

<!-- Manual script block -->
<script id="json-logic-rules" type="application/json">
<?= json_encode($jsonLogic ?? []) ?>
</script>

Individual Field Validation Attributes ​

php
<?= $this->Form->control('username', [
    'validation-rule' => json_encode([
        'type' => 'json-logic',
        'rules' => [
            [
                'rule' => ['!=', [['var' => 'username'], '']],
                'message' => 'Username is required'
            ],
            [
                'rule' => ['>=', [['length' => ['var' => 'username']], 3]],
                'message' => 'Username must be at least 3 characters'
            ]
        ]
    ])
]) ?>

Available Attributes ​

AttributePurposeExample
data-json-logicReferences script element containing all form rules#json-logic-rules
validation-ruleInline validation rules for specific fieldJSON-encoded rule object
data-field-nameOverride field name for validationCustom field identifier

Auto Watch Functionality ​

The Auto Watch system (form-watcher-auto.js) automatically initializes client-side validation for forms without requiring manual setup.

How Auto Watch Works ​

  1. Automatic Detection: Scans page for forms with data-json-logic attributes
  2. Rule Loading: Loads validation rules from referenced script elements
  3. Validator Creation: Creates field validators using JSON Logic evaluation
  4. Event Binding: Automatically binds validation to form field events
  5. Form Submission: Prevents submission if validation fails

Auto Watch Configuration ​

javascript
// Initialize with default options
initializeFormWatcherAuto();

// Initialize with custom options
initializeFormWatcherAuto({
    showValidationSummary: true,        // Show summary of all errors
    summaryAutoRemoveTimeout: 5000,     // Auto-remove summary after 5 seconds
    focusFirstErrorField: true          // Focus first field with error
});

Autoload Configuration ​

The Auto Watch system can be configured to initialize automatically when the page loads, or you can control initialization manually:

Automatic Initialization (Default) ​

javascript
// The system automatically initializes when the page loads
// No additional configuration needed

Manual Initialization Control ​

javascript
// Disable automatic initialization
window.FormWatcherAutoConfig = {
    autoInit: false  // Prevents automatic initialization
};

// Then manually initialize when needed
document.addEventListener('DOMContentLoaded', function() {
    initializeFormWatcherAuto({
        showValidationSummary: true,
        focusFirstErrorField: true
    });
});

Complete Disable ​

javascript
// Completely disable the Auto Watch system
window.FormWatcherAutoConfig = {
    enabled: false  // Disables all Auto Watch functionality
};

Auto Watch Features ​

  • Zero Configuration: Works automatically with enhanced FormHelper
  • Multiple Forms: Handles multiple forms on same page
  • Real-time Validation: Validates fields as user types/changes values
  • Form Submission Prevention: Blocks form submission when validation fails
  • Error Display: Shows validation messages near form fields
  • Validation Summary: Optional summary of all validation errors
  • Configurable Autoload: Control when and how the system initializes

Auto Rules Loader ​

The Auto Rules Loader (ValidationRuleLoader class) handles the loading and parsing of validation rules from various sources.

Rule Sources ​

  1. Data Attributes: Rules embedded in data-json-logic attributes
  2. Script Elements: Rules in <script type="application/json"> elements
  3. Inline Attributes: Rules in validation-rule attributes on form fields

Rule Loading Process ​

javascript
const loader = new ValidationRuleLoader();

// Load rules from form's data-json-logic attribute
const rules = loader.parseAllValidationRules(form);

// Create validator for specific field
const validator = loader.createValidator('username');

// Use validator
const result = validator(inputValue, formData);
if (result !== true) {
    console.log('Validation errors:', result);
}

Rule Loader Features ​

  • Caching: Caches parsed rules for performance
  • Error Handling: Graceful handling of malformed JSON
  • Multiple Sources: Combines rules from different sources
  • Field Mapping: Maps HTML field names to internal validation names

Dynamic Fields Support ​

The Dynamic Form Watcher (form-watcher-dynamic.js) provides advanced support for dynamically added form fields.

Dynamic Field Patterns ​

The system uses pattern matching to apply validation rules to dynamically added fields:

javascript
// Original field: articles.0.title
// Pattern: articles.*.title
// Matches: articles.1.title, articles.2.title, etc.

Dynamic Field Features ​

  1. Pattern Recognition: Automatically detects field naming patterns
  2. Rule Inheritance: New fields inherit validation rules from pattern
  3. Mutation Observer: Watches for DOM changes and new fields
  4. Auto-Validation: Automatically applies validation to new fields

Dynamic Field Example ​

Original Form Field:

html
<input name="items[0][name]" validation-rule='{"type":"json-logic","rules":[...]}'>

Dynamically Added Field:

html
<input name="items[1][name]">
<!-- Automatically inherits validation rules from items[0][name] pattern -->

Using Dynamic Form Watcher ​

javascript
// Initialize dynamic form watcher
const dynamicWatcher = initializeFormWatcherWithDynamic({
    showValidationSummary: true,
    focusFirstErrorField: true
});

// The system automatically:
// 1. Detects existing field patterns
// 2. Watches for new fields
// 3. Applies matching validation rules
// 4. Validates new fields in real-time

Configuration Parameters ​

Global Configuration (FormWatcherAutoConfig) ​

The Auto Watch system can be configured globally using the FormWatcherAutoConfig object:

javascript
window.FormWatcherAutoConfig = {
    // Enable/disable the entire Auto Watch system
    enabled: true,

    // Control automatic initialization on page load
    autoInit: true,

    // Default options for all forms
    showValidationSummary: false,
    summaryAutoRemoveTimeout: 0,
    focusFirstErrorField: true,

    // Custom operations for validation
    customOperations: {
        // Add custom validation functions here
        custom_rule: function(value) {
            return /* validation logic */;
        }
    }
};

Auto Watch Options ​

javascript
const options = {
    // Show validation summary panel
    showValidationSummary: false,

    // Auto-remove validation summary after N milliseconds (0 = no auto-remove)
    summaryAutoRemoveTimeout: 0,

    // Focus first field with validation error
    focusFirstErrorField: true,

    // Custom error display callback
    errorDisplayHandler: function(fieldName, errors) {
        // Custom error display logic
    },

    // Custom form validation callback
    formValidationHandler: function(form, isValid, errors) {
        // Custom form-level validation handling
    }
};

Dynamic Field Options ​

javascript
const dynamicOptions = {
    // All auto watch options plus:

    // Debounce timeout for DOM mutation handling (milliseconds)
    mutationDebounceTimeout: 300,

    // Pattern detection sensitivity
    patternMatchStrict: false,

    // Custom field name conversion
    fieldNameConverter: function(htmlName) {
        return htmlName.replace(/\[(\d+)\]/g, '.$1');
    }
};

Error Messaging and Display ​

Error Message Sources ​

  1. CakePHP Validator Messages: Original validation rule messages
  2. Custom Rule Messages: Override messages in JSON Logic rules
  3. Default Messages: Fallback messages for undefined rules

Error Display Methods ​

Automatic Error Display ​

javascript
// Errors automatically displayed near form fields
// Uses CSS classes: validation-error, field-error, error-message

Custom Error Display ​

javascript
initializeFormWatcherAuto({
    errorDisplayHandler: function(fieldName, errors) {
        // Custom error display implementation
        const field = document.querySelector(`[name="${fieldName}"]`);
        const errorDiv = document.createElement('div');
        errorDiv.className = 'custom-error';
        errorDiv.textContent = Array.isArray(errors) ? errors.join(', ') : errors;
        field.parentNode.appendChild(errorDiv);
    }
});

Error CSS Classes ​

  • .validation-error: Applied to fields with validation errors
  • .field-error: Container for error messages
  • .error-message: Individual error message elements
  • .validation-summary: Validation summary panel
  • .error-list: List of errors in summary

Error Message Customization ​

In CakePHP Validator:

php
$validator
    ->notBlank('username', 'Please enter a username')
    ->minLength('username', 3, 'Username is too short');

In JSON Logic Rules:

json
{
  "rule": {"!=": [{"var": "username"}, ""]},
  "message": "Custom error message for this specific rule"
}

Complete Integration Example ​

1. Controller Setup ​

php
class ArticlesController extends AppController
{
    public function initialize(): void
    {
        parent::initialize();
        $this->loadComponent('RuleFlow.Rule');
    }

    public function add()
    {
        $article = $this->Articles->newEmptyEntity();

        if ($this->request->is('post')) {
            $article = $this->Articles->patchEntity($article, $this->request->getData());
            if ($this->Articles->save($article)) {
                $this->Flash->success('Article saved successfully.');
                return $this->redirect(['action' => 'index']);
            }
            $this->Flash->error('Unable to save article.');
        }

        // Configure client-side validation rules
        $this->Rule->configureFormRules($this->Articles);

        $this->set(compact('article'));
    }
}

2. View Template ​

php
<?= $this->Form->create($article) ?>
    <fieldset>
        <legend><?= __('Add Article') ?></legend>
        <?= $this->Form->control('title') ?>
        <?= $this->Form->control('content', ['type' => 'textarea']) ?>
        <?= $this->Form->control('status', [
            'type' => 'select',
            'options' => ['draft' => 'Draft', 'published' => 'Published']
        ]) ?>
    </fieldset>
<?= $this->Form->button('Submit') ?>
<?= $this->Form->end() ?>

<!-- Include validation JavaScript -->
<?= $this->Html->script('RuleFlow.validate/json-logic') ?>
<?= $this->Html->script('RuleFlow.validate/form-watcher') ?>
<?= $this->Html->script('RuleFlow.validate/form-watcher-auto') ?>

<script>
document.addEventListener('DOMContentLoaded', function() {
    initializeFormWatcherAuto({
        showValidationSummary: true,
        focusFirstErrorField: true
    });
});
</script>

3. Table Validation Rules ​

php
class ArticlesTable extends Table
{
    public function validationDefault(Validator $validator): Validator
    {
        $validator
            ->notBlank('title', 'Title is required')
            ->maxLength('title', 255, 'Title cannot exceed 255 characters')
            ->notEmpty('content', 'Content cannot be empty')
            ->inList('status', ['draft', 'published'], 'Invalid status');

        return $validator;
    }
}

This setup provides complete server-to-client validation rule transformation with automatic form validation, error display, and user feedback.

Released under the MIT License.