Repository files navigation

SvarohJsFormValidatorBundle

CITotal Downloads

SvarohJsFormValidatorBundle converts Symfony form validation metadata into JavaScript validation rules and attaches client-side validators to rendered forms.

Status

This branch targets the current PHP/Symfony baseline:

  • PHP 8.4+ runtime support; CI currently verifies PHP 8.4, 8.5, and 8.6 nightly
  • Symfony 8.x components as declared in composer.json
  • Twig 3
  • PHPUnit 13
  • PHPStan static analysis
  • PHP and JavaScript coverage thresholds
  • PSR-4 autoloading from src/

For older Symfony applications, use the historical branches of formapro/JsFormValidatorBundle:

Installation

Install the bundle with Composer:

composer require svaroh/jsformvalidator-bundle

If you are testing before the first tagged release, require the development branch explicitly:

composer require svaroh/jsformvalidator-bundle:"dev-main"

Register the bundle in config/bundles.php:

<?phpreturn [
// ...Svaroh\JsFormValidatorBundle\SvarohJsFormValidatorBundle::class => ['all' => true],
];

Configuration

Validation is enabled for every form by default. You can disable it globally:

# config/packages/svaroh_js_form_validator.yamlsvaroh_js_form_validator:
js_validation: false

Per-form and per-field disabling is documented in Disabling validation.

The browser validates a form on its own before this bundle sees the submit. You can opt into letting the bundle own that reporting:

# config/packages/svaroh_js_form_validator.yamlsvaroh_js_form_validator:
html5_validation: true

See HTML5 validation for what that changes.

UniqueEntity Route

If you use Symfony's Doctrine UniqueEntity constraint, import the bundle route:

# config/routes/svaroh_js_form_validator.yamlsvaroh_js_form_validator:
resource: '@SvarohJsFormValidatorBundle/Resources/config/routing.yaml'prefix: /svaroh_js_form_validator

Make sure your security configuration allows requests to this route.

The endpoint answers whether a matching record exists, but only for a field combination that a UniqueEntity constraint on the named entity class actually declares; the repository method comes from that constraint too. Everything else is refused. For the combinations you did declare unique it is still a public, unthrottled existence check, so restrict it in your firewall when that answer is sensitive, or point svaroh_js_form_validator.routing.check_unique_entity at your own controller as described in Checking entity uniqueness.

JavaScript Assets

There are two common ways to load the JavaScript files.

Add an Encore Entry

Encore
// ...
.addEntry('app', './assets/js/app.js')
+ .addEntry(+ 'SvarohJsFormValidator',+ './vendor/svaroh/jsformvalidator-bundle/src/Resources/public/js/SvarohJsFormValidatorWithJqueryInit.js'+ )
// ...
;

Then include the entry in your template:

{{ encore_entry_script_tags('SvarohJsFormValidator') }}
{{ encore_entry_script_tags('app') }}

Import From Your Main JavaScript

 import $ from 'jquery';
+import '../vendor/svaroh/jsformvalidator-bundle/src/Resources/public/js/SvarohJsFormValidator';+import '../vendor/svaroh/jsformvalidator-bundle/src/Resources/public/js/jquery.svarohjsformvalidator';

Adjust the import path to your application structure.

JavaScript Namespace

The library registers its constraints and its view transformers in a single global object named after the Svaroh\JsFormValidatorBundle PHP namespace:

Svaroh.constraints// constraints, keyed by class name without the separatorsSvaroh.transformers// view transformers, keyed the same way

Register your own classes there, as shown in custom constraints and custom data transformers. The object is created by the library, so run your registrations after its script is loaded.

Every bundled constraint and transformer is still exported under its own global name, such as window.SymfonyComponentValidatorConstraintsNotBlank, and a class your application defines as a global is still picked up. Both are deprecated and will be dropped in a future release.

Render Bundle Config And Form Models

After the scripts are loaded, render the generated config and queued form models:

{{ js_validator_config() }}
{{ init_js_validation() }}

If you need manual initialization for a specific form or event, see manual initialization.

Usage

After the bundle is registered, the form extension adds every enabled root form to an internal queue. Calling init_js_validation() renders JavaScript models for the queued forms:

{{ form_start(form) }}
{{ form_widget(form) }}
{{ form_end(form) }}
{{ init_js_validation(form) }}

You can pass false as the second argument to avoid automatic initialization on page load:

{{ init_js_validation(form, false) }}

Documentation

  1. Disabling validation
  2. Forms in sub-requests
  3. Manual initialization

Customization

This bundle finds related DOM elements for each Symfony form element and attaches an object validator to them. The validator contains the properties and methods that define the validation process for that form element.

If your form rendering is customized, start with custom rendering notes.

  1. Disable validation for a specified field
  2. Error display
  3. Get validation groups from a closure
  4. Getters validation
  5. The Callback constraint
  6. The Choice constraint callback
  7. Custom constraints
  8. Custom data transformers
  9. Checking entity uniqueness
  10. Form submit by JavaScript
  11. onValidate callback
  12. Run validation on custom event
  13. Collections validation
  14. Localized numbers
  15. HTML5 validation
  16. The NotBlank constraint
  17. Comparing a field with another field
  18. The Range constraint on dates
  19. Repeated fields
  20. One form rendered several times
  21. Validation events
  22. File uploads
  23. Pluralized messages

Development

The recommended development environment is the Nix shell:

nix develop

It provides the latest PHP available in the pinned nixpkgs input, currently PHP 8.5, with Xdebug coverage support, Composer, Node.js 24, npm, zip/unzip, and Cypress runtime libraries. If flakes are not enabled globally, prefix Nix commands with nix --extra-experimental-features "nix-command flakes".

For a fresh checkout:

composer update
npm install

If Cypress reports a missing binary, install it into the local cache:

npx cypress install

You can also run commands without entering the shell:

nix develop -c composer test
nix develop -c npm test

Without Nix, install PHP 8.4 or newer, Composer, Node.js 24, npm, and the Cypress system dependencies locally before running the same commands.

To install vendors via Docker instead of host PHP/Composer:

docker compose build php-fpm
docker compose run --rm --no-deps -u "$(id -u):$(id -g)" php-fpm composer update
docker compose run --rm --no-deps -u "$(id -u):$(id -g)" php-fpm npm install

Install or refresh Composer dependencies:

composer update

Run the PHP test suite:

composer test

Run PHPStan static analysis:

composer phpstan

Run PHP coverage:

composer coverage

Run the JavaScript unit tests and Cypress browser smoke test:

npm test

Run JavaScript coverage:

npm run test:coverage

Useful local checks:

composer validate --strict
git diff --check

The same maintained test, static-analysis, and coverage checks are also run by GitHub Actions on pushes and pull requests. Coverage runs generate Cobertura reports and upload them to GitHub Code Quality when workflow permissions allow.

The Docker stack uses PHP 8.5, Composer 2, and Node.js 24. It is maintained for dependency installation and ad hoc local commands; Nix remains the preferred environment for exact local parity with the documented checks.

About

The JavaScript validation for Symfony forms

Resources

Contributing

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Add copy buttons to all
 blocks\n(function() {\n function addCopyButtons() {\n document.querySelectorAll('pre code').forEach(function(codeBlock) {\n if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;\n codeBlock.parentElement.setAttribute('data-copy-added', 'true');\n \n var btn = document.createElement('button');\n btn.textContent = 'Copy';\n btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';\n btn.onmouseover = function() { this.style.opacity = '1'; };\n btn.onmouseout = function() { this.style.opacity = '0.7'; };\n btn.onclick = function() {\n navigator.clipboard.writeText(codeBlock.textContent).then(function() {\n btn.textContent = 'Copied!';\n setTimeout(function() { btn.textContent = 'Copy'; }, 1500);\n });\n };\n codeBlock.parentElement.style.position = 'relative';\n codeBlock.parentElement.appendChild(btn);\n });\n }\n \n addCopyButtons();\n \n // Re-run on dynamic content\n var observer = new MutationObserver(addCopyButtons);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Add Copy Buttons to Code Blocks");
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
Skip to content

Repository files navigation

SvarohJsFormValidatorBundle

CITotal Downloads

SvarohJsFormValidatorBundle converts Symfony form validation metadata into JavaScript validation rules and attaches client-side validators to rendered forms.

Status

This branch targets the current PHP/Symfony baseline:

  • PHP 8.4+ runtime support; CI currently verifies PHP 8.4, 8.5, and 8.6 nightly
  • Symfony 8.x components as declared in composer.json
  • Twig 3
  • PHPUnit 13
  • PHPStan static analysis
  • PHP and JavaScript coverage thresholds
  • PSR-4 autoloading from src/

For older Symfony applications, use the historical branches of formapro/JsFormValidatorBundle:

Installation

Install the bundle with Composer:

composer require svaroh/jsformvalidator-bundle

If you are testing before the first tagged release, require the development branch explicitly:

composer require svaroh/jsformvalidator-bundle:"dev-main"

Register the bundle in config/bundles.php:

<?phpreturn [
// ...Svaroh\JsFormValidatorBundle\SvarohJsFormValidatorBundle::class => ['all' => true],
];

Configuration

Validation is enabled for every form by default. You can disable it globally:

# config/packages/svaroh_js_form_validator.yamlsvaroh_js_form_validator:
js_validation: false

Per-form and per-field disabling is documented in Disabling validation.

The browser validates a form on its own before this bundle sees the submit. You can opt into letting the bundle own that reporting:

# config/packages/svaroh_js_form_validator.yamlsvaroh_js_form_validator:
html5_validation: true

See HTML5 validation for what that changes.

UniqueEntity Route

If you use Symfony's Doctrine UniqueEntity constraint, import the bundle route:

# config/routes/svaroh_js_form_validator.yamlsvaroh_js_form_validator:
resource: '@SvarohJsFormValidatorBundle/Resources/config/routing.yaml'prefix: /svaroh_js_form_validator

Make sure your security configuration allows requests to this route.

The endpoint answers whether a matching record exists, but only for a field combination that a UniqueEntity constraint on the named entity class actually declares; the repository method comes from that constraint too. Everything else is refused. For the combinations you did declare unique it is still a public, unthrottled existence check, so restrict it in your firewall when that answer is sensitive, or point svaroh_js_form_validator.routing.check_unique_entity at your own controller as described in Checking entity uniqueness.

JavaScript Assets

There are two common ways to load the JavaScript files.

Add an Encore Entry

Encore
// ...
.addEntry('app', './assets/js/app.js')
+ .addEntry(+ 'SvarohJsFormValidator',+ './vendor/svaroh/jsformvalidator-bundle/src/Resources/public/js/SvarohJsFormValidatorWithJqueryInit.js'+ )
// ...
;

Then include the entry in your template:

{{ encore_entry_script_tags('SvarohJsFormValidator') }}
{{ encore_entry_script_tags('app') }}

Import From Your Main JavaScript

 import $ from 'jquery';
+import '../vendor/svaroh/jsformvalidator-bundle/src/Resources/public/js/SvarohJsFormValidator';+import '../vendor/svaroh/jsformvalidator-bundle/src/Resources/public/js/jquery.svarohjsformvalidator';

Adjust the import path to your application structure.

JavaScript Namespace

The library registers its constraints and its view transformers in a single global object named after the Svaroh\JsFormValidatorBundle PHP namespace:

Svaroh.constraints// constraints, keyed by class name without the separatorsSvaroh.transformers// view transformers, keyed the same way

Register your own classes there, as shown in custom constraints and custom data transformers. The object is created by the library, so run your registrations after its script is loaded.

Every bundled constraint and transformer is still exported under its own global name, such as window.SymfonyComponentValidatorConstraintsNotBlank, and a class your application defines as a global is still picked up. Both are deprecated and will be dropped in a future release.

Render Bundle Config And Form Models

After the scripts are loaded, render the generated config and queued form models:

{{ js_validator_config() }}
{{ init_js_validation() }}

If you need manual initialization for a specific form or event, see manual initialization.

Usage

After the bundle is registered, the form extension adds every enabled root form to an internal queue. Calling init_js_validation() renders JavaScript models for the queued forms:

{{ form_start(form) }}
{{ form_widget(form) }}
{{ form_end(form) }}
{{ init_js_validation(form) }}

You can pass false as the second argument to avoid automatic initialization on page load:

{{ init_js_validation(form, false) }}

Documentation

  1. Disabling validation
  2. Forms in sub-requests
  3. Manual initialization

Customization

This bundle finds related DOM elements for each Symfony form element and attaches an object validator to them. The validator contains the properties and methods that define the validation process for that form element.

If your form rendering is customized, start with custom rendering notes.

  1. Disable validation for a specified field
  2. Error display
  3. Get validation groups from a closure
  4. Getters validation
  5. The Callback constraint
  6. The Choice constraint callback
  7. Custom constraints
  8. Custom data transformers
  9. Checking entity uniqueness
  10. Form submit by JavaScript
  11. onValidate callback
  12. Run validation on custom event
  13. Collections validation
  14. Localized numbers
  15. HTML5 validation
  16. The NotBlank constraint
  17. Comparing a field with another field
  18. The Range constraint on dates
  19. Repeated fields
  20. One form rendered several times
  21. Validation events
  22. File uploads
  23. Pluralized messages

Development

The recommended development environment is the Nix shell:

nix develop

It provides the latest PHP available in the pinned nixpkgs input, currently PHP 8.5, with Xdebug coverage support, Composer, Node.js 24, npm, zip/unzip, and Cypress runtime libraries. If flakes are not enabled globally, prefix Nix commands with nix --extra-experimental-features "nix-command flakes".

For a fresh checkout:

composer update
npm install

If Cypress reports a missing binary, install it into the local cache:

npx cypress install

You can also run commands without entering the shell:

nix develop -c composer test
nix develop -c npm test

Without Nix, install PHP 8.4 or newer, Composer, Node.js 24, npm, and the Cypress system dependencies locally before running the same commands.

To install vendors via Docker instead of host PHP/Composer:

docker compose build php-fpm
docker compose run --rm --no-deps -u "$(id -u):$(id -g)" php-fpm composer update
docker compose run --rm --no-deps -u "$(id -u):$(id -g)" php-fpm npm install

Install or refresh Composer dependencies:

composer update

Run the PHP test suite:

composer test

Run PHPStan static analysis:

composer phpstan

Run PHP coverage:

composer coverage

Run the JavaScript unit tests and Cypress browser smoke test:

npm test

Run JavaScript coverage:

npm run test:coverage

Useful local checks:

composer validate --strict
git diff --check

The same maintained test, static-analysis, and coverage checks are also run by GitHub Actions on pushes and pull requests. Coverage runs generate Cobertura reports and upload them to GitHub Code Quality when workflow permissions allow.

The Docker stack uses PHP 8.5, Composer 2, and Node.js 24. It is maintained for dependency installation and ad hoc local commands; Nix remains the preferred environment for exact local parity with the documented checks.

About

The JavaScript validation for Symfony forms

Resources

Contributing

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Force GitHub README to respect dark mode\n(function() {\n var style = document.createElement('style');\n style.textContent = '\n .markdown-body {\n color-scheme: dark light;\n }\n .markdown-body pre { background: #161b22 !important; }\n .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; }\n .markdown-body table th, .markdown-body table td { border-color: #30363d !important; }\n .markdown-body img { background: #0d1117; }\n .markdown-body blockquote { border-left-color: #8b949e; }\n .markdown-body hr { border-color: #30363d; }\n ';\n document.head.appendChild(style);\n})();", "GitHub Dark Mode README Fix"); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Repository files navigation

SvarohJsFormValidatorBundle

CITotal Downloads

SvarohJsFormValidatorBundle converts Symfony form validation metadata into JavaScript validation rules and attaches client-side validators to rendered forms.

Status

This branch targets the current PHP/Symfony baseline:

  • PHP 8.4+ runtime support; CI currently verifies PHP 8.4, 8.5, and 8.6 nightly
  • Symfony 8.x components as declared in composer.json
  • Twig 3
  • PHPUnit 13
  • PHPStan static analysis
  • PHP and JavaScript coverage thresholds
  • PSR-4 autoloading from src/

For older Symfony applications, use the historical branches of formapro/JsFormValidatorBundle:

Installation

Install the bundle with Composer:

composer require svaroh/jsformvalidator-bundle

If you are testing before the first tagged release, require the development branch explicitly:

composer require svaroh/jsformvalidator-bundle:"dev-main"

Register the bundle in config/bundles.php:

<?phpreturn [
// ...Svaroh\JsFormValidatorBundle\SvarohJsFormValidatorBundle::class => ['all' => true],
];

Configuration

Validation is enabled for every form by default. You can disable it globally:

# config/packages/svaroh_js_form_validator.yamlsvaroh_js_form_validator:
js_validation: false

Per-form and per-field disabling is documented in Disabling validation.

The browser validates a form on its own before this bundle sees the submit. You can opt into letting the bundle own that reporting:

# config/packages/svaroh_js_form_validator.yamlsvaroh_js_form_validator:
html5_validation: true

See HTML5 validation for what that changes.

UniqueEntity Route

If you use Symfony's Doctrine UniqueEntity constraint, import the bundle route:

# config/routes/svaroh_js_form_validator.yamlsvaroh_js_form_validator:
resource: '@SvarohJsFormValidatorBundle/Resources/config/routing.yaml'prefix: /svaroh_js_form_validator

Make sure your security configuration allows requests to this route.

The endpoint answers whether a matching record exists, but only for a field combination that a UniqueEntity constraint on the named entity class actually declares; the repository method comes from that constraint too. Everything else is refused. For the combinations you did declare unique it is still a public, unthrottled existence check, so restrict it in your firewall when that answer is sensitive, or point svaroh_js_form_validator.routing.check_unique_entity at your own controller as described in Checking entity uniqueness.

JavaScript Assets

There are two common ways to load the JavaScript files.

Add an Encore Entry

Encore
// ...
.addEntry('app', './assets/js/app.js')
+ .addEntry(+ 'SvarohJsFormValidator',+ './vendor/svaroh/jsformvalidator-bundle/src/Resources/public/js/SvarohJsFormValidatorWithJqueryInit.js'+ )
// ...
;

Then include the entry in your template:

{{ encore_entry_script_tags('SvarohJsFormValidator') }}
{{ encore_entry_script_tags('app') }}

Import From Your Main JavaScript

 import $ from 'jquery';
+import '../vendor/svaroh/jsformvalidator-bundle/src/Resources/public/js/SvarohJsFormValidator';+import '../vendor/svaroh/jsformvalidator-bundle/src/Resources/public/js/jquery.svarohjsformvalidator';

Adjust the import path to your application structure.

JavaScript Namespace

The library registers its constraints and its view transformers in a single global object named after the Svaroh\JsFormValidatorBundle PHP namespace:

Svaroh.constraints// constraints, keyed by class name without the separatorsSvaroh.transformers// view transformers, keyed the same way

Register your own classes there, as shown in custom constraints and custom data transformers. The object is created by the library, so run your registrations after its script is loaded.

Every bundled constraint and transformer is still exported under its own global name, such as window.SymfonyComponentValidatorConstraintsNotBlank, and a class your application defines as a global is still picked up. Both are deprecated and will be dropped in a future release.

Render Bundle Config And Form Models

After the scripts are loaded, render the generated config and queued form models:

{{ js_validator_config() }}
{{ init_js_validation() }}

If you need manual initialization for a specific form or event, see manual initialization.

Usage

After the bundle is registered, the form extension adds every enabled root form to an internal queue. Calling init_js_validation() renders JavaScript models for the queued forms:

{{ form_start(form) }}
{{ form_widget(form) }}
{{ form_end(form) }}
{{ init_js_validation(form) }}

You can pass false as the second argument to avoid automatic initialization on page load:

{{ init_js_validation(form, false) }}

Documentation

  1. Disabling validation
  2. Forms in sub-requests
  3. Manual initialization

Customization

This bundle finds related DOM elements for each Symfony form element and attaches an object validator to them. The validator contains the properties and methods that define the validation process for that form element.

If your form rendering is customized, start with custom rendering notes.

  1. Disable validation for a specified field
  2. Error display
  3. Get validation groups from a closure
  4. Getters validation
  5. The Callback constraint
  6. The Choice constraint callback
  7. Custom constraints
  8. Custom data transformers
  9. Checking entity uniqueness
  10. Form submit by JavaScript
  11. onValidate callback
  12. Run validation on custom event
  13. Collections validation
  14. Localized numbers
  15. HTML5 validation
  16. The NotBlank constraint
  17. Comparing a field with another field
  18. The Range constraint on dates
  19. Repeated fields
  20. One form rendered several times
  21. Validation events
  22. File uploads
  23. Pluralized messages

Development

The recommended development environment is the Nix shell:

nix develop

It provides the latest PHP available in the pinned nixpkgs input, currently PHP 8.5, with Xdebug coverage support, Composer, Node.js 24, npm, zip/unzip, and Cypress runtime libraries. If flakes are not enabled globally, prefix Nix commands with nix --extra-experimental-features "nix-command flakes".

For a fresh checkout:

composer update
npm install

If Cypress reports a missing binary, install it into the local cache:

npx cypress install

You can also run commands without entering the shell:

nix develop -c composer test
nix develop -c npm test

Without Nix, install PHP 8.4 or newer, Composer, Node.js 24, npm, and the Cypress system dependencies locally before running the same commands.

To install vendors via Docker instead of host PHP/Composer:

docker compose build php-fpm
docker compose run --rm --no-deps -u "$(id -u):$(id -g)" php-fpm composer update
docker compose run --rm --no-deps -u "$(id -u):$(id -g)" php-fpm npm install

Install or refresh Composer dependencies:

composer update

Run the PHP test suite:

composer test

Run PHPStan static analysis:

composer phpstan

Run PHP coverage:

composer coverage

Run the JavaScript unit tests and Cypress browser smoke test:

npm test

Run JavaScript coverage:

npm run test:coverage

Useful local checks:

composer validate --strict
git diff --check

The same maintained test, static-analysis, and coverage checks are also run by GitHub Actions on pushes and pull requests. Coverage runs generate Cobertura reports and upload them to GitHub Code Quality when workflow permissions allow.

The Docker stack uses PHP 8.5, Composer 2, and Node.js 24. It is maintained for dependency installation and ad hoc local commands; Nix remains the preferred environment for exact local parity with the documented checks.

About

The JavaScript validation for Symfony forms

Resources

Contributing

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Highlight search terms from Google/DuckDuckGo/Bing referrer\n(function() {\n var ref = document.referrer;\n var terms = [];\n \n if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) {\n var url = new URL(ref);\n var q = url.searchParams.get('q') || url.searchParams.get('p');\n if (q) {\n terms = q.split(/\\s+/).filter(function(t) { return t.length > 2; });\n }\n }\n \n if (terms.length === 0) return;\n \n var style = document.createElement('style');\n style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }';\n document.head.appendChild(style);\n \n function highlight(node) {\n if (node.nodeType === 3) { // text node\n var text = node.textContent;\n var found = false;\n terms.forEach(function(term) {\n var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\') + ')', 'gi');\n if (regex.test(text)) {\n found = true;\n var frag = document.createDocumentFragment();\n var parts = text.split(regex);\n parts.forEach(function(part, i) {\n if (i % 2 === 0) {\n frag.appendChild(document.createTextNode(part));\n } else {\n var span = document.createElement('span');\n span.className = 'userscript-highlight';\n span.textContent = part;\n frag.appendChild(span);\n }\n });\n node.parentNode.replaceChild(frag, node);\n }\n });\n } else if (node.nodeType === 1 && node.childNodes) { // element\n var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT'];\n if (!skipTags.includes(node.tagName)) {\n Array.from(node.childNodes).forEach(highlight);\n }\n }\n }\n \n highlight(document.body);\n \n // Re-highlight on dynamic content\n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1 || node.nodeType === 3) highlight(node);\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Highlight Search Terms"); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Repository files navigation

SvarohJsFormValidatorBundle

CITotal Downloads

SvarohJsFormValidatorBundle converts Symfony form validation metadata into JavaScript validation rules and attaches client-side validators to rendered forms.

Status

This branch targets the current PHP/Symfony baseline:

  • PHP 8.4+ runtime support; CI currently verifies PHP 8.4, 8.5, and 8.6 nightly
  • Symfony 8.x components as declared in composer.json
  • Twig 3
  • PHPUnit 13
  • PHPStan static analysis
  • PHP and JavaScript coverage thresholds
  • PSR-4 autoloading from src/

For older Symfony applications, use the historical branches of formapro/JsFormValidatorBundle:

Installation

Install the bundle with Composer:

composer require svaroh/jsformvalidator-bundle

If you are testing before the first tagged release, require the development branch explicitly:

composer require svaroh/jsformvalidator-bundle:"dev-main"

Register the bundle in config/bundles.php:

<?phpreturn [
// ...Svaroh\JsFormValidatorBundle\SvarohJsFormValidatorBundle::class => ['all' => true],
];

Configuration

Validation is enabled for every form by default. You can disable it globally:

# config/packages/svaroh_js_form_validator.yamlsvaroh_js_form_validator:
js_validation: false

Per-form and per-field disabling is documented in Disabling validation.

The browser validates a form on its own before this bundle sees the submit. You can opt into letting the bundle own that reporting:

# config/packages/svaroh_js_form_validator.yamlsvaroh_js_form_validator:
html5_validation: true

See HTML5 validation for what that changes.

UniqueEntity Route

If you use Symfony's Doctrine UniqueEntity constraint, import the bundle route:

# config/routes/svaroh_js_form_validator.yamlsvaroh_js_form_validator:
resource: '@SvarohJsFormValidatorBundle/Resources/config/routing.yaml'prefix: /svaroh_js_form_validator

Make sure your security configuration allows requests to this route.

The endpoint answers whether a matching record exists, but only for a field combination that a UniqueEntity constraint on the named entity class actually declares; the repository method comes from that constraint too. Everything else is refused. For the combinations you did declare unique it is still a public, unthrottled existence check, so restrict it in your firewall when that answer is sensitive, or point svaroh_js_form_validator.routing.check_unique_entity at your own controller as described in Checking entity uniqueness.

JavaScript Assets

There are two common ways to load the JavaScript files.

Add an Encore Entry

Encore
// ...
.addEntry('app', './assets/js/app.js')
+ .addEntry(+ 'SvarohJsFormValidator',+ './vendor/svaroh/jsformvalidator-bundle/src/Resources/public/js/SvarohJsFormValidatorWithJqueryInit.js'+ )
// ...
;

Then include the entry in your template:

{{ encore_entry_script_tags('SvarohJsFormValidator') }}
{{ encore_entry_script_tags('app') }}

Import From Your Main JavaScript

 import $ from 'jquery';
+import '../vendor/svaroh/jsformvalidator-bundle/src/Resources/public/js/SvarohJsFormValidator';+import '../vendor/svaroh/jsformvalidator-bundle/src/Resources/public/js/jquery.svarohjsformvalidator';

Adjust the import path to your application structure.

JavaScript Namespace

The library registers its constraints and its view transformers in a single global object named after the Svaroh\JsFormValidatorBundle PHP namespace:

Svaroh.constraints// constraints, keyed by class name without the separatorsSvaroh.transformers// view transformers, keyed the same way

Register your own classes there, as shown in custom constraints and custom data transformers. The object is created by the library, so run your registrations after its script is loaded.

Every bundled constraint and transformer is still exported under its own global name, such as window.SymfonyComponentValidatorConstraintsNotBlank, and a class your application defines as a global is still picked up. Both are deprecated and will be dropped in a future release.

Render Bundle Config And Form Models

After the scripts are loaded, render the generated config and queued form models:

{{ js_validator_config() }}
{{ init_js_validation() }}

If you need manual initialization for a specific form or event, see manual initialization.

Usage

After the bundle is registered, the form extension adds every enabled root form to an internal queue. Calling init_js_validation() renders JavaScript models for the queued forms:

{{ form_start(form) }}
{{ form_widget(form) }}
{{ form_end(form) }}
{{ init_js_validation(form) }}

You can pass false as the second argument to avoid automatic initialization on page load:

{{ init_js_validation(form, false) }}

Documentation

  1. Disabling validation
  2. Forms in sub-requests
  3. Manual initialization

Customization

This bundle finds related DOM elements for each Symfony form element and attaches an object validator to them. The validator contains the properties and methods that define the validation process for that form element.

If your form rendering is customized, start with custom rendering notes.

  1. Disable validation for a specified field
  2. Error display
  3. Get validation groups from a closure
  4. Getters validation
  5. The Callback constraint
  6. The Choice constraint callback
  7. Custom constraints
  8. Custom data transformers
  9. Checking entity uniqueness
  10. Form submit by JavaScript
  11. onValidate callback
  12. Run validation on custom event
  13. Collections validation
  14. Localized numbers
  15. HTML5 validation
  16. The NotBlank constraint
  17. Comparing a field with another field
  18. The Range constraint on dates
  19. Repeated fields
  20. One form rendered several times
  21. Validation events
  22. File uploads
  23. Pluralized messages

Development

The recommended development environment is the Nix shell:

nix develop

It provides the latest PHP available in the pinned nixpkgs input, currently PHP 8.5, with Xdebug coverage support, Composer, Node.js 24, npm, zip/unzip, and Cypress runtime libraries. If flakes are not enabled globally, prefix Nix commands with nix --extra-experimental-features "nix-command flakes".

For a fresh checkout:

composer update
npm install

If Cypress reports a missing binary, install it into the local cache:

npx cypress install

You can also run commands without entering the shell:

nix develop -c composer test
nix develop -c npm test

Without Nix, install PHP 8.4 or newer, Composer, Node.js 24, npm, and the Cypress system dependencies locally before running the same commands.

To install vendors via Docker instead of host PHP/Composer:

docker compose build php-fpm
docker compose run --rm --no-deps -u "$(id -u):$(id -g)" php-fpm composer update
docker compose run --rm --no-deps -u "$(id -u):$(id -g)" php-fpm npm install

Install or refresh Composer dependencies:

composer update

Run the PHP test suite:

composer test

Run PHPStan static analysis:

composer phpstan

Run PHP coverage:

composer coverage

Run the JavaScript unit tests and Cypress browser smoke test:

npm test

Run JavaScript coverage:

npm run test:coverage

Useful local checks:

composer validate --strict
git diff --check

The same maintained test, static-analysis, and coverage checks are also run by GitHub Actions on pushes and pull requests. Coverage runs generate Cobertura reports and upload them to GitHub Code Quality when workflow permissions allow.

The Docker stack uses PHP 8.5, Composer 2, and Node.js 24. It is maintained for dependency installation and ad hoc local commands; Nix remains the preferred environment for exact local parity with the documented checks.

About

The JavaScript validation for Symfony forms

Resources

Contributing

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Strip utm_, fbclid, gclid, etc. from all links on page\n(function() {\n var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content',\n 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid',\n 'ref', 'ref_src', 'source', 'medium', 'campaign'];\n \n function cleanUrl(url) {\n try {\n var u = new URL(url, window.location.origin);\n var changed = false;\n trackingParams.forEach(function(p) {\n if (u.searchParams.has(p)) {\n u.searchParams.delete(p);\n changed = true;\n }\n });\n return changed ? u.toString() : url;\n } catch (e) {\n return url;\n }\n }\n \n function cleanLinks() {\n document.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n \n cleanLinks();\n \n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1) {\n if (node.tagName === 'A') cleanLinks();\n node.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Remove Tracking Parameters from Links"); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + '
Skip to content

Repository files navigation

SvarohJsFormValidatorBundle

CITotal Downloads

SvarohJsFormValidatorBundle converts Symfony form validation metadata into JavaScript validation rules and attaches client-side validators to rendered forms.

Status

This branch targets the current PHP/Symfony baseline:

  • PHP 8.4+ runtime support; CI currently verifies PHP 8.4, 8.5, and 8.6 nightly
  • Symfony 8.x components as declared in composer.json
  • Twig 3
  • PHPUnit 13
  • PHPStan static analysis
  • PHP and JavaScript coverage thresholds
  • PSR-4 autoloading from src/

For older Symfony applications, use the historical branches of formapro/JsFormValidatorBundle:

Installation

Install the bundle with Composer:

composer require svaroh/jsformvalidator-bundle

If you are testing before the first tagged release, require the development branch explicitly:

composer require svaroh/jsformvalidator-bundle:"dev-main"

Register the bundle in config/bundles.php:

<?phpreturn [
// ...Svaroh\JsFormValidatorBundle\SvarohJsFormValidatorBundle::class => ['all' => true],
];

Configuration

Validation is enabled for every form by default. You can disable it globally:

# config/packages/svaroh_js_form_validator.yamlsvaroh_js_form_validator:
js_validation: false

Per-form and per-field disabling is documented in Disabling validation.

The browser validates a form on its own before this bundle sees the submit. You can opt into letting the bundle own that reporting:

# config/packages/svaroh_js_form_validator.yamlsvaroh_js_form_validator:
html5_validation: true

See HTML5 validation for what that changes.

UniqueEntity Route

If you use Symfony's Doctrine UniqueEntity constraint, import the bundle route:

# config/routes/svaroh_js_form_validator.yamlsvaroh_js_form_validator:
resource: '@SvarohJsFormValidatorBundle/Resources/config/routing.yaml'prefix: /svaroh_js_form_validator

Make sure your security configuration allows requests to this route.

The endpoint answers whether a matching record exists, but only for a field combination that a UniqueEntity constraint on the named entity class actually declares; the repository method comes from that constraint too. Everything else is refused. For the combinations you did declare unique it is still a public, unthrottled existence check, so restrict it in your firewall when that answer is sensitive, or point svaroh_js_form_validator.routing.check_unique_entity at your own controller as described in Checking entity uniqueness.

JavaScript Assets

There are two common ways to load the JavaScript files.

Add an Encore Entry

Encore
// ...
.addEntry('app', './assets/js/app.js')
+ .addEntry(+ 'SvarohJsFormValidator',+ './vendor/svaroh/jsformvalidator-bundle/src/Resources/public/js/SvarohJsFormValidatorWithJqueryInit.js'+ )
// ...
;

Then include the entry in your template:

{{ encore_entry_script_tags('SvarohJsFormValidator') }}
{{ encore_entry_script_tags('app') }}

Import From Your Main JavaScript

 import $ from 'jquery';
+import '../vendor/svaroh/jsformvalidator-bundle/src/Resources/public/js/SvarohJsFormValidator';+import '../vendor/svaroh/jsformvalidator-bundle/src/Resources/public/js/jquery.svarohjsformvalidator';

Adjust the import path to your application structure.

JavaScript Namespace

The library registers its constraints and its view transformers in a single global object named after the Svaroh\JsFormValidatorBundle PHP namespace:

Svaroh.constraints// constraints, keyed by class name without the separatorsSvaroh.transformers// view transformers, keyed the same way

Register your own classes there, as shown in custom constraints and custom data transformers. The object is created by the library, so run your registrations after its script is loaded.

Every bundled constraint and transformer is still exported under its own global name, such as window.SymfonyComponentValidatorConstraintsNotBlank, and a class your application defines as a global is still picked up. Both are deprecated and will be dropped in a future release.

Render Bundle Config And Form Models

After the scripts are loaded, render the generated config and queued form models:

{{ js_validator_config() }}
{{ init_js_validation() }}

If you need manual initialization for a specific form or event, see manual initialization.

Usage

After the bundle is registered, the form extension adds every enabled root form to an internal queue. Calling init_js_validation() renders JavaScript models for the queued forms:

{{ form_start(form) }}
{{ form_widget(form) }}
{{ form_end(form) }}
{{ init_js_validation(form) }}

You can pass false as the second argument to avoid automatic initialization on page load:

{{ init_js_validation(form, false) }}

Documentation

  1. Disabling validation
  2. Forms in sub-requests
  3. Manual initialization

Customization

This bundle finds related DOM elements for each Symfony form element and attaches an object validator to them. The validator contains the properties and methods that define the validation process for that form element.

If your form rendering is customized, start with custom rendering notes.

  1. Disable validation for a specified field
  2. Error display
  3. Get validation groups from a closure
  4. Getters validation
  5. The Callback constraint
  6. The Choice constraint callback
  7. Custom constraints
  8. Custom data transformers
  9. Checking entity uniqueness
  10. Form submit by JavaScript
  11. onValidate callback
  12. Run validation on custom event
  13. Collections validation
  14. Localized numbers
  15. HTML5 validation
  16. The NotBlank constraint
  17. Comparing a field with another field
  18. The Range constraint on dates
  19. Repeated fields
  20. One form rendered several times
  21. Validation events
  22. File uploads
  23. Pluralized messages

Development

The recommended development environment is the Nix shell:

nix develop

It provides the latest PHP available in the pinned nixpkgs input, currently PHP 8.5, with Xdebug coverage support, Composer, Node.js 24, npm, zip/unzip, and Cypress runtime libraries. If flakes are not enabled globally, prefix Nix commands with nix --extra-experimental-features "nix-command flakes".

For a fresh checkout:

composer update
npm install

If Cypress reports a missing binary, install it into the local cache:

npx cypress install

You can also run commands without entering the shell:

nix develop -c composer test
nix develop -c npm test

Without Nix, install PHP 8.4 or newer, Composer, Node.js 24, npm, and the Cypress system dependencies locally before running the same commands.

To install vendors via Docker instead of host PHP/Composer:

docker compose build php-fpm
docker compose run --rm --no-deps -u "$(id -u):$(id -g)" php-fpm composer update
docker compose run --rm --no-deps -u "$(id -u):$(id -g)" php-fpm npm install

Install or refresh Composer dependencies:

composer update

Run the PHP test suite:

composer test

Run PHPStan static analysis:

composer phpstan

Run PHP coverage:

composer coverage

Run the JavaScript unit tests and Cypress browser smoke test:

npm test

Run JavaScript coverage:

npm run test:coverage

Useful local checks:

composer validate --strict
git diff --check

The same maintained test, static-analysis, and coverage checks are also run by GitHub Actions on pushes and pull requests. Coverage runs generate Cobertura reports and upload them to GitHub Code Quality when workflow permissions allow.

The Docker stack uses PHP 8.5, Composer 2, and Node.js 24. It is maintained for dependency installation and ad hoc local commands; Nix remains the preferred environment for exact local parity with the documented checks.

About

The JavaScript validation for Symfony forms

Resources

Contributing

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Auto-enable theater mode on YouTube\n(function() {\n function tryTheater() {\n var btn = document.querySelector('button[aria-label=\"Theater mode\"], ytd-player #player button[title=\"Theater mode\"]');\n if (btn && !btn.classList.contains('activated')) {\n btn.click();\n }\n }\n \n // Try immediately\n tryTheater();\n \n // Try after navigation (SPA)\n var lastUrl = location.href;\n setInterval(function() {\n if (location.href !== lastUrl) {\n lastUrl = location.href;\n setTimeout(tryTheater, 500);\n }\n }, 1000);\n \n // Also try on player load\n var observer = new MutationObserver(tryTheater);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "YouTube Theater Mode Default"); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Repository files navigation

SvarohJsFormValidatorBundle

CITotal Downloads

SvarohJsFormValidatorBundle converts Symfony form validation metadata into JavaScript validation rules and attaches client-side validators to rendered forms.

Status

This branch targets the current PHP/Symfony baseline:

  • PHP 8.4+ runtime support; CI currently verifies PHP 8.4, 8.5, and 8.6 nightly
  • Symfony 8.x components as declared in composer.json
  • Twig 3
  • PHPUnit 13
  • PHPStan static analysis
  • PHP and JavaScript coverage thresholds
  • PSR-4 autoloading from src/

For older Symfony applications, use the historical branches of formapro/JsFormValidatorBundle:

Installation

Install the bundle with Composer:

composer require svaroh/jsformvalidator-bundle

If you are testing before the first tagged release, require the development branch explicitly:

composer require svaroh/jsformvalidator-bundle:"dev-main"

Register the bundle in config/bundles.php:

<?phpreturn [
// ...Svaroh\JsFormValidatorBundle\SvarohJsFormValidatorBundle::class => ['all' => true],
];

Configuration

Validation is enabled for every form by default. You can disable it globally:

# config/packages/svaroh_js_form_validator.yamlsvaroh_js_form_validator:
js_validation: false

Per-form and per-field disabling is documented in Disabling validation.

The browser validates a form on its own before this bundle sees the submit. You can opt into letting the bundle own that reporting:

# config/packages/svaroh_js_form_validator.yamlsvaroh_js_form_validator:
html5_validation: true

See HTML5 validation for what that changes.

UniqueEntity Route

If you use Symfony's Doctrine UniqueEntity constraint, import the bundle route:

# config/routes/svaroh_js_form_validator.yamlsvaroh_js_form_validator:
resource: '@SvarohJsFormValidatorBundle/Resources/config/routing.yaml'prefix: /svaroh_js_form_validator

Make sure your security configuration allows requests to this route.

The endpoint answers whether a matching record exists, but only for a field combination that a UniqueEntity constraint on the named entity class actually declares; the repository method comes from that constraint too. Everything else is refused. For the combinations you did declare unique it is still a public, unthrottled existence check, so restrict it in your firewall when that answer is sensitive, or point svaroh_js_form_validator.routing.check_unique_entity at your own controller as described in Checking entity uniqueness.

JavaScript Assets

There are two common ways to load the JavaScript files.

Add an Encore Entry

Encore
// ...
.addEntry('app', './assets/js/app.js')
+ .addEntry(+ 'SvarohJsFormValidator',+ './vendor/svaroh/jsformvalidator-bundle/src/Resources/public/js/SvarohJsFormValidatorWithJqueryInit.js'+ )
// ...
;

Then include the entry in your template:

{{ encore_entry_script_tags('SvarohJsFormValidator') }}
{{ encore_entry_script_tags('app') }}

Import From Your Main JavaScript

 import $ from 'jquery';
+import '../vendor/svaroh/jsformvalidator-bundle/src/Resources/public/js/SvarohJsFormValidator';+import '../vendor/svaroh/jsformvalidator-bundle/src/Resources/public/js/jquery.svarohjsformvalidator';

Adjust the import path to your application structure.

JavaScript Namespace

The library registers its constraints and its view transformers in a single global object named after the Svaroh\JsFormValidatorBundle PHP namespace:

Svaroh.constraints// constraints, keyed by class name without the separatorsSvaroh.transformers// view transformers, keyed the same way

Register your own classes there, as shown in custom constraints and custom data transformers. The object is created by the library, so run your registrations after its script is loaded.

Every bundled constraint and transformer is still exported under its own global name, such as window.SymfonyComponentValidatorConstraintsNotBlank, and a class your application defines as a global is still picked up. Both are deprecated and will be dropped in a future release.

Render Bundle Config And Form Models

After the scripts are loaded, render the generated config and queued form models:

{{ js_validator_config() }}
{{ init_js_validation() }}

If you need manual initialization for a specific form or event, see manual initialization.

Usage

After the bundle is registered, the form extension adds every enabled root form to an internal queue. Calling init_js_validation() renders JavaScript models for the queued forms:

{{ form_start(form) }}
{{ form_widget(form) }}
{{ form_end(form) }}
{{ init_js_validation(form) }}

You can pass false as the second argument to avoid automatic initialization on page load:

{{ init_js_validation(form, false) }}

Documentation

  1. Disabling validation
  2. Forms in sub-requests
  3. Manual initialization

Customization

This bundle finds related DOM elements for each Symfony form element and attaches an object validator to them. The validator contains the properties and methods that define the validation process for that form element.

If your form rendering is customized, start with custom rendering notes.

  1. Disable validation for a specified field
  2. Error display
  3. Get validation groups from a closure
  4. Getters validation
  5. The Callback constraint
  6. The Choice constraint callback
  7. Custom constraints
  8. Custom data transformers
  9. Checking entity uniqueness
  10. Form submit by JavaScript
  11. onValidate callback
  12. Run validation on custom event
  13. Collections validation
  14. Localized numbers
  15. HTML5 validation
  16. The NotBlank constraint
  17. Comparing a field with another field
  18. The Range constraint on dates
  19. Repeated fields
  20. One form rendered several times
  21. Validation events
  22. File uploads
  23. Pluralized messages

Development

The recommended development environment is the Nix shell:

nix develop

It provides the latest PHP available in the pinned nixpkgs input, currently PHP 8.5, with Xdebug coverage support, Composer, Node.js 24, npm, zip/unzip, and Cypress runtime libraries. If flakes are not enabled globally, prefix Nix commands with nix --extra-experimental-features "nix-command flakes".

For a fresh checkout:

composer update
npm install

If Cypress reports a missing binary, install it into the local cache:

npx cypress install

You can also run commands without entering the shell:

nix develop -c composer test
nix develop -c npm test

Without Nix, install PHP 8.4 or newer, Composer, Node.js 24, npm, and the Cypress system dependencies locally before running the same commands.

To install vendors via Docker instead of host PHP/Composer:

docker compose build php-fpm
docker compose run --rm --no-deps -u "$(id -u):$(id -g)" php-fpm composer update
docker compose run --rm --no-deps -u "$(id -u):$(id -g)" php-fpm npm install

Install or refresh Composer dependencies:

composer update

Run the PHP test suite:

composer test

Run PHPStan static analysis:

composer phpstan

Run PHP coverage:

composer coverage

Run the JavaScript unit tests and Cypress browser smoke test:

npm test

Run JavaScript coverage:

npm run test:coverage

Useful local checks:

composer validate --strict
git diff --check

The same maintained test, static-analysis, and coverage checks are also run by GitHub Actions on pushes and pull requests. Coverage runs generate Cobertura reports and upload them to GitHub Code Quality when workflow permissions allow.

The Docker stack uses PHP 8.5, Composer 2, and Node.js 24. It is maintained for dependency installation and ad hoc local commands; Nix remains the preferred environment for exact local parity with the documented checks.

About

The JavaScript validation for Symfony forms

Resources

Contributing

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Remove or un-stick sticky/fixed headers that block content\n(function() {\n function unstick() {\n document.querySelectorAll('header, nav, [role=\"banner\"], .header, .navbar, .sticky, .fixed-top, [style*=\"position: fixed\"], [style*=\"position:sticky\"]').forEach(function(el) {\n if (el.style.position === 'fixed' || el.style.position === 'sticky' || \n getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') {\n el.style.position = 'static';\n el.style.top = 'auto';\n el.style.zIndex = 'auto';\n }\n });\n }\n \n unstick();\n \n var observer = new MutationObserver(unstick);\n observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] });\n})();", "Kill Sticky Headers"); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Repository files navigation

SvarohJsFormValidatorBundle

CITotal Downloads

SvarohJsFormValidatorBundle converts Symfony form validation metadata into JavaScript validation rules and attaches client-side validators to rendered forms.

Status

This branch targets the current PHP/Symfony baseline:

  • PHP 8.4+ runtime support; CI currently verifies PHP 8.4, 8.5, and 8.6 nightly
  • Symfony 8.x components as declared in composer.json
  • Twig 3
  • PHPUnit 13
  • PHPStan static analysis
  • PHP and JavaScript coverage thresholds
  • PSR-4 autoloading from src/

For older Symfony applications, use the historical branches of formapro/JsFormValidatorBundle:

Installation

Install the bundle with Composer:

composer require svaroh/jsformvalidator-bundle

If you are testing before the first tagged release, require the development branch explicitly:

composer require svaroh/jsformvalidator-bundle:"dev-main"

Register the bundle in config/bundles.php:

<?phpreturn [
// ...Svaroh\JsFormValidatorBundle\SvarohJsFormValidatorBundle::class => ['all' => true],
];

Configuration

Validation is enabled for every form by default. You can disable it globally:

# config/packages/svaroh_js_form_validator.yamlsvaroh_js_form_validator:
js_validation: false

Per-form and per-field disabling is documented in Disabling validation.

The browser validates a form on its own before this bundle sees the submit. You can opt into letting the bundle own that reporting:

# config/packages/svaroh_js_form_validator.yamlsvaroh_js_form_validator:
html5_validation: true

See HTML5 validation for what that changes.

UniqueEntity Route

If you use Symfony's Doctrine UniqueEntity constraint, import the bundle route:

# config/routes/svaroh_js_form_validator.yamlsvaroh_js_form_validator:
resource: '@SvarohJsFormValidatorBundle/Resources/config/routing.yaml'prefix: /svaroh_js_form_validator

Make sure your security configuration allows requests to this route.

The endpoint answers whether a matching record exists, but only for a field combination that a UniqueEntity constraint on the named entity class actually declares; the repository method comes from that constraint too. Everything else is refused. For the combinations you did declare unique it is still a public, unthrottled existence check, so restrict it in your firewall when that answer is sensitive, or point svaroh_js_form_validator.routing.check_unique_entity at your own controller as described in Checking entity uniqueness.

JavaScript Assets

There are two common ways to load the JavaScript files.

Add an Encore Entry

Encore
// ...
.addEntry('app', './assets/js/app.js')
+ .addEntry(+ 'SvarohJsFormValidator',+ './vendor/svaroh/jsformvalidator-bundle/src/Resources/public/js/SvarohJsFormValidatorWithJqueryInit.js'+ )
// ...
;

Then include the entry in your template:

{{ encore_entry_script_tags('SvarohJsFormValidator') }}
{{ encore_entry_script_tags('app') }}

Import From Your Main JavaScript

 import $ from 'jquery';
+import '../vendor/svaroh/jsformvalidator-bundle/src/Resources/public/js/SvarohJsFormValidator';+import '../vendor/svaroh/jsformvalidator-bundle/src/Resources/public/js/jquery.svarohjsformvalidator';

Adjust the import path to your application structure.

JavaScript Namespace

The library registers its constraints and its view transformers in a single global object named after the Svaroh\JsFormValidatorBundle PHP namespace:

Svaroh.constraints// constraints, keyed by class name without the separatorsSvaroh.transformers// view transformers, keyed the same way

Register your own classes there, as shown in custom constraints and custom data transformers. The object is created by the library, so run your registrations after its script is loaded.

Every bundled constraint and transformer is still exported under its own global name, such as window.SymfonyComponentValidatorConstraintsNotBlank, and a class your application defines as a global is still picked up. Both are deprecated and will be dropped in a future release.

Render Bundle Config And Form Models

After the scripts are loaded, render the generated config and queued form models:

{{ js_validator_config() }}
{{ init_js_validation() }}

If you need manual initialization for a specific form or event, see manual initialization.

Usage

After the bundle is registered, the form extension adds every enabled root form to an internal queue. Calling init_js_validation() renders JavaScript models for the queued forms:

{{ form_start(form) }}
{{ form_widget(form) }}
{{ form_end(form) }}
{{ init_js_validation(form) }}

You can pass false as the second argument to avoid automatic initialization on page load:

{{ init_js_validation(form, false) }}

Documentation

  1. Disabling validation
  2. Forms in sub-requests
  3. Manual initialization

Customization

This bundle finds related DOM elements for each Symfony form element and attaches an object validator to them. The validator contains the properties and methods that define the validation process for that form element.

If your form rendering is customized, start with custom rendering notes.

  1. Disable validation for a specified field
  2. Error display
  3. Get validation groups from a closure
  4. Getters validation
  5. The Callback constraint
  6. The Choice constraint callback
  7. Custom constraints
  8. Custom data transformers
  9. Checking entity uniqueness
  10. Form submit by JavaScript
  11. onValidate callback
  12. Run validation on custom event
  13. Collections validation
  14. Localized numbers
  15. HTML5 validation
  16. The NotBlank constraint
  17. Comparing a field with another field
  18. The Range constraint on dates
  19. Repeated fields
  20. One form rendered several times
  21. Validation events
  22. File uploads
  23. Pluralized messages

Development

The recommended development environment is the Nix shell:

nix develop

It provides the latest PHP available in the pinned nixpkgs input, currently PHP 8.5, with Xdebug coverage support, Composer, Node.js 24, npm, zip/unzip, and Cypress runtime libraries. If flakes are not enabled globally, prefix Nix commands with nix --extra-experimental-features "nix-command flakes".

For a fresh checkout:

composer update
npm install

If Cypress reports a missing binary, install it into the local cache:

npx cypress install

You can also run commands without entering the shell:

nix develop -c composer test
nix develop -c npm test

Without Nix, install PHP 8.4 or newer, Composer, Node.js 24, npm, and the Cypress system dependencies locally before running the same commands.

To install vendors via Docker instead of host PHP/Composer:

docker compose build php-fpm
docker compose run --rm --no-deps -u "$(id -u):$(id -g)" php-fpm composer update
docker compose run --rm --no-deps -u "$(id -u):$(id -g)" php-fpm npm install

Install or refresh Composer dependencies:

composer update

Run the PHP test suite:

composer test

Run PHPStan static analysis:

composer phpstan

Run PHP coverage:

composer coverage

Run the JavaScript unit tests and Cypress browser smoke test:

npm test

Run JavaScript coverage:

npm run test:coverage

Useful local checks:

composer validate --strict
git diff --check

The same maintained test, static-analysis, and coverage checks are also run by GitHub Actions on pushes and pull requests. Coverage runs generate Cobertura reports and upload them to GitHub Code Quality when workflow permissions allow.

The Docker stack uses PHP 8.5, Composer 2, and Node.js 24. It is maintained for dependency installation and ad hoc local commands; Nix remains the preferred environment for exact local parity with the documented checks.

About

The JavaScript validation for Symfony forms

Resources

Contributing

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Universal Dark Mode - works on any site\n(function() {\n var enabled = true;\n \n function applyDarkMode() {\n if (!enabled) return;\n \n // Create style element if it doesn't exist\n var style = document.getElementById('universal-dark-mode-style');\n if (!style) {\n style = document.createElement('style');\n style.id = 'universal-dark-mode-style';\n document.head.appendChild(style);\n }\n \n // Dark mode CSS - inverts colors but preserves images/video\n style.textContent = '\n /* Invert everything except media */\n html {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #1a1a2e !important;\n }\n \n /* Restore images, videos, iframes, canvas */\n img, video, iframe, canvas, svg, picture, [style*=\"background-image\"] {\n filter: invert(1) hue-rotate(180deg) !important;\n }\n \n /* Preserve specific elements that should not be inverted */\n .no-dark-mode, .no-dark-mode *,\n [data-theme=\"light\"], [data-theme=\"light\"],\n .ace_editor, .ace_editor *,\n .CodeMirror, .CodeMirror *,\n .monaco-editor, .monaco-editor *,\n .markdown-body pre, .markdown-body pre *,\n .highlight, .highlight *,\n pre code, pre code * {\n filter: none !important;\n }\n \n /* Fix common UI elements */\n .modal, .popup, .dropdown-menu, .tooltip, .popover {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #2d2d44 !important;\n border-color: #444 !important;\n }\n \n /* Scrollbars */\n ::-webkit-scrollbar { background: #1a1a2e !important; }\n ::-webkit-scrollbar-thumb { background: #444 !important; }\n ::-webkit-scrollbar-thumb:hover { background: #555 !important; }\n \n /* Selection */\n ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ';\n }\n \n function removeDarkMode() {\n var style = document.getElementById('universal-dark-mode-style');\n if (style) style.remove();\n }\n \n // Toggle with Alt+Shift+D\n document.addEventListener('keydown', function(e) {\n if (e.altKey && e.shiftKey && e.key === 'D') {\n e.preventDefault();\n enabled = !enabled;\n if (enabled) {\n applyDarkMode();\n console.log('[Universal Dark Mode] Enabled');\n } else {\n removeDarkMode();\n console.log('[Universal Dark Mode] Disabled');\n }\n }\n });\n \n // Apply on load\n applyDarkMode();\n \n // Re-apply on dynamic content\n var observer = new MutationObserver(function(mutations) {\n if (enabled && !document.getElementById('universal-dark-mode-style')) {\n applyDarkMode();\n }\n });\n observer.observe(document.head, { childList: true });\n \n console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle');\n})();", "Universal Dark Mode"); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })();
Skip to content

Repository files navigation

SvarohJsFormValidatorBundle

CITotal Downloads

SvarohJsFormValidatorBundle converts Symfony form validation metadata into JavaScript validation rules and attaches client-side validators to rendered forms.

Status

This branch targets the current PHP/Symfony baseline:

  • PHP 8.4+ runtime support; CI currently verifies PHP 8.4, 8.5, and 8.6 nightly
  • Symfony 8.x components as declared in composer.json
  • Twig 3
  • PHPUnit 13
  • PHPStan static analysis
  • PHP and JavaScript coverage thresholds
  • PSR-4 autoloading from src/

For older Symfony applications, use the historical branches of formapro/JsFormValidatorBundle:

Installation

Install the bundle with Composer:

composer require svaroh/jsformvalidator-bundle

If you are testing before the first tagged release, require the development branch explicitly:

composer require svaroh/jsformvalidator-bundle:"dev-main"

Register the bundle in config/bundles.php:

<?phpreturn [
// ...Svaroh\JsFormValidatorBundle\SvarohJsFormValidatorBundle::class => ['all' => true],
];

Configuration

Validation is enabled for every form by default. You can disable it globally:

# config/packages/svaroh_js_form_validator.yamlsvaroh_js_form_validator:
js_validation: false

Per-form and per-field disabling is documented in Disabling validation.

The browser validates a form on its own before this bundle sees the submit. You can opt into letting the bundle own that reporting:

# config/packages/svaroh_js_form_validator.yamlsvaroh_js_form_validator:
html5_validation: true

See HTML5 validation for what that changes.

UniqueEntity Route

If you use Symfony's Doctrine UniqueEntity constraint, import the bundle route:

# config/routes/svaroh_js_form_validator.yamlsvaroh_js_form_validator:
resource: '@SvarohJsFormValidatorBundle/Resources/config/routing.yaml'prefix: /svaroh_js_form_validator

Make sure your security configuration allows requests to this route.

The endpoint answers whether a matching record exists, but only for a field combination that a UniqueEntity constraint on the named entity class actually declares; the repository method comes from that constraint too. Everything else is refused. For the combinations you did declare unique it is still a public, unthrottled existence check, so restrict it in your firewall when that answer is sensitive, or point svaroh_js_form_validator.routing.check_unique_entity at your own controller as described in Checking entity uniqueness.

JavaScript Assets

There are two common ways to load the JavaScript files.

Add an Encore Entry

Encore
// ...
.addEntry('app', './assets/js/app.js')
+ .addEntry(+ 'SvarohJsFormValidator',+ './vendor/svaroh/jsformvalidator-bundle/src/Resources/public/js/SvarohJsFormValidatorWithJqueryInit.js'+ )
// ...
;

Then include the entry in your template:

{{ encore_entry_script_tags('SvarohJsFormValidator') }}
{{ encore_entry_script_tags('app') }}

Import From Your Main JavaScript

 import $ from 'jquery';
+import '../vendor/svaroh/jsformvalidator-bundle/src/Resources/public/js/SvarohJsFormValidator';+import '../vendor/svaroh/jsformvalidator-bundle/src/Resources/public/js/jquery.svarohjsformvalidator';

Adjust the import path to your application structure.

JavaScript Namespace

The library registers its constraints and its view transformers in a single global object named after the Svaroh\JsFormValidatorBundle PHP namespace:

Svaroh.constraints// constraints, keyed by class name without the separatorsSvaroh.transformers// view transformers, keyed the same way

Register your own classes there, as shown in custom constraints and custom data transformers. The object is created by the library, so run your registrations after its script is loaded.

Every bundled constraint and transformer is still exported under its own global name, such as window.SymfonyComponentValidatorConstraintsNotBlank, and a class your application defines as a global is still picked up. Both are deprecated and will be dropped in a future release.

Render Bundle Config And Form Models

After the scripts are loaded, render the generated config and queued form models:

{{ js_validator_config() }}
{{ init_js_validation() }}

If you need manual initialization for a specific form or event, see manual initialization.

Usage

After the bundle is registered, the form extension adds every enabled root form to an internal queue. Calling init_js_validation() renders JavaScript models for the queued forms:

{{ form_start(form) }}
{{ form_widget(form) }}
{{ form_end(form) }}
{{ init_js_validation(form) }}

You can pass false as the second argument to avoid automatic initialization on page load:

{{ init_js_validation(form, false) }}

Documentation

  1. Disabling validation
  2. Forms in sub-requests
  3. Manual initialization

Customization

This bundle finds related DOM elements for each Symfony form element and attaches an object validator to them. The validator contains the properties and methods that define the validation process for that form element.

If your form rendering is customized, start with custom rendering notes.

  1. Disable validation for a specified field
  2. Error display
  3. Get validation groups from a closure
  4. Getters validation
  5. The Callback constraint
  6. The Choice constraint callback
  7. Custom constraints
  8. Custom data transformers
  9. Checking entity uniqueness
  10. Form submit by JavaScript
  11. onValidate callback
  12. Run validation on custom event
  13. Collections validation
  14. Localized numbers
  15. HTML5 validation
  16. The NotBlank constraint
  17. Comparing a field with another field
  18. The Range constraint on dates
  19. Repeated fields
  20. One form rendered several times
  21. Validation events
  22. File uploads
  23. Pluralized messages

Development

The recommended development environment is the Nix shell:

nix develop

It provides the latest PHP available in the pinned nixpkgs input, currently PHP 8.5, with Xdebug coverage support, Composer, Node.js 24, npm, zip/unzip, and Cypress runtime libraries. If flakes are not enabled globally, prefix Nix commands with nix --extra-experimental-features "nix-command flakes".

For a fresh checkout:

composer update
npm install

If Cypress reports a missing binary, install it into the local cache:

npx cypress install

You can also run commands without entering the shell:

nix develop -c composer test
nix develop -c npm test

Without Nix, install PHP 8.4 or newer, Composer, Node.js 24, npm, and the Cypress system dependencies locally before running the same commands.

To install vendors via Docker instead of host PHP/Composer:

docker compose build php-fpm
docker compose run --rm --no-deps -u "$(id -u):$(id -g)" php-fpm composer update
docker compose run --rm --no-deps -u "$(id -u):$(id -g)" php-fpm npm install

Install or refresh Composer dependencies:

composer update

Run the PHP test suite:

composer test

Run PHPStan static analysis:

composer phpstan

Run PHP coverage:

composer coverage

Run the JavaScript unit tests and Cypress browser smoke test:

npm test

Run JavaScript coverage:

npm run test:coverage

Useful local checks:

composer validate --strict
git diff --check

The same maintained test, static-analysis, and coverage checks are also run by GitHub Actions on pushes and pull requests. Coverage runs generate Cobertura reports and upload them to GitHub Code Quality when workflow permissions allow.

The Docker stack uses PHP 8.5, Composer 2, and Node.js 24. It is maintained for dependency installation and ad hoc local commands; Nix remains the preferred environment for exact local parity with the documented checks.

About

The JavaScript validation for Symfony forms

Resources

Contributing

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages